← Results index

Re-audit VIX contango experiment — Pine VIX/VIX3M EMA50/252 fidelity

2026-08-18T18:00:00Z Experiment completed Re-derived Pine VIX/VIX3M EMA50/252 contango regime tick-for-tick (ratio VIX/VIX3M, ta.ema SMA-seed 50 vs 252, sell when short > long) and fixed a 31.9% date drift vs the prior 4-point ensemble (1528/4785 dates), verified on a pinned 300-row fixture (6 tests pass); audited on maximal native span 2007-07-17→2026-07-22 (4785 valid, 43.2% active, 88 transitions) the corrected SPY long/cash overlay underperforms B&H (CAGR 4.24% vs 10.58%, Sharpe 0.44 vs 0.61), rejected for risk-off promotion and published as a qm-kdnj experiment with strategy parity.

Objective

Re-derive the VIX contango signal exactly as the pinned Pine defines it (VIX/VIX3M ratio EMA50 vs EMA252, continuous regime sell=short>long), re-audit existing experiment qm-4bx.15 for signal-date fidelity, fix any date/definition drift (ratio construction, EMA adjust/span/seed, signal-date alignment, 4-point curve ensemble divergence), persist inputs offline, and republish under the qm-kdnj experiment-as-strategy contract with strategy parity plus notebook narrative.

Approach

Froze Pine verbatim: vix_data=request.security(VIX,D,close), vix3m_data=request.security(VIX3M,D,close), vix_ratio_long_ema=ta.ema(vix_data/vix3m_data,252), vix_ratio_short_ema=ta.ema(vix_data/vix3m_data,50), sell=short>long strict, buy=not sell continuous. Documented ta.ema as alpha 2/(len+1) SMA-seed NaN until len (not pandas ewm adjust=False), request.security D close as daily close with next_close execution (+1 bar), timezone America/New_York trading days. Corrected backtest/vix_contango.py (new file) to use SMA-seed EMA with leading-NaN handling (first consecutive valid window), ratio, continuous sell/buy, VixContangoRegime.generate_weights via validate_weights. Prior backtest/vix_backwardation.py 4-point ensemble retained as reference and excluded. Pinned 300-row fixture research/fixtures/vix-contango-pine-fixture.csv (50/252, hand-verified TV seed) plus SMA-seed and leading-NaN unit tests give tick-for-tick offline guarantee. Provenance: Yahoo ^VIX 1990-01-02→2026-08-04 9215 rows, ^VIX3M 2006-07-17→2026-07-17 5032 rows data/market.sqlite:ohlcv close_only (TV alternate CBOE:VIX/CBOE:VIX3M same depth-capped per probe), publication lag 0 (available at close, traded next bar), warmup 252 → first valid 2007-07-17, pre-2006 synthetic NO-GO (rejected prior OLS __VIX3M_SYNTH__). Offline replay via read_ohlcv verified.

Files changed

Validation

Results

Fidelity frozen and validated: 4785 valid bars 2007-07-17→2026-07-22, 43.2% active, 88 transitions, stable across subperiods (pre 43.6% post 42.9%) and adjacent EMAs (40/200 42.8% 60/300 43.5%). Date-fidelity audit fixes 31.9% mismatch vs prior sma10 quantile ensemble (1528 dates, prior 12.2% active, root causes ensemble vs 2-ticker, quantile vs EMA crossover, pandas ewm vs SMA seed, ffill vs strict NaN). Equity overlay SPY long/cash next_close 10bps CAGR 4.24% vol 10.9% Sharpe 0.435 vs B&H 10.58% vol 19.8% Sharpe 0.608, forward 21d active 1.28% vs inactive 0.76% diff +52bp — insufficient to overcome whipsaw/costs. Disposition rejected — do not promote to risk-off-indicators/v1; published as qm-kdnj experiment with frozen implementation, provenance, and negative result retained. No synthetic history invented, offline repro succeeds without live fetches.

Links

Source artifact: research/results/qm-kdnj.3.md