Files
PythagorasGoal/Old/docs/diary/2026-06-01-sh01-horizon-exit-bug.md
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.4 KiB
Raw Permalink Blame History

2026-06-01 — Bugfix: SH01 usciva a 3 barre invece di H=12 (exit a orizzonte)

Diagnosi partita da un check sulla debolezza apparente di SH01_BTC nel paper trading live PORT06 (accuratezza 33,3% su 3 trade). Non era sfortuna statistica: era un bug di exit nello StrategyWorker.

Sintomo

Nel live PORT06 (Docker pythagoras-portfolio), SH01_BTC mostrava 3 trade tutti long, tutti chiusi con reason: "hold_limit" a bars_held: 3, con tp: null sl: null:

# entry exit bars net % esito
1 73529.5 73433.0 3 0,46%
2 73759.5 73839.5 3 +0,02%
3 73811.5 73766.0 3 0,32%

oos_signal_precision nei log di TRAIN scendeva 55,6% → 50,0% → 43,3%.

Causa

SH01 (scripts/strategies/SH01_shape_ml.py, config W24 H12 th0.58) è una strategia horizon-only: predice il segno del rendimento a H=12 barre ed esce a H barre. I suoi Signal portano metadata={"max_bars": H} (=12) e nessun TP/SL.

Nello StrategyWorker.tick() la logica di uscita era:

if self.tp and self.sl:          # SH01: False (tp=sl=0)
    ... usa self.max_bars ...     #   -> max_bars=12 consultato SOLO qui
elif self.bars_held >= self.hold_bars:   # fallback legacy hold_bars=3
    self._close_position(..., "hold_limit")   # SH01 finiva QUI

self.max_bars (=12, settato correttamente in _open_position) era onorato solo dentro il ramo tp and sl. Senza TP/SL, SH01 cadeva sul fallback hold_bars=3 e chiudeva a 3 barre. L'edge di SH01 — per CLAUDE.md è nell'asimmetria sull'orizzonte H, non nella frequenza (win-rate ~50%) — non aveva tempo di realizzarsi: tagliato a 3/12, degenera in rumore.

Solo SH01 (BTC+ETH) era colpito: tutte le fade (MR01/MR02/MR07, DIP01) portano tp+sl+max_bars e usano il ramo intrabar corretto.

Fix

src/live/strategy_worker.py: aggiunto un ramo per l'exit a orizzonte puro, prima del fallback hold_bars:

elif self.max_bars:
    # Exit puro a orizzonte (strategie senza TP/SL, es. SH01 shape-ML H=12):
    # onora max_bars dalla metadata del Signal, non il fallback hold_bars=3.
    if self.bars_held >= self.max_bars:
        self._close_position(current_price, "time_limit")

Le fade restano invariate (entrano nel ramo tp and sl).

Verifica

  • Nuovo test tests/portfolio/test_horizon_exit.py (2 casi): con max_bars=12 resta in posizione a 3 barre; esce a 12 con reason: "time_limit" e bars_held: 12.
  • Suite completa: 43 passed.
  • Container riavviato: tutti i 17 sleeve RESUME puliti, inclusa una posizione SH01_ETH short aperta che ora seguirà l'exit a 12 barre.

Atteso d'ora in poi

I trade SH01 nei log mostreranno reason: "time_limit" con bars_held: 12 invece di hold_limit / 3. Il 33% di accuratezza era un artefatto dell'exit prematuro; ora la strategia gira sull'orizzonte su cui è validata (BTC OOS Sharpe 2,72, expanding). Resta comunque un diversificatore del MASTER, non un motore di ritorno standalone.

Lezione

Il backtest di SH01 (fade_base/engine onesto) esce a H barre via max_bars; il worker live deve replicarlo. Quando una strategia non porta TP/SL ma solo un orizzonte, il fallback hold_bars del worker la falsa silenziosamente. Verificare sempre che la convenzione di exit del worker live coincida con quella del backtest validato — non solo l'ingresso.