fix(live): exit a orizzonte per strategie senza TP/SL (SH01)

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>
This commit is contained in:
Adriano Dal Pastro
2026-06-01 09:05:53 +00:00
parent aaf0221957
commit 53e0965c4b
2 changed files with 64 additions and 0 deletions
+5
View File
@@ -237,6 +237,11 @@ class StrategyWorker:
self._close_position(self.tp, "take_profit")
elif self.max_bars and self.bars_held >= self.max_bars:
self._close_position(current_price, "time_limit")
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")
elif self.bars_held >= self.hold_bars:
self._close_position(current_price, "hold_limit")
else: