#!/usr/bin/env python3 """The strategy class we never tested: HARVEST structural premia with the risk system, not predict. Diversified multi-asset futures (equity/rates/metals/energy/ags/FX). Build a ladder: equal-weight -> inverse-vol (risk-parity) -> + vol-target -> + trend-overlay (long-flat by 252d trend, the crisis-alpha de-risk). Measure RISK-ADJUSTED (Sharpe, ann-vol, max-DD, Calmar, per-year) vs benchmarks (equal-weight, equity-only, 60/40). No prediction/alpha needed — just disciplined harvesting + risk control (what the engine is actually good at). Roll-zeroed returns (understates carry; fine for comparing the risk-management strategies). """ import math import os import sys import numpy as np sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from signal_sweep import load_panel, build_returns # noqa: E402 TARGET_VOL = 0.10 # 10% annualized portfolio vol def metrics(r): r = r[np.isfinite(r)] if len(r) < 50 or r.std() == 0: return dict(sr=float("nan"), ann=float("nan"), vol=float("nan"), dd=float("nan"), calmar=float("nan")) ann = r.mean() * 252; vol = r.std() * math.sqrt(252); sr = ann / vol eq = np.cumprod(1 + r); dd = float((eq / np.maximum.accumulate(eq) - 1).min()) return dict(sr=sr, ann=ann, vol=vol, dd=dd, calmar=ann / (abs(dd) + 1e-9)) def main(): roots, days, close, op, inst, weekday = load_panel() lc, R, ov, intr = build_returns(close, op, inst) T, N = close.shape year = (1970 + days / 365.25).astype(int) vol63 = np.full_like(lc, np.nan) for t in range(63, T): vol63[t] = np.nanstd(R[t - 63:t], axis=0) iv = 1.0 / np.where(vol63 > 0, vol63, np.nan) avail = np.isfinite(close) & np.isfinite(vol63) & (vol63 > 0) def port(weights): w = np.nan_to_num(weights) w = np.where(avail, w, 0.0) g = np.sum(np.abs(w), axis=1, keepdims=True); g[g == 0] = 1 w = w / g # unit gross (fully invested) return np.sum(w[:-1] * R[1:], axis=1) def voltarget(r): out = np.zeros_like(r) for t in range(63, len(r)): rv = np.std(r[t - 63:t]) * math.sqrt(252) out[t] = r[t] * min(3.0, TARGET_VOL / (rv + 1e-9)) # scale to target vol, cap 3x leverage return out # weight schemes eqw = np.where(avail, 1.0, 0.0) rp = np.where(avail, iv, 0.0) # inverse-vol risk parity trend = (np.full_like(lc, np.nan)); trend[252:] = lc[252:] - lc[:-252] rp_trend = np.where(avail & (trend > 0), iv, 0.0) # trend-overlay: hold only uptrending assets books = { "equal-weight": port(eqw), "risk-parity (inv-vol)": port(rp), "risk-parity + vol-target": voltarget(port(rp)), "RP + trend + vol-target": voltarget(port(rp_trend)), } # benchmarks es = roots.index("ES") if "ES" in roots else 0 bench = {"equity-only (ES)": R[1:, es]} if "ZN" in roots: zn = roots.index("ZN") w6040 = np.zeros((T, N)); w6040[:, es] = 0.6; w6040[:, zn] = 0.4 bench["60/40 (ES/ZN)"] = port(w6040) print(f"\n===== PREMIUM HARVEST (diversified futures, {N} assets, {T} days, target {int(TARGET_VOL*100)}% vol) =====") print(f"{'strategy':>26} {'Sharpe':>7} {'ann%':>6} {'vol%':>6} {'maxDD%':>7} {'Calmar':>7}") for nm, r in {**bench, **books}.items(): m = metrics(r) print(f"{nm:>26} {m['sr']:>+7.2f} {100*m['ann']:>+6.1f} {100*m['vol']:>5.1f} {100*m['dd']:>+7.1f} {m['calmar']:>7.2f}") print("\nper-year Sharpe (RP + trend + vol-target):") rtv = books["RP + trend + vol-target"] print(" " + " ".join(f"{y}:{metrics(rtv[year[1:]==y])['sr']:+.1f}" for y in range(2010, 2027) if (year[1:] == y).sum() > 100)) print("\nVERDICT: if risk-managed harvest beats benchmarks on Sharpe/Calmar (esp lower maxDD) = the engine's") print("real job (risk management of real premia) delivers, no alpha needed. Modest but robust = the honest win.") if __name__ == "__main__": main()