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>
3.6 KiB
2026-06-01 — SH01 live eseguiva la strategia SBAGLIATA (squeeze scartato), non shape-ML
Scoperto verificando perché SH01 continuava a chiudere a
hold_limit/3anche dopo il rebuild col fix horizon-exit. Il fix era corretto ma in un ramo morto: SH01 live non passava daStrategyWorker.tick().
Sintomo
Dopo il deploy del fix SH01 (exit a H=12), un close SH01_BTC delle 12:00 era ancora
reason=hold_limit bars=3 (perdita −1,27%). Il fix non aveva effetto sul path reale.
Causa (bug di wiring, più grave del previsto)
src/portfolio/runner.py importava MLWorkerWrapper da src/live/multi_runner.py e
ci avvolgeva lo sleeve SH01:
if spec.kind == "ml":
return MLWorkerWrapper(worker, {"retrain_hours": 24})
Ma quel wrapper è legacy, per la famiglia squeeze ML01 (scartata, vedi CLAUDE.md):
- usa
SignalEngine= squeeze-detection + GradientBoosting (NON SH01_shape_ml); - ha una
tick()propria che apre con unSignalnudo (niente tp/sl/max_bars) ed esce conif bars_held >= hold_bars: close("hold_limit")→ ignora del tutto la strategia caricata e il fix horizon.
Quindi lo sleeve "SH01" del portafoglio live non eseguiva shape-ML: eseguiva il
motore squeeze scartato. I log TRAIN OK / oos_signal_precision venivano da lì. Il
worker con strategy=SH01_shape_ml era costruito ma la sua generate_signals non
veniva mai chiamata.
Fix
SH01 (kind="ml") ora gira come StrategyWorker normale: SH01_shape_ml.generate_signals
fa il walk-forward (retraining) internamente ad ogni tick (ml_wf_entries) ed emette
metadata.max_bars=H=12 → gli exit passano per StrategyWorker.tick() e il fix horizon
si applica davvero.
# runner.py: niente più MLWorkerWrapper per kind="ml"
return StrategyWorker(strategy=strategy, asset=spec.asset, tf=spec.tf, ...)
Lookback dati. ml_wf_entries ha train_min=4000 → servono ≥4000 barre 1h prima di
produrre segnali (con 90g/2160 barre → 0 segnali, runtime 0.01s — il falso "muto"). Le
candele 1h di BTC/ETH già arrivano a 440g (le richiede TSM01/ROT02 a 1d), ma per non
dipendere da quella coincidenza ho aggiunto _ML_LOOKBACK_DAYS=365: gli asset usati da
sleeve ml fetchano ≥365g (~8760 barre). Costo generate_signals su 365g: 0,17–0,24s
(modello logit) → trascurabile sul poll 60s.
Verifica. Build SH01 → StrategyWorker con strategy.name=="SH01_shape_ml", niente
attributo engine (regression test test_build_ml_sh01_is_plain_strategyworker). Smoke
su 365g: 766–1786 segnali, tutti max_bars=12; tick live 0,17s. ml_wf_entries non
predice mai l'ultima barra (n-1) ma fino a n-2 = esattamente la condizione di apertura
del worker (idx >= last_idx-1) → apre quando il segnale è fresco. Suite: 51 passed.
Stato live. SH01 BTC/ETH erano flat: contatori resettati a 0 (capitale preservato
58,76/58,78), vecchi trade squeeze archiviati in trades_squeeze_archive.jsonl. Rebuild
- recreate: 14 worker RESUME puliti, container healthy, nessun log TRAIN/squeeze, zero errori.
Lezione
- Verificare il path REALE, non solo il codice del fix. Il fix horizon era giusto ma SH01 non lo attraversava. Un fix non testato end-to-end sul percorso vivo è un fix presunto. (Mi ero fidato del rebuild senza confermare il reason dei close SH01.)
- Riusare un wrapper legacy "perché c'è" è un rischio:
MLWorkerWrapperdi multi_runner era per la famiglia squeeze scartata, non per shape-ML. - Un modello ML "muto" può essere solo fame di dati (train_min), non un bug logico: controllare sempre la dimensione della finestra prima di concludere.