feat(live): worker con exit TP/SL/max_bars per MR01 + doc aggiornata

StrategyWorker ora supporta exit guidati dalla strategia via Signal.metadata
(take-profit alla media / stop-loss ad ATR / time-limit), con fallback al
vecchio hold_bars/stop -2% per strategie senza metadata. Usa fee_rt della
strategia (MR01 = 0.10% RT reale Deribit, non piu' 0.20% hardcoded).
Persistenza di tp/sl/max_bars in status.json per resume.

Re-validato col worker reale (replay finestre mobili 1h, fee 0.10%):
  BTC 1h MR01: +196% OOS, ETH 1h: +251% OOS (nov 2023->mag 2026) — coerente col backtest.

README + CLAUDE.md riscritti: squeeze = artefatto di look-ahead -> waste,
MR01 mean-reversion unica attiva, metodologia anti-look-ahead e fee reali 0.10% RT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-05-28 20:46:35 +00:00
parent 9879b46688
commit 48435f6858
4 changed files with 218 additions and 94 deletions
+65 -54
View File
@@ -8,47 +8,56 @@ Partendo da un capitale iniziale di €1.000, raggiungere un profitto medio di
## Risultati
Oltre 35 strategie testate su dati storici 20182026 (BTC e ETH, timeframe 15m / 1h, fee 0.2% round-trip, leva 3x, posizione 15%). Le migliori:
> ⚠️ **Revisione 2026-05-28.** La famiglia squeeze-breakout (SQ/MT/ML/AD/CM/PD, con
> accuracy storiche dichiarate 76-82%) è stata **scartata**: quei numeri erano un
> **artefatto di look-ahead**. I backtest decidevano la direzione dalla candela di
> breakout `close[i]` ma entravano a `close[i-1]` — impossibile dal vivo. Sotto
> ingresso onesto (`close[i]`) e fee reali, l'edge sparisce e tutte perdono, anche
> a fee zero. Dettagli e prove: `scripts/analysis/oos_validation.py`.
| Codice | Strategia | Mercato | Accuracy | Trades | Max DD | Robustezza |
|--------|-----------|---------|----------|--------|--------|------------|
| MT01 | Squeeze + MTF Momentum | BTC 15m | **82.7%** | 503 | 5.9% | ✅ 9/9 anni |
| MT01 | Squeeze + MTF Momentum | ETH 15m | 81.2% | 404 | 2.9% | ✅ 9/9 anni |
| PD01 | Price-Volume Divergence | ETH 15m | 80.9% | 465 | **2.3%** | ✅ 9/9 anni |
| PD01 | Price-Volume Divergence | BTC 15m | 80.6% | 578 | 2.7% | ✅ 9/9 anni |
| CM01 | Cross-Market Momentum | ETH 15m | 80.6% | 433 | **2.2%** | ✅ 9/9 anni |
| AD01 | Adaptive Squeeze | BTC 15m | 79.9% | 1364 | 9.9% | ✅ 9/9 anni |
| SQ02 | Antifake + Volume | BTC 15m | 79.7% | 1250 | 6.5% | ✅ 9/9 anni |
Dopo una validazione **out-of-sample, fee-aware** di tutte le famiglie, l'unica con
edge netto reale è il **mean-reversion** (i breakout *rientrano*, non continuano):
La famiglia squeeze (compressione → espansione di volatilità) è il nucleo comune. Le migliori varianti aggiungono un filtro indipendente: conferma del trend su timeframe superiore (MT01), trend del volume al breakout (PD01), momentum dell'asset correlato (CM01), o soglia di squeeze adattiva al regime di volatilità (AD01). Tutte mantengono accuracy ≥67% in ogni singolo anno dal 2018, con i drawdown più contenuti (2-3%) su ETH.
| Codice | Strategia | Mercato | Edge OOS netto | Max DD | Robustezza |
|--------|-----------|---------|----------------|--------|------------|
| **MR01** | Bollinger Fade (mean-reversion) | BTC 1h | **+196 / +201%** | 15% | ✅ |
| **MR01** | Bollinger Fade (mean-reversion) | ETH 1h | **+251%** | ~25% | ⚠️ DD alto |
Netto dopo **fee realistiche Deribit 0.10% RT** (taker), leva 3x, pos 15%, su finestra
held-out (nov 2023→mag 2026). MR01 è positivo su **tutta** la griglia parametri
(`n∈{14,20,30,50}` × `k∈{2.0,2.5,3.0}`) e per **ogni** livello di fee 0.00-0.20% RT —
margine di sicurezza ampio, niente parametro fortunato. Ri-validato col worker live reale.
## Come funziona
### Volatility Squeeze Breakout
### MR01 — Bollinger Fade (mean-reversion)
Il meccanismo centrale sfrutta i cicli naturali di compressione ed espansione della volatilità:
La strategia attiva sfrutta il fatto, emerso dai dati, che su BTC/ETH a 1h gli estremi
di prezzo **rientrano verso la media** più di quanto proseguano:
1. **Compressione** — le Bollinger Bands entrano dentro i Keltner Channel (il prezzo si muove sempre meno, accumulando "energia").
2. **Breakout** — le bande escono dal canale. Un impulso direzionale parte.
3. **Filtri** — anti-fakeout (scarta breakout con retrace >60%) + volume confirmation (breakout >1.3× media).
4. **ML opzionale** — un modello GradientBoosting (GBM), addestrato walk-forward su feature strutturali, conferma la direzione e filtra i segnali deboli.
1. **Bollinger Bands** (window `n`, `k` deviazioni standard) sul close.
2. **Entry** — quando il close esce *sotto* la banda inferiore → **long** (o *sopra* la superiore → **short**). Ingresso a `close[i]`, eseguibile dal vivo.
3. **Take-profit** alla media mobile (il rientro atteso).
4. **Stop-loss** a `sl_atr × ATR` oltre l'estremo; **time-limit** a `max_bars`.
### Filtri di conferma indipendenti
Nessun look-ahead: direzione e livelli sono calcolati con dati fino a `close[i]`.
Le varianti più recenti aggiungono un singolo filtro di conferma al breakout, ciascuno motivato da una dinamica di mercato reale (non da ottimizzazione dei parametri):
### Perché lo squeeze breakout è stato abbandonato
- **MT01 — Multi-timeframe momentum.** Entra solo se la EMA su timeframe orario conferma il trend nella direzione del breakout. Filtra i breakout controtendenza.
- **PD01 — Price-volume divergence.** Richiede che il volume sia in *crescita* al momento del breakout, non solo elevato: un breakout su volume calante è debole e viene scartato.
- **CM01 — Cross-market momentum.** Entra solo se l'asset correlato (BTC ↔ ETH) mostra momentum nella stessa direzione nelle ultime barre.
- **AD01 — Adaptive squeeze.** La soglia di squeeze si adatta al regime di volatilità: più selettiva nei mercati agitati, più permissiva in quelli calmi.
L'ipotesi originale era opposta — *continuazione* dopo la compressione di volatilità
(Bollinger dentro Keltner → breakout direzionale). Su dati storici sembrava dare
76-82% di accuracy, ma era un **artefatto di look-ahead**: il backtest entrava a
`close[i-1]` con direzione decisa da `close[i]`. Replicando l'esecuzione reale
(ingresso a `close[i]`) l'edge collassa al ~47% (lancio di moneta) e i costi fanno
il resto. Il test sui breakout intra-barra a 5m conferma che il movimento *rientra*
subito (mean-reversion), giustificando MR01. Tutta la famiglia squeeze è in `scripts/waste/`.
### Feature ML (44 dimensioni)
### Lezione metodologica
- Rapporti body/shadow normalizzati su finestre multiple (12, 24, 48 candele)
- Momentum, volatilità, skewness, kurtosis dei rendimenti logaritmici
- Autocorrelazione lag-1 e profilo volumetrico
- Durata della fase di squeeze e rapporto di espansione Keltner
- Posizione del prezzo rispetto al range recente e ATR normalizzato
Ogni nuova strategia deve passare: (1) **ingresso eseguibile** senza look-ahead,
(2) backtest **netto** dopo fee realistiche (0.10% RT Deribit), (3) validazione
**out-of-sample** + robustezza su griglia parametri + sweep fee. Strumenti in
`scripts/analysis/` (`strategy_research.py`, `oos_validation.py`, `intrabar_test.py`).
## Struttura progetto
@@ -66,12 +75,12 @@ PythagorasGoal/
│ ├── strategy_worker.py # Worker indipendente con stato persistente
│ ├── strategy_loader.py # Import dinamico classi Strategy
│ ├── cerbero_client.py # Client HTTP per Cerbero MCP
│ ├── signal_engine.py # Squeeze + ML real-time (per ML01)
│ ├── signal_engine.py # Squeeze + ML real-time (legacy) + validazione OOS
│ └── telegram_notifier.py
├── scripts/
│ ├── strategies/ # Strategie attive (SQ01-SQ04, ML01, MT01, PD01, CM01, AD01)
│ ├── waste/ # Strategie scartate (W01-W28)
│ └── analysis/ # Script di confronto e report
│ ├── strategies/ # Strategie con edge validato OOS (solo MR01_bollinger_fade)
│ ├── waste/ # Strategie scartate (W01-W28 + famiglia squeeze SQ/MT/ML/AD/CM/PD)
│ └── analysis/ # Ricerca/validazione OOS fee-aware (strategy_research, oos_validation, ...)
├── strategies.yml # Config multi-strategy paper trader
├── data/
│ └── raw/ # Parquet OHLCV (gitignored, ~70 MB)
@@ -85,35 +94,32 @@ PythagorasGoal/
## Strategie attive
Tutte le strategie estendono `src.strategies.base.Strategy` con interfaccia comune: `generate_signals() → backtest() → report()`.
Tutte le strategie estendono `src.strategies.base.Strategy` (`generate_signals() → backtest()`).
| Codice | Script | Tipo | Descrizione |
|--------|--------|------|-------------|
| SQ01 | `SQ01_squeeze_base.py` | Regole | Squeeze breakout puro |
| SQ02 | `SQ02_squeeze_antifake_vol.py` | Regole | Squeeze + antifakeout + volume confirm |
| SQ03 | `SQ03_squeeze_all_filters.py` | Regole | Squeeze + filtri selezionabili (9 preset) |
| SQ04 | `SQ04_squeeze_ultimate.py` | Regole | Combo incrementali con correlazione/trend |
| ML01 | `ML01_squeeze_gbm.py` | ML | Squeeze + GBM walk-forward |
| MT01 | `MT01_squeeze_mtf_momentum.py` | Regole | Squeeze 15m + conferma trend EMA 1h (max accuracy) |
| PD01 | `PD01_price_volume_divergence.py` | Regole | Squeeze + trend del volume al breakout (DD minimo) |
| CM01 | `CM01_cross_market_momentum.py` | Regole | Squeeze + momentum dell'asset correlato (BTC ↔ ETH) |
| AD01 | `AD01_adaptive_squeeze.py` | Regole | Squeeze con soglia adattiva al regime di volatilità |
| **MR01** | `MR01_bollinger_fade.py` | Mean-reversion | Fada la banda di Bollinger, TP alla media, SL ad ATR. Unica con edge netto validato OOS. |
Per eseguire il backtest di una strategia:
La famiglia squeeze (SQ01-04, ML01, MT01, PD01, CM01, AD01) è in `scripts/waste/`:
edge storico = artefatto di look-ahead (vedi sezione *Come funziona*).
Per eseguire il backtest della strategia:
```bash
uv run python scripts/strategies/MT01_squeeze_mtf_momentum.py
uv run python scripts/strategies/MR01_bollinger_fade.py
```
Per il confronto completo per anno e mercato:
Per la ricerca/validazione fee-aware out-of-sample:
```bash
uv run python scripts/analysis/yearly_market_report.py
uv run python scripts/analysis/strategy_research.py # screening famiglie + deep-dive MR01
uv run python scripts/analysis/oos_validation.py # perche' la famiglia squeeze e' scartata
uv run python scripts/analysis/validate_worker_mr01.py # replay del worker live su MR01
```
## Paper Trading Live
Il multi-strategy runner esegue N strategie in parallelo su dati live da Cerbero MCP, ognuna con €1000 USDC virtuali indipendenti. Le strategie multi-timeframe (MT01) ricevono anche l'1h **live** da Cerbero ad ogni poll, così la conferma del trend non resta indietro rispetto al feed 15m.
Il multi-strategy runner esegue N strategie in parallelo su dati live da Cerbero MCP, ognuna con €1000 USDC virtuali indipendenti. Se un `Signal` porta `tp`/`sl`/`max_bars` in `metadata` (come MR01), il worker chiude su take-profit alla media / stop-loss ad ATR / time-limit; altrimenti usa il fallback `hold_bars`/stop -2%.
### Avvio
@@ -136,10 +142,15 @@ defaults:
leverage: 3
strategies:
- name: SQ02_antifake_vol
- name: MR01_bollinger_fade
asset: BTC
tf: 15m
tf: 1h
enabled: true
params:
bb_window: 50
k: 2.5
sl_atr: 2.0
max_bars: 24
```
Per aggiungere una strategia: nuova riga in `strategies.yml`, poi `docker compose restart`. Lo storico delle strategie esistenti rimane intatto.
@@ -150,9 +161,9 @@ Ogni strategia ha la sua directory in `data/paper_trades/`:
```
data/paper_trades/
SQ02_antifake_vol__BTC__15m/
MR01_bollinger_fade__BTC__1h/
trades.jsonl # Storico trade append-only
status.json # Stato corrente (resume al restart)
status.json # Stato corrente (resume al restart, include tp/sl/max_bars)
```
Notifiche Telegram per ogni trade (richiede `TELEGRAM_BOT_TOKEN` e `TELEGRAM_CHAT_ID` in `.env`).
@@ -167,8 +178,8 @@ uv sync
# Scarica dati storici (~70 MB)
uv run python -m src.data.downloader
# Backtest strategia migliore
uv run python scripts/strategies/MT01_squeeze_mtf_momentum.py
# Backtest strategia attiva
uv run python scripts/strategies/MR01_bollinger_fade.py
# Paper trading live
uv run python -m src.live.multi_runner