2026-05-29 17:39:11 +02:00

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 68 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
│   └── portfolio/         # Portafogli di prima classe (capitale condiviso, backtest + live)
│       ├── base.py        # SleeveSpec, Portfolio (.backtest), load_active_portfolio
│       ├── weighting.py   # Schemi di ponderazione: equal, cap, inverse_vol, cluster_rp, manual
│       ├── sleeves.py     # Builder unificato equity-per-sleeve (fonte unica, parità report)
│       ├── ledger.py      # PortfolioLedger: PnL/DD aggregati, persistenza e resume
│       └── runner.py      # PortfolioRunner live (Cerbero v2, sizing, ribilancio giornaliero)
├── scripts/
│   ├── strategies/        # Strategie con edge validato OOS (FADE, HONEST, PAIRS, TSMOM + portafogli)
│   ├── portfolios/        # Definizioni PORT01-06 e report run() dei portafogli di prima classe
│   ├── 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

# 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

# Locale
uv run python -m src.live.multi_runner

# Docker
docker compose up -d

Configurazione

Le strategie attive sono definite in strategies.yml:

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).

Paper Trading a Portafoglio

Accanto al multi-strategy runner originale — in cui ogni strategia gestisce autonomamente il proprio conto virtuale da €1.000 — il progetto dispone ora di un paper trader a portafoglio (src/portfolio/) che tratta l'insieme delle strategie come un unico organismo con un capitale condiviso.

Come funziona

La definizione di un portafoglio (SleeveSpec + schema di peso) ha due facce sulla stessa sorgente dati:

  • Backtest (.backtest()): ricostruisce le equity-curve di ogni sleeve tramite il builder unificato in sleeves.py, le pondera secondo lo schema scelto e calcola le metriche aggregate (CAGR, Sharpe, max DD). La parità con i report prodotti da report_families.py è garantita dalla fonte unica.
  • Live (PortfolioRunner): ogni ora il runner scarica le candele aggiornate via Cerbero v2, calcola i pesi correnti, avvia i worker appropriati per ogni sleeve attiva e registra il PnL aggregato nel ledger (data/portfolios/{code}/). Il ledger persiste tra i riavvii.

Schemi di ponderazione

Il modulo weighting.py mette a disposizione cinque schemi: equal (default), cap (tetto per famiglia — p.es. pairs: 0.33 per limitare la concentrazione), inverse_vol (pesi inversamente proporzionali alla volatilità storica), cluster_rp (equal tra cluster naturali poi inverse-vol all'interno del cluster) e manual (pesi liberi). Lo schema si specifica in portfolios.yml insieme al codice portafoglio e alla leva.

Portafoglio di default: PORT06

La configurazione raccomandata è PORT06 (scripts/portfolios/PORT06_master_shape.py): portafoglio master esteso che include tutte e sei le famiglie (FADE, HONEST, PAIRS, TSMOM, SHAPE), con schema cap che limita i pairs al 33% del capitale per moderare la loro concentrazione di rischio. Risultati del backtest: Sharpe 6.07 (FULL) / 8.19 (OOS), drawdown massimo 4.9% (FULL) / 2.3% (OOS), leva 2×.

Scope live (v1)

Il runner esegue le famiglie per cui esiste un worker dedicato: fade (MR01, MR02, MR07), pairs (PR01, cinque coppie) e shape (SH01, con retraining periodico via MLWorkerWrapper). Le famiglie honest (DIP01, TR01, ROT02) e TSMOM (TSM01) sono al momento escluse dall'esecuzione live — restano nel backtest — e il runner lo segnala nel log, rinormalizzando automaticamente i pesi sugli sleeve attivi. Il supporto ai worker honest e TSM01 è previsto nella fase 2.

Avvio del paper trader a portafoglio

# Backtest del portafoglio di default (PORT06)
uv run python scripts/portfolios/PORT06_master_shape.py

# Paper trading live a portafoglio
uv run python -m src.portfolio.runner

# Smoke test del data layer Cerbero v2
uv run python scripts/analysis/smoke_portfolio.py

Setup

# Clona e installa
git clone <repo-url> && 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 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:

uv run python -m src.data.instruments

Simboli Deribit: BTC/ETH = <COIN>-PERPETUAL (inverse); altcoin = <COIN>_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.

S
Description
No description provided
Readme 64 MiB
Languages
Python 98.8%
JavaScript 1.1%