#!/usr/bin/env python3 """Deployable nano multi-strat book with 2x leverage + the foxhunt risk-management layer. Streams (risk-parity, vol-normalized): equity, bond, gold, commodity, trend, crypto. RISK LAYER (the foxhunt principles applied to the book): 1. vol-target -> scale exposure to TARGET_VOL on trailing realized vol 2. drawdown CB -> de-lever at -15% (1x) / -25% (0.5x) / -35% (0.25x) [CMDP circuit-breaker] 3. corr de-risk -> when avg cross-stream corr spikes (diversification breaking in a crisis), cut leverage 4. Kelly cap -> leverage <= Kelly fraction (mean/var), never over-lever a degrading book L[t] = min(MAXLEV, L_vol, L_kelly) * dd_mult * corr_mult, applied to yesterday's signal. Financing cost charged on the borrowed (>1x) portion. Backtest risk-managed-2x vs naive-2x; emit live target weights for a given capital. ETF mapping for deployment in the verdict. """ 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 import pit_sweep # noqa: E402 TARGET_VOL = 0.10 MAXLEV = 2.0 FIN = 0.06 # 6%/yr financing on borrowed portion DD1, DD2, DD3 = -0.15, -0.25, -0.35 CORR_HI = 0.45 # avg pairwise corr above which to de-risk def volnorm(r, tv=TARGET_VOL, win=63): out = np.zeros_like(r) for t in range(win, len(r)): rv = np.std(r[t - win:t]) * math.sqrt(252) out[t] = r[t] * min(5.0, tv / (rv + 1e-9)) return out def stats(r): r = r[np.isfinite(r)] ann = r.mean() * 252; vol = r.std() * math.sqrt(252) eq = np.cumprod(1 + r); dd = float((eq / np.maximum.accumulate(eq) - 1).min()) return ann, vol, (ann / vol if vol > 0 else float("nan")), dd def build_streams(): roots, days, close, op, inst = load_panel()[:5] lc, R, ov, intr = build_returns(close, op, inst) T, N = close.shape 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) tsig = np.full_like(lc, np.nan); tsig[252:] = np.sign(lc[252:] - lc[:-252]) avail = np.isfinite(close) & np.isfinite(vol63) & (vol63 > 0) & np.isfinite(tsig) w = np.where(avail, tsig * iv, 0.0); g = np.abs(w).sum(1, keepdims=True); g[g == 0] = 1; w = w / g trend = np.zeros(T); trend[1:] = np.sum(w[:-1] * R[1:], axis=1) c = {r: roots.index(r) for r in ("ES", "ZN", "GC", "CL")} fut = {"equity": R[:, c["ES"]], "bond": R[:, c["ZN"]], "gold": R[:, c["GC"]], "commod": R[:, c["CL"]], "trend": trend} syms, cdays, cc, _, _ = pit_sweep.load() j = syms.index("BTCUSDT"); lcb = np.log(cc[:, j]) btc = {int(cdays[t]): (lcb[t] - lcb[t - 1]) for t in range(1, len(cdays)) if np.isfinite(lcb[t]) and np.isfinite(lcb[t - 1])} idx = np.array([i for i, d in enumerate(days) if int(d) in btc]) streams = {k: v[idx] for k, v in fut.items()} streams["crypto"] = np.array([btc[int(days[i])] for i in idx]) return streams, days[idx], (1970 + days[idx] / 365.25).astype(int) def risk_managed(M, maxlev, with_risk=True): """M: [T, S] vol-normalized stream returns. Returns book daily returns under the risk layer.""" base = np.nanmean(M, axis=1) # risk-parity combination T = len(base) out = np.zeros(T); eq = 1.0; peak = 1.0 for t in range(63, T - 1): rv = np.std(base[t - 63:t]) * math.sqrt(252) L = min(maxlev, TARGET_VOL / (rv + 1e-9)) # (1) vol-target, capped at maxlev if with_risk: mu = base[t - 63:t].mean() * 252; var = (base[t - 63:t].std() ** 2) * 252 L = min(L, max(0.0, mu / (var + 1e-9))) # (4) Kelly cap dd = eq / peak - 1.0 # (2) drawdown circuit-breaker ddm = 1.0 if dd > DD1 else (0.5 if dd > DD2 else (0.25 if dd > DD3 else 0.0)) cm = np.corrcoef(np.nan_to_num(M[t - 63:t]).T) # (3) correlation de-risk ac = (cm.sum() - cm.shape[0]) / (cm.shape[0] ** 2 - cm.shape[0]) corrm = 1.0 if ac < CORR_HI else max(0.4, 1 - (ac - CORR_HI) * 2) L *= ddm * corrm L = max(0.0, min(L, maxlev)) r = L * base[t + 1] - FIN * max(L - 1.0, 0.0) / 252 # financing on borrowed portion out[t + 1] = r eq *= (1 + r); peak = max(peak, eq) return out def main(): streams, days, year = build_streams() names = list(streams) M = np.column_stack([volnorm(streams[n]) for n in names]) print(f"DEPLOYABLE MULTI-STRAT BOOK — {len(names)} streams, {M.shape[0]} days ({names})") for lab, wr, lev in [("risk-managed 2x", True, 2.0), ("NAIVE 2x (no risk layer)", False, 2.0), ("risk-managed 1x", True, 1.0)]: r = risk_managed(M, lev, wr) a, v, sh, dd = stats(r) print(f" {lab:>26}: Sharpe {sh:+.2f} ann {100*a:+.1f}% vol {100*v:.0f}% maxDD {100*dd:+.1f}%") rm = risk_managed(M, 2.0, True) print(f" per-year Sharpe (risk-managed 2x): " + " ".join(f"{y}:{stats(rm[year == y])[2]:+.1f}" for y in sorted(set(year)) if (year == y).sum() > 150)) # live sizing: current leverage + target $ per stream for capital base = np.nanmean(M, axis=1); t = len(base) - 1 rv = np.std(base[t - 63:t]) * math.sqrt(252) Lv = min(MAXLEV, TARGET_VOL / (rv + 1e-9)) cap = 35000 print(f"\n LIVE SIZING (today): vol-target leverage {Lv:.2f}x -> deploy ${cap*Lv:,.0f} gross on ${cap:,.0f}") per = cap * Lv / len(names) etf = {"equity": "SPY", "bond": "IEF", "gold": "GLD", "commod": "PDBC", "trend": "DBMF", "crypto": "BTC(spot)"} for n in names: print(f" {n:>7} ({etf[n]:>9}): ${per:,.0f}") print("\n VERDICT: risk-managed 2x should keep maxDD bounded (~-20-30%) vs naive 2x (~-40-50%) at higher") print(" return than 1x -> the hedge-fund model at retail. Deploy via the ETFs above (2x Reg-T margin) +") print(" small crypto sleeve. Same ~0.7-Sharpe book; leverage+risk-layer = the fund. Honest: still beta,") print(" drawdowns real, financing drags, single-window crypto sleeve -> size crypto small.") if __name__ == "__main__": main()