diff --git a/src/live/dashboard.py b/src/live/dashboard.py index 8db1053..71bd5ff 100644 --- a/src/live/dashboard.py +++ b/src/live/dashboard.py @@ -15,11 +15,13 @@ sys.path.insert(0, str(PROJECT_ROOT)) import numpy as np, pandas as pd from src.portfolio.portfolio import StrategyPortfolio, metrics, HOLDOUT from src.portfolio.sleeves import active_sleeves +from src.portfolio.gtaa import gtaa_weights from src.live.shadow import shadow_report, tp01_trades from src.version import APP_VERSION PAPER = PROJECT_ROOT / "data" / "paper_portfolio" / "state.json" PREVDAY = PROJECT_ROOT / "data" / "paper_prevday" / "state.json" +COMBO = PROJECT_ROOT / "data" / "paper_combo" / "state.json" _CACHE = {"t": 0.0, "data": None} _TTL = 120.0 @@ -35,6 +37,11 @@ def build(): spark = [(str(idx[i].date()), float(eq[i])) for i in range(0, len(eq), step)] paper = json.loads(PAPER.read_text()) if PAPER.exists() else None prevday = json.loads(PREVDAY.read_text()) if PREVDAY.exists() else None + combo = json.loads(COMBO.read_text()) if COMBO.exists() else None + try: + gtaa_w = gtaa_weights() # pesi ETF correnti azionabili (cache eq_*) + except Exception: + gtaa_w = None try: shadow = shadow_report() # mainnet sola lettura, best-effort except Exception as e: @@ -49,6 +56,7 @@ def build(): full=bt["full"], holdout=bt["holdout"], weights=bt["weights"], per_sleeve=bt["per_sleeve"], yearly=bt["yearly"], positions=pf.current_positions(), spark=spark, paper=paper, prevday=prevday, + combo=combo, gtaa_weights=gtaa_w, shadow=shadow, trades=trades, bh=None, ) _CACHE.update(t=time.time(), data=data) @@ -104,6 +112,24 @@ def html(): f"forward da {pd.Timestamp(pv['start_ts'], unit='ms').date()}") else: prevday_html = "non inizializzato (gira scripts/live/paper_prevday.py)" + cb = d.get("combo") + if cb: + cdays = (pd.Timestamp(cb["last"]) - pd.Timestamp(cb["start"])).days + cret = cb["equity"] / cb["initial"] - 1 + wc = cb.get("w_crypto", 0.5) + combo_html = (f"{cb['equity']:.2f} (start {cb['initial']:.0f}, {cb['start'][:10]} → " + f"{cb['last'][:10]}, {cdays}g, {cb['n_days']} barre)   ret {cret*100:+.2f}% " + f"  maxDD {cb['max_dd']*100:.1f}%   blend {wc*100:.0f}/{(1-wc)*100:.0f} TP01/GTAA") + else: + combo_html = "non inizializzato (gira scripts/live/paper_combo.py)" + gw = d.get("gtaa_weights") + if gw: + asof = gw.get("_asof", "?"); cash = gw.get("_cash") + gw_html = (", ".join(f"{k} {v:.0%}" for k, v in gw.items() if not k.startswith("_") and v) + + (f" · cash {cash:.0%}" if cash is not None else "") + + f" (asof {asof})") + else: + gw_html = "n/d (cache ETF assente — gira fetch_ib_equities.py)" sh = d.get("shadow") if sh and "error" not in sh: bits = "  ·  ".join( @@ -175,6 +201,10 @@ th{{color:#8a93a0;font-weight:500}}.y{{display:inline-block;background:#161b22;b

Trades TP01 — entry/exit (segnale causale, ultimi 15)

{trows}
dataassetazioneposizioneprezzo
{yrs}
+
COMBO DEPLOYABLE — cross-venue (paper, forward-only)
+
TP01 (Deribit) + GTAA (IB) — le DUE gambe ESEGUIBILI a basso capitale, scorrelate (corr ~0.21) → blend Sharpe ~1.5, drawdown dimezzato. Nessuna esecuzione reale:
{combo_html}
+posizioni azionabili IB (GTAA, peso ETF): {gw_html}
+

⚠️ PAPER cross-venue: valida l'operativita' su due conti (Deribit + IB) a rischio zero. Lo Sharpe ~1.5 e' ottimistico (finestra crypto corta/favorevole); il dato robusto e' la diversificazione (corr 0.21, DD dimezzato), non il livello. XS01/VRP01 esclusi (STAT-MODE): qui solo TP01+GTAA.

FORWARD-MONITOR — lead paper (non deploy)
PREVDAY range-breakout — lead ORTOGONALE a TP01 (corr ~0.15 full / ~0 hold; marginal ADDS, non-hedge, robusto allo shift del confine-giorno). Forward-only, nessuna esecuzione reale:
{prevday_html}

⚠️ LEAD in osservazione, NON deployato. Sopravvissuto alla verifica avversariale dell'onda intraday; lo teniamo in paper per validarlo fuori-campione-vero. I due libri (modeled vs real-$600) mostrano l'haircut di fill che lo scettico aveva segnalato.