Files
PythagorasGoal/CLAUDE.md
T
Adriano Dal Pastro 5ac9ebed5b docs: documenta discovery/validazione strumenti e gate del downloader
CLAUDE.md, README.md, API_REFERENCE.md aggiornati per il nuovo layer
src/data/instruments.py: validazione strumenti per exchange (Deribit +
Hyperliquid; esclusi Alpaca e Bybit testnet), congruenza prezzo cross-exchange,
registry come allowlist, gate nel downloader. Aggiunti schemi param
get_instruments/get_markets/get_historical per exchange e convenzione simboli
Deribit (inverse vs USDC lineari). Universo dati esteso con SOL/LTC/ADA 1h.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 07:51:47 +00:00

238 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PythagorasGoal — Istruzioni per agenti
## Panoramica
Progetto di ricerca: riconoscimento pattern frattali per trading algoritmico su criptovalute (BTC, ETH). L'obiettivo è arrivare a €50/giorno di profitto partendo da €1.000, entro 68 mesi.
## Stack
- **Linguaggio:** Python 3.11+
- **Package manager:** uv (dipendenze in `pyproject.toml`, lock in `uv.lock`)
- **Dati:** Parquet in `data/raw/` (non committati, ~70 MB)
- **ML:** scikit-learn (GradientBoostingClassifier)
- **Analisi:** numpy, pandas, scipy
- **API dati:** Cerbero MCP su `cerbero-mcp.tielogic.xyz` (Deribit, Bybit, Hyperliquid), ccxt/Binance come fallback
- **Config:** pyyaml per `strategies.yml`
## Struttura
```
src/data/ → download e caricamento dati
downloader.py → download/caricamento parquet (gate: solo strumenti validati)
instruments.py → discovery + validazione strumenti per exchange, registry
src/fractal/ → indicatori frattali (patterns.py, indicators.py, similarity.py)
src/backtest/ → engine di backtesting (engine.py)
src/strategies/ → classe base Strategy ABC + indicatori condivisi
base.py → Strategy, Signal, BacktestResult, YearlyStats
indicators.py → keltner_ratio, detect_squeezes, ema, atr, rv, correlation
src/live/ → paper trading live multi-strategia
multi_runner.py → orchestratore: carica YAML, fetch candele, tick worker
strategy_worker.py → worker indipendente: capital, trade log, stato persistente.
Exit guidati da strategia (TP/SL/max_bars via Signal.metadata),
fallback hold_bars/stop -2%. Usa fee_rt della strategia.
strategy_loader.py → import dinamico classi Strategy da scripts/strategies/
cerbero_client.py → client HTTP per Cerbero MCP (Deribit testnet)
signal_engine.py → squeeze + ML real-time (legacy ML01, ora in waste) + validazione OOS
telegram_notifier.py → notifiche Telegram per trade
scripts/strategies/ → strategie con edge validato OOS (solo MR01_bollinger_fade)
scripts/waste/ → strategie scartate (W01-W28 + famiglia squeeze SQ/MT/ML/AD/CM/PD)
scripts/analysis/ → ricerca/validazione OOS fee-aware (strategy_research, oos_validation, ...)
strategies.yml → config multi-strategy paper trader
docs/diary/ → diario di ricerca giornaliero
docs/specs/ → specifiche di design
data/raw/ → file .parquet OHLCV (gitignored)
data/instruments_registry.json → allowlist strumenti validati (gate del downloader)
```
## Comandi
```bash
uv sync # installa dipendenze
uv run python -m src.data.downloader # scarica dati storici (solo strumenti validati)
uv run python -m src.data.instruments # (ri)costruisci il registry strumenti validati
uv run python scripts/strategies/MR01_bollinger_fade.py # strategia attiva (mean-reversion)
uv run python scripts/analysis/strategy_research.py # ricerca strategie fee-aware OOS
uv run python scripts/analysis/oos_validation.py # perche' la famiglia squeeze e' scartata
uv run python scripts/analysis/validate_worker_mr01.py # replay worker reale su MR01
uv run python -m src.live.multi_runner # paper trading live multi-strategia
docker compose up -d # deploy Docker
uv run pytest # test
```
## Dati storici
Scaricati e salvati localmente in Parquet. Per rigenerarli:
```python
from src.data.downloader import download_all, load_data
download_all() # scarica BTC + ETH su 5m/15m/1h dal 2018
df = load_data("ETH", "15m") # carica un asset/timeframe
```
Fonte primaria: Cerbero MCP (endpoint `/mcp-deribit/tools/get_historical`).
Token observer: nel file `secrets/observer.token` del progetto CerberoSuite.
### Strumenti & validazione (gate raccolta dati)
`src/data/instruments.py` scopre e **valida** gli strumenti per ogni exchange
implementato — **Deribit** e **Hyperliquid** (esclusi Alpaca/stocks e **Bybit**,
il cui feed testnet è farlocco). Per ogni perpetuo enumera via `get_instruments`
/`get_markets` e verifica sui **dati storici realmente raccoglibili**:
esistenza, congruenza OHLC, not-flat (scarta contratti morti), liquidità (volume
daily) e **congruenza prezzo cross-exchange** (scostamento dalla mediana del
base-coin ≤ 5% → scarta outlier come `SOL-PERPETUAL`=9.6 vs SOL reale ~82).
Output: `data/instruments_registry.json` (strumenti validi, timeframe, start-date).
**Gate:** `_download_cerbero_range` rifiuta gli strumenti non validati (override
`allow_unvalidated=True` solo per casi eccezionali). Rigenera con
`python -m src.data.instruments`.
> **NB testnet.** Il token Cerbero punta a testnet; la congruenza cross-exchange
> è il filtro che distingue i feed realistici (Deribit, Hyperliquid) da quelli
> farlocchi (Bybit). Simboli Deribit: BTC/ETH = `<COIN>-PERPETUAL` (inverse);
> alt = `<COIN>_USDC-PERPETUAL` (lineari USDC). Registry attuale: Deribit 18/106,
> Hyperliquid 66/74 validi (major liquidi: BTC dal 2018, alt dal 2022).
## Strategie attive
> **LEZIONE CRITICA (2026-05-28).** L'intera famiglia squeeze-breakout (SQ01-04,
> MT01, ML01, AD01, CM01, PD01) è stata **scartata in `scripts/waste/`**: le
> accuratezze storiche 76-82% erano un **artefatto di look-ahead**. Quei backtest
> decidono la direzione con `sign(close[i]-close[i-1])` (la candela di breakout `i`)
> ma entrano a `close[i-1]` — cioè comprano *prima* della candela che usano per
> scegliere la direzione. Dal vivo il worker scopre il breakout solo a `close[i]`
> ed entra lì: l'edge sparisce (win-rate ~47%, lancio di moneta). Sotto ingresso
> onesto e fee reali **tutte perdono, anche a fee zero**. Inoltre i breakout
> *rientrano* (mean-reversion > continuation). Vedi `scripts/analysis/oos_validation.py`
> e `intrabar_test.py`.
Tutte le strategie estendono `src.strategies.base.Strategy`
(`generate_signals() → backtest()`). Le strategie mean-reversion condividono
`src.strategies.fade_base.FadeStrategy` (backtest intrabar TP/SL/max_bars).
**Strategie con edge netto validato OOS fee-aware (tutte fade/mean-reversion):**
| Codice | Nome | Meccanismo | Edge OOS netto (1h, fee 0.10% RT) | DD | Note |
|--------|------|-----------|-----------------------------------|----|------|
| **MR01** | Bollinger Fade | banda std attorno a SMA | BTC +201% / ETH +1238% | 15-72% | Fada la banda, TP alla media, SL ad ATR |
| **MR02** | Donchian Fade | estremi canale H/L | BTC +172% / ETH enorme | 30-42% | Fada la rottura del canale, TP al centro |
| **MR07** | Return Reversal | z dei rendimenti di barra | BTC +105% / ETH +195% | 25-46% | Fada il movimento estremo, exit in ATR; esposizione ~8% |
> **MR03 Keltner Fade** spostata in `scripts/waste/`: era la fade più debole
> (BTC Sharpe 1.22, il filtro trend la peggiorava) e ridondante con MR01 (stessa
> idea di banda). Rimuoverla dal portafoglio ne ha *migliorato* le metriche.
> La funzione `keltner_fade` resta in `strategy_research_v2.py` come record.
**Lezione confermata:** l'edge è sempre *mean-reversion* (i breakout rientrano).
Il trend-following (Donchian trend, RSI cross) e gli oscillatori senza filtro
(RSI revert, ADX-filtered fade) perdono netti → restano scartati.
Ogni strategia è robusta su **tutta** la sua griglia parametri (entrambi gli asset
→ tutte positive OOS) e su **tutte** le fee 0.00-0.20% RT (margine ampio).
MR01 validato col worker reale: BTC +196% / ETH +251% OOS (nov 2023→mag 2026).
Ricerca completa: `scripts/analysis/strategy_research.py` (MR01) e
`scripts/analysis/strategy_research_v2.py` (MR02/MR03/MR07).
Validazione live-path: `scripts/analysis/oos_validation.py`.
**Filtro trend (riduzione DD + aumento Acc).** Tutte le fade accettano i parametri
opzionali `trend_max` / `ema_long`: saltano i segnali quando il prezzo è troppo
esteso rispetto al trend di fondo (`|close EMA(ema_long)| / ATR(14) > trend_max`),
cioè quando si starebbe fadando un trend/crollo estremo. Con `trend_max=3.0`,
`ema_long=200` (default in `strategies.yml`): accuratezza su tutti gli sleeve
e DD giù drasticamente su ETH (MR01 71%→26%, MR02 42%→25%, MR03 66%→34%,
MR07 46%→21%), edge OOS confermato (vedi `scripts/analysis/risk_management.py`).
Unica eccezione: MR03 BTC, dove il filtro peggiora entrambe → lasciato disattivo.
Leva non robusta scartate: vol-target sizing e skip-alta-volatilità (peggiorano).
**Portafoglio.** Diversificare su sotto-conti indipendenti equipesati (le 4 strategie
× BTC/ETH, pos 0.15 ciascuno) abbatte il DD aggregato: ~14% full / ~10% OOS sul
paniere di 8 sleeve, contro il 20-70% del singolo. È la vera leva anti-drawdown.
**Combinare le due famiglie (fade + honest).** Le fade (reversione intraday 1h) e le
honest (DIP/TR/ROT trend+rotazione multi-crypto) sono **quasi scorrelate**
(correlazione cross-famiglia ~0.05). Combinarle in un unico portafoglio migliora il
rischio/rendimento rispetto a ciascuna famiglia da sola: equal-weight dei 9 sleeve
→ DD 5.2% full / 4.7% OOS e Sharpe 4.23 full / 4.33 OOS (vs honest-only 12.6% DD /
2.20 Sharpe e fade-only 8.2% DD / 4.09 Sharpe), CAGR ~47% mantenuta. Studio in
`scripts/analysis/combine_portfolio.py`.
**ROT02 — riduzione DD (top_k 2→3).** La rotazione dual-momentum honest concentrava
il book su 2 soli asset (DD 40%). Diversificare su 3 (`top_k=3`) dimezza quasi il DD
(40%→26%) e *alza* pure il ritorno full (+1095%→+1303%, ret/DD da 27 a 50); il
vol-target abbassa il DD ma sacrifica ritorno, quindi si tiene top_k=3 senza VT.
Applicato a `ROT02_dual_momentum.py` e a `_rot_daily_equity` (usata dai portafogli).
**Portafogli pronti (artefatti accorpati e migliorati).** Oltre a `PORT01` (solo
honest), due script in `scripts/strategies/`:
- `PORT02_fade_master.py` — le 3 fade × BTC/ETH accorpate (6 sleeve, filtro trend),
equal-weight daily: DD ~8.2% full / 5.9% OOS, Sharpe 3.95/4.09, CAGR ~46%.
- `PORT03_all_master.py` — portafoglio MASTER (fade + honest, 9 sleeve). Due varianti:
`equal` (massimo Sharpe: DD 5.2%/4.7% OOS, Sharpe 4.23/4.33) e `5050` fra le due
famiglie (minimo DD: 5.0% full / 4.5% OOS). È la configurazione consigliata.
Come `PORT01`, sono meta-portafogli (script `run()` di report), non `Strategy` con
`generate_signals`, quindi non nel `strategy_loader`.
**Esplorazione famiglie alternative (branch `strategy_explore`, 2026-05-29).** Esplorate
9 famiglie nuove con agenti paralleli su harness onesto condiviso
(`scripts/analysis/explore_lab.py`). 7 sono rumore (rifiutate: stagionalità oraria/mensile,
cross-sectional reversal, opening-range breakout, lead-lag BTC→alt, continuation intraday —
quest'ultima riconferma la dominanza mean-reversion). Due edge reali:
- **PR01 Pairs** (`scripts/strategies/PR01_pairs_reversion.py`): spread reversion
market-neutral sul log-ratio z-score, **config UNIVERSALE** `n=50 z_in=2.0 z_exit=0.75
max_bars=72` (anti-overfit, niente tuning per-coppia). **5 coppie robuste**: ETH/BTC
(Sharpe 4.36), LTC/ETH (3.08), ADA/ETH (2.69), BTC/LTC (2.36, robusta anche 4h), ETH/SOL
(1.96, la più debole). Pattern: sempre alt-liquido vs major. Plateau confermato
(heatmap 20/20 Sharpe>1) + walk-forward (ETH/BTC 11/12 finestre+). **BNB/ETH scartata**
(overfit). Corr col mercato ~0.02-0.08. Fee su **2 gambe** (worker da estendere). Verifica: `pairs_research.py`.
- **TSM01** (`scripts/analysis/tsmom_research.py`): TSMOM multi-orizzonte 3/6/12m + risk-off,
**gross 0.30**, distinto da ROT02 (corr 0.62), DD 15-22%, mai un anno negativo. Robusto
(36/36 config OOS+) ma diversificatore, non motore di ritorno (rende meno di ROT02).
Aggiungere i **5 pairs** al MASTER (quasi scorrelati, ~0.02-0.09) è il free-lunch più
grande (`scripts/analysis/combine_v2.py`). **Numeri sobri onesti** (l'OOS singolo 2024-25
è regime calmo → ottimistico ~50%): worst-DD su 90g rolling **~6%** (non 2.3%), Sharpe
atteso **~5** (mediana semestrale), ogni anno positivo dal 2021, regge **leva 2x +
slippage doppio** (CAGR 36%, Sharpe 5.1). Config robusta raccomandata: **MASTER-esteso
equal-weight, leva 2x, cap pairs ~30-35%** (i pairs sono ~57% del rischio e non ancora
validati col worker live a 2 gambe). La confluenza multi-TF è stata SCARTATA (overfit).
**Metodologia obbligatoria per ogni nuova strategia** (per non ripetere l'errore squeeze):
1. Ingresso eseguibile: direzione e prezzo decisi con dati **fino a `close[i]`**, mai `close[i-1]` con direzione da `i`.
2. Backtest **NETTO** dopo fee realistiche Deribit (**0.10% RT** taker, non 0.20%) + leva.
3. Validazione **out-of-sample** (held-out) + robustezza su griglia parametri + sweep fee.
4. Crea script in `scripts/strategies/`, aggiungi a `MODULE_MAP` (`strategy_loader.py`) e a `strategies.yml`.
Strategie scartate storiche in `scripts/waste/` (W01-W28 + la famiglia squeeze).
**Verso €50/giorno.** Con 4 strategie indipendenti (MR01/MR02/MR03/MR07) × 2 asset
(BTC/ETH) su €1000 ciascuna, il PnL medio storico aggregato è ben oltre €50/giorno;
ma quei numeri sono backtest a leva 3x su 8 anni e includono anni eccezionali (es.
ETH 2024). Stima onesta: il target è *plausibile* su un portafoglio diversificato di
queste fade, ma va confermato col paper trader live prima di rischiare capitale reale.
## Multi-Strategy Paper Trader
Orchestratore che esegue N strategie in parallelo su dati live Cerbero, ognuna con €1000 USDC virtuali indipendenti.
**Config:** `strategies.yml` — lista strategie con asset, tf, sizing, parametri. Attualmente solo MR01 (BTC/ETH 1h).
**Persistenza:** `data/paper_trades/{strategy}___{asset}__{tf}/` con `trades.jsonl` (append-only) + `status.json` (resume al restart, include tp/sl/max_bars).
**Hot-add:** aggiungi riga YAML → `docker compose restart` → storico intatto.
**Exit strategia:** se un `Signal` porta `tp`/`sl`/`max_bars` in `metadata` (come MR01), il worker esce su take-profit/stop-loss/time-limit a quei livelli; altrimenti usa il fallback `hold_bars`/stop -2%.
**Notifiche:** Telegram per ogni trade (richiede `.env` con `TELEGRAM_BOT_TOKEN` e `TELEGRAM_CHAT_ID`).
## Convenzioni
- Strategie in `scripts/strategies/` con codice univoco (MR01, ...).
- Script scartati in `scripts/waste/` (W01-W28 + famiglia squeeze).
- Diario in `docs/diary/YYYY-MM-DD.md`. Aggiornare dopo ogni esperimento significativo.
- Nessun dato sensibile nei commit (token, chiavi API). Usare `.gitignore`.
- Verificare sempre assenza di data leakage prima di fidarsi dei risultati. In particolare: `returns[i-w : i]` include `close[i]` che è un candle nel futuro — usare `returns[i-w : i-1]`.
## Attenzione
- **Data leakage:** è stata trovata e corretta nello script 05. Ogni volta che si usano rendimenti logaritmici (`np.diff(np.log(close))`), ricordare che `returns[k]` usa `close[k+1]`. I feature devono fermarsi a `returns[i-2]` se il prezzo corrente è `close[i-1]`.
- **Fee:** Deribit perp reale = taker ~0.05%/lato (**0.10% round-trip**), maker ~0%. Usare 0.10% RT come baseline (lo 0.20% storico era pessimista 2x). Includere SEMPRE nel backtest: sono vincolo di prim'ordine, molte operazioni = morte per fee. Il worker usa `strategy.fee_rt` (MR01 = 0.001).
- **Leva:** testato con 3x. Aumentare a 5x migliora i rendimenti ma raddoppia il drawdown.
- **GBM:** GradientBoostingClassifier di scikit-learn. Ensemble di alberi decisionali sequenziali. Walk-forward per evitare leakage temporale.
- **Cerbero `get_historical` (fix 2026-05-28):** `end_date` come data nuda è inclusivo dell'intera giornata fino all'ultima candela chiusa (es. `end=oggi` arriva fino ad ora, non più a mezzanotte); accettati anche timestamp con orario (`...T14:00:00`, naive=UTC); nessun cap a ~5000 righe (paginazione interna). Il client passa già `end=oggi`, ora corretto. Prima del fix il paper trader restava a zero trade perché il feed era fermo a mezzanotte.
- **Dati ETH Deribit 15m:** 14-30%/anno di candele *flat* (O=H=L=C, volume 0, run fino a ~54h) per bassa liquidità del perpetuo. Verificato (2026-05-28): escluderle NON cambia i backtest (Δacc ≤0.5pp) → edge robusto. Resta un caveat operativo (slippage/fill in trading reale, irrilevante per paper). BTC pulito eccetto picco ~8% nel 2024.