"""Run TrendRider V9 suites through the official engine path. PYTHONPATH=. uv run python -m research.tr9_run baseline PYTHONPATH=. uv run python -m research.tr9_run ablate """ from __future__ import annotations import sys import research.tr9_lab as lab M = lab.TrendRiderV9 BASELINES = ["trend_rider_v7", "trend_rider_v7_vt24", "trend_rider_v7_vt32", "trend_rider_v7_vt36", "trend_rider_v5_vt30", "trend_rider_v3_vt32"] def register_all() -> list[str]: reg = lab.register names = [] # exact V7 replica in the V9 code path (sanity) names.append(reg("v9_base", lambda **kw: M())) # risk-on basket extensions names.append(reg("v9_soxl", lambda **kw: M(risk_on=("TQQQ", "UPRO", "TECL", "SOXL")))) names.append(reg("v9_soxl_tna", lambda **kw: M(risk_on=("TQQQ", "UPRO", "TECL", "SOXL", "TNA")))) # risk-off extensions names.append(reg("v9_tmf", lambda **kw: M(tmf="TMF"))) names.append(reg("v9_sqqq", lambda **kw: M(sqqq="SQQQ"))) names.append(reg("v9_tmf_sqqq", lambda **kw: M(tmf="TMF", sqqq="SQQQ"))) names.append(reg("v9_soxl_tmf", lambda **kw: M(risk_on=("TQQQ", "UPRO", "TECL", "SOXL"), tmf="TMF"))) names.append(reg("v9_soxl_tmf_sqqq", lambda **kw: M( risk_on=("TQQQ", "UPRO", "TECL", "SOXL"), tmf="TMF", sqqq="SQQQ"))) # risk-off gating variants (fixed: TLT/QQQ gate refs now included) names.append(reg("v9_sqqq05", lambda **kw: M(sqqq="SQQQ", sqqq_trigger=0.05))) names.append(reg("v9_sqqq10", lambda **kw: M(sqqq="SQQQ", sqqq_trigger=0.10))) names.append(reg("v9_tmf_sqqq05", lambda **kw: M(tmf="TMF", sqqq="SQQQ", sqqq_trigger=0.05))) names.append(reg("v9_sqqq_rostop", lambda **kw: M(sqqq="SQQQ", ro_stop_loss=0.15))) names.append(reg("v9_tmf_sqqq_rostop", lambda **kw: M( tmf="TMF", sqqq="SQQQ", ro_stop_loss=0.15))) # profit-take / park variants names.append(reg("v9_park_qqq", lambda **kw: M(pt_park_mix={"SHY": 0.5, "QQQ": 0.5}))) names.append(reg("v9_ladder", lambda **kw: M( pt_mode="ladder", pt_ladder=((0.30, 0.5), (0.60, 1.0))))) names.append(reg("v9_no_pt", lambda **kw: M(pt_mode="none"))) # vol target variants names.append(reg("v9_assetvt", lambda **kw: M(vt_mode="asset"))) names.append(reg("v9_ewma", lambda **kw: M(vt_ewma=20))) # pick metric names.append(reg("v9_momdiv", lambda **kw: M(mom_pick_divisor=True))) # trailing-stop on the leveraged risk-on leg names.append(reg("v9_trail18", lambda **kw: M(trail_pct=0.18))) names.append(reg("v9_trail22", lambda **kw: M(trail_pct=0.22))) names.append(reg("v9_trail26", lambda **kw: M(trail_pct=0.26))) return names def main() -> None: suite = sys.argv[1] if len(sys.argv) > 1 else "baseline" if suite == "baseline": curves = lab.run(BASELINES) lab.report(curves, "baseline replication") elif suite == "ablate": names = register_all() curves = lab.run(BASELINES + names) lab.report(curves, "ablation") elif suite == "riskoff": names = register_all() pick = ["v9_base", "v9_tmf", "v9_sqqq", "v9_sqqq05", "v9_sqqq10", "v9_tmf_sqqq", "v9_tmf_sqqq05", "v9_sqqq_rostop", "v9_tmf_sqqq_rostop"] curves = lab.run(BASELINES[:4] + pick) lab.report(curves, "risk-off extensions") lab.yearly_table(curves, ["trend_rider_v7", "v9_tmf", "v9_sqqq", "v9_tmf_sqqq05"]) elif suite == "trail": names = register_all() def vt(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, **kw) extra = [ lab.register("v9vt36", lambda **kw: vt(0.36, 0.75)), lab.register("v9vt36_t18", lambda **kw: vt(0.36, 0.75, trail_pct=0.18)), lab.register("v9vt36_t22", lambda **kw: vt(0.36, 0.75, trail_pct=0.22)), lab.register("v9vt36_t26", lambda **kw: vt(0.36, 0.75, trail_pct=0.26)), lab.register("v9vt32_t22", lambda **kw: vt(0.32, 0.7, trail_pct=0.22)), lab.register("v9vt36_b15", lambda **kw: vt(0.36, 0.75, pt_band=0.15)), lab.register("v9vt36_thr25", lambda **kw: vt(0.36, 0.75, pt_threshold=0.25)), lab.register("v9vt36_thr35", lambda **kw: vt(0.36, 0.75, pt_threshold=0.35)), ] curves = lab.run(BASELINES[:4] + ["v9_trail22"] + extra) lab.report(curves, "trail / PT tuning") lab.yearly_table(curves, ["trend_rider_v7_vt36", "v9vt36", "v9vt36_t22", "v9vt36_t26"]) elif suite == "grid": def vt(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, **kw) extra = [] for t in (0.20, 0.21, 0.22, 0.23, 0.24): extra.append(lab.register(f"g36_t{int(t*100)}", lambda t=t, **kw: vt(0.36, 0.75, trail_pct=t))) for t in (0.20, 0.22, 0.24): extra.append(lab.register(f"g32_t{int(t*100)}", lambda t=t, **kw: vt(0.32, 0.7, trail_pct=t))) extra.append(lab.register("g36_t22_w20", lambda **kw: vt(0.36, 0.75, trail_pct=0.22, trail_window=20))) extra.append(lab.register("g36_t22_w40", lambda **kw: vt(0.36, 0.75, trail_pct=0.22, trail_window=40))) extra.append(lab.register("g36_t22_r5", lambda **kw: vt(0.36, 0.75, trail_pct=0.22, trail_reentry_days=5))) extra.append(lab.register("g36_t22_r10", lambda **kw: vt(0.36, 0.75, trail_pct=0.22, trail_reentry_days=10))) extra.append(lab.register("g34_t22", lambda **kw: vt(0.34, 0.72, trail_pct=0.22))) curves = lab.run(BASELINES[:4] + extra) lab.report(curves, "trail grid") lab.yearly_table(curves, ["trend_rider_v7_vt36", "g36_t20", "g36_t22", "g36_t24", "g32_t22"]) elif suite == "frontier": def vt(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, **kw) extra = [] for tv, ml in ((0.30, 0.65), (0.32, 0.70), (0.34, 0.72), (0.35, 0.73), (0.36, 0.75), (0.38, 0.78)): extra.append(lab.register(f"f{int(tv*100)}_t20", lambda tv=tv, ml=ml, **kw: vt(tv, ml, trail_pct=0.20))) extra.append(lab.register("f36_t18", lambda **kw: vt(0.36, 0.75, trail_pct=0.18))) extra.append(lab.register("f36_t19", lambda **kw: vt(0.36, 0.75, trail_pct=0.19))) extra.append(lab.register("f36_t22_w25", lambda **kw: vt(0.36, 0.75, trail_pct=0.22, trail_window=25))) extra.append(lab.register("f36_t22_w35", lambda **kw: vt(0.36, 0.75, trail_pct=0.22, trail_window=35))) extra.append(lab.register("f32_t18", lambda **kw: vt(0.32, 0.70, trail_pct=0.18))) curves = lab.run(BASELINES[:4] + extra) lab.report(curves, "frontier map") elif suite == "macro": MACRO_UNIVERSE = lab.V9_UNIVERSE + ["^VIX9D", "^VIX3M", "^VIX", "HYG"] def mv(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, trail_pct=0.20, **kw) def reg_macro(name, **kw): return lab.register(name, lambda **kw2: mv(**kw, **kw2), universe=MACRO_UNIVERSE) extra = [ reg_macro("mc32_m1", tv=0.32, ml=0.70, throttle_vix_inv=True), reg_macro("mc32_m2", tv=0.32, ml=0.70, throttle_vix_spike=True), reg_macro("mc32_m3", tv=0.32, ml=0.70, throttle_credit=True), reg_macro("mc32_m13", tv=0.32, ml=0.70, throttle_vix_inv=True, throttle_credit=True), reg_macro("mc32_m123", tv=0.32, ml=0.70, throttle_vix_inv=True, throttle_vix_spike=True, throttle_credit=True), reg_macro("mc36_m1", tv=0.36, ml=0.75, throttle_vix_inv=True), reg_macro("mc36_m3", tv=0.36, ml=0.75, throttle_credit=True), reg_macro("mc36_m123", tv=0.36, ml=0.75, throttle_vix_inv=True, throttle_vix_spike=True, throttle_credit=True), reg_macro("mc34_m3", tv=0.34, ml=0.72, throttle_credit=True), reg_macro("mc34_m13", tv=0.34, ml=0.72, throttle_vix_inv=True, throttle_credit=True), ] curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v9_vt36"] + extra) lab.report(curves, "macro throttle") lab.yearly_table(curves, ["trend_rider_v9_vt32", "mc32_m3", "mc32_m13", "mc32_m123"]) elif suite == "knobs": KNOB_UNIVERSE = lab.V9_UNIVERSE + ["RSP"] def kv(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, trail_pct=0.20, **kw) def reg_knob(name, **kw): return lab.register(name, lambda **kw2: kv(**kw, **kw2), universe=KNOB_UNIVERSE) extra = [ reg_knob("k32_base", tv=0.32, ml=0.70), reg_knob("k32_instma50", tv=0.32, ml=0.70, instma_exit=50), reg_knob("k32_instma30", tv=0.32, ml=0.70, instma_exit=30), reg_knob("k32_fast", tv=0.32, ml=0.70, fast_reentry_days=60), reg_knob("k32_instma50_fast", tv=0.32, ml=0.70, instma_exit=50, fast_reentry_days=60), reg_knob("k32_breadth100", tv=0.32, ml=0.70, breadth_ma=100), reg_knob("k32_dd4", tv=0.32, ml=0.70, dd_stop=0.04), reg_knob("k32_ddw30", tv=0.32, ml=0.70, dd_window=30), reg_knob("k32_conf2", tv=0.32, ml=0.70, confirm_days=2), reg_knob("k32_mom84", tv=0.32, ml=0.70, mom_lookback=84), ] curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v9_vt36"] + extra) lab.report(curves, "structural knobs") import numpy as np a = curves.get("trend_rider_v9_vt32") b = curves.get("k32_base") if a is not None and b is not None: print("vt32 fidelity:", np.allclose(a.to_numpy(), b.to_numpy()), "maxdiff", float(np.abs(a.to_numpy() - b.to_numpy()).max())) elif suite == "pt2": def pv(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, trail_pct=0.20, **kw) extra = [ lab.register("p32_base", lambda **kw: pv(0.32, 0.70)), lab.register("p32_band06", lambda **kw: pv(0.32, 0.70, pt_band=0.06)), lab.register("p32_band08", lambda **kw: pv(0.32, 0.70, pt_band=0.08)), lab.register("p32_hold10", lambda **kw: pv(0.32, 0.70, pt_min_hold=10)), lab.register("p32_hold21", lambda **kw: pv(0.32, 0.70, pt_min_hold=21)), lab.register("p32_ononly", lambda **kw: pv(0.32, 0.70, pt_only=("TQQQ", "UPRO"))), lab.register("p36_band06", lambda **kw: pv(0.36, 0.75, pt_band=0.06)), lab.register("p36_hold10", lambda **kw: pv(0.36, 0.75, pt_min_hold=10)), lab.register("p36_ononly", lambda **kw: pv(0.36, 0.75, pt_only=("TQQQ", "UPRO"))), lab.register("p34_hold10", lambda **kw: pv(0.34, 0.72, pt_min_hold=10)), ] curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v9_vt36"] + extra) lab.report(curves, "PT variants 2") lab.yearly_table(curves, ["trend_rider_v9_vt32", "p32_band06", "p32_hold10", "p32_ononly"]) elif suite == "pt3": def qv(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, trail_pct=0.20, **kw) extra = [ lab.register("q33_h10", lambda **kw: qv(0.33, 0.71, pt_min_hold=10)), lab.register("q34_h10", lambda **kw: qv(0.34, 0.72, pt_min_hold=10)), lab.register("q34_b08_h10", lambda **kw: qv(0.34, 0.72, pt_min_hold=10, pt_band=0.08)), lab.register("q34_b06_h10", lambda **kw: qv(0.34, 0.72, pt_min_hold=10, pt_band=0.06)), lab.register("q32_b06_h10", lambda **kw: qv(0.32, 0.70, pt_min_hold=10, pt_band=0.06)), lab.register("q36_b06_h10", lambda **kw: qv(0.36, 0.75, pt_min_hold=10, pt_band=0.06)), lab.register("q32_b08_h10", lambda **kw: qv(0.32, 0.70, pt_min_hold=10, pt_band=0.08)), lab.register("q34_h10_thr28", lambda **kw: qv(0.34, 0.72, pt_min_hold=10, pt_threshold=0.28)), ] curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v9_vt36", "trend_rider_v9_vt24"] + extra) lab.report(curves, "PT hold + band grid") lab.yearly_table(curves, ["trend_rider_v9_vt32", "q34_h10", "q34_b06_h10", "q32_b06_h10"]) elif suite == "pt4": def rv(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, trail_pct=0.20, pt_min_hold=10, **kw) extra = [] for tv, ml in ((0.33, 0.71), (0.34, 0.72)): for thr in (0.26, 0.27, 0.28, 0.29, 0.30): extra.append(lab.register( f"r{int(tv*100)}_thr{int(thr*100)}", lambda tv=tv, ml=ml, thr=thr, **kw: rv(tv, ml, pt_threshold=thr))) extra.append(lab.register("r34_thr28_b08", lambda **kw: rv(0.34, 0.72, pt_threshold=0.28, pt_band=0.08))) extra.append(lab.register("r34_thr28_t22", lambda **kw: M( target_vol=0.34, min_lev=0.72, trail_pct=0.22, pt_min_hold=10, pt_threshold=0.28))) curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v9_vt36"] + extra) lab.report(curves, "thr neighborhood") lab.yearly_table(curves, ["trend_rider_v9_vt36", "r34_thr28", "r33_thr28", "r34_thr27"]) elif suite == "final": def fv(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, trail_pct=0.20, pt_min_hold=10, pt_threshold=0.28, pt_band=0.08, **kw) extra = [ lab.register("f10_34", lambda **kw: fv(0.34, 0.72)), lab.register("f10_32", lambda **kw: fv(0.32, 0.70)), lab.register("f10_36", lambda **kw: fv(0.36, 0.75)), lab.register("f10_34_t22", lambda **kw: M(target_vol=0.34, min_lev=0.72, trail_pct=0.22, pt_min_hold=10, pt_threshold=0.28, pt_band=0.08)), ] curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v9_vt36", "trend_rider_v9_vt24"] + extra, end="2026-10-07") lab.report(curves, "finalists @ official endpoint 2026-10-07") elif suite == "v10robe": def w(tv, ml, **kw): return M(target_vol=tv, min_lev=ml, pt_min_hold=10, **kw) extra = [] for t in (0.18, 0.19, 0.20, 0.21, 0.22): extra.append(lab.register(f"w34_t{int(t*100)}", lambda t=t, **kw: w( 0.34, 0.72, trail_pct=t, pt_threshold=0.28, pt_band=0.08))) for thr in (0.26, 0.27, 0.28, 0.29, 0.30): for band in (0.06, 0.08, 0.10): extra.append(lab.register(f"w34_{int(thr*100)}_{int(band*100)}", lambda thr=thr, band=band, **kw: w( 0.34, 0.72, trail_pct=0.20, pt_threshold=thr, pt_band=band))) curves = lab.run(["trend_rider_v9", "trend_rider_v9_vt32", "trend_rider_v10"] + extra, end="2026-10-07") lab.report(curves, "v10 robustness grids @2026-10-07") else: raise SystemExit(f"unknown suite {suite}") if __name__ == "__main__": main()