{"record":{"id":"20e8a4ce995dec8a","repo":"HKUDS/Vibe-Trading","slug":"panel-missing-close-cannot-derive-forward-retu","errorCode":null,"errorMessage":"panel missing 'close' — cannot derive forward returns","messagePattern":"panel missing 'close' — cannot derive forward returns","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/alpha_bench_tool.py","lineNumber":675,"sourceCode":"                break\n            delay = base_delay * (2 ** attempt)\n            logger.debug(\"retry %d/%d after %.1fs: %s\", attempt + 1, tries, delay, exc)\n            time.sleep(delay)\n    if last_exc is not None:\n        logger.warning(\"retry exhausted: %s\", last_exc)\n    return None\n\n\n# ---------------------------------------------------------------------------\n# Per-alpha IC bench\n# ---------------------------------------------------------------------------\n\n\ndef _compute_forward_returns(panel: dict[str, pd.DataFrame]) -> pd.DataFrame:\n    \"\"\"Next-bar forward simple returns from close, aligned to factor timestamp.\"\"\"\n    close = panel.get(\"close\")\n    if close is None:\n        raise ValueError(\"panel missing 'close' — cannot derive forward returns\")\n    # Next-period return aligned to current row (use t+1 close, shift back).\n    fwd = close.pct_change(fill_method=None).shift(-1)\n    return fwd\n\n\ndef _bench_one_alpha(\n    registry: Any,\n    alpha_id: str,\n    panel: dict[str, pd.DataFrame],\n    return_df: pd.DataFrame,\n) -> dict[str, Any]:\n    \"\"\"Compute IC stats for one alpha. Returns a dict, may raise SkipAlpha / RegistryError.\"\"\"\n    from src.factors.factor_analysis_core import compute_ic_series  # local import\n\n    factor_df = registry.compute(alpha_id, panel)\n    ic_series = compute_ic_series(factor_df, return_df)\n    if ic_series.empty:\n        raise RuntimeError(","sourceCodeStart":657,"sourceCodeEnd":693,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/alpha_bench_tool.py#L657-L693","documentation":"_compute_forward_returns computes next-bar simple returns from panel['close']; if the panel dict has no 'close' key it cannot proceed and raises this ValueError.","triggerScenarios":"Passing a hand-built or cached panel dict to run_bench/_bench flows that lacks the 'close' DataFrame (e.g. only 'open'/'volume' loaded, or a malformed cache pickle).","commonSituations":"Custom data loaders that omit the close frame; stale/corrupt ~/.vibe-trading cache pickles from an older panel format; constructing panels from CSV exports that rename columns.","solutions":["Ensure the loader produces panel['close'] as a dates x symbols DataFrame","Delete the stale cache pickle under ~/.vibe-trading/cache and reload","If building panels manually, copy the shape produced by _load_universe_panel"],"exampleFix":"# before\npanel = {'open': open_df}          # missing 'close'\n# after\npanel = {'open': open_df, 'close': close_df}","handlingStrategy":"validation","validationCode":"assert isinstance(panel, dict) and 'close' in panel and not panel['close'].empty","typeGuard":"def has_close_panel(panel: dict) -> bool:\n    return isinstance(panel, dict) and isinstance(panel.get('close'), pd.DataFrame) and not panel['close'].empty","tryCatchPattern":"try:\n    _compute_forward_returns(panel)\nexcept ValueError as e:\n    if \"missing 'close'\" in str(e):\n        panel['close'] = rebuild_close_frame()","preventionTips":["Validate panel shape right after loading/caching","Version cache pickles and invalidate on format changes"],"tags":["data-validation","panel","alpha-bench"],"backgroundTag":"missing-required-dataframe-column","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}