# PythagorasGoal Sistema di riconoscimento pattern frattali e predizione per il trading di criptovalute (BTC, ETH), ispirato al framework teorico di Serleto & Malanga (*Pythagoras Trading Prediction*). ## Obiettivo Partendo da un capitale iniziale di €1.000, raggiungere un profitto medio di €50 al giorno entro 6–8 mesi, tramite un portafoglio di strategie algoritmiche poco correlate fra loro — mean-reversion, trend/rotazione e spread market-neutral — validate out-of-sample e fee-aware. ## Risultati > ⚠️ **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`. Dopo una validazione **out-of-sample, fee-aware** di molte famiglie di strategie, emergono quattro famiglie con edge netto reale, tutte radicate nella stessa lezione (in cripto la **mean-reversion** funziona, la continuazione no) o nella diversificazione: | Famiglia | Meccanismo | Strategie | Profilo (netto OOS) | |----------|-----------|-----------|---------------------| | **FADE** | mean-reversion intraday 1h (long/short, BTC/ETH) | MR01 Bollinger, MR02 Donchian, MR07 Return-reversal | Acc 52-55%, DD 18-34% | | **HONEST** | long-only multi-regime multi-crypto | DIP01 dip-buy, TR01 EMA-trend, ROT02 dual-momentum | CAGR 31-56%, DD 15-27% | | **PAIRS** | spread reversion *market-neutral* (2 gambe) | PR01 ETH/BTC, LTC/ETH, ADA/ETH, BTC/LTC, ETH/SOL | Sharpe 2.0-4.4, corr col mercato ~0.05 | | **TSMOM** | time-series momentum multi-orizzonte | TSM01 (3/6/12m + risk-off) | diversificatore, DD 15-22% | Tutti i numeri sono **netti** dopo fee realistiche (Deribit 0.10% RT single-leg, 0.20% RT/coppia sui pairs), leva 3x, su finestra held-out. Le strategie sono robuste su griglia parametri, sweep fee 0.00-0.20% RT e — per i pairs — validate con **walk-forward** e config universale (niente cherry-picking). ### Portafoglio combinato (la vera leva anti-drawdown) Le famiglie sono **quasi scorrelate fra loro** (~0.05). Combinandole in un unico portafoglio equipesato il drawdown crolla sotto quello di ogni singola sleeve: | Portafoglio | CAGR | Max DD | Sharpe | |-------------|------|--------|--------| | FADE (6 sleeve) | ~46% | 8% | 3.9 | | HONEST (3 sleeve) | ~46% | 13% | 2.2 | | **MASTER** (FADE + HONEST, 9) | ~47% | **5%** | 4.2 | | **MASTER + PAIRS + TSM01** (15) | ~67% | ~5% | ~6 | > 🔎 **Numeri sobri (anti-overfit).** L'OOS singolo cade nel regime favorevole 2024-25: > i valori di Sharpe/DD sopra sono ottimistici di circa il 50%. Da pianificare per le > decisioni: **Sharpe atteso ~5**, **worst-drawdown su 90 giorni ~6%**, profilo che regge > a leva 2x con slippage raddoppiato. Configurazione raccomandata: equal-weight, leva 2x, > con un cap sull'allocazione ai pairs (~30-35%, poiché concentrano ~57% del rischio). > Tutto resta da confermare nel paper trading live. ## Come funziona ### MR01 — Bollinger Fade (mean-reversion) 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. **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`. Nessun look-ahead: direzione e livelli sono calcolati con dati fino a `close[i]`. ### Le altre famiglie - **FADE** (oltre MR01): MR02 fada la rottura del canale Donchian verso il centro; MR07 fada il movimento di barra estremo misurato in deviazioni standard dei rendimenti. Stessa logica di reversione, indicatori indipendenti. - **HONEST** (long-only, multi-crypto): DIP01 compra i dip estremi e rivende al recupero; TR01 segue il trend con incrocio di EMA su un paniere; ROT02 ruota ogni giorno sui tre asset col momentum più forte, andando in cash quando BTC è sotto la sua media (risk-off). Coprono i regimi di trend e rotazione, complementari alle fade. - **PAIRS** (market-neutral): scommette sul rientro verso la media del log-ratio fra due cripto (z-score). Long su una, short sull'altra: l'esposizione netta al mercato è quasi nulla (correlazione ~0.02), il che la rende un diversificatore eccellente. - **TSMOM**: tiene gli asset con momentum positivo persistente su più orizzonti (3/6/12 mesi), con overlay risk-off. Rende meno ma è poco correlato, utile in ensemble. ### Perché lo squeeze breakout è stato abbandonato 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/`. ### Lezione metodologica 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 ``` PythagorasGoal/ ├── src/ │ ├── data/ # Download e gestione dati (Cerbero MCP + Binance) │ ├── fractal/ # Indicatori frattali: Hurst, Higuchi FD, self-similarity │ ├── backtest/ # Motore di backtesting con fee e metriche │ ├── strategies/ # Classe base Strategy ABC + indicatori condivisi │ │ ├── base.py # Strategy, Signal, BacktestResult, YearlyStats │ │ └── indicators.py # keltner_ratio, detect_squeezes, ema, atr, rv, corr │ └── live/ # Paper trading live su Deribit testnet │ ├── multi_runner.py # Orchestratore multi-strategia (strategie + pairs) │ ├── strategy_worker.py # Worker single-leg con stato persistente │ ├── pairs_worker.py # Worker a 2 gambe per i pairs (market-neutral) │ ├── strategy_loader.py # Import dinamico classi Strategy │ ├── cerbero_client.py # Client HTTP per Cerbero MCP │ ├── signal_engine.py # Squeeze + ML real-time (legacy) + validazione OOS │ └── telegram_notifier.py ├── scripts/ │ ├── strategies/ # Strategie con edge validato OOS (FADE, HONEST, PAIRS, TSMOM + portafogli) │ ├── waste/ # Strategie scartate (squeeze SQ/MT/ML/AD/CM/PD, MR03, ROT01, W01-W28) │ └── analysis/ # Ricerca/validazione OOS fee-aware, gestione rischio, report ├── strategies.yml # Config multi-strategy paper trader ├── data/ │ └── raw/ # Parquet OHLCV (gitignored, ~70 MB) ├── docs/ │ ├── diary/ # Diario di ricerca giornaliero │ └── specs/ # Specifiche di design ├── Dockerfile ├── docker-compose.yml └── pyproject.toml ``` ## Strategie attive Le strategie single-asset estendono `src.strategies.base.Strategy` (`generate_signals() → backtest()`); i pairs hanno un worker dedicato a 2 gambe. | Codice | Script | Famiglia | Descrizione | |--------|--------|----------|-------------| | **MR01** | `MR01_bollinger_fade.py` | FADE | Fada la banda di Bollinger, TP alla media, SL ad ATR | | **MR02** | `MR02_donchian_fade.py` | FADE | Fada la rottura del canale Donchian, TP al centro | | **MR07** | `MR07_return_reversal.py` | FADE | Fada il movimento di barra estremo (z dei rendimenti) | | **DIP01** | `DIP01_dip_reversion.py` | HONEST | Dip-buy long-only su z-score estremo | | **TR01** | `TR01_ema_trend.py` | HONEST | EMA 20/100 trend-following su paniere cripto (4h) | | **ROT02** | `ROT02_dual_momentum.py` | HONEST | Rotazione cross-sectional top-3 + risk-off (1d) | | **PR01** | `PR01_pairs_reversion.py` | PAIRS | Spread reversion market-neutral su 5 coppie | | **TSM01** | `tsmom_research.py` | TSMOM | Time-series momentum multi-orizzonte + risk-off | Le fade applicano un **filtro trend** opzionale (`trend_max`/`ema_long`): saltano i segnali quando il prezzo è troppo esteso rispetto alla EMA200 — alza l'accuratezza e abbassa il drawdown. Portafogli pronti: `PORT01` (honest), `PORT02` (fade), `PORT03` (master fade+honest). **Scartate** (in `scripts/waste/`): la famiglia squeeze (SQ01-04, ML01, MT01, PD01, CM01, AD01 — artefatto di look-ahead), MR03 Keltner (debole/ridondante con MR01) e ROT01 (dominata da ROT02). ### Comandi utili ```bash # Backtest di una strategia uv run python scripts/strategies/MR01_bollinger_fade.py uv run python scripts/strategies/PR01_pairs_reversion.py # Ricerca e validazione fee-aware out-of-sample uv run python scripts/analysis/strategy_research.py # screening famiglie + deep-dive fade uv run python scripts/analysis/strategy_research_v2.py # MR02 / MR03 / MR07 uv run python scripts/analysis/oos_validation.py # perche' la famiglia squeeze e' scartata uv run python scripts/analysis/pairs_research.py # ricerca + verifica no-look-ahead dei pairs # Gestione rischio, combinazione, report uv run python scripts/analysis/risk_management.py # filtro trend + portafoglio fade uv run python scripts/analysis/combine_portfolio.py # combinare fade + honest uv run python scripts/analysis/combine_v2.py # master esteso con pairs + TSM01 uv run python scripts/analysis/report_families.py # report per anno di tutte le famiglie # Validazione dei worker live (replay == backtest) uv run python scripts/analysis/validate_worker_mr01.py # worker single-leg su MR01 uv run python scripts/analysis/validate_worker_pairs.py # worker a 2 gambe sui pairs uv run python scripts/analysis/live_smoke_pairs.py # smoke test feed live reale dei pairs ``` ## Paper Trading Live Il multi-strategy runner esegue N strategie in parallelo su dati live da Cerbero MCP, ognuna con €1000 USDC virtuali indipendenti. Gestisce due tipi di worker: - **Single-leg** (`strategy_worker.py`): per le strategie direzionali. Se un `Signal` porta `tp`/`sl`/`max_bars` in `metadata` (come le fade), chiude su take-profit / stop-loss / time-limit; altrimenti usa il fallback `hold_bars`/stop -2%. - **Due gambe** (`pairs_worker.py`): per i pairs market-neutral. Apre long su una gamba e short sull'altra, esce sul rientro dello z-score o per time-limit, conta le fee su entrambe le gambe. Validato: il replay storico coincide *esattamente* col backtest. ### Avvio ```bash # Locale uv run python -m src.live.multi_runner # Docker docker compose up -d ``` ### Configurazione Le strategie attive sono definite in `strategies.yml`: ```yaml defaults: capital: 1000 position_size: 0.15 leverage: 3 strategies: # strategie single-leg - name: MR01_bollinger_fade asset: BTC tf: 1h enabled: true params: { bb_window: 50, k: 2.5, sl_atr: 2.0, max_bars: 24, trend_max: 3.0, ema_long: 200 } pairs: # strategie a 2 gambe (market-neutral) - name: PR01_pairs_reversion a: ETH b: BTC tf: 1h enabled: true params: { n: 50, z_in: 2.0, z_exit: 0.75, max_bars: 72, jump_max: 0.08 } ``` Per aggiungere una strategia: nuova riga in `strategies.yml` (sezione `strategies` o `pairs`), poi `docker compose restart`. Lo storico delle strategie esistenti rimane intatto. ### Persistenza Ogni strategia ha la sua directory in `data/paper_trades/`: ``` data/paper_trades/ MR01_bollinger_fade__BTC__1h/ trades.jsonl # Storico trade append-only 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`). ## Setup ```bash # Clona e installa git clone && cd PythagorasGoal uv sync # Scarica dati storici (~70 MB) uv run python -m src.data.downloader # Backtest strategia attiva uv run python scripts/strategies/MR01_bollinger_fade.py # Paper trading live uv run python -m src.live.multi_runner ``` ### Requisiti - Python ≥ 3.11 - [uv](https://docs.astral.sh/uv/) come package manager - Accesso a Cerbero MCP (`cerbero-mcp.tielogic.xyz`) per dati Deribit live - Docker (opzionale, per deploy su VPS) ## Dati | Asset | Timeframe | Copertura | |-------|-----------|-----------| | BTC, ETH | 5m / 15m / 1h | 2018-01 → oggi | | SOL, LTC, ADA, XRP, BNB, DOGE | 15m / 1h | 2019-2022 → oggi (variabile per asset) | Fonte primaria: perpetual Deribit via Cerbero MCP. Fallback: Binance spot via ccxt. Formato: Apache Parquet (in `data/raw/`, gitignored). > **Nota sul naming Deribit (per il feed live).** I major sono perpetui *inverse* > (`BTC-PERPETUAL`, `ETH-PERPETUAL`); gli altcoin sono perpetui *lineari USDC* > (`SOL_USDC-PERPETUAL`, `LTC_USDC-PERPETUAL`, …) con storia dal 2022. Attenzione: > `LTC-PERPETUAL`/`ADA-PERPETUAL` non esistono e `SOL-PERPETUAL` restituisce dati > errati — per gli altcoin usare sempre la forma `_USDC-PERPETUAL`. ### Discovery & validazione strumenti `src/data/instruments.py` scopre e **valida** gli strumenti disponibili sugli exchange implementati — **Deribit** e **Hyperliquid** (esclusi Alpaca/stocks e **Bybit**, feed testnet inaffidabile). Ogni perpetuo viene testato sui dati storici realmente raccoglibili: esistenza, congruenza OHLC, contratto non-morto, liquidità e **congruenza prezzo cross-exchange** (mediana per base-coin, tolleranza 5%) — così feed farlocchi e contratti sbagliati (es. `SOL-PERPETUAL`=9.6) vengono scartati. Il risultato è `data/instruments_registry.json` (strumenti validi + timeframe + data d'inizio). **Solo gli strumenti validati possono essere scaricati**: il downloader ha un gate (`_download_cerbero_range`) che rifiuta quelli non nel registry. Rigenera con: ```bash uv run python -m src.data.instruments ``` Simboli Deribit: BTC/ETH = `-PERPETUAL` (inverse); altcoin = `_USDC-PERPETUAL` (lineari USDC). Registry attuale (testnet): Deribit 18/106 validi (major liquidi, BTC dal 2018), Hyperliquid 66/74. ## Riferimenti - Serleto, L. & Malanga, C. — *Pythagoras Trading Prediction* (2024) - Serleto, L. & Malanga, C. — *Libro dei Frattali* (2024) ## Licenza Uso privato. Non destinato alla distribuzione.