2026-06-17 09:28:15 +00:00
|
|
|
|
# Fase 3 — Modello di MEAN-REVERSION (rientro alla Mediana)
|
|
|
|
|
|
|
|
|
|
|
|
> Questo è il **modello principale** della Fase 3. Nasce dopo aver dimostrato
|
|
|
|
|
|
> (vedi `README.md` sez. 5b, validazione esterna) che l'edge **direzionale**
|
|
|
|
|
|
> "su/giù" **non generalizza** fuori da EURUSD, mentre la **mean-reversion** è
|
|
|
|
|
|
> universale (rientro alla Mediana entro 20g nell'87–90% dei casi su tutti i
|
|
|
|
|
|
> major FX). Quindi modelliamo ciò che è davvero robusto: il **rientro alla
|
|
|
|
|
|
> Mediana**.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Idea
|
|
|
|
|
|
|
|
|
|
|
|
Dopo un incrocio il prezzo tende a tornare sulla Mediana. Non vogliamo prevedere
|
|
|
|
|
|
la direzione, ma **caratterizzare il rientro**. Tre target, costruiti da esiti
|
|
|
|
|
|
già presenti nei CSV (nessuna baseline di regime: sono osservazioni dirette):
|
|
|
|
|
|
|
|
|
|
|
|
| target | tipo | colonna | domanda |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| `rev` | classificazione | `rev_10` | rientra alla Mediana **entro 10 giorni**? (sì/no) |
|
|
|
|
|
|
| `speed` | regressione | `bars_to_revert` | in **quanti giorni** rientra (solo eventi rientrati) |
|
|
|
|
|
|
| `disc` | regressione | `disc_max_pct` | **quanto si allontana** (max %) prima di rientrare |
|
|
|
|
|
|
|
|
|
|
|
|
Esclusione del banale (`drop_trivial`): gli eventi già praticamente sulla
|
|
|
|
|
|
Mediana (`|dist_med_pct| < 0.05%`) rientrano per costruzione; vengono esclusi per
|
|
|
|
|
|
studiare il rientro "vero".
|
|
|
|
|
|
|
|
|
|
|
|
## 2. Feature (note al momento dell'incrocio)
|
|
|
|
|
|
|
|
|
|
|
|
`abs_dist` (=|dist_med_pct|), `dist_med_pct`, `cluster_pct`, `cluster_exp`,
|
|
|
|
|
|
`slope_a`, `slope_b`, `vel_med`, `acc_med`, `vol_med` (numeriche) +
|
|
|
|
|
|
`pair`, `dir`, `trend`, `dow`, `month` (categoriche). Nessuna colonna di esito
|
|
|
|
|
|
futuro è tra le feature.
|
|
|
|
|
|
|
|
|
|
|
|
## 3. Pooling pulito + validazione (anti-inquinamento)
|
|
|
|
|
|
|
|
|
|
|
|
I 4 major FX (EURUSD, USDJPY, USDCHF, GBPUSD) hanno mean-reversion omogenea →
|
|
|
|
|
|
si possono **mettere in pool**. Le feature sono già in percentuale/relative,
|
|
|
|
|
|
quindi confrontabili tra simboli. Due validazioni, entrambe oneste:
|
|
|
|
|
|
|
|
|
|
|
|
1. **Walk-forward pooled**: train tutti i simboli fino all'anno T, test anno T+1
|
|
|
|
|
|
→ generalizzazione **nel tempo**.
|
|
|
|
|
|
2. **Leave-one-symbol-out (LOSO)**: train su 3 simboli, test sul 4° **mai visto**
|
|
|
|
|
|
→ generalizzazione **tra strumenti** (la prova più severa anti-inquinamento).
|
|
|
|
|
|
|
|
|
|
|
|
Ogni metrica è confrontata con una **baseline banale**:
|
|
|
|
|
|
- classificazione → accuratezza della classe maggioritaria;
|
|
|
|
|
|
- regressione → MAE ottenuto prevedendo sempre la mediana del train
|
|
|
|
|
|
(`skill_% = 1 − MAE/MAE_baseline`).
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Risultati (pool 4 major FX, ~39k incroci)
|
|
|
|
|
|
|
|
|
|
|
|
**Walk-forward (nel tempo):**
|
|
|
|
|
|
- `rev` : **AUC ≈ 0.65** (la baseline è 0.5) → il modello sa **ordinare** quali
|
|
|
|
|
|
incroci rientreranno entro 10g e quali no.
|
|
|
|
|
|
- `speed` : skill ≈ **+2%** → marginale (la mediana è ~3g e cambia poco).
|
|
|
|
|
|
- `disc` : skill ≈ **−3%** → non meglio della mediana.
|
|
|
|
|
|
|
|
|
|
|
|
**Leave-one-symbol-out (su simbolo mai visto):**
|
|
|
|
|
|
|
|
|
|
|
|
| target | EURUSD | USDJPY | USDCHF | GBPUSD |
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
| `rev` AUC | 0.677 | 0.687 | 0.682 | 0.688 |
|
|
|
|
|
|
| `speed` skill | +1.3% | +4.8% | −2.9% | +2.8% |
|
|
|
|
|
|
| `disc` skill | +2.0% | +5.8% | −1.1% | −0.1% |
|
|
|
|
|
|
|
|
|
|
|
|
**Lettura:** il classificatore di rientro (`rev`) ha un edge **reale e
|
|
|
|
|
|
generalizzabile** — AUC ~0.68 anche su un simbolo completamente fuori dal
|
|
|
|
|
|
training. I due regressori (`speed`, `disc`) aggiungono poco: la velocità e
|
|
|
|
|
|
l'ampiezza dell'allontanamento sono in pratica vicine alla mediana storica.
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Cosa guida il rientro (importanza, permutation su holdout 2018+)
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
abs_dist +0.104 <- distanza dalla Mediana: di gran lunga il fattore #1
|
|
|
|
|
|
dist_med_pct +0.025 <- il segno della distanza (sopra/sotto)
|
|
|
|
|
|
trend +0.021
|
|
|
|
|
|
cluster_exp +0.017 <- cluster in espansione/contrazione
|
|
|
|
|
|
vel_med +0.010
|
|
|
|
|
|
... (vol_med, cluster_pct ~0)
|
|
|
|
|
|
pair ~0 <- QUALI linee si incrociano e' irrilevante
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Conferma economica: il rientro dipende da **quanto sei lontano dalla Mediana** e
|
|
|
|
|
|
dal **regime**, non dallo specifico tipo di incrocio. È coerente con la Fase 2 e
|
|
|
|
|
|
con la validazione esterna (il "pattern" di linee era rumore).
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Uso operativo
|
|
|
|
|
|
|
|
|
|
|
|
Il modello `rev` non dice "compra/vendi": stima la **probabilità di rientro
|
|
|
|
|
|
rapido**. Serve da **filtro**: tra i setup di mean-reversion (prezzo lontano
|
|
|
|
|
|
dalla Mediana), privilegiare quelli con alta probabilità ed evitare il ~25% che
|
|
|
|
|
|
tende a NON rientrare in fretta (i casi rischiosi, spesso inizio di trend).
|
|
|
|
|
|
|
|
|
|
|
|
## 7. File e come eseguire
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Modello/
|
|
|
|
|
|
├── config_mr.yaml parametri del modello di mean-reversion
|
|
|
|
|
|
├── src/
|
|
|
|
|
|
│ ├── mr_labeling.py costruzione dei 3 target + maschere
|
2026-06-17 09:59:35 +00:00
|
|
|
|
│ ├── mr_train.py pool + walk-forward + LOSO + modelli finali
|
|
|
|
|
|
│ └── mr_calibrate.py calibrazione + curva precisione/copertura
|
2026-06-17 09:28:15 +00:00
|
|
|
|
└── results/
|
2026-06-17 09:59:35 +00:00
|
|
|
|
├── mr_wf_<task>.csv metriche walk-forward per anno
|
|
|
|
|
|
├── mr_loso_<task>.csv metriche leave-one-symbol-out
|
|
|
|
|
|
├── mr_precision_coverage.csv soglia -> copertura/precisione/lift
|
|
|
|
|
|
├── mr_calibration_metrics.json Brier prima/dopo + LOSO
|
|
|
|
|
|
├── mr_*.png grafici (affidabilita', precisione/copertura)
|
|
|
|
|
|
└── mr_*.joblib modelli (non versionati)
|
2026-06-17 09:28:15 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
pip install -r requirements.txt
|
|
|
|
|
|
# copia in ./data i CSV crosses+bars dei 4 simboli (vedi data/README.md), poi:
|
|
|
|
|
|
cd src
|
|
|
|
|
|
python mr_train.py # usa ../config_mr.yaml
|
2026-06-17 09:59:35 +00:00
|
|
|
|
python mr_calibrate.py # calibrazione + soglia operativa (sez. 8)
|
2026-06-17 09:28:15 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-17 09:59:35 +00:00
|
|
|
|
## 8. Calibrazione e soglia operativa (`src/mr_calibrate.py`)
|
|
|
|
|
|
|
|
|
|
|
|
Il modello `rev` **ordina** bene gli eventi, ma la probabilità grezza non è
|
|
|
|
|
|
"vera" (vedi curva rossa sotto: un 0.55 grezzo corrispondeva a ~46% di rientri
|
|
|
|
|
|
reali). La **calibrazione isotonica** la rende affidabile nella zona operativa
|
|
|
|
|
|
(0.7–0.9) e migliora il Brier score da **0.198 → 0.189** (più basso = meglio).
|
|
|
|
|
|
|
|
|
|
|
|
Split temporale onesto: modello base su anni `< 2016`, calibratore su `2016–2017`,
|
|
|
|
|
|
valutazione su `2018+` (mai visto). LOSO calibrato: AUC 0.67–0.70 su simbolo mai
|
|
|
|
|
|
visto → regge.
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
### Curva precisione/copertura (test 2018+, base rate 73%)
|
|
|
|
|
|
|
|
|
|
|
|
Per ogni soglia di probabilità: **copertura** = quanti segnali tieni,
|
|
|
|
|
|
**precisione** = tasso di rientro effettivo tra quelli tenuti.
|
|
|
|
|
|
|
|
|
|
|
|
| soglia | copertura | precisione | lift |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| 0.50 | 99% | 73.1% | 1.00 |
|
|
|
|
|
|
| 0.70 | 85% | 76.2% | 1.04 |
|
|
|
|
|
|
| **0.75** | **51%** | **81.2%** | **1.11** |
|
|
|
|
|
|
| 0.80 | 42% | 82.2% | 1.13 |
|
|
|
|
|
|
| 0.85 | 28% | 83.3% | 1.14 |
|
|
|
|
|
|
| 0.90 | 6% | 87.0% | 1.19 |
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
**Soglia consigliata: ~0.75** → l'EA opera su ~metà dei setup di mean-reversion
|
|
|
|
|
|
ma il tasso di rientro sale dal 73% all'**81%**. Chi vuole essere più selettivo
|
|
|
|
|
|
usa 0.80–0.85 (precisione ~82–83%, copertura 28–42%). La soglia è un parametro:
|
|
|
|
|
|
la tabella completa è in `results/mr_precision_coverage.csv`.
|
|
|
|
|
|
|
|
|
|
|
|
Nota: tra 0.70 e 0.75 la copertura crolla (85%→51%) perché lì si concentra la
|
|
|
|
|
|
massa delle probabilità; è il punto in cui il filtro inizia a "mordere".
|
|
|
|
|
|
|
|
|
|
|
|
## 9. Prossimi passi
|
2026-06-17 09:28:15 +00:00
|
|
|
|
|
|
|
|
|
|
- Aggiungere altri major FX al pool per irrobustire ancora il LOSO.
|
2026-06-17 09:59:35 +00:00
|
|
|
|
- **Fase 4**: export del modello `rev` **calibrato** in **ONNX** (skl2onnx) e
|
|
|
|
|
|
inferenza in MT5 come filtro dei segnali di mean-reversion (soglia ~0.75).
|