"""Is the basket uplift just 'helps when TP01 is weak'? Quantify regime-conditionality.""" from __future__ import annotations import importlib.util, sys from pathlib import Path import numpy as np import pandas as pd HERE = Path(__file__).resolve().parent sys.path.insert(0, str(HERE)) sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt") import ortholib as ol import altlib as al AGENTS = HERE / "agents" def _book(path): spec = importlib.util.spec_from_file_location(path.stem, path) mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod) return mod.book def _sh(s): r = np.asarray(pd.Series(s).dropna().values, float) return float(np.mean(r) / np.std(r) * np.sqrt(365.25)) if len(r) > 2 and np.std(r) > 0 else 0.0 def main(): B = al.tp01_baseline_daily() excl = ["12_rebalance_harvest"] rows = {} for p in sorted(AGENTS.glob("agent_*.py")): nm = p.stem.replace("agent_", "") if nm in excl: continue ev = ol.eval_book(_book(p)) if ev["daily"].std() > 0: rows[nm] = ev["daily"] M = pd.concat(rows, axis=1, join="inner").dropna() basket = M.mean(axis=1) J = pd.concat({"B": B, "C": basket}, axis=1, join="inner").dropna() print("Per-year: TP01 own Sharpe | basket Sharpe | basket ret | blend-uplift") print(" (does the basket help SPECIFICALLY in TP01's weak years?)") for y in sorted(set(J.index.year)): sub = J[J.index.year == y] if len(sub) < 20: continue tp_sh = _sh(sub["B"]); bk_sh = _sh(sub["C"]) bk_ret = float((1 + sub["C"]).prod() - 1) up = _sh(0.75 * sub["B"] + 0.25 * sub["C"]) - _sh(sub["B"]) print(f" {y}: TP01 Sh {tp_sh:+6.2f} | basket Sh {bk_sh:+6.2f} | ret {bk_ret:+7.2%} | uplift {up:+.3f}") # correlation: does basket-year-uplift track NEGATIVE TP01-year-Sharpe? rows2 = [] for y in sorted(set(J.index.year)): sub = J[J.index.year == y] if len(sub) < 20: continue rows2.append((_sh(sub["B"]), _sh(0.75*sub["B"]+0.25*sub["C"]) - _sh(sub["B"]))) arr = np.array(rows2) if len(arr) > 2: c = np.corrcoef(arr[:,0], arr[:,1])[0,1] print(f"\n corr(TP01 yearly Sharpe, basket yearly uplift) = {c:+.2f}") print(" (strongly NEGATIVE => basket only helps when TP01 is weak = regime hedge, not standing alpha)") # conditional uplift: split days by whether TP01 trailing-60d return is up or down tp_trail = J["B"].rolling(60).sum() up_days = J[tp_trail > 0]; dn_days = J[tp_trail <= 0] for lbl, d in [("TP01 trailing-60d UP", up_days), ("TP01 trailing-60d DOWN", dn_days)]: if len(d) < 30: continue u = _sh(0.75*d["B"]+0.25*d["C"]) - _sh(d["B"]) print(f" [{lbl}] n={len(d)} basket Sh {_sh(d['C']):+.2f} blend-uplift {u:+.3f}") # ETH/BTC ratio regime: is the basket net-short ETH (i.e. is it just shorting the bleed)? btc, eth = ol.aligned() wbs, wes = [], [] for nm in rows: wb, we = _book(AGENTS / f"agent_{nm}.py")(btc, eth) wbs.append(np.nan_to_num(np.asarray(wb,float))); wes.append(np.nan_to_num(np.asarray(we,float))) wb = np.clip(np.mean(wbs,axis=0),-0.5,0.5); we = np.clip(np.mean(wes,axis=0),-0.5,0.5) idx = pd.DatetimeIndex(btc["dt"]) wbS = pd.Series(wb, index=idx); weS = pd.Series(we, index=idx) print("\n Mean basket leg weights per year (is it structurally short ETH / long BTC?):") print(" year w_btc w_eth (positive=long)") for y in sorted(set(idx.year)): m = idx.year == y print(f" {y}: {wbS[m].mean():+.3f} {weS[m].mean():+.3f}") print(f"\n FULL mean: w_btc {wbS.mean():+.3f} w_eth {weS.mean():+.3f}") print(" (a persistent long-BTC/short-ETH tilt = it's a static ETH-bleed short, not RV alpha)") if __name__ == "__main__": main()