Files
quant-trading/research/tr9_audit.py
Gahow Wang 36cb125719 live: commit the TrendRider V9/V10 registrations the monitor already runs
trader.py registers trend_rider_v9 (+ vt24/vt32/vt36) and trend_rider_v10
(+ vt32/vt36) from strategies/trend_rider_v9.py, and bridge.py labels them.
These were left uncommitted by the 2026-10-07 research session while the
monitor ran them from the working tree (state files data/trader_us_trend_rider_v9*/v10*).
research/tr9_*.py is the research trail CLAUDE.md cites.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 22:20:28 -07:00

70 lines
2.9 KiB
Python

"""Full-window audit: every registered US strategy vs TrendRider V9.
Runs the official engine path (run_market, same params as precompute) over
the current 10y common window and writes the comparison table plus the
head-to-head verdict (does V9 beat every other strategy on BOTH CAGR and
Sharpe?) to data/research/results/tr9_full_comparison.json.
PYTHONPATH=. uv run python -m research.tr9_audit
"""
from __future__ import annotations
import json
import os
import pandas as pd
from trader import (AGENT_REVIEW_STRATEGIES, STRATEGY_REGISTRY,
strategy_supports_market)
import research.tr9_lab as lab
OUT = os.path.join("data", "research", "results", "tr9_full_comparison.json")
V9_NAMES = ["trend_rider_v9", "trend_rider_v9_vt24", "trend_rider_v9_vt32", "trend_rider_v9_vt36",
"trend_rider_v10", "trend_rider_v10_vt32", "trend_rider_v10_vt36"]
NEW_NAMES = [n for n in V9_NAMES if "v10" in n]
def main() -> None:
us_names = [n for n in STRATEGY_REGISTRY
if strategy_supports_market(n, "us") and n not in AGENT_REVIEW_STRATEGIES
and not n.startswith("sim_")]
end = "2026-10-07"
print(f"auditing {len(us_names)} US strategies (window ...{end})")
curves = lab.run(us_names, start="2017-12-26", end=end)
rows = []
for name, eq in curves.items():
m = lab.metrics(eq)
rows.append({"name": name, **m})
df = pd.DataFrame(rows).sort_values("cagr", ascending=False)
pd.set_option("display.width", 200)
print(f"{'name':44s} {'CAGR':>8s} {'vol':>7s} {'Sharpe':>7s} {'MDD':>7s}")
for _, r in df.iterrows():
print(f"{r['name']:44s} {r['cagr']*100:7.1f}% {r['vol']*100:6.1f}% "
f"{r['sharpe']:7.2f} {r['mdd']*100:6.1f}%")
others = df[~df["name"].isin(NEW_NAMES)]
best_cagr = others.loc[others["cagr"].idxmax()]
best_sharpe = others.loc[others["sharpe"].idxmax()]
print(f"\nexisting best CAGR : {best_cagr['name']} {best_cagr['cagr']*100:.1f}%")
print(f"existing best Sharpe : {best_sharpe['name']} {best_sharpe['sharpe']:.2f}")
verdict = {}
for v9 in NEW_NAMES:
row = df[df["name"] == v9].iloc[0]
beat_cagr = bool((others["cagr"] < row["cagr"]).all())
beat_sharpe = bool((others["sharpe"] < row["sharpe"]).all())
verdict[v9] = {"cagr": float(row["cagr"]), "sharpe": float(row["sharpe"]),
"mdd": float(row["mdd"]),
"beats_all_cagr": beat_cagr, "beats_all_sharpe": beat_sharpe,
"beats_all_both": beat_cagr and beat_sharpe}
print(f"{v9}: CAGR {row['cagr']*100:.1f}% (beats all: {beat_cagr}), "
f"Sharpe {row['sharpe']:.2f} (beats all: {beat_sharpe})")
with open(OUT, "w") as fh:
json.dump({"window": {"start": "2017-12-26", "end": end},
"rows": rows, "verdict": verdict}, fh, indent=1)
print("wrote", OUT)
if __name__ == "__main__":
main()