#!/usr/bin/env python3 """Clean OOS validation of the funding-harvest regime filter. Protocol (no peeking): choose the regime-filter params on IN-SAMPLE 2019-2024 by IS Sharpe, then apply that EXACT filter BLIND to OUT-OF-SAMPLE 2025-2026. If the IS-best filter still works OOS, the edge is validated, not curve-fit. Also reports the full grid's OOS so we can see if it's robust across reasonable filters (real) or only the lucky one (suspicious). Strategy structure fixed; only the regime filter (trailing window, hurdle) is the tuned degree of freedom. Raw Sharpe is funding-only (vol understated ~2-3x); realistic ~ raw / 2.5. """ import math import os import sys import numpy as np sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import pit_sweep # noqa: E402 def sharpe(r): r = r[np.isfinite(r)] return float("nan") if len(r) < 20 or r.std() == 0 else r.mean() / r.std() * math.sqrt(365) def apr(r): r = r[np.isfinite(r)] return 100 * r.sum() * 365 / max(len(r), 1) def main(): syms, days, close, qv, fund = pit_sweep.load() T, N = fund.shape year = (1970 + days / 365.25).astype(int) qv30 = np.full_like(qv, np.nan) for t in range(30, T): qv30[t] = np.nanmean(qv[t - 30:t], axis=0) elig = np.isfinite(qv30) & (qv30 > 5e6) & np.isfinite(fund) f = np.nan_to_num(fund) # precompute trailing means trailmean = {} for tr in (14, 30): tm = np.full_like(fund, np.nan) for t in range(tr, T): tm[t] = np.nanmean(fund[t - tr:t], axis=0) trailmean[tr] = tm def harvest(trail, hurdle, c=0.0010): cond = (fund > hurdle) if trail == 0 else (trailmean[trail] > hurdle) sig = np.zeros((T, N)) sig[1:] = np.where(elig[1:] & cond[:-1], 1.0, 0.0) # causal w = sig / np.maximum(sig.sum(1, keepdims=True), 1) gross = np.sum(w[:-1] * f[1:], axis=1) turn = np.sum(np.abs(w[1:] - w[:-1]), axis=1) net = gross - turn * (c / 2) inmkt = (sig.sum(1)[1:] > 0) return net, inmkt yr = year[1:] IS = yr <= 2024 OOS = yr >= 2025 grid = [(tr, h) for tr in (0, 14, 30) for h in (0.0, 0.0002, 0.0003, 0.0005)] rows = [] for tr, h in grid: net, inmkt = harvest(tr, h) rows.append(dict(tr=tr, h=h, net=net, inmkt=inmkt, is_sr=sharpe(net[IS]), oos_sr=sharpe(net[OOS]), oos_apr=apr(net[OOS]), oos_inmkt=float(inmkt[OOS].mean()))) print(f"\n===== CLEAN OOS VALIDATION — IS 2019-2024 / OOS 2025-2026 =====") print(f"{'filter':>18} {'IS Sharpe':>10} {'OOS Sharpe':>11} {'OOS APR%':>9} {'OOS in-mkt%':>11}") for r in rows: nm = "naive thr=0" if (r["tr"] == 0 and r["h"] == 0) else (f"inst>{r['h']*1e4:.0f}bp" if r["tr"] == 0 else f"tf{r['tr']}>{r['h']*1e4:.0f}bp") print(f"{nm:>18} {r['is_sr']:>+10.1f} {r['oos_sr']:>+11.1f} {r['oos_apr']:>+9.1f} {100*r['oos_inmkt']:>10.0f}") best = max(rows, key=lambda r: r["is_sr"]) bnm = f"tf{best['tr']}>{best['h']*1e4:.0f}bp" if best["tr"] else f"inst>{best['h']*1e4:.0f}bp" print(f"\n IS-BEST filter (chosen blind to OOS): {bnm} -> IS Sharpe {best['is_sr']:+.1f}") print(f" ITS OOS RESULT: Sharpe {best['oos_sr']:+.1f} APR {best['oos_apr']:+.1f}% in-market {100*best['oos_inmkt']:.0f}% of days") print(f" (realistic Sharpe after basis vol ~ raw / 2.5 = {best['oos_sr']/2.5:+.1f})") # robustness: how many filters with IS Sharpe>2 also have OOS Sharpe>1 good = [r for r in rows if r["is_sr"] > 2] robust = [r for r in good if r["oos_sr"] > 1] print(f"\n robustness: of {len(good)} filters with IS Sharpe>2, {len(robust)} also have OOS Sharpe>1") print("\nVERDICT: IS-best filter OOS Sharpe>1 (realistic) + broad robustness = VALIDATED, deployable.") print("If IS-best collapses OOS or only 1 filter works = curve-fit, not real.") if __name__ == "__main__": main()