"""REPORT del portafoglio di strategie attivo (estensibile). Costruisce il portafoglio dagli sleeve attivi (src/portfolio/sleeves.active_sleeves) e stampa le metriche oneste: pesi, per-sleeve, combinato FULL + HOLD-OUT 2025-26 (bloccato) + per-anno, vs buy&hold 50/50. Per ora c'e' solo TP01; aggiungere sleeve = una riga in sleeves.py. uv run python scripts/portfolio/run_portfolio.py """ from __future__ import annotations import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(PROJECT_ROOT)) import numpy as np import pandas as pd from src.data.downloader import load_data from src.strategies.trend_portfolio import resample_1d, simple_returns from src.portfolio.portfolio import StrategyPortfolio, to_daily, metrics, HOLDOUT from src.portfolio.sleeves import active_sleeves CAPITAL = 2000.0 def buy_hold_daily() -> pd.Series: s = {} for a in ("BTC", "ETH"): df = resample_1d(load_data(a, "1h")) s[a] = pd.Series(simple_returns(df["close"].values.astype(float)), index=pd.to_datetime(df["datetime"])) J = pd.concat(s, axis=1, join="inner").fillna(0.0) return to_daily(pd.Series(0.5 * J["BTC"].values + 0.5 * J["ETH"].values, index=J.index)) def fmt(m, cap=CAPITAL): yrs = m["n"] / 365.25 eur_day = (cap * m["ret"]) / (yrs * 365.25) if yrs > 0 else 0.0 return (f"Sh {m['sharpe']:>5.2f} | ret {m['ret']*100:>+8.1f}% CAGR {m['cagr']*100:>+6.1f}% | " f"DD {m['maxdd']*100:>5.1f}% | ~€/g(2k) {eur_day:>+5.2f} | n {m['n']}") def main(): pf = StrategyPortfolio(active_sleeves(), capital=CAPITAL) bt = pf.backtest() print("=" * 96) print(f" PORTAFOGLIO DI STRATEGIE — {len(pf.sleeves)} sleeve | capitale {CAPITAL:,.0f} | hold-out {HOLDOUT.date()}+ bloccato") print("=" * 96) print("\n PESI:", " ".join(f"{k} {v*100:.0f}%" for k, v in bt["weights"].items())) print("\n PER-SLEEVE (standalone):") for name, d in bt["per_sleeve"].items(): print(f" {name:<16s} [{d['weight']*100:>3.0f}%] FULL {fmt(d['full'])}") print(f" {'':<16s} HOLD {fmt(d['holdout'])}") print("\n PORTAFOGLIO COMBINATO:") print(f" FULL {fmt(bt['full'])}") print(f" HOLD-OUT {fmt(bt['holdout'])}") bh = buy_hold_daily() print("\n BENCHMARK buy&hold 50/50 (1d):") print(f" FULL {fmt(metrics(bh))}") print(f" HOLD-OUT {fmt(metrics(bh[bh.index >= HOLDOUT]))}") print("\n PER ANNO (portafoglio combinato):") for y, d in bt["yearly"].items(): print(f" {y}: ret {d['ret']*100:>+7.1f}% DD {d['dd']*100:>5.1f}%") print("\n POSIZIONI CORRENTI (ultima barra chiusa):") for name, pos in pf.current_positions().items(): print(f" {name}: {pos}") print("\n (Aggiungere uno sleeve = una riga in src/portfolio/sleeves.active_sleeves, dopo validazione.)") if __name__ == "__main__": main()