HKUDS/Vibe-Trading · error · ValueError

panel missing 'close' — cannot derive forward returns

Error message

panel missing 'close' — cannot derive forward returns

What it means

_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.

Source

Thrown at agent/src/tools/alpha_bench_tool.py:675

                break
            delay = base_delay * (2 ** attempt)
            logger.debug("retry %d/%d after %.1fs: %s", attempt + 1, tries, delay, exc)
            time.sleep(delay)
    if last_exc is not None:
        logger.warning("retry exhausted: %s", last_exc)
    return None


# ---------------------------------------------------------------------------
# Per-alpha IC bench
# ---------------------------------------------------------------------------


def _compute_forward_returns(panel: dict[str, pd.DataFrame]) -> pd.DataFrame:
    """Next-bar forward simple returns from close, aligned to factor timestamp."""
    close = panel.get("close")
    if close is None:
        raise ValueError("panel missing 'close' — cannot derive forward returns")
    # Next-period return aligned to current row (use t+1 close, shift back).
    fwd = close.pct_change(fill_method=None).shift(-1)
    return fwd


def _bench_one_alpha(
    registry: Any,
    alpha_id: str,
    panel: dict[str, pd.DataFrame],
    return_df: pd.DataFrame,
) -> dict[str, Any]:
    """Compute IC stats for one alpha. Returns a dict, may raise SkipAlpha / RegistryError."""
    from src.factors.factor_analysis_core import compute_ic_series  # local import

    factor_df = registry.compute(alpha_id, panel)
    ic_series = compute_ic_series(factor_df, return_df)
    if ic_series.empty:
        raise RuntimeError(

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Ensure the loader produces panel['close'] as a dates x symbols DataFrame
  2. Delete the stale cache pickle under ~/.vibe-trading/cache and reload
  3. If building panels manually, copy the shape produced by _load_universe_panel

Example fix

# before
panel = {'open': open_df}          # missing 'close'
# after
panel = {'open': open_df, 'close': close_df}
Defensive patterns

Strategy: validation

Validate before calling

assert isinstance(panel, dict) and 'close' in panel and not panel['close'].empty

Type guard

def has_close_panel(panel: dict) -> bool:
    return isinstance(panel, dict) and isinstance(panel.get('close'), pd.DataFrame) and not panel['close'].empty

Try / catch

try:
    _compute_forward_returns(panel)
except ValueError as e:
    if "missing 'close'" in str(e):
        panel['close'] = rebuild_close_frame()

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/20e8a4ce995dec8a. Report an issue: GitHub.