{"record":{"id":"c58201ae450f7f48","repo":"HKUDS/Vibe-Trading","slug":"delay-requires-n-1-lookahead-ban-c58201","errorCode":null,"errorMessage":"delay requires n >= 1 (lookahead ban)","messagePattern":"delay requires n >= 1 \\(lookahead ban\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/factors/zoo/alpha101/alpha_047.py","lineNumber":62,"sourceCode":"    'extras_required': [],\n    'requires_sector': False,\n    'universe': ['equity_us', 'equity_in', 'equity_kr'],\n    'frequency': ['1D'],\n    'decay_horizon': 5,\n    'min_warmup_bars': 25,\n    'notes': '',\n}\n\n\ndef _rolling_sum(df: pd.DataFrame, n: int) -> pd.DataFrame:\n    \"\"\"Rolling window sum; warmup -> NaN.\"\"\"\n    return df.rolling(window=n, min_periods=n).sum()\n\n\ndef _delay(df: pd.DataFrame, n: int) -> pd.DataFrame:\n    \"\"\"Backward shift by n (lookahead-safe; n>=1 required).\"\"\"\n    if n < 1:\n        raise ValueError(\"delay requires n >= 1 (lookahead ban)\")\n    return df.shift(n)\n\n\ndef _make_one(ref: pd.DataFrame) -> pd.DataFrame:\n    \"\"\"A DataFrame of 1.0 with the same shape/index/columns as ``ref``.\"\"\"\n    return pd.DataFrame(1.0, index=ref.index, columns=ref.columns)\n\n\ndef compute(panel: dict) -> pd.DataFrame:\n    \"\"\"Compute the alpha on the OHLCV+ panel and return a wide DataFrame.\"\"\"\n    close = panel[\"close\"]\n    high = panel[\"high\"]\n    volume = panel[\"volume\"]\n    vwap = panel[\"vwap\"]\n    adv20 = ts_mean(volume, 20)\n\n    # Helper aliases (local closures keep the file standalone & purity-safe).\n    rolling_sum = _rolling_sum","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/factors/zoo/alpha101/alpha_047.py#L44-L80","documentation":"In alpha_047.py, _delay guards df.shift(n) with an explicit n >= 1 requirement (lookahead ban) and raises ValueError otherwise. The helper sits next to _make_one, used to construct constant frames for the alpha's where/ternary logic.","triggerScenarios":"Any _delay(..., 0) (or negative) call in alpha #47's compute chain — typically a lag typo or derived expression hitting 0.","commonSituations":"Hand-porting Alpha#47's conditional expression and dropping a lag to 0; batch-editing alpha files; parameterized backtests with unvalidated lag lists.","solutions":["Read each _delay call in alpha_047.py and correct non-positive lags","Substitute the raw DataFrame where delay 0 is intended","Validate lag configs at load time (reject < 1 loudly and early)","Re-run compute on a fixture panel to verify"],"exampleFix":"// before\nx = _delay(close, 0) * _delay(close, 1)\n// after\nx = close * _delay(close, 1)","handlingStrategy":"validation","validationCode":"lags = [int(l) for l in lags]\nbad = [l for l in lags if l < 1]\nif bad:\n    raise ValueError(f\"lags must be >= 1, offending values: {bad}\")","typeGuard":"def is_valid_delay(n: int) -> bool:\n    return isinstance(n, int) and not isinstance(n, bool) and n >= 1","tryCatchPattern":null,"preventionTips":["Replace _delay(x, 0) with x","Start lag ranges at 1 in tuning scripts","Pin lag constants in tests"],"tags":["pandas","alpha101","lookahead-bias","input-validation"],"backgroundTag":"invalid-window-argument","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}