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
| data | asset | azione | posizione | prezzo |
|---|
⚠️ 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.
⚠️ 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.