← Results index

Wire generic opposite-signal harness for S5FI HMA20 experiment qm-kdnj.1

2026-08-19T05:40:00Z Experiment completed Wired the qm-kdnj generic opposite-signal harness for S&P 500 breadth low HMA20 8.5/0 qm-kdnj.1 (INDEX:S5FI 4956 rows 2006-12-29..2026-08-11 tradingview daily persisted, Pine HMA20 WMA(2*WMA10-WMA20,4) crossover 8.5/crossunder 0 hw20, 18 triggers SPY-aligned 224 active) as head-to-head indicator+generic vs generic-only on same window/costs/lag 2007-01-03→2026-07-24 BacktestConfig.allocatesmartly next_close 10bps via backtest/generic_signals.py showing SPX <50DMA +76.32% (2.23→3.93 CAGR +3.07% Sharpe +0.14 MaxDD +8.22% hit 198/false 26), <200DMA +72.79% (5.13→8.86 CAGR +3.09% Sharpe +0.07), 50/200 death-cross +44.93%, trailing-stop 10% +80.40%, 15% +73.65%, 20% +59.03%, B&H 0% as deterministic delta table with ΔCAGR/ΔSharpe/ΔMaxDD, rendered in Research Narrative and verified offline via ensure_ohlcv offline=True.

Objective

For qm-kdnj.1 (INDEX:S5FI HMA20 8.5/0 Pine fidelity already verified, INDEX:S5FI 4956 rows 2006-12-29..2026-08-11 tradingview daily persisted in data/market.sqlite), wire the qm-kdnj generic opposite-signal harness (SPX close<50DMA, <200DMA, 50/200 death-cross, trailing-stop 10/15/20% via backtest/generic_signals.py) as head-to-head indicator+generic vs generic-only deltas (ΔCAGR/ΔSharpe/ΔMaxDD, hit/false-signal) on same window/costs/lag (next_close, fee_bps=10). Acceptance: docs/site-data/experiments/qm-kdnj.1.json gains strategy-parity performance vs generic-only delta table, docs/experiments/qm-kdnj.1.html renders deltas in Research Narrative, offline repro via ensure_ohlcv offline=True, no hand-edited payloads.

Approach

  1. Created reusable publisher research/scripts/publish_s5fi_hma_qm_kdnj1.py (compute_harness, build_manifest offline): loads INDEX:S5FI via read_ohlcv("INDEX:S5FI") 4956 rows tradingview daily and SPY via ensure_universe(["SPY"], start="2007-01-01", end="2026-08-04", offline=True) 4920 bars, prepares S5FI daily ffilled to SPY calendar, runs spx_breadth_buy_signal HMA20 8.5/0 crossover/crossunder OR + apply_holding_window 20d fixed (18 triggers 224 active 4.55%), generates generics via backtest/generic_signals.py sma_signal 50/200, cross_signal 50/200 death-cross, trailing_stop_signal 0.10/0.15/0.20 expanding cummax, bh_signal, builds paired backtests per generic on same window with BacktestConfig.allocatesmartly() next_close 10bps via _Strat OR override blended.loc[active, SPY]=1.0 + validate_weights, computes metrics Δ% ΔCAGR ΔSharpe ΔMaxDD hit/false-signal, emits research/experiments/qm-kdnj.1.json with metrics.generic_exit_harness + supplemental.generic_exit_harness/generic_exit_harness_rows 7 rows + generic_exit_harness_detail + research_narrative Generic opposite-signal harness entry, provenance backtest/generic_signals.py hash.
  1. Existing research/reports/scaffold.py:render_experiment_detail already renders generic-exit harness table from supplemental.generic_exit_harness_rows fallback to dict mapping (header Generic/Generic-only/Signal+Generic/Δ%/ΔCAGR/ΔSharpe, window note via BacktestConfig.allocatesmartly next_close 10bps); no scaffold change required — publisher rows drive deterministic rendering, parity payload remains canonical producer.
  1. Rebuilt site-data and static site via python3 -m research.reports build --render exporting 139/139 payloads, writing docs/site-data/experiments/qm-kdnj.1.json (34071 bytes) with supplemental rows 7 and docs/experiments/qm-kdnj.1.html with data-test=generic-exit-harness table (sma50 2.2269→3.9265 76.32%, sma200 5.1262→8.8577 72.79%, cross_50_200 44.93%, trailing_10pct 80.40%, trailing_15pct 73.65%, trailing_20pct 59.03%, bh 0%).
  1. Added tests/test_s5fi_hma_generic_harness.py (7 tests offline no network no cache mutation): ensure_ohlcv offline S5FI 4956/SPY 4920, generic signals deterministic/causal trailing expanding, S5FI signal 18/224 tick-for-tick, harness offline deltas matching computed fixtures (sma200 72.79% etc), manifest+site-data+html contain harness with hit/false-signal, no DB WAL mutation, one-bar lag and costs via BacktestConfig.

Files changed

Validation

Results

Offline harness verified: INDEX:S5FI 4956 rows 2006-12-29→2026-08-11 tradingview daily persisted in data/market.sqlite:instruments/ohlcv and verified offline via ensure_universe offline=True — signal HMA20 8.5/0 Pine tick-for-tick hw20 fixed yields 18 triggers /224 active 4.55% on same window 2007-01-03→2026-07-24. Generic harness paired each defensive head-to-head same window/costs/lag BacktestConfig.allocatesmartly next_close 10bps: SMA50 +76.32% (2.2269→3.9265 CAGR 4.19%→7.26% Δ+3.07% Sharpe 0.43→0.57 Δ+0.14 MaxDD -38.01%→-29.78% Δ+8.22% hit 198/false 26), SMA200 +72.79% (5.1262→8.8577 CAGR +3.09% Sharpe +0.07 MaxDD -20.93%→-23.02% Δ-2.09% hit 204/false 20), cross 50/200 +44.93% (5.3075→7.6923 CAGR +2.09% Sharpe +0.05 MaxDD -33.72%→-33.72% hit 179/false 45), trailing-stop 10% +80.40% (3.9991→7.2142 CAGR +3.29% Sharpe +0.10 MaxDD -22.84%→-23.48% hit 186/false 38), 15% +73.65% (3.3143→5.7555 CAGR +3.05% Sharpe +0.12 MaxDD -32.10%→-28.05% hit 160/false 64), 20% +59.03% (4.4288→7.0430 CAGR +2.60% Sharpe +0.09 MaxDD -38.22%→-31.50% hit 110/false 114), BH 0% (7.4701→7.4701 already max long). Delta table renders in Research Narrative generic-exit-harness section and site-data supplemental; offline repro deterministic without live fetch, no hand-edited payloads, no DB mutation, no private data.

Links

Source artifact: research/results/qm-pum2.md