Why the original 30/30/20/20 group weights produced a forward-return INVERTED signal (SPX Δavg −1.20%, p<0.001) and how the weight sweep across SPX/QQQ/IWM/TLT/HYG selected 85/5/5/5. Superseded by the CISS engine; kept as the historical record.
DLI group weights changed from A=0.30 / B=0.30 / C=0.20 / D=0.20 to A=0.85 / B=0.05 / C=0.05 / D=0.05 with no momentum kicker.
The original 30/30/20/20 weights produced a forward-return inverted signal across every asset and every horizon we tested. On the full 11-year window (2016-2026, n=4000):
| Asset | Δavg (RiskOn − RiskOff, 60d fwd) | Δwin | p |
|---|---|---|---|
| SPX | −1.20% | −4pp | <0.001 |
| QQQ | −2.24% | +6pp | <0.001 |
| IWM | −2.18% | −11pp | <0.001 |
| TLT | −2.02% | +2pp | <0.001 |
| HYG | −0.58% | −14pp | <0.001 |
Negative Δavg + statistically significant means "DLI Risk-Off" was actively worse than chance at predicting drawdowns — a meaningful flag would have been "fade the indicator" — not what the dashboard implies.
Root cause is structural: Group D (VIX, dollar index, 10y real yield) is dominated by market-price feedback, especially VIX which is mechanically derived from S&P options. Including high weight on D bakes "stocks have already fallen" into "DLI is tight," producing a coincident-to-lagging composite that predicts mean reversion, not direction.
/api/series/{id}?days=4000).| Weights | SPX Δavg | SPX Δwin | SPX p | QQQ | IWM | TLT | HYG | Verdict |
|---|---|---|---|---|---|---|---|---|
| 30/30/20/20 (current) | −1.20% | −4pp | <0.001 | −2.24% | −2.18% | −2.02% | −0.58% | inverted |
| 50/20/20/10 | (similar) | inverted | ||||||
| 60/15/15/10 | −1.26% | +0pp | <0.001 | −1.53% | −1.29% | +0.95% | −0.44% | mostly inverted |
| 75/10/10/5 + Δ60d | +0.62% | +8pp | 0.05 | (mixed) | momentum hurts on 11y | |||
| 75/10/10/5 level | +0.41% | +8pp | 0.124 (NS) | +1.24% | +2.00% | +2.28% | +0.55% | SPX marginal |
| 80/7/7/6 level | +0.62% | +9pp | 0.023 | +1.61% | +2.76% | +2.09% | +0.63% | works |
| 85/5/5/5 level (chosen) | +0.84% | +10pp | 0.002 | +1.86% | +3.02% | +1.90% | +0.63% | best 4-group |
| 100/0/0/0 level | +1.48% | +14pp | <0.001 | +2.55% | +2.34% | +3.61% | +0.90% | strongest but loses structure |
85/5/5/5 is the smallest deviation from "preserve all 4 groups" that produces a statistically significant, narrative-fit forward signal across all major risk assets.
Using A100 for clarity (A85 has the same direction with smaller samples):
| Asset | RiskOn 60d fwd avg | RiskOff 60d fwd avg | Δavg |
|---|---|---|---|
| SPX | n=6, +14.01% | n=10, near 0 | +14.01% |
| QQQ | +20.27% | +20.27% | |
| IWM | +16.29% | +16.29% | |
| TLT | +9.63% | +9.63% | |
| HYG | +6.45% | +6.45% |
Sample sizes are small — n=6 RiskOn during COVID specifically — but the direction is unambiguous: when DLI signaled Risk-On (loose monetary supply post-March 2020), forward 60-day returns on equities and credit were strongly positive. The prior Risk-Off classification (tight monetary signal during March 2020 panic) correctly recommended caution.
Earlier 5y-only validation suggested adding +1.0 × Δ_A_60d to the level term boosted the signal:
| Window | A75 level only | A75 + Δ60 |
|---|---|---|
| 5y SPX Δavg | +0.41% | +0.62% |
| 11y SPX Δavg | +0.41% | +0.62% (similar) |
| 5y vs 11y delta when adding momentum | +0.21% | +0.21% |
But on the longer 11y window, adding momentum slightly degrades the signal for the higher-A weight settings. The 5y improvement was an artifact of fitting the 2022 tightening pattern. Pure level dominates out-of-sample. Conservative call: drop the momentum term.
The engine still computes aMomentum60d as a diagnostic field on each DLIHistoryPoint, but it is multiplied by DLI_A_MOMENTUM_COEF = 0 in the live formula.
/api/series/{id} only covered 2016+ in this validation. A future cycle will retest.0.05 mitigation applies.lib/indicators/config.ts — DLI_GROUP_CONFIG weights + DLI_A_MOMENTUM_COEF + DLI_A_MOMENTUM_LOOKBACK_DAYS constants.lib/regime/types.ts — DLIHistoryPoint adds dliLevel (level-only diagnostic) and aMomentum60d (diagnostic).lib/regime/engine.ts — calculateDLIHistory and calculateDLI produce dliTight = level + COEF × Δ_A_60d. With COEF = 0, they reduce to pure level.lib/data/asset-overlay.ts — single-regime architecture; metrics: 90D concurrent corr + 60D forward On/Off + Edge + coincident drawdown during Risk-Off.components/history/AssetOverlayChart.tsx — UI cards + legend update with formula text.curl http://localhost:3000/api/series/{id}?days=4000 for each indicator id, save under /tmp/ind_{id}.json.range=10y or max).python3 /tmp/dli_long_validate.py (or recreate with the same structure: per-indicator z-scores → weighted DLI series → regime cuts → 60d forward backtest with Welch's t per asset).