14522262e6
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>
177 lines
9.8 KiB
Markdown
177 lines
9.8 KiB
Markdown
# 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.
|