Files
PythagorasGoal/Old/docs/diary/2026-06-01-sh01-wiring-squeeze-bug.md
T
Adriano Dal Pastro 14522262e6 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>
2026-06-19 15:20:59 +00:00

3.6 KiB
Raw Blame History

2026-06-01 — SH01 live eseguiva la strategia SBAGLIATA (squeeze scartato), non shape-ML

Scoperto verificando perché SH01 continuava a chiudere a hold_limit/3 anche dopo il rebuild col fix horizon-exit. Il fix era corretto ma in un ramo morto: SH01 live non passava da StrategyWorker.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 un Signal nudo (niente tp/sl/max_bars) ed esce con if 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,170,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: 7661786 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

  1. 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.)
  2. Riusare un wrapper legacy "perché c'è" è un rischio: MLWorkerWrapper di multi_runner era per la famiglia squeeze scartata, non per shape-ML.
  3. 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.