"""PORT03 — Portafoglio MASTER: accorpa TUTTE le strategie (fade + honest). Unisce le due famiglie del progetto, quasi scorrelate (correlazione cross-famiglia ~0.05), in un unico portafoglio diversificato: FADE (reversione intraday 1h, long/short, BTC/ETH, col filtro trend): MR01 Bollinger · MR02 Donchian · MR07 Return-reversal -> 6 sleeve HONEST (long-only multi-regime multi-crypto): DIP01 dip-buy (1h) · TR01 EMA-trend (4h basket) · ROT02 dual-momentum (1d) -> 3 sleeve Combinare le due famiglie migliora il rischio/rendimento rispetto a ciascuna da sola: il DD scende e lo Sharpe sale (la honest, da sola piu' lumpy, viene stabilizzata dalle fade ad alta frequenza). Vedi scripts/analysis/combine_portfolio.py. Risultato (netto, equal-weight daily, finestra comune 2021-2026, OOS = ultimo 30%): FADE only (6) DD 8.2% Sharpe 3.95 (OOS DD 5.9 / Shrp 4.09) HONEST only (3) DD 12.0% Sharpe 1.90 (OOS DD 6.5 / Shrp 2.23) MASTER eq (9) DD 5.2% Sharpe 3.95 (OOS DD 4.7 / Shrp 4.42) <- miglior Sharpe MASTER 50/50 DD 5.1% Sharpe 3.31 (OOS DD 4.3) <- miglior DD CAGR ~46% mantenuta in entrambe le varianti combinate. Due varianti operative selezionabili: weighting="equal" -> equal-weight sui 9 sleeve (massimo Sharpe) weighting="5050" -> 50% famiglia fade + 50% famiglia honest (minimo DD) """ from __future__ import annotations import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(PROJECT_ROOT)) from scripts.analysis.combine_portfolio import ( # noqa: E402 build_all_sleeves, port_returns, metrics, yearly_returns, SPLIT, OOS_DATE, IDX, ) def master_returns(sleeves: dict, weighting: str = "equal"): """Rendimenti giornalieri del portafoglio master. equal = equal-weight su tutti gli 11 sleeve; 5050 = media fra le due famiglie.""" fade = {k: v for k, v in sleeves.items() if k.startswith("MR")} honest = {k: v for k, v in sleeves.items() if not k.startswith("MR")} if weighting == "5050": return (port_returns(fade) + port_returns(honest)) / 2 return port_returns(sleeves) def run(): sleeves = build_all_sleeves() fade = {k: v for k, v in sleeves.items() if k.startswith("MR")} honest = {k: v for k, v in sleeves.items() if not k.startswith("MR")} print("=" * 90) print(f" PORT03 — MASTER (fade + honest) | {IDX[0].date()} -> {IDX[-1].date()} | OOS da {OOS_DATE}") print("=" * 90) print(f" {'portafoglio':<22s}{'Ret%':>9s}{'CAGR':>7s}{'DD%':>7s}{'Shrp':>7s}" f" | {'oRet%':>9s}{'oDD%':>7s}{'oShrp':>7s}") print(" " + "-" * 86) def line(label, pr): f, o = metrics(pr), metrics(pr, lo=SPLIT) print(f" {label:<22s}{f['ret']:>+9.0f}{f['cagr']:>7.0f}{f['dd']:>7.1f}{f['sharpe']:>7.2f}" f" | {o['ret']:>+9.0f}{o['dd']:>7.1f}{o['sharpe']:>7.2f}") line(f"FADE only ({len(fade)})", port_returns(fade)) line(f"HONEST only ({len(honest)})", port_returns(honest)) line(f"MASTER equal ({len(sleeves)})", master_returns(sleeves, "equal")) line("MASTER 50/50 fam", master_returns(sleeves, "5050")) print(" " + "-" * 86) pa = yearly_returns(master_returns(sleeves, "equal")) print(" MASTER equal per-anno: " + " ".join(f"{y}:{v:+.0f}%" for y, v in pa.items())) print(" -> combinare le due famiglie scorrelate (~0.05) abbassa il DD e alza lo Sharpe.") if __name__ == "__main__": run()