diff --git a/src/live/dashboard.py b/src/live/dashboard.py
index a913e48..0cacb98 100644
--- a/src/live/dashboard.py
+++ b/src/live/dashboard.py
@@ -32,6 +32,21 @@ def build():
pf = StrategyPortfolio(active_sleeves(), capital=2000.0)
bt = pf.backtest()
eq = bt["equity"]; idx = bt["index"]
+ # BOOK DERIBIT-ONLY eseguibile (TP01 75% + SKH01 25%), riusando i daily gia' calcolati
+ try:
+ sl_by = {s.name: s for s in pf.sleeves}
+ tp_d, sk_d = sl_by["TP01_trend_1d"].daily(), sl_by["SKH01_skyhook"].daily()
+ Jd = pd.concat({"t": tp_d, "s": sk_d}, axis=1, join="inner").fillna(0.0)
+ der = 0.75 * Jd["t"] + 0.25 * Jd["s"]
+ mm = ((1.0 + der).resample("ME").prod() - 1.0).dropna()
+ d_cagr = float(np.prod(1.0 + mm.values) ** (12.0 / len(mm)) - 1.0) if len(mm) else 0.0
+ cons = d_cagr * 0.5
+ rd = (1.0 + cons) ** (1.0 / 365.0) - 1.0 if cons > 0 else 0.0
+ deribit = dict(full=metrics(der), hold=metrics(der[der.index >= HOLDOUT]),
+ cagr=d_cagr, cons_cagr=cons, eday_5k=5000.0 * rd,
+ eq5_5y=5000.0 * (1.0 + cons) ** 5, eq5_10y=5000.0 * (1.0 + cons) ** 10)
+ except Exception as e:
+ deribit = {"error": f"{type(e).__name__}: {e}"}
# sparkline: subsample ~400 punti
step = max(1, len(eq) // 400)
spark = [(str(idx[i].date()), float(eq[i])) for i in range(0, len(eq), step)]
@@ -56,7 +71,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,
+ combo=combo, gtaa_weights=gtaa_w, deribit=deribit,
shadow=shadow, trades=trades, bh=None,
)
_CACHE.update(t=time.time(), data=data)
@@ -146,6 +161,18 @@ def html():
+ f" (asof {asof})")
else:
gw_html = "n/d (cache ETF assente — gira fetch_ib_equities.py)"
+ db = d.get("deribit")
+ if db and "error" not in db:
+ f2, h2 = db["full"], db["hold"]
+ deribit_html = (
+ f"FULL Sh {f2['sharpe']:.2f} ret {f2['ret']*100:+.0f}% DD {f2['maxdd']*100:.1f}% · "
+ f"HOLD-OUT Sh {h2['sharpe']:.2f} DD {h2['maxdd']*100:.1f}%
"
+ f"accumulo (reinvesti le vincite, no leva) — CAGR storico "
+ f"{db['cagr']*100:.0f}%, conservativo {db['cons_cagr']*100:.0f}%: "
+ f"da €5k → ~€{db['eq5_5y']:,.0f} (5a) / ~€{db['eq5_10y']:,.0f} (10a) · "
+ f"run-rate oggi ~€{db['eday_5k']:.2f}/g @conservativo")
+ else:
+ deribit_html = "n/d" + (f" — {db['error']}" if db and db.get("error") else "")
sh = d.get("shadow")
if sh and "error" not in sh:
bits = " · ".join(
@@ -221,6 +248,10 @@ th{{color:#8a93a0;font-weight:500}}.y{{display:inline-block;background:#161b22;b
⚠️ 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.
+scripts/portfolio/forecast_deribit_book.py · report: scripts/portfolio/run_deribit_book.py⚠️ Accumulo = proiezione condizionata (storico bull crypto → pianifica sul conservativo); nessuna leva; SKH01 research/forward-monitor (solo TP01 armato live). A €50/g servono ~€177k @conservativo: la via è capitale+tempo, non leva.
⚠️ 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.