GOAL: limitare le perdite delle fade in regime sfavorevole. Diagnosi (3022 trade): le perdite/stop si concentrano nel regime PERSISTENTE (hurst>0.55: stop-rate 43% vs 21% anti-persistente), NON in bassa vol (low-vol e' net positivo). Ricerca web + workflow 11 agenti: l'UNICO meccanismo che riduce DD senza uccidere l'edge e' il filtro Hurst (ADX, vol-expansion, time-stop, ER, vol-target falliscono il gate FR01). Test esterni ADX/vol-expansion NON si replicano su queste fade crypto. TEST DECISIVO PORT06 (gate FR01) SUPERATO: Hurst-skip h<0.55 sulle 6 fade -> FULL Sharpe 6.62->6.76, FULL DD 4.10%->2.39% (quasi dimezzato), OOS Sharpe 8.89->9.15. Migliora il portafoglio (a differenza di FR01 che diluiva). Implementazione: hurst_skip_mask in fade_base.py (rolling-Hurst causale dalle SOLE close -> nessun feed dati esterno, deployabile inline dal worker) + param hurst_max (default None=off) in MR01/MR02/MR07. Test: test_hurst_lossguard.py. Default off -> zero impatto su backtest/parita'/live finche' non attivato. FIX collaterale: regime_fetcher/regime_lab scrivevano DVOL/funding/feature in data/raw/ -> inquinavano la discovery asset del backtest (rompeva il regression-lock PORT06). Spostati in data/regime/ (gitignored). Suite: 54 passed (lock incluso). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.9 KiB
2026-06-02 — Loss-guard per le fade: filtro Hurst (regime persistente)
Goal: limitare le perdite delle fade in "bassa vol". Diagnosi empirica + ricerca web + workflow 11 agenti + test decisivo a livello PORT06. Branch
feat/fade-lossguard.
Riformulazione del problema (la premessa era imprecisa)
Diagnosi su 3022 trade fade (MR01/MR02/MR07 × BTC/ETH, 2021+): le perdite NON si concentrano in bassa vol — anzi il terzile low-DVOL è net positivo (+2,30%/trade). Il vero driver è il regime PERSISTENTE/trending, misurato dall'Hurst:
- somma perdite peggiore: hurst>0,55 (−2695% in low-vol, dominante in ogni terzile vol)
- stop-rate 43% per hurst>0,55 vs 21% per hurst<0,45 (anti-persistente) — 2x
- peggiori 1% trade: Hurst medio 0,61 (77% con hurst>0,55, solo 13% in bassa-DVOL)
Ricerca web (confermata e smentita dai dati reali)
- Hurst regime filter (MR solo H<0,45, evitare H>0,55): CONFERMATO sui dati reali. ✅
- ADX (PF 1,62 sotto 20 vs −0,74 sopra 30): NON si replica — ADX-skip uccide l'edge (Sharpe 4,82→0,99) e lo stop-rate non scende. ❌
- vol-expansion ATR-ratio>1,5 (−72% perdite): NON si replica — alza DD e stop-rate. ❌
- time-stop ~15 barre: riduce stop-rate ma alza il DD full → non passa standalone. ❌
Workflow 11 agenti — meccanismi testati
| Meccanismo | OOS Sharpe (base→filt) | DD full | Buon loss-guard? |
|---|---|---|---|
| Hurst-SKIP h<0,55 | 4,82→4,96 ↑ | 24,3→13,8% ↓ | SÌ |
| Hurst-SIZE 1/0,5/0,25 | 4,65→5,32 ↑ (full) | 33,6→11,3% maxDD ↓ | SÌ |
| ADX-skip | 4,82→0,99 ✗ | — | NO (uccide edge) |
| vol-expansion vratio | 4,82→4,04 | 24,3→27,5% ✗ | NO |
| Kaufman ER, time-stop, vol-target, DVOL-rising, combo | tutti ↓ o DD↑ | — | NO |
Solo l'Hurst isola chirurgicamente il regime tossico; gli altri sono "dimmer uniformi" che tagliano winner insieme ai loser (gate FR01 fallito).
TEST DECISIVO a livello PORT06 — SUPERATO ✅
Applicato l'Hurst-skip alle 6 fade dentro il PORT06 intero (equal-weight, le altre 11 sleeve invariate):
| Portafoglio | FULL Sharpe | FULL DD | OOS Sharpe | OOS DD | OOS ret |
|---|---|---|---|---|---|
| PORT06 baseline | 6,62 | 4,10% | 8,89 | 1,22% | +175% |
| + Hurst-skip h<0,55 | 6,76 | 2,39% | 9,15 | 1,54% | +158% |
| + Hurst-skip h<0,50 | 6,61 | 2,08% | 9,02 | 1,54% | +150% |
A differenza di FR01 (che diluiva), il filtro Hurst MIGLIORA il PORT06: FULL Sharpe ↑, FULL DD quasi dimezzato (4,10→2,39%), OOS Sharpe ↑ (8,89→9,15). Costo: OOS DD +0,3pp (resta minuscolo), OOS ret −17pp. h<0,55 è il pick (0,50 taglia più ritorno). Non aumenta il profitto: è puro rischio — dimezza il DD mantenendo/alzando lo Sharpe.
Implementazione
Aggiunto hurst_skip_mask in src/strategies/fade_base.py (rolling-Hurst causale dalle SOLE close)
- parametro
hurst_max(default None=off) in MR01/MR02/MR07. Test:test_hurst_lossguard.py.
Vantaggio operativo decisivo vs FR01: l'Hurst si calcola dalle sole close → nessun feed
DVOL/regime live necessario. Lo StrategyWorker lo computa inline dai dati che già ha → deployabile
senza nuova infrastruttura, basta settare hurst_max: 0.55 nei params degli sleeve fade.
Da fare per attivarlo live (deploy)
- Settare
hurst_max: 0.55nei params delle fade in_defs.py(sleeve live) + aggiornare i params fade del backtest (combine_portfolio/report_families) per PARITÀ + rigenerare il regression-lock PORT06 (i numeri canonici cambiano: DD 4,9→~2,4%). - Verificare che il rolling-Hurst live nel worker coincida col backtest (stessa finestra 100, stesso stepping causale).
- Rebuild immagine Docker (
up -d --build, non restart) + verifica RESUME.
Default attuale: hurst_max OFF → zero impatto su backtest/parità/live finché non lo si attiva
esplicitamente. Il SISTEMA è trovato e validato; l'attivazione è una decisione di deploy.