Files
Adriano Dal Pastro 14522262e6 chore(reset): v2.0.0 — storico certificato Deribit mainnet, ripartenza pulita
Reset del progetto su fondamenta verificate dopo la scoperta che l'intera
libreria "validata OOS" era artefatto di feed contaminato (print fantasma del
feed Cerbero TESTNET + storico Binance/USDT).

- Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e
  CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia
  (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample
  (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE
  50-82% barre flat; XRP/BNB non certificabili).
- Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni
  portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST
  con segnale residuo, da ri-validare in isolamento.
- Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio,
  runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/
  portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/
  (preservati, non cancellati). Diario consolidato in un unico documento.
- Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal +
  src/backtest/engine + load_data; tool dati certificati (rebuild_history,
  certify_feed, audit_feed, multi_source_check).
- Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico
  (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 15:20:59 +00:00

177 lines
9.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-06-04 — EXIT LAB: ricerca massiva exit dinamiche (34 agenti) → EXIT-16 close-confirm SL PROMOSSO
## Obiettivo
Cercare exit migliori per le fade attive: TP dinamici, SL dinamici/protettivi,
meccanismi per "cavalcare il prezzo". Mandato: ≥20 agenti con specifiche
differenti, guardia anti-overfitting, test su tutto lo storico disponibile.
**Esito in una riga: "cavalcare" non esiste (17ª conferma), ma la ricerca ha
trovato una cosa più grossa — LO STOP-LOSS INTRABAR FISSO È IL COMPONENTE CHE
DISTRUGGE PIÙ VALORE NELLE FADE, e la forma robusta del fix (SL confermato in
chiusura, EXIT-16) è PROMOSSA a livello PORT06: OOS Sharpe 8.82→10.06,
FULL DD 4.10→2.60.**
## Infrastruttura (riusabile)
- `scripts/analysis/exit_lab.py` — harness CONDIVISO: cache segnali live-params
delle 3 fade (`data/cache/exit_lab_signals.pkl`, 73.6k barre 1h 2018→2026-05,
BTC+ETH), engine intrabar identico a `fade_base` (parità verificata al punto
percentuale su tutti e 6 gli sleeve), contratto anti-look-ahead esplicito
(`levels(j)` solo dati ≤ j-1; `after_bar(j)` sul close = eseguibile al poll),
protocollo train/OOS (selezione parametri SOLO su pre-2023-11; OOS letto una
volta), fill parziali, `ExitPolicy` pluggable.
- `scripts/analysis/exit_policies/` — 23 policy + 10 script di verifica.
- `scripts/analysis/exit16_port06_impact.py` — replay canonico `build_trades`/
`fade_daily_equity` con parità ESATTA (corr 1.00000) + innesto EXIT-16 +
ricalcolo PORT06 (cap pairs 0.33, leva 2x).
## Fase 1 — Explore: 23 agenti, una famiglia ciascuno
Tally: **3 PROMISING, 5 NEUTRAL, 15 REJECT.**
REJECT (la famiglia "cavalca il prezzo" è stata falcidiata): trail_atr_ride,
trail_pct, breakeven, sar_trail, tp_decay, tp_extend_momentum, tp_moving_mean,
partial_tp_trail, hurst_exit, giveback, loser_timestop, donchian_trail,
ema_cross_exit, vol_rescale, sl_tp_ride. Autopsia ricorrente: **il TP delle
fade sta ALLA MEDIA; lì il movimento è esaurito per costruzione → oltre quel
punto non c'è coda da cavalcare** (il runner finiva oltre il TP ~3% delle
volte). Caso da manuale `trail_atr_ride`: train 5/6 a favore, **OOS 0/6**
(MR01 ETH ret 134%→1%) — senza l'embargo train/OOS l'avremmo promosso.
NEUTRAL: ratchet, sl_tighten, z_overshoot, wide_sl_trail, swing_stop
(miglioramenti misti, mai 5/6).
PROMISING — tre meccanismi diversi, UNA stessa tesi ("gli stop intrabar da
wick sono falsi negativi: l'overshoot che buca lo stop è esattamente ciò che
la fade vuole fadare, e rientra"):
- **EXIT-02 trail_atr_keep_tp** (chandelier k=1.5 + TP fisso): 6/6 train, 5/6 OOS.
- **EXIT-16 close_confirm_sl** (SL solo se la barra CHIUDE oltre sl0±0.5·ATR):
**6/6 train E 6/6 OOS**, plateau.
- **EXIT-22 no_sl** (diagnostica: SL rimosso): 6/6+6/6, plateau monotono
perfetto `SL stretto < base < SL 2x < niente SL`.
## Fase 2 — Verify: 10 avversari (leakage / overfit / stress × 3 + tail-risk)
- **EXIT-02 CONFUTATO (2/3).** (a) Overfit: è **Pareto-dominato da no_sl a
ZERO parametri** su tutti i 6 sleeve OOS (Sharpe base→trail→noSL: MR01 BTC
2.77→3.08→5.67; MR02 ETH 12.35→11.41→17.24 — il trail PEGGIORA lo sleeve di
punta) → overfit di selezione: la forma parametrizzata sbagliata di una tesi
giusta. (b) Leakage: codice pulito MA **scoperta di metodo: il 54% degli
stop del trail è GAP-THROUGH** (l'open del bar è già oltre il livello;
gap mediano 62-174 bps): l'engine che filla gli stop "al livello" SOVRASTIMA
ogni policy a stop stretti; col fill realistico `worse(level, open)` il
confronto si ribalta. **Da oggi ogni ricerca con stop tight deve modellare
il gap-through.** Lo SL largo della base ne è quasi immune.
- **EXIT-16 SUPERA 4/4.** Leakage: contratto pulito, robusto a 1-3 bar di lag
e al fill a `open[j+1]` (esce deliberatamente tardi → il timing fine è
irrilevante per costruzione). Overfit: plateau monotono su buffer 0.4→1.0
FUORI griglia, il ponte SL-largo k=1.5→4 converge, 4 finestre temporali ok,
e **indipendente dal loss-guard Hurst** (segnali rigenerati senza guard:
la tesi regge anche nel regime trending). Stress: fee 2x 6/6, slippage
20 bps simmetrico 6/6, bear 2021-22 ok.
- **EXIT-22 invalidato SENZA mitigazione (tail-risk).** p99 MAE ~raddoppia
(MR01 ETH 38.8→−59.7%); finestra FTX 2022-11: MR02 ETH **39% (worst 48%,
MAE 70%)** dove la base faceva +2.7% uscendo in 2-3 barre. E un fatto di
wiring: con `sl=0` il worker cade nel ramo `elif max_bars` → **il fallback
2% è codice morto: no_sl live girerebbe SENZA ALCUNO stop**. Il disaster-SL
4× tiene ~95% del ritorno ma il worst pooled resta 47%.
- **Raccomandazione convergente del tail-auditor: EXIT-16** — neutralizza
quasi tutta la coda DA SOLO (p99/worst ≈ base; FTX: +2.4%) mantenendo
l'immunità ai wick. Mai usare uno stop stretto 2% come fallback (cappa
l'edge insieme alla coda).
## Fase 3 — Test decisivo a livello PORT06 (path canonico)
Replay di `build_trades`/`fade_daily_equity` con **parità ESATTA** (corr
1.00000, ritorni identici, PORT06 base == `Portfolio.backtest()` al centesimo:
FULL 6.47/4.10%, OOS 8.82/1.30% — i numeri 6.07/8.19 citati in CLAUDE.md sono
pre-refresh-dati). Poi SOLO il ramo SL sostituito col close-confirm 0.5·ATR:
| PORT06 | FULL Sharpe | FULL DD | FULL CAGR | OOS Sharpe | OOS DD | OOS CAGR |
|--------|------------|---------|-----------|-----------|--------|----------|
| base | 6.47 | 4.10% | 61% | 8.82 | 1.30% | 86% |
| **EXIT-16** | **7.84** | **2.60%** | **79%** | **10.06** | **1.15%** | **102%** |
Gate (lo stesso del loss-guard Hurst): **PROMOSSO** — migliora OGNI metrica,
FULL e OOS. Per-sleeve: ritorni FULL ~4-10x (MR01 BTC 299→1963%) e DD giù su
5/6 (eccezione MR02 ETH +3.4pp, assorbita in aggregato).
## Verdetto e piano di deploy (DA FARE, non ancora implementato)
**EXIT-16 close_confirm_sl, buffer 0.5·ATR14, SOLO sulle 6 fade.**
1. Param `sl_confirm_atr=0.5` nelle fade (default None = comportamento
attuale, per non rompere i backtest canonici/regression-lock).
2. `FadeStrategy.backtest` + `StrategyWorker.tick`: disattivare l'uscita
intrabar a sl0; aggiungere il ramo sul CLOSE del bar (long: esci se
`close < sl0 0.5·ATR14`; short speculare). TP intrabar e max_bars
INVARIATI. ATR14 causale già disponibile.
3. Shadow reale: nessun nuovo tipo d'ordine (il close-confirm esce al close
del worker → market reduce-only come oggi; il limit resting al TP di
v1.0.7 resta identico).
4. DIP01/pairs/rotation/tsmom/shape NON toccati.
## Caveat onesti
- L'uscita al close può essere PEGGIO di sl0 sui veri sfondamenti (già nei
numeri del backtest, ma la coda dipende dai gap: campione 1h crypto,
stress estremi sottorappresentati).
- Niente stop fisico sul book → rischio gap/disconnessione fra i poll
(mitigazione possibile in futuro: disaster-SL intrabar a 4× come cintura,
costa ~5% del guadagno).
- avg_bars +~18% (esposizione su; già nei numeri via non-overlap).
- I numeri per-sleeve FULL (ret 4-10x) vanno letti col solito sconto del
compounding su 8 anni; la decisione è presa sul gate PORT06, non su quelli.
## Scoperte collaterali da NON perdere
1. **Gap-through fill**: l'engine intrabar filla gli stop al livello anche
quando l'open è già oltre → bias sistematico PRO stop-stretti. Aggiungere
il fill `worse(level, open)` all'harness prima di future ricerche su stop.
2. **Wiring worker**: una strategia con `sl=0`+`max_bars` gira nel ramo
`elif max_bars` → il fallback 2% non si applica. Oggi nessuna strategia
attiva emette sl=0, ma il ramo va reso esplicito se mai si deployasse
una policy senza SL.
3. Il prior ladder di stamattina è confermato e generalizzato: 4 conferme
indipendenti che oltre il TP non c'è nulla da cavalcare.
## Costi della ricerca
34 agenti (23 explore + 10 verify + 1 PORT06), ~1.65M token subagente,
~70 minuti wall-clock su 2 core. Workflow: `exit-policy-explore`
(wf_4b23e922-f48) + `exit-policy-verify` (wf_f2bb98df-c43).
## IMPLEMENTATO E DEPLOYATO (sera stessa, v1.1.0)
Param `sl_confirm_atr` (default None = comportamento storico):
- `src/strategies/fade_base.py` `FadeStrategy.backtest` + `scripts/strategies/
MR01_bollinger_fade.py` (ha un backtest proprio, duplicato storico — patch
identica): ramo close-confirm al posto dell'SL intrabar; TP intrabar e
max_bars invariati; in modalità confirm il TP ha priorità nel bar (come la
policy validata in exit_lab).
- `src/live/strategy_worker.py` `tick`: con `sl_confirm_atr` nei params dello
sleeve, TP intrabar al livello come prima; stop SOLO se `close` sfonda
`sl ∓ buf·ATR14(df)`, uscita al prezzo corrente (reason `stop_loss`
invariata → il monitor stop-rate di `hourly_report` continua a funzionare).
- `scripts/portfolios/_defs.py`: `SL_CONFIRM_ATR = 0.5` sulle 6 fade (path
live, come `hurst_max`). Il backtest canonico resta NON filtrato.
- Test: `tests/portfolio/test_close_confirm_sl.py` (wick non stoppa; breach
sul close stoppa al close; TP intrabar resta; buffer regge; regressione
senza param). 59/59 verdi.
**Nota onesta dal sanity-check sul path GREZZO (nessun filtro):** il ritorno
esplode (MR02 ETH cap 366k→3.0M) ma il **DD per-sleeve SALE** (MR01 BTC
32→52%): senza trend-filter/hurst il close-confirm tiene posizione anche nei
trend profondi. La riduzione di DD vive nella config live (trend_max 3.0 +
hurst 0.55) e nella diversificazione — esattamente ciò che il test PORT06
canonico ha misurato (DD 4.10→2.60). Le tre protezioni sono COMPLEMENTARI:
hurst toglie l'esposizione al regime tossico, il trend-filter gli ingressi
sovra-estesi, il close-confirm i falsi stop da wick.
**Monitoraggio live:** lo stop-rate fade su `hourly_report` dovrebbe scendere
sotto il ~38% atteso post-hurst; gli stop avranno exit leggermente oltre il
livello (uscita al close), i TP restano al livello (e nello shadow reale al
limit reduce-only di v1.0.7).
Deploy: commit `a2579d2` (+ research `ad65a0b`), release v1.1.0.