HKUDS/Vibe-Trading · error · ValueError
delay requires n >= 1 (lookahead ban)
Error message
delay requires n >= 1 (lookahead ban)
What it means
alpha_048.py raises this ValueError from _delay when n < 1, upholding the no-lookahead invariant before calling df.shift. The file also neutralizes by industry (_ind_neutralize), but the failure is purely in the lag argument.
Source
Thrown at agent/src/factors/zoo/alpha101/alpha_048.py:62
'extras_required': [],
'requires_sector': True,
'universe': ['equity_us', 'equity_in', 'equity_kr'],
'frequency': ['1D'],
'decay_horizon': 5,
'min_warmup_bars': 251,
'notes': "Industry neutralization implemented via per-row sector group demean (panel['sector'] required). When sector tag is absent the registry rejects via SkipAlpha; the compute() also has a degraded global demean fallback. This is a partial approximation of the paper's IndClass.industry/subindustry/sector neutralization.",
}
def _rolling_sum(df: pd.DataFrame, n: int) -> pd.DataFrame:
"""Rolling window sum; warmup -> NaN."""
return df.rolling(window=n, min_periods=n).sum()
def _delay(df: pd.DataFrame, n: int) -> pd.DataFrame:
"""Backward shift by n (lookahead-safe; n>=1 required)."""
if n < 1:
raise ValueError("delay requires n >= 1 (lookahead ban)")
return df.shift(n)
def _ind_neutralize(x: pd.DataFrame, panel: dict) -> pd.DataFrame:
"""Industry/sector neutralize: subtract the row-wise sector group mean.
If panel has a 'sector' DataFrame (same shape as close), subtract the
per-sector cross-sectional mean per row. If absent, degrade to global
cross-sectional demean (subtract row mean). This is a degraded fallback
relative to the paper's industry/subindustry neutralization; see notes.
"""
sector_df = panel.get("sector")
if sector_df is None:
row_mean = x.mean(axis=1, skipna=True)
return x.sub(row_mean, axis=0)
# Per-row group demean. Iterate rows; numpy-fast enough for small panels.
arr = x.to_numpy(dtype=np.float64, na_value=np.nan).copy()
sec_arr = sector_df.to_numpy()View on GitHub (pinned to 80ffdda44c)
Solutions
- Inspect every _delay call site in alpha_048.py; fix lags < 1
- Pass the frame directly when 'today' is meant
- Reject lag parameters < 1 at the config/boundary layer
- Add a unit test for compute() with a toy panel
Example fix
// before raw = _delay(close, 0) / _delay(close, 2) // after raw = close / _delay(close, 2)
Defensive patterns
Strategy: validation
Validate before calling
if lag < 1:
raise ValueError(f"delay lag must be >= 1, got {lag}")
neutral = _ind_neutralize(_delay(close, lag), panel) Type guard
def is_valid_delay(n: int) -> bool:
return isinstance(n, int) and not isinstance(n, bool) and n >= 1 Prevention
- Use the raw frame for current-bar access
- Validate config lags before invoking the zoo
- Smoke-test each alpha after lag edits
When it happens
Trigger: compute() for alpha #48 passes a non-positive lag to _delay while assembling the inputs to _ind_neutralize — e.g. `_delay(x, n)` with n == 0 from a mistyped constant.
Common situations: Porting Alpha#48 (industry-neutral formulation) and miswriting one lag; refactors that rewrite lag arithmetic; config-driven lags permitting 0.
Related errors
- delay requires n >= 1 (lookahead ban)
- delay requires n >= 1 (lookahead ban)
- delay requires n >= 1 (lookahead ban)
- delay requires n >= 1 (lookahead ban)
- delay requires n >= 1 (lookahead ban)
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/bf1e7d0917f4da02.
Report an issue: GitHub.