feat(dashboard): pannello COMBO cross-venue (TP01 Deribit + GTAA IB)

Aggiunge alla dashboard la sezione "COMBO DEPLOYABLE — cross-venue (paper)": equity paper forward
del blend 50/50 TP01+GTAA (da data/paper_combo/state.json) + posizioni azionabili IB correnti
(gtaa_weights: peso ETF + cash, asof). Nota onesta: paper rischio-zero, Sharpe ~1.5 ottimistico, il
robusto e' la diversificazione (corr 0.21, DD dimezzato); XS01/VRP01 esclusi (STAT-MODE).
Container ricostruito (codice baked nell'immagine).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-23 12:32:19 +00:00
parent 3b552a92da
commit 389573e517
+30
View File
@@ -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 <code>scripts/live/paper_prevday.py</code>)"
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"<b>{cb['equity']:.2f}</b> (start {cb['initial']:.0f}, {cb['start'][:10]}"
f"{cb['last'][:10]}, {cdays}g, {cb['n_days']} barre) &nbsp; ret <b>{cret*100:+.2f}%</b> "
f"&nbsp; maxDD {cb['max_dd']*100:.1f}% &nbsp; blend {wc*100:.0f}/{(1-wc)*100:.0f} TP01/GTAA")
else:
combo_html = "non inizializzato (gira <code>scripts/live/paper_combo.py</code>)"
gw = d.get("gtaa_weights")
if gw:
asof = gw.get("_asof", "?"); cash = gw.get("_cash")
gw_html = (", ".join(f"{k} <b>{v:.0%}</b>" for k, v in gw.items() if not k.startswith("_") and v)
+ (f" · cash <b>{cash:.0%}</b>" if cash is not None else "")
+ f" <span style='color:#8a93a0'>(asof {asof})</span>")
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 = " &nbsp;·&nbsp; ".join(
@@ -175,6 +201,10 @@ th{{color:#8a93a0;font-weight:500}}.y{{display:inline-block;background:#161b22;b
<h3 style="font-size:14px;color:#8a93a0">Trades TP01 — entry/exit (segnale causale, ultimi 15)</h3>
<table><tr><th>data</th><th>asset</th><th>azione</th><th>posizione</th><th>prezzo</th></tr>{trows}</table>
<div style="margin-top:10px">{yrs}</div>
<div class="section">COMBO DEPLOYABLE — cross-venue (paper, forward-only)</div>
<div class=box><b>TP01 (Deribit) + GTAA (IB)</b> — le DUE gambe ESEGUIBILI a basso capitale, scorrelate (corr ~0.21) → blend Sharpe ~1.5, drawdown dimezzato. <b>Nessuna esecuzione reale</b>:<br>{combo_html}<br>
<span style="color:#8a93a0;font-size:13px">posizioni azionabili IB (GTAA, peso ETF):</span> {gw_html}</div>
<p class=warn>⚠️ 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.</p>
<div class="section">FORWARD-MONITOR — lead paper (non deploy)</div>
<div class=box><b>PREVDAY range-breakout</b> — lead ORTOGONALE a TP01 (corr ~0.15 full / ~0 hold; marginal ADDS, non-hedge, robusto allo shift del confine-giorno). Forward-only, <b>nessuna esecuzione reale</b>:<br>{prevday_html}</div>
<p class=warn>⚠️ 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.</p>