ef52ad6a79
src/portfolio/: Sleeve (serie rendimenti netti per-barra, causale/fee-aware) + StrategyPortfolio (combina N sleeve per peso su griglia giornaliera comune, metriche FULL/HOLD-OUT/per-anno + standalone per-sleeve, vs buy&hold). Registry sleeve attivi in sleeves.py: per ora SOLO TP01 (peso 100%); aggiungere = una riga (dopo validazione col gauntlet). Report (run_portfolio.py): TP01 FULL Sh 1.30 / DD 14.3% / ~€1.52/g, HOLD-OUT 0.31 / +3.5% (buy&hold -0.32 / -39%). Posizione corrente flat (difensivo). tests/test_portfolio.py (6 test). CLAUDE.md aggiornato (struttura + comando + come aggiungere uno sleeve). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
177 lines
12 KiB
Markdown
177 lines
12 KiB
Markdown
# PythagorasGoal — Istruzioni per agenti
|
||
|
||
## Stato del progetto — v2.0.0 RESET (2026-06-19)
|
||
|
||
**LEGGERE PRIMA DI TUTTO.** Il progetto è stato resettato dopo aver scoperto che l'intera
|
||
libreria di strategie "validata OOS" (FADE, PAIRS, DIP01, TR01, ROT02, TSM01, XS01, SH01) era
|
||
**artefatto di uno storico contaminato** — print fantasma del feed Cerbero **testnet** + storico
|
||
**Binance/USDT**. Ri-testate sul feed reale, tutte perdono ogni anno (vedi
|
||
`docs/diary/2026-06-19-deribit-history.md`, il documento di fondazione).
|
||
|
||
Cosa è cambiato:
|
||
- Lo storico è stato **ricostruito da Deribit mainnet** e **certificato**. Universo affidabile =
|
||
**solo BTC/ETH** (tutti i TF). Gli alt sono esclusi (illiquidi/divergenti/non certificabili).
|
||
- Tutto il codice vecchio (strategie, stack live, ~100 script di ricerca/gate, dati non
|
||
certificati, 60+ diari) è **archiviato in `Old/`** (preservato in git, non cancellato).
|
||
- L'esecuzione è **DISABILITATA**, il conto mainnet è flat. **Non c'è trading live attivo.**
|
||
- Si riparte dalla ricerca di strategie NUOVE, su dati certi, con la metodologia qui sotto.
|
||
|
||
### Ricerca post-reset (2026-06-19) — esito
|
||
|
||
Prima ondata di ricerca onesta su BTC/ETH certificati (5 track, harness condiviso
|
||
`src/backtest/harness.py`). Sintesi in `docs/diary/2026-06-19-research-synthesis.md`.
|
||
|
||
- **TP01 Trend Portfolio — strategia DIFENSIVA robusta (non alpha)** —
|
||
`src/strategies/trend_portfolio.py`. TSMOM multi-orizzonte (1-3-6 mesi) vol-targeted, long-flat,
|
||
50/50 BTC+ETH. Config canonica **PORT LF1d** (**>=12h, 1d raccomandato**, vol-target 20%, leva cap 2x):
|
||
**FULL Sharpe ~1.30, maxDD ~14%; HOLD-OUT 2025-26 Sharpe ~0.31 / +3.5%** mentre il buy&hold 50/50
|
||
faceva −39%/DD60%. Verificata indipendentemente col gauntlet onesto (hold-out + cross-asset +
|
||
plateau + deflated-Sharpe 0.999): **regge**. **Valore = taglio del drawdown ~6× vs buy&hold**, NON
|
||
generazione di ritorno (CAGR ~16% vs ~48% del buy&hold sul toro).
|
||
⚠️ **LOOK-AHEAD (2026-06-19):** un ffill MIXED-TIMEFRAME su barre open-labeled gonfiava il 4h
|
||
(~1.60 → reale ~1.1). Il calcolo per-singolo-TF è leak-free, ma **NON scendere sotto le 12h**:
|
||
costi+overfitting dominano senza vantaggio (FULL Sh piatto ~1.3 da 12h a 4h; hold-out migliore a 1d).
|
||
Deploy/paper a **1d**. Diari `2026-06-19-tp01-verification.md` / `-tp01-lookahead-fix-lf.md`.
|
||
Paper trader: `scripts/live/paper_trend.py` (1d). Test: `tests/test_trend_portfolio.py`.
|
||
Ri-verifica: `scripts/analysis/{verify_tp01,stress_tp01,tp01_lowfreq}.py`.
|
||
- **Edge deboli ma reali** (NON standalone, NON migliorano il portafoglio): ML walk-forward
|
||
su BTC (Sharpe ~0.57), trend 1h long-short (Sharpe ~1.0), relative-value market-neutral
|
||
ETH/BTC (scorrelato ~0.05 ma Sharpe solo 0.27 → troppo debole per alzare lo Sharpe).
|
||
- **MORTO/confermato artefatto:** mean-reversion / fade (negativo anche a fee zero su dati
|
||
certi — la vecchia libreria +201%/+1238% era pura contaminazione); trend 5m/15m (fee).
|
||
- **Soffitto strutturale:** con i soli BTC/ETH lo Sharpe di portafoglio si ferma a **~1.3**.
|
||
Combinare TF o aggiungere la RV non aiuta (ridondanza/edge troppo debole).
|
||
- **Onestà sul target €50/giorno:** NON raggiungibile su 2000 in 1-2 anni (servono ~130k di
|
||
capitale o un DD da rovina). La leva non è la scorciatoia; la via è target-vol + capitale +
|
||
tempo. La strategia che *guadagna* esiste, ma a ~+€1.5/giorno su 2000.
|
||
|
||
Script ricerca: `scripts/research/track{A,B,C,D,E}_*.py` + `trackD_timing.py`.
|
||
|
||
## Obiettivo
|
||
|
||
Ricerca: riconoscimento pattern frattali per trading algoritmico su crypto. Target dichiarato
|
||
€50/giorno partendo da €1.000. **Onestà prima di tutto**: nessun numero va creduto finché non è
|
||
netto fee, out-of-sample, robusto su griglia, e su dati certificati + liquidi + eseguibili.
|
||
|
||
## Stack
|
||
|
||
- **Linguaggio:** Python 3.11+ — **Package manager:** uv (`pyproject.toml`, `uv.lock`)
|
||
- **Dati:** Parquet in `data/raw/` (gitignored). Solo BTC/ETH (5m/15m/1h).
|
||
- **Analisi/ML:** numpy, pandas, scipy, scikit-learn
|
||
- **Fonte dati storici:** Deribit mainnet via `ccxt` (pubblico, tokenless)
|
||
|
||
## Struttura (post-reset)
|
||
|
||
```
|
||
src/data/downloader.py → load_data(asset, tf): legge i parquet certificati da data/raw/
|
||
src/strategies/base.py → Strategy (ABC), Signal, BacktestResult, YearlyStats
|
||
src/strategies/indicators.py → indicatori condivisi (ema, atr, keltner, ...)
|
||
src/strategies/trend_portfolio.py → TP01: strategia DIFENSIVA robusta (PORT LF1d, >=12h), causale
|
||
src/portfolio/ → PORTAFOGLIO DI STRATEGIE estensibile (Sleeve + StrategyPortfolio)
|
||
portfolio.py → combina N sleeve per peso su griglia giornaliera; metriche FULL/hold-out/anno
|
||
sleeves.py → REGISTRY sleeve attivi (ora solo TP01). Aggiungere = una riga qui
|
||
src/fractal/ → indicatori frattali (patterns.py, indicators.py, similarity.py)
|
||
src/backtest/engine.py → engine di backtesting riusabile
|
||
src/backtest/harness.py → harness ONESTO (load BTC/ETH, backtest_signals no-leakage, OOS)
|
||
src/version.py → APP_VERSION (legge il file VERSION)
|
||
scripts/research/ → ricerca post-reset: track{A-E}_*.py (trend/ML/MR/portfolio/xsec)
|
||
scripts/portfolio/run_portfolio.py → report del portafoglio attivo (pesi, FULL/hold-out/anno, vs B&H)
|
||
scripts/live/paper_trend.py → paper trader forward-only di TP01 (1d) (no esecuzione reale)
|
||
scripts/analysis/ → SOLO i tool dati certificati:
|
||
rebuild_history.py → (ri)costruisce lo storico da Deribit mainnet (base 5m + resample)
|
||
certify_feed.py → certifica il feed (integrità, coerenza resample, spike, cross-venue)
|
||
audit_feed.py → audit per-barra vs riferimento esterno
|
||
multi_source_check.py → cross-check multi-venue (quale venue è "vero")
|
||
data/raw/ → btc/eth × {5m,15m,1h} (gitignored). UNICO dato attivo.
|
||
data/instruments_registry.json → registry strumenti (reference)
|
||
docs/diary/ → diario di ricerca (1 voce: il reset; aggiungere dopo ogni esperimento)
|
||
Old/ → ARCHIVIO: tutto il vecchio (strategie, live, ricerca, dati, diari)
|
||
VERSION → semver (2.0.0)
|
||
```
|
||
|
||
## Comandi
|
||
|
||
```bash
|
||
uv sync # installa dipendenze
|
||
uv run python scripts/analysis/rebuild_history.py --asset BTC ETH # (ri)costruisci storico da Deribit mainnet
|
||
uv run python scripts/analysis/certify_feed.py # certifica i feed (locale + cross-venue)
|
||
uv run python scripts/analysis/certify_feed.py --local # solo check locali (veloce)
|
||
uv run python scripts/research/trackD_trendport.py # backtest strategia vincente (full report)
|
||
uv run python scripts/research/trackD_timing.py # vincitrice su 15m/1h/4h/1d + PnL/DD/trade per anno
|
||
uv run python scripts/portfolio/run_portfolio.py # report del PORTAFOGLIO attivo (sleeve + metriche)
|
||
uv run python scripts/live/paper_trend.py # avanza il paper trader TP01 (forward-only, 1d)
|
||
uv run pytest # test
|
||
```
|
||
|
||
```python
|
||
from src.data.downloader import load_data
|
||
df = load_data("BTC", "1h") # OK. load_data("SOL", ...) -> FileNotFoundError (guardrail: solo dati certi)
|
||
```
|
||
|
||
## IL DATO — fonte di verità (regola di prim'ordine)
|
||
|
||
- **La verità è Deribit mainnet**, perché è dove (in futuro) eseguiamo. Cross-check multi-venue:
|
||
Deribit mainnet è a 0-1 bps dal consenso. **Binance NON è la verità** (è USDT, ~10 bps fuori, e
|
||
sotto depeg USDT fino al 3% off) → usare Binance/Coinbase SOLO come audit indipendente, mai come
|
||
ancora per "ripulire" i dati.
|
||
- **Aggiornare lo storico SOLO con `rebuild_history.py`** (ccxt Deribit mainnet, base 5m unica +
|
||
resample → coerenza interna garantita). **MAI** il vecchio downloader Cerbero (token testnet =
|
||
feed farlocco: è la causa della contaminazione).
|
||
- **Certificare sempre** dopo un rebuild con `certify_feed.py` (integrità OHLC, zero gap, coerenza
|
||
resample maxΔ≈0, spike = solo crash reali, accordo cross-venue per-anno vs Coinbase USD).
|
||
|
||
### Universo ricercabile certificato
|
||
- **BTC / ETH**: puliti (2-6 bps vs Coinbase USD su tutta la storia), liquidi (~0% barre flat a 1h),
|
||
storia lunga (2018/2019→oggi) → **ogni timeframe (5m/15m/1h)**. È l'unico dato in `data/raw`.
|
||
- **Alt (SOL/XRP/ADA/LTC/DOGE/BNB): FUORI.** Illiquidi (LTC 5m 82% barre flat O=H=L=C, run fino a
|
||
~3 giorni), divergenti (LTC/DOGE >1% su 10-21% delle barre 2022-23), o non certificabili
|
||
(XRP delistato da Coinbase per causa SEC; BNB non listato + storia da 2024-10). Sono archiviati in
|
||
`Old/data/raw`. Riammetterne uno richiede prima una ricertificazione che dimostri liquidità + accordo.
|
||
|
||
## Metodologia obbligatoria per ogni nuova strategia
|
||
|
||
1. **Ingresso eseguibile**: direzione e prezzo decisi con dati **fino a `close[i]`**, mai
|
||
`close[i-1]` con direzione presa da `i`; mai entry sull'estremo (high/low) di una candela.
|
||
2. **Backtest NETTO** dopo fee realistiche Deribit (**0.10% RT** taker; maker ~0%) + leva.
|
||
3. **Out-of-sample** held-out + robustezza su **griglia parametri** (entrambi gli asset, tutte le
|
||
celle positive) + **sweep fee** (0.00-0.20% RT, margine ampio).
|
||
4. **Liquidità & plausibilità** (lezione v2.0.0): incrociare ogni edge con la liquidità reale del
|
||
book (quota di barre flat) e con la plausibilità del prezzo (cross-venue). Un edge full+OOS
|
||
robusto su un book fermo o su wick fantasma NON è un edge.
|
||
5. Strategia in `scripts/strategies/` (codice univoco), test in `tests/`, diario aggiornato.
|
||
|
||
## Lezioni critiche (da NON ripetere — la storia di questo progetto)
|
||
|
||
- **Feed contaminato → libreria fasulla (v2.0.0).** Print fantasma testnet + Binance/USDT hanno
|
||
prodotto edge inesistenti (+201%/+1238%/+16492% "OOS"). Tutti spariti sul feed reale. Lezione: il
|
||
dato viene prima della strategia; certificare sempre.
|
||
- **Look-ahead squeeze (storico).** L'intera famiglia squeeze-breakout aveva accuratezze 76-82% che
|
||
erano artefatto: decideva la direzione con la candela di breakout `i` ma entrava a `close[i-1]`.
|
||
Con ingresso onesto: lancio di moneta. (Dettagli nei diari in `Old/`.)
|
||
- **Entry sugli estremi di candela.** Strategie che entrano a `close` quando `close` è all'estremo
|
||
del range (≤0.1% o ≥99.9%) gonfiano i ritorni in modo irrealistico (ETH 2024: +30.848% → +2.725%
|
||
rimuovendoli). Spesso è un artefatto di dato o di entry non eseguibile.
|
||
- **Mean-reversion vs breakout.** Sui dati storici l'unica direzione che mostrava edge era la
|
||
mean-reversion (i breakout rientrano) — MA anche quegli edge erano per lo più artefatto del feed:
|
||
da riverificare da zero su dati certi.
|
||
- **Fee** = vincolo di prim'ordine. 0.10% RT baseline. Molte operazioni = morte per fee.
|
||
- **Leva**: testare 3x; 5x raddoppia il drawdown. I numeri a leva alta NON sono il caso base.
|
||
- **Data leakage** con rendimenti log: `returns[k] = log(close[k+1]/close[k])` usa `close[k+1]`. I
|
||
feature devono fermarsi a `returns[i-2]` se il prezzo corrente è `close[i-1]`. Verificare SEMPRE.
|
||
|
||
## Convenzioni
|
||
|
||
- Strategie in `scripts/strategies/` con codice univoco; scartate documentate nel diario.
|
||
- Diario in `docs/diary/YYYY-MM-DD.md`, aggiornato dopo ogni esperimento significativo.
|
||
- **Nessun segreto nei commit** (token/chiavi). `.env` e `.env.mainnet` sono gitignored.
|
||
- Versionamento: `VERSION` (semver) + `scripts/bump_version.py`. `src/version.py` lo legge.
|
||
|
||
## Archivio `Old/`
|
||
|
||
Tutto il lavoro pre-reset (preservato in git per consultazione storica): strategie
|
||
(`Old/scripts/strategies`), stack live e portafogli (`Old/src/live`, `Old/src/portfolio`,
|
||
`Old/scripts/portfolios`), ricerca/gate (`Old/scripts/analysis`), dati non certificati
|
||
(`Old/data`), 60+ diari (`Old/docs/diary`), test (`Old/tests`). Consultabile come riferimento
|
||
("come facevamo X"), ma **nessun edge lì dentro è fidato** finché non è ri-validato su dati certi.
|
||
```
|