feat(analysis): ladder_search — harness caccia Price Ladder che passi il gate PORT06

Goal "decine di agenti a cercare strategie Price Ladder" (Deribit). Riusa il motore
grid_mtm mark-to-market ONESTO (SL gap-aware, flat-skip, fee 0.10% RT taker = CONSERVATIVO
su Deribit, dove i fill ai livelli LIMIT sono maker ~0%) ed espone:
  - eval  <asset tf rd ru levels sl_buf tp_buf max_bars [regime] [trend_max]>
  - scan  <asset tf [regime] [trend_max]>  (sub-griglia struttura, gate PORT06, baseline
    cachata) -> top celle con verdetto gate + max_corr coi 19 sleeve + FULL DD.
Leva NUOVA: regime-gate `range` (deploy_mask in grid_mtm, retro-compatibile) = deploya la
griglia SOLO in regime di range (|close-EMA200|/ATR < trend_max), dove la griglia vive, e
non in trend dove muore. Contesto della ricerca: la griglia ETH del gioco e' BOCCIATA
(ridondante, corr 0.40); i ladder BTC sono meno correlati (~0.18) e passano il gate, MA il
nodo e' la FULL DD (coda di trend 2021/22, ~60% standalone) che il verdetto del gate NON
controlla -> la harness la espone (full_dd standalone + full_full_dd di portafoglio).
grid_mtm: aggiunto param deploy_mask (None = comportamento storico, parita' col gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-18 12:29:25 +00:00
parent 57758ffcb1
commit d733196564
2 changed files with 199 additions and 1 deletions
+8 -1
View File
@@ -68,11 +68,15 @@ 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):
close_only=False, deploy_mask=None):
"""Griglia STRATEGIA_GRIGLIA.md con contabilita' mark-to-market.
Ritorna (equity daily Series base 1.0, stats dict). Causale: deploy sul
close, fill dalle barre successive lungo il percorso O->L->H->C / O->H->L->C.
`deploy_mask` (opzionale, np.bool array lungo come la serie, causale): se
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 = _load(asset, tf)
op = df["open"].to_numpy(float)
@@ -106,6 +110,9 @@ def grid_mtm(asset="ETH", *, tf, range_down, range_up, levels, sl_buf, tp_buf,
i = 20
for j in range(20, n):
if not active:
if deploy_mask is not None and not deploy_mask[j]:
eq[j] = capital # regime-gate: niente deploy, resta in cash
continue
# deploy sul close di j (fill da j+1)
px = cl[j]
rl_ = px * (1 - range_down)