Phase 9 — per-stock baseline + L47 bug + news audit
Phase 9 had two threads: a per-stock harness diagnostic (9.A) and a hand-audit of the news-channel anti-edge from L46 (9.B).
9.A — the L47 bug
_per_stock_zscore used sigma.clamp(min=1e-8) which blew up for warmup-period features (vol_60d ≈ 0 for the first 60 days → tiny std → 10^7+ z-scores). LayerNorm inside StrategyNet absorbed the scaling for the honest run (so it looked OK at -0.4 Sharpe) but DROWNED the cheat column (~1.0 scale) inside look_ahead_cheat_test. Plus _run_per_stock passed already-z-scored features to leakage tests, causing transform_fn to corrupt the head columns.
Both fixed:
clamp(min=1e-3)— keeps warmup-period z-scores in a sane range.- Pass RAW features to cheat tests inside
_run_per_stockso the cheat columns travel through the standardisation as designed.
Post-fix: look_ahead_cheat = +30 (was -2.28). The harness is now trustworthy for per-stock evaluation.
9.B — the news-channel audit (L48)
Hand-walked the L46 anti-edge cluster from raw GDELT row → feature_engineering_v2 → model input. Findings:
corr(gkg_avg_tone_t, next_ret)= -0.0164 overall (N=25,795)- Strengthens to -0.11 at
|tone| > 5and|tone| > 8 - Per-ticker mean correlation = -0.023 (median -0.021)
- Sign-alignment at strong-tone cells (
|tone| > 8): 44.4% (vs 50% noise)
No code bug — feature_engineering_v2 preserves sign, magnitude, and date alignment (Audit 2 + Audit 4). The L46 -3.4 Sharpe cluster was the model correctly extracting this weak contrarian signal, just at a magnitude too large to be honest at this sample size.
Conclusion: GDELT daily news on Indian large-caps is a weak contrarian signal, not momentum. Plausible mechanism: news reports react to returns rather than predict them — by the time GDELT indexes a story, the move has already happened, so the next day mean-reverts.
Practical implication: explicit -1 * tone features would produce honest Sharpe ~0.0-0.1 after costs, in the noise band. Not enough to be the project's edge, but a real signed finding worth preserving as a feature transform when news is used downstream.
What it produced
L47 (harness bug now closed) and L48 (the news channel characterised). The per-stock harness diagnostic also produced one of the two leakage-clean noise-band results documented on Best candidates: nifty_50_per_stock_momentum at Sharpe -0.51.