Due correzioni emerse da close live con win=True ma pnl<0.
1) Metrica win lorda -> netta. _close_position contava is_win=trade_return>0
(lordo), gonfiando l'accuracy: un take-profit colpito con mossa < fee RT
risultava "win" pur perdendo. 51 close live: 39 win (76,5%) -> 13 falsi win
-> accuracy netta reale 52,9%. Fix: is_win = net > 0. Capitale/PnL erano
già corretti (netti). Contatori persistiti riconciliati a parte (MR01/DIP01
BTC 7->1).
2) Filtro edge-minimo min_tp_frac. I 13 falsi win erano tutti MR01/DIP01 BTC in
regime piatto: TP (la media) entro il costo round-trip -> perdenti garantiti.
Aggiunto param min_tp_frac (default 0.0=off) a tutte e 4 le fade (MR01 banda,
MR02 midpoint, MR07 ATR, DIP01): salta i segnali col TP entro la soglia.
Non si "allarga" il TP (rischierebbe di perdere di piu'): si evita la trade.
Cablato live a 0.0015 (1,5x fee) in _defs.py.
Validazione backtest BTC+ETH 1h: neutro su tutte le fade (0-1 trade rimossi,
pnl invariato o +leggero su DIP01). I micro-scalp sotto-fee non esistono nello
storico -> artefatto del regime attuale. Filtro puro-upside.
Test: test_win_net_of_fees.py, test_min_tp_frac.py (monotonia + gap > soglia +
default-off invariato). Suite: 50 passed.
NB deploy: il sorgente e' COPY nell'immagine, non montato -> serve
`docker compose up -d --build`, non un semplice restart (vale anche per il fix
SH01 horizon-exit, andato live solo con questo rebuild). Volume ./data persiste,
14 worker in RESUME puliti.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lo StrategyWorker onorava max_bars (orizzonte del Signal) solo nel ramo
`if self.tp and self.sl`. SH01 (shape-ML, H=12) non porta TP/SL, quindi
cadeva sul fallback legacy hold_bars=3 e chiudeva a 3 barre invece delle
12 validate: l'edge (asimmetria sull'orizzonte, non frequenza) non aveva
tempo di realizzarsi -> accuratezza live falsata (33%), tutti exit
"hold_limit" a bars_held=3.
Aggiunto un ramo `elif self.max_bars` che esce a "time_limit" quando
bars_held>=max_bars, prima del fallback hold_bars. Tocca solo le
strategie horizon-only (SH01); le fade con tp+sl+max_bars sono invariate.
Test: tests/portfolio/test_horizon_exit.py (resta in posizione a 3 barre
con max_bars=12; esce a 12 con reason time_limit). Suite: 43 passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Chiude il gap live-vs-backtest delle fade/DIP01: prima il worker controllava solo il
close, ora controlla high/low della barra ed esce AL LIVELLO tp/sl (SL prioritario),
identico alla semantica intrabar del backtest. +4 test. Pairs/rotation/tsmom invariati.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
StrategyWorker ora supporta exit guidati dalla strategia via Signal.metadata
(take-profit alla media / stop-loss ad ATR / time-limit), con fallback al
vecchio hold_bars/stop -2% per strategie senza metadata. Usa fee_rt della
strategia (MR01 = 0.10% RT reale Deribit, non piu' 0.20% hardcoded).
Persistenza di tp/sl/max_bars in status.json per resume.
Re-validato col worker reale (replay finestre mobili 1h, fee 0.10%):
BTC 1h MR01: +196% OOS, ETH 1h: +251% OOS (nov 2023->mag 2026) — coerente col backtest.
README + CLAUDE.md riscritti: squeeze = artefatto di look-ahead -> waste,
MR01 mean-reversion unica attiva, metodologia anti-look-ahead e fee reali 0.10% RT.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Il paper trader restava a zero trade: il feed Cerbero era fermo a
mezzanotte (bug end_date lato cerbero-mcp, poi risolto) e MT01 leggeva
il trend 1h da un parquet statico, di fatto congelandolo (gap ~15h sul
bar corrente). Ora il runner fa fetch 1h live per le strategie MTF e lo
passa a generate_signals via il parametro df_1h (fallback al parquet se
assente). Aggiornati CLAUDE.md, README e diario 2026-05-28.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>