← Results index

Wire generic harness for ADL Volume-Ratio experiment qm-kdnj.2

2026-08-19T06:30:00Z Experiment completed Wired a reusable generic opposite-signal harness for the ADL Volume Ratio buy signal qm-kdnj.2 (USI:UVOL 7616 rows 1996-04-19→2026-08-11, USI:DVOL 8643 rows 1992-01-02→2026-08-11 tradingview close_only, persisted offline via ensure_universe offline=True) and published deterministic head-to-head indicator+generic versus generic-only deltas on same window/costs/lag (1996-04-19→2026-07-24 7604 valid bars, BacktestConfig.allocatesmartly next_close 10bps, hw20 override) showing SMA200 +65.09% (10.01→16.52, CAGR +1.81% Sharpe +0.10), SMA50 +23.43%, 50/200 cross +66.32%, trailing-stop 10% +50.70% and B&H 0% as Δ table, verified by 7 offline harness tests (83 focused tests pass, artifacts deterministic, no hand-edited docs).

Objective

For qm-kdnj.2 (Pine USI:UVOL/USI:DVOL request.security D close ratio upratio=upvol/downvol >22 strict level hw20, timeframe=5 input declared but not wired to D in verbatim, 7616 ratios 1996-04-19→2026-08-11, 24 triggers 259 active hw20, 0 date drift vs prior qm-4bx.17/22, persisted tradingview USI:UVOL 7616 rows 1996-04-19→2026-08-11 and USI:DVOL 8643 rows 1992-01-02→2026-08-11 in data/market.sqlite), wire the qm-kdnj generic opposite-signal harness (SPX SMA50/200, 50/200 death-cross, trailing-stop 10% via backtest/generic_signals.py + backtest/adl_vol_ratio.py apply_overlay override) as head-to-head indicator+generic vs generic-only deltas (ΔCAGR/ΔSharpe/ΔMaxDD) on same window/costs/lag (next_close, fee_bps=10). Acceptance: docs/site-data/experiments/qm-kdnj.2.json gains strategy-parity generic harness rows, docs/experiments/qm-kdnj.2.html renders deltas in Research Narrative, offline repro via ensure_universe offline=True, no hand-edited payloads.

Approach

  1. Froze datastore provenance: instruments USI:UVOL 7616 and USI:DVOL 8643 rows tradingview close_only (Volume=0 per qm-zl9.1), verified SELECT ticker,start_date,end_date,n_rows FROM instruments and read_ohlcv mode=ro query_only succeeds offline, no WAL mutation, 7604 valid intersect bars 1996-04-19→2026-07-24 with SPY 8428 1993-01-29→2026-07-24.
  1. Reused deterministic backtest/generic_signals.py (causal UTC-naive, no lookahead): sma_signal (closecross_signal (SMA50trailing_stop_signal (close < expanding peak*(1-0.10) window None trailing 10% min per qm-kdnj contract), bh_signal (never defensive), generic_weights/all_generic_signals via validate_weights; all boolean daily on SPY closes, one-bar execution via BacktestConfig.allocatesmartly() next_close 10bps.
  1. Created research/scripts/publish_adl_vol_ratio_qm_kdnj2.py (compute_harness/build_manifest offline): loads SPY+UVOL+DVOL via ensure_universe(["SPY","USI:UVOL","USI:DVOL"], offline=True), loads full UVOL/DVOL via read_ohlcv → adl_vol_buy_signal daily threshold 22.0 strict level → apply_holding_window 20 fixed, slices to valid_idx (7604), runs paired backtests per generic on aligned window with same BacktestConfig.allocatesmartly() via generic_weights and apply_overlay OR override (long if either generic long or ADL active hw20), computes generic_exit_harness (Δ% ΔCAGR ΔSharpe ΔMaxDD) and richer generic_exit_harness_detail + generic_exit_harness_rows for table, emits research/experiments/qm-kdnj.2.json validated via experiment_registry.validate_manifest.
  1. Updated research/experiments/qm-kdnj.2.json supplemental to carry generic_exit_harness dict, generic_exit_harness_rows (5 rows sma50/sma200/cross_50_200/trailing_10pct/bh), generic_exit_harness_detail and research_narrative Generic exit harness entry; window 1996-04-19→2026-07-24 native 7616 ratio etc.
  1. Existing research/reports/scaffold.py:render_experiment_detail already renders harness table from supplemental.generic_exit_harness_rows (fallback dict mapping) plus window/note/detail; no scaffold code change needed for ADL — verified table renders after python3 -m research.reports scaffold and build --render.
  1. Added tests/test_adl_vol_ratio_generic_harness.py (7 tests, offline, no network, no cache mutation): ensure_ohlcv 7616/8643 offline, deterministic/causal trailing-stop, ADL signal tick-for-tick threshold strict >22 24/259, harness deltas (SMA200 65.09% etc matching offline compute), manifest + site-data + html contain harness with Δ table, no DB/WAL mutation guard, one-bar lag and costs via BacktestConfig.

Files changed

Validation

Results

Datastore provenance frozen: USI:UVOL 7616 rows 1996-04-19→2026-08-11 and USI:DVOL 8643 rows 1992-01-02→2026-08-11 tradingview close_only, persisted in data/market.sqlite:instruments/ohlcv and verified offline via ensure_universe offline=True — ratio 7616 on valid intersect 7604 bars 1996-04-19→2026-07-24 (SPY limit) with 24 triggers /259 active hw20 fixed (3.406% pct_active, 0.8/yr sparse). Generic harness paired each defensive as head-to-head generic-only vs signal+generic on same anchored window with identical costs/lag (BacktestConfig.allocatesmartly next_close 10bps, OR override hw20): SMA200 Δ65.09% (generic_only 10.0058 → signal+generic 16.5190, CAGR 7.93%→9.74% Δ+1.81% Sharpe 0.68→0.78 Δ+0.10, MaxDD -29.4%→-29.4%), SMA50 Δ23.43% (2.8243→3.4858, CAGR 3.50%→4.23% Δ+0.73% Sharpe 0.36→0.41), cross 50/200 Δ66.32% (15.4286→25.6613, CAGR 9.49%→11.36% Δ+1.86% Sharpe 0.71→0.81), trailing-stop 10% Δ50.70% (5.8122→8.7591, CAGR 6.01%→7.46% Δ+1.45% Sharpe 0.55→0.63), B&H Δ0.00% (19.2833→19.2833) verifying no lookahead. Delta table renders in docs/experiments/qm-kdnj.2.html and docs/site-data/experiments/qm-kdnj.2.json; offline harness recomputable without live fetch; experiment remains rejected for risk-off promotion (sparse/brittle) but published as risk-signals/v1 sparse buy signal with frozen Pine semantics.

Links

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