From b5db59bea9d7e51b07fe110d9bb6e7ca4f8a904d Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Sun, 21 Jun 2026 19:27:27 +0000 Subject: [PATCH] feat(dashboard): mostra il forward-monitor PREVDAY (lead ortogonale a TP01) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nuova sezione "FORWARD-MONITOR — lead paper (non deploy)" nel dashboard, tra PAPER e LIVE: legge data/paper_prevday/state.json e mostra i due libri (modeled €2k nominale vs real-$600 con min-order $5), ret/maxDD di entrambi, il fill-haircut, le posizioni correnti BTC/ETH e i giorni/flip forward. Nota esplicita: LEAD in osservazione, NON deployato. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/live/dashboard.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/live/dashboard.py b/src/live/dashboard.py index 385fb30..8db1053 100644 --- a/src/live/dashboard.py +++ b/src/live/dashboard.py @@ -19,6 +19,7 @@ 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" _CACHE = {"t": 0.0, "data": None} _TTL = 120.0 @@ -33,6 +34,7 @@ def build(): step = max(1, len(eq) // 400) 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 try: shadow = shadow_report() # mainnet sola lettura, best-effort except Exception as e: @@ -46,8 +48,8 @@ def build(): last_data=str(idx[-1].date()), 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, shadow=shadow, trades=trades, - bh=None, + positions=pf.current_positions(), spark=spark, paper=paper, prevday=prevday, + shadow=shadow, trades=trades, bh=None, ) _CACHE.update(t=time.time(), data=data) return data @@ -86,6 +88,22 @@ def html(): f"{pp['last'][:10]}, {days}g)   ret {ret*100:+.2f}%   maxDD {pp['max_dd']*100:.1f}%") else: paper_html = "non inizializzato (gira paper_portfolio.py)" + pv = d.get("prevday") + if pv: + days = (pv["last_ts"] - pv["start_ts"]) / 86400_000 + rm = pv["cap_modeled"] / 2000.0 - 1 + rr = pv["cap_real"] / 600.0 - 1 + prevday_html = ( + f"${pv['cap_modeled']:,.2f} modeled (€2k nom.)  ·  " + f"${pv['cap_real']:,.2f} real-$600 (min-order $5)
" + f"ret {rm*100:+.2f}% / {rr*100:+.2f}%  ·  " + f"maxDD {pv['dd_modeled']*100:.1f}% / {pv['dd_real']*100:.1f}%  ·  " + f"fill-haircut {(rm-rr)*100:+.2f}pp
" + f"posizione: BTC {pv['pos_real']['BTC']:+.3f} · ETH {pv['pos_real']['ETH']:+.3f}  ·  " + f"{pv['n_bars']} barre 1h (~{days:.0f}g) · {pv['n_trades']} flip · " + f"forward da {pd.Timestamp(pv['start_ts'], unit='ms').date()}") + else: + prevday_html = "non inizializzato (gira scripts/live/paper_prevday.py)" sh = d.get("shadow") if sh and "error" not in sh: bits = "  ·  ".join( @@ -157,6 +175,9 @@ th{{color:#8a93a0;font-weight:500}}.y{{display:inline-block;background:#161b22;b

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

{trows}
dataassetazioneposizioneprezzo
{yrs}
+
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.

LIVE — Deribit mainnet (conto reale, sola lettura)
Shadow TP01 (cosa farebbe ORA sul conto reale, nessun ordine inviato):
{shadow_html}

Trades REALI eseguiti su Deribit