feat(live): GridWorker (Price Ladder) SIM/PAPER + validazione replay==backtest — shadow stage 1

Stage 1 dello shadow per il Price Ladder (config finale: BTC 1h range1.5 rd0.20 ru0.06 L6
sl0.10 tp0.03). GridWorker (src/live/grid_worker.py) gira sul feed LIVE e contabilizza
l'equity mark-to-market col motore CANONICO grid_mtm (parita' col backtest per costruzione),
SENZA piazzare ordini reali (sim/paper). Stato persistente + resume. grid_mtm esteso con
param df=None (retro-compatibile: il feed live passa il df; None = _load come prima, gate
invariato — BTC ladder 10.8/5.9, PORT06 base 8.18 identici). Validazione
validate_grid_worker.py: [A] full-tick == grid_mtm esatto, [B] replay incrementale converge
esatto, [C] resume entro la persistenza (4 dec) -> VALIDAZIONE OK.

NB SICUREZZA: nessuna modifica a runner/portfolios.yml/_defs -> il sistema mainnet (€500
reali) e' INTATTO; il worker e' inerte finche' non wirato. L'esecuzione REALE (griglia di
LIMIT resting su Deribit, fill parziali/episodi) e' lo stage 2-3, dietro testnet +
autorizzazione esplicita. Il runner avvia ordini reali solo per kind in (single,ml);
kind=grid resta sim per costruzione.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-18 14:58:11 +00:00
parent 587fbc0f61
commit b3d4ab7150
3 changed files with 210 additions and 2 deletions
+4 -2
View File
@@ -68,7 +68,7 @@ def _load(asset, tf):
def grid_mtm(asset="ETH", *, tf, range_down, range_up, levels, sl_buf, tp_buf,
max_bars, pos=POS, lev=LEV, fee_side=FEE_SIDE, flat_skip=True,
close_only=False, deploy_mask=None):
close_only=False, deploy_mask=None, df=None):
"""Griglia STRATEGIA_GRIGLIA.md con contabilita' mark-to-market.
Ritorna (equity daily Series base 1.0, stats dict). Causale: deploy sul
@@ -77,8 +77,10 @@ def grid_mtm(asset="ETH", *, tf, range_down, range_up, levels, sl_buf, tp_buf,
fornito, una NUOVA griglia si deploya SOLO dove mask[j]=True (regime-gate);
None = comportamento storico (deploy sempre). Una griglia gia' attiva non
viene interrotta dal mask (gestisce il suo episodio fino a SL/TP/timeout).
`df` (opzionale): OHLCV gia' caricato (per il feed LIVE del GridWorker); None
= carica da _load(asset, tf) (comportamento storico, parita' col gate).
"""
df = _load(asset, tf)
df = _load(asset, tf) if df is None else df
op = df["open"].to_numpy(float)
hi = df["high"].to_numpy(float)
lo = df["low"].to_numpy(float)