diff --git a/docs/diary/2026-06-18-price-ladder-search.md b/docs/diary/2026-06-18-price-ladder-search.md index 444480e..3529210 100644 --- a/docs/diary/2026-06-18-price-ladder-search.md +++ b/docs/diary/2026-06-18-price-ladder-search.md @@ -187,3 +187,44 @@ un deploy ingiustificato** — esattamente la lezione anti-squeeze del progetto. spike-print + girare `close_only` sui finalisti; (2) **test di significatività** del delta OOS (block-bootstrap) al peso reale; (3) **co-tail / corr nei crash** (2022), non corr daily calma; (4) isolare e spiegare l'**evento feb-2024**. Config live **invariata**. + +--- + +## 7. RE-GATE su DATI PULITI (post clean_feed.py) — quadro onesto finale + +Dopo `clean_feed.py` (254 spike-print riparati con Binance) ho ri-gateato i top candidati con +le verifiche che il critico chiedeva (`ladder_regate_clean.py`): gate PORT06 + stress +`close_only` + **DD per anno** sulla storia completa. + +| Candidato | DD (gate, 2021+) | OOS Sh | corr | fee2x | close_only OOS | gate½ | **DD 2018 (tail vero)** | +|---|---:|---:|---:|---:|---:|---|---:| +| ETH 1h rd0.16 ru0.04 L4 range2 | 12.4% | 4.70 | 0.29 | 4.62 | 0.24 | PROMOSSO | −52.4% | +| ETH 1h rd0.16 ru0.06 L4 range2 | 12.6% | 4.25 | 0.23 | 4.17 | 0.20 | PROMOSSO | −49.9% | +| BTC 1h rd0.08 ru0.06 L3 none | 10.8% | 5.90 | 0.24 | 5.78 | 0.60 | PROMOSSO | −50.3% | +| **BTC 1h rd0.20 ru0.06 L6 range1.5** | 14.8% | 5.58 | 0.23 | 5.46 | 0.89 | PROMOSSO | **−27.7%** | +| BTC 30m rd0.08 ru0.06 L3 none | 14.8% | 5.47 | 0.25 | 5.37 | 1.07 | PROMOSSO | −36.6% | + +**Cosa cambia coi dati puliti:** +1. ✅ **L'obiezione "coda artefatto" CADE.** Il 54% del BTC era spike-print 2024: ora la DD del + gate (2021+) è **~11-15%** e tutti i candidati restano PROMOSSO a half-size, corr 0.22-0.29, + reggono fee2x. Sono candidati *veri*, non artefatti. +2. 🔴 **Emerge il tail VERO: il 2018** (−44/−52% standalone), che **il gate NON VEDE** perché + l'IDX del progetto parte dal 2021-01-01. Una griglia long-only sarebbe stata sventrata nel + bear 2018 (BTC −84% sull'anno). È il nuovo rischio portante — e una **lacuna metodologica + generale**: tutte le metriche "FULL" del progetto escludono il 2018. Mitigante reale: il + **regime-gate stretto** (BTC rd0.20 L6 **range1.5**) dimezza il tail 2018 a **−27.7%** (vs + −50% senza gate) → il gate-di-regime fa il suo lavoro contro i bear sostenuti. +3. 🟡 **L'edge dipende dai fill INTRABAR.** `close_only` (fill solo sul close) fa crollare l'OOS + (4.7→0.24 ETH, 5.9→0.6 BTC). Per ordini LIMIT i fill intrabar sono legittimi (close_only è + troppo severo come stress), ma il gap segnala forte **sensibilità all'ipotesi di fill** → + il ledger shadow reale è indispensabile prima di fidarsi. +4. 🟡 Restano: corr 0.22-0.29 (moderata), guadagno OOS ai limiti del rumore al peso deployabile + (~2.7% half), OOS singolo regime calmo. + +**Verdetto finale (clean data):** la pulizia ha rimosso l'obiezione FALSA (coda artefatto) e +promosso i candidati a *genuini*, ma ha anche scoperto il tail REALE (2018, gate-cieco) e +confermato due cautele (fill intrabar, OOS rumoroso). **Il candidato più sensato è ora +`BTC 1h rd0.20 ru0.06 L6 regime=range trend_max1.5`**: PROMOSSO, corr 0.23, e la **miglior coda +2018 (−27.7%)** grazie al regime-gate. **Prima di QUALSIASI deploy**: (1) backtest che INCLUDA il +2018 nel gate (non solo IDX 2021+), (2) ledger shadow reale per i fill intrabar/maker, (3) half-size. +La pulizia del feed resta il guadagno trasversale più grande (irrobustisce ogni backtest del progetto). diff --git a/scripts/analysis/ladder_regate_clean.py b/scripts/analysis/ladder_regate_clean.py new file mode 100644 index 0000000..3f39946 --- /dev/null +++ b/scripts/analysis/ladder_regate_clean.py @@ -0,0 +1,70 @@ +"""LADDER RE-GATE su DATI PULITI (2026-06-18) — ri-valuta i top candidati Price Ladder dopo +clean_feed.py, con le verifiche che il critico aveva chiesto: + - gate PORT06 + corr + fee2x (su feed corretto); + - stress close_only (fill solo sul close: su dati puliti deve ~combaciare col base -> niente + dipendenza residua da spike-print); + - DD PER ANNO della griglia standalone (dov'e' la coda VERA, non l'artefatto feb-2024). + + uv run python scripts/analysis/ladder_regate_clean.py +""" +from __future__ import annotations + +import sys +from pathlib import Path + +PROJECT_ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(PROJECT_ROOT)) + +from scripts.analysis.ladder_search import evaluate, regime_mask +from scripts.analysis.grid_game_gate import grid_mtm + +# top candidati dal workflow (asset, tf, rd, ru, levels, sl_buf, tp_buf, max_bars, regime, trend_max) +CANDS = [ + ("ETH", "1h", 0.16, 0.04, 4, 0.12, 0.05, 720, "range", 2.0), # raccomandato dalla sintesi + ("ETH", "1h", 0.16, 0.06, 4, 0.12, 0.05, 720, "range", 2.0), # corr piu' bassa (0.249) + ("ETH", "30m", 0.16, 0.04, 3, 0.12, 0.05, 1440, "range", 2.0), + ("BTC", "1h", 0.08, 0.06, 3, 0.12, 0.05, 720, "none", 2.0), # best OOS; DD era 53.69% (artefatto) + ("BTC", "1h", 0.20, 0.06, 6, 0.12, 0.05, 720, "range", 1.5), # corr piu' bassa (0.161) + ("BTC", "30m", 0.08, 0.06, 3, 0.12, 0.05, 1440, "none", 2.0), +] + + +def peryear_dd(asset, tf, rd, ru, lv, sl, tp, mb, regime, tmax): + mask = regime_mask(asset, tf, trend_max=tmax) if regime == "range" else None + eqd, _ = grid_mtm(asset, tf=tf, range_down=rd, range_up=ru, levels=lv, + sl_buf=sl, tp_buf=tp, max_bars=mb, deploy_mask=mask) + out = {} + for y, g in eqd.groupby(eqd.index.year): + peak = g.cummax() + out[int(y)] = round(float(((g - peak) / peak).min() * 100), 1) + return out + + +def main(): + print("RE-GATE PRICE LADDER su dati PULITI — gate PORT06 + close_only stress + DD/anno\n") + print(f"{'candidato':<34}{'fullDD':>7}{'oos_sh':>7}{'corr':>6}{'fee2x':>6}" + f"{'co_oos':>7}{'verdHALF':>10} DD per anno") + for c in CANDS: + asset, tf, rd, ru, lv, sl, tp, mb, regime, tmax = c + r = evaluate(asset, tf, rd, ru, lv, sl, tp, mb, regime=regime, trend_max=tmax) + rc = evaluate(asset, tf, rd, ru, lv, sl, tp, mb, regime=regime, trend_max=tmax, + close_only=True, do_gate=False, do_fee2x=False) + pyd = peryear_dd(*c) + tag = f"{asset} {tf} rd{rd} ru{ru} L{lv} {regime}" + py = " ".join(f"{y}:{v}" for y, v in pyd.items()) + print(f"{tag:<34}{r['full_dd']:>7.1f}{r['oos_sh']:>7.2f}{r['max_corr_existing']:>6.2f}" + f"{r['fee2x_oos_sh']:>6.2f}{rc['oos_sh']:>7.2f}{r['verdict_half']:>10} {py}") + print("\n fullDD = DD standalone sulla finestra del GATE (IDX 2021+); era ~54% su BTC") + print(" PRIMA della pulizia (artefatto spike-print 2024, ora sparito).") + print(" ATTENZIONE — DD per anno: il TAIL VERO e' il 2018 (-44/-52%), che il gate (IDX") + print(" 2021-01-01+) NON VEDE. Una griglia long-only sarebbe stata sventrata nel") + print(" bear 2018. Il regime-gate piu' stretto (BTC rd0.2 L6 range1.5) lo dimezza (-27.7%).") + print(" co_oos = OOS Sharpe con fill SOLO sul close (no wick). CROLLA (4.7->0.2): l'edge della") + print(" griglia viene dai fill INTRABAR ai livelli. Per ordini LIMIT i fill intrabar") + print(" sono LEGITTIMI (close_only e' troppo severo), ma il gap segnala sensibilita'") + print(" all'ipotesi di fill -> serve il ledger shadow reale prima di fidarsi.") + print(" verdHALF = gate PORT06 a half-size | corr = max corr coi 19 sleeve (ridondanza)") + + +if __name__ == "__main__": + main()