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