chore(reset): v2.0.0 — storico certificato Deribit mainnet, ripartenza pulita
Reset del progetto su fondamenta verificate dopo la scoperta che l'intera libreria "validata OOS" era artefatto di feed contaminato (print fantasma del feed Cerbero TESTNET + storico Binance/USDT). - Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE 50-82% barre flat; XRP/BNB non certificabili). - Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST con segnale residuo, da ri-validare in isolamento. - Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio, runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/ portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/ (preservati, non cancellati). Diario consolidato in un unico documento. - Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal + src/backtest/engine + load_data; tool dati certificati (rebuild_history, certify_feed, audit_feed, multi_source_check). - Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
# 2026-05-28 — Giorno 3: Bug dati Cerbero, paper trader fermo, fix MT01 multi-timeframe
|
||||
|
||||
### 12:20 — Sintomo: paper trader live a zero trade
|
||||
|
||||
**Cosa:** check del container `pythagoras-multi` (multi-strategy paper trader, 6 strategie).
|
||||
**Reale:** container healthy da ore, ma **0 trade** su tutte le strategie, tutte FLAT a €1000.
|
||||
Primo falso indizio: `last_bar_ts: 0` in tutti gli `status.json`. Indagando il worker,
|
||||
quel campo si aggiorna **solo a posizione aperta** (contatore `hold_bars`), non ad ogni
|
||||
candela → non è la causa. Il loop era vivo (status.json riscritti ogni 60s).
|
||||
**Lezione:** non fidarsi del nome di un campo; verificare nel codice quando viene scritto.
|
||||
L'healthcheck del container controlla solo l'esistenza di `status.json`, non la freschezza
|
||||
→ un loop bloccato risulterebbe comunque "healthy".
|
||||
|
||||
### 12:45 — Causa radice: bug lato Cerbero MCP `get_historical`
|
||||
|
||||
**Cosa:** probe dirette all'endpoint `/mcp-deribit/tools/get_historical`.
|
||||
**Reale:** due bug lato server:
|
||||
1. **`end_date` data-nuda tronca a mezzanotte:** `end=oggi` restituiva candele solo fino a
|
||||
`oggi 00:00`. Il `df` live finiva sempre alla barra di mezzanotte e **non avanzava** durante
|
||||
la giornata → nessun breakout fresco sull'ultima barra → nessun ingresso (condizione worker
|
||||
`last_signal.idx >= last_idx - 1`).
|
||||
2. **Cap a ~5000 righe** che ignora `start_date`: una richiesta di 365g a 15m restituiva ~52
|
||||
giorni. Ecco perché ML01 si addestrava su soli 88 samples (overfit, train_acc 100%).
|
||||
**Lezione:** lo zero-trade non era nelle strategie ma nel feed dati. Sempre validare la
|
||||
freschezza/copertura dei dati prima di sospettare la logica.
|
||||
|
||||
### 13:30 — Fix lato Cerbero + verifica
|
||||
|
||||
**Cosa:** report passato al dev di `cerbero-mcp`; fix deployato (riavvio container) + doc
|
||||
aggiornata in `cerbero-mcp/docs/API_REFERENCE.md`.
|
||||
**Reale dopo deploy (verificato con probe):**
|
||||
- `end=oggi` (data nuda) → ultima candela = ora corrente (age ~3 min). ✅
|
||||
- 365g a 15m → **35.099 candele**, span 365.6g, nessun cap. ✅
|
||||
- Supportati anche timestamp con orario (`...T14:00:00`, naive = UTC). ✅
|
||||
|
||||
Nostro client (`src/live/cerbero_client.py`) invariato: passa già `end=oggi`, ora corretto.
|
||||
**Lezione:** "trust but verify" — la doc dichiarava i fix prima che fossero deployati; solo
|
||||
la probe diretta ha confermato cosa era davvero attivo sul server.
|
||||
|
||||
### 14:00 — Problema residuo: MT01 usava un trend 1h STANTIO
|
||||
|
||||
**Cosa:** check di tutte le strategie sul percorso di codice reale con dati freschi.
|
||||
**Reale:**
|
||||
- Tutte le 6 strategie girano senza crash; SQ01/SQ02 generano molti segnali.
|
||||
- **MT01 leggeva il trend 1h dal parquet statico** (`load_data(asset,"1h")`), non da Cerbero.
|
||||
Il parquet finiva a mezzanotte → per ogni barra 15m di oggi `searchsorted` cadeva oltre la
|
||||
fine e si agganciava sempre alla candela di mezzanotte (gap 14.8h). La conferma
|
||||
multi-timeframe — il cuore di MT01 — era di fatto congelata e il gap cresce ogni giorno.
|
||||
- In `data/raw/` mancavano del tutto i parquet **15m** (`btc_15m`, `eth_15m`) → backtest 15m rotti.
|
||||
**Lezione:** una strategia live che dipende da un file statico ha un punto cieco temporale;
|
||||
il dato live e quello di backtest devono provenire da fonti coerenti.
|
||||
|
||||
### 14:30 — Fix MT01: trend 1h live da Cerbero
|
||||
|
||||
**Cosa:** modifica al runner perché MT01 prenda l'1h live, non dal parquet.
|
||||
- `MT01.generate_signals` accetta un `df_1h` opzionale (fallback al parquet se assente).
|
||||
- `StrategyWorker.tick(df, df_1h=None)` lo inoltra ai signal.
|
||||
- `multi_runner` fa fetch 1h live (resolution 60) per gli asset MT01 ad ogni poll (`htf_cache`).
|
||||
**Reale (verificato a codice montato, pre-rebuild):** gap del trend 1h sull'ultima barra
|
||||
**0.75h** (fresco) contro **14.8h** col parquet statico. Segnali invariati sullo storico.
|
||||
**Lezione:** isolare la dipendenza dal file statico rende MT01 immune al drift tra un
|
||||
`download_all()` e l'altro.
|
||||
|
||||
### 14:55 — Rigenerazione dati + rebuild
|
||||
|
||||
**Cosa:** `download_asset` per 15m+1h (saltati 1m/5m, lenti e inutilizzati), poi
|
||||
`docker compose up -d --build` (il codice `src/` è baked nell'immagine).
|
||||
**Reale:** parquet rigenerati con storia completa 2018→2026 e freschi (15m fino alle 14:45,
|
||||
1h fino alle 14:00). Container ripartito: 6 strategie attive, ML01 riaddestrato su **534
|
||||
samples** (anno pieno), MT01 senza errori, fetch 1h live OK.
|
||||
|
||||
### 15:00 — Regressione backtest sui dati rigenerati
|
||||
|
||||
**Cosa:** rilanciati i backtest per confermare che i numeri documentati si riproducano sui
|
||||
dati ricreati da zero (BTC/ETH 15m, hold=3, fee 0.2% RT, leva 3x, pos 15%).
|
||||
**Reale:** accuratezze e drawdown **identici**, solo +1/+3 trade dalle barre recenti in più.
|
||||
|
||||
| Strategia | Ottenuto | Documentato | Esito |
|
||||
|---|---|---|---|
|
||||
| SQ01 BTC 15m | 76.7% / DD 6.7% / 4063t | 76.7% / 6.7% / 4062 | ✓ |
|
||||
| SQ01 ETH 15m | 76.4% / 6.2% / 2951t | 76.4% / 6.2% / 2948 | ✓ |
|
||||
| SQ02 BTC 15m | 79.7% / 6.5% / 1251t | 79.7% / 6.5% / 1250 | ✓ |
|
||||
| SQ02 ETH 15m | 78.6% / 3.4% / 944t | 78.6% / 3.4% / 942 | ✓ |
|
||||
| **MT01 BTC 15m (ema20+vol)** | **82.7% / 5.9% / 503t** | 82.7% / 5.9% / 503 | ✓ esatto |
|
||||
| MT01 ETH 15m (ema20+vol) | 81.2% / 2.9% / 404t | — | ok |
|
||||
|
||||
**Lezione:** l'integrità dei dati rigenerati è confermata — la pipeline di download produce
|
||||
risultati riproducibili. La config live di MT01 (ema20+vol) coincide col best documentato.
|
||||
|
||||
### Punti aperti
|
||||
|
||||
1. **Backtest e drift dati:** MT01 live ora è immune (1h da Cerbero), ma i backtest girano
|
||||
sempre sui dati fino all'ultimo `download_all()`. Per dati di backtest sempre freschi
|
||||
serve uno scheduling del download (cron/job).
|
||||
2. **Healthcheck:** valutare un check su mtime di `status.json` (< 180s) per rilevare uno
|
||||
stallo del loop, non solo l'esistenza del file.
|
||||
|
||||
---
|
||||
|
||||
### 23:00 — 3 nuove strategie con edge OOS fee-aware (branch `strategy_free`)
|
||||
|
||||
**Obiettivo:** trovare almeno 3 nuove strategie (oltre MR01), edge netto validato
|
||||
out-of-sample e fee-aware, per il target €1.000 → ~€50/giorno.
|
||||
|
||||
**Metodologia (invariata dalla lezione squeeze):** ingresso eseguibile a `close[i]`
|
||||
(nessun look-ahead), backtest netto dopo fee Deribit 0.10% RT + leva 3x, OOS = ultimo
|
||||
30% held-out, robustezza su griglia parametri + sweep fee 0.00–0.20% RT, exit
|
||||
TP/SL intrabar o time-limit, una posizione per volta, capitale composto.
|
||||
|
||||
**Candidati** (`scripts/analysis/strategy_research_v2.py`), tutti mean-reversion
|
||||
(l'edge è sempre il rientro, mai la continuazione):
|
||||
|
||||
| Candidato | Esito | Motivo |
|
||||
|---|---|---|
|
||||
| **MR02 Donchian Fade** | ✅ | Robusto su tutta la griglia `n × sl_atr` e tutte le fee |
|
||||
| **MR03 Keltner Fade** | ✅ | Robusto su tutta la griglia `n × k`; banda ATR, indipendente da Bollinger |
|
||||
| **MR07 Return Reversal** | ✅ | Intero blocco `tp_atr=2.0` positivo full+OOS; esposizione ~8% |
|
||||
| MR04 Z-score Reversion | ⛔ | Robusto ma è MR01 riparametrizzato (stessa banda std): edge non *nuovo* |
|
||||
| MR05 Bollinger + filtro ADX | ⛔ | Non robusto: negativo su gran parte della griglia BTC |
|
||||
| MR06 RSI(2) Connors | ⛔ | ETH 1h negativo; non robusto su entrambi gli asset |
|
||||
|
||||
**Risultati** (netto 0.10% RT, leva 3x, OOS, 1h):
|
||||
|
||||
| Codice | Meccanismo | BTC OOS | ETH OOS | DD (full) |
|
||||
|---|---|---|---|---|
|
||||
| MR02 | estremi canale Donchian H/L | +172% | enorme | 30% / 42% |
|
||||
| MR03 | canale ATR su EMA | +112% | +886% | 37% / 66% |
|
||||
| MR07 | z dei rendimenti di barra | +105% | +195% | 25% / 46% |
|
||||
|
||||
**Validazione live-path** (`oos_validation.py`, legge `strategies.yml`, exit hold
|
||||
del worker): tutte e tre positive netto OOS su tutto lo sweep fee, anche al
|
||||
pessimistico 0.20% RT → edge robusto pure al meccanismo di exit.
|
||||
|
||||
**Verifiche:** equivalenza esatta backtest produzione vs research engine (MR02 BTC:
|
||||
2039 trade, DD 29% identici); le 3 classi si caricano dal `strategy_loader`;
|
||||
aggiunte a `strategies.yml` (BTC+ETH 1h). Nessuna suite di test nel progetto.
|
||||
|
||||
**Onestà sul target:** con 4 fade indipendenti × 2 asset il PnL storico aggregato
|
||||
supera €50/giorno, ma sono backtest a leva 3x su 8 anni con annate eccezionali
|
||||
(ETH 2024). Plausibile ma da confermare col paper trader live prima del capitale reale.
|
||||
DD alto su ETH (MR03 ~66%, come MR01) → leva più bassa consigliata per quell'asset.
|
||||
|
||||
**File:** `strategy_research_v2.py`, `src/strategies/fade_base.py`,
|
||||
`scripts/strategies/MR0{2,3,7}_*.py` (nuovi); `strategy_loader.py`, `strategies.yml`,
|
||||
`CLAUDE.md` (aggiornati).
|
||||
**Lezione confermata:** ogni edge robusto trovato finora è mean-reversion; ogni
|
||||
variante trend/continuation o oscillatore senza filtro perde netto.
|
||||
|
||||
---
|
||||
|
||||
### 23:45 — Aumentare Acc e ridurre DD (filtro trend + portafoglio)
|
||||
|
||||
**Obiettivo:** alzare accuratezza e abbassare drawdown sulle 4 fade, senza
|
||||
distruggere l'edge né overfittare (ogni leva misurata FULL **e** OOS).
|
||||
|
||||
**Diagnosi:** perdite/DD concentrati 2018–2021 (bear/covid/caos vol), su ETH DD
|
||||
pieno 66–71%. Banco di prova: `scripts/analysis/risk_improvements.py` e
|
||||
`risk_portfolio.py`.
|
||||
|
||||
**Leve testate:**
|
||||
|
||||
| Leva | Esito | Motivo |
|
||||
|---|---|---|
|
||||
| Sizing vol-target (size ∝ 1/dist-SL) | ⛔ | Over-size sui trade a stop stretto → DD su, ritorno giù |
|
||||
| Skip alta volatilità (ATR% in coda alta) | ⛔ | L'alta vol è *positiva* per le fade (più reversione): Acc e ritorno giù |
|
||||
| **Filtro trend** (`\|close−EMA200\|/ATR > soglia` → salta) | ✅ | Non fada trend/crolli estremi: Acc↑ ovunque, DD↓ molto su ETH, OOS regge |
|
||||
| **Portafoglio** equipesato (sotto-conti indipendenti) | ✅ | Curve poco correlate → DD aggregato 14% (full)/10% (OOS) vs 20-70% singolo |
|
||||
|
||||
**Filtro trend — sweep soglia** (assoluta in ATR, regola unica per tutte = niente
|
||||
overfit): 3.0 ATR è l'equilibrio (2.0 taglia troppo ritorno). Effetto su config
|
||||
deployata (base → filtro):
|
||||
|
||||
| Sleeve | Acc | DD |
|
||||
|---|---|---|
|
||||
| MR01 ETH | 46→55 | **71→26** |
|
||||
| MR02 ETH | 49→55 | 42→25 |
|
||||
| MR03 ETH | 49→52 | 66→34 |
|
||||
| MR07 ETH | 48→54 | 46→21 |
|
||||
| MR01 BTC | 51→54 | 32→34* |
|
||||
| MR02 BTC | 48→52 | 29→23 |
|
||||
| MR07 BTC | 49→53 | 25→18 |
|
||||
| MR03 BTC | 47→47 | 37→37 (filtro OFF) |
|
||||
|
||||
\*MR01 BTC: DD full +2pt ma Acc +3.7 e DD OOS piatto (14.8→15.0). **MR03 BTC**:
|
||||
il filtro peggiora entrambe (unico sleeve) → lasciato disattivo nello yaml.
|
||||
|
||||
**Implementazione:** helper `trend_distance()` in `fade_base.py`; param opzionali
|
||||
`trend_max`/`ema_long` (default None = retro-compatibile) in tutte le strategie
|
||||
(MR01/02/03/07); `strategies.yml` con `trend_max: 3.0, ema_long: 200` (eccetto
|
||||
MR03 BTC). Verificato: equivalenza produzione vs ricerca.
|
||||
|
||||
**Lezione:** il modo onesto di ridurre il DD non è strozzare il sizing (peggiora),
|
||||
ma (a) non opporsi a trend estremi e (b) diversificare su strategie scorrelate.
|
||||
Reference in New Issue
Block a user