ad65a0b344
23 famiglie esplorate (harness condiviso exit_lab, train/OOS embargo nov-2023, tutto lo storico 1h 2018-2026) + 10 verifiche avversariali + test PORT06. 'Cavalcare il prezzo' non esiste (4a conferma: oltre il TP=media non c'e' coda). Scoperta: lo SL intrabar fisso e' il distruttore di valore n.1 delle fade (stop da wick = falsi negativi). Forma robusta: SL solo su CHIUSURA oltre sl0±0.5·ATR14 — PORT06 FULL Sharpe 6.47→7.84 DD 4.10→2.60, OOS 8.82→10.06. Collaterali: bias gap-through dell'engine sugli stop stretti; ramo -2% del worker morto con sl=0. Diario: docs/diary/2026-06-04-exit-lab.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
"""EXIT-17 — wide_sl_trail: RESPIRA POI PROTEGGI.
|
|
|
|
Idea: l'SL fisso all'entrata (sl0) puo' essere troppo stretto -> stoppa fade che
|
|
poi sarebbero rientrate alla media. Qui ALLARGHIAMO l'SL iniziale a
|
|
sl_w = entry - w*(entry - sl0) (long, w>1 -> stop piu' lontano = piu' respiro)
|
|
sl_w = entry + w*(sl0 - entry) (short)
|
|
ma attiviamo SUBITO un trailing chandelier a k*ATR dall'estremo favorevole. Lo stop
|
|
attivo nel bar j e' il PIU' PROTETTIVO fra l'SL allargato e il chandelier:
|
|
long : sl = max(sl_w, max(high[i..j-1]) - k*ATR[j-1])
|
|
short: sl = min(sl_w, min(low[i..j-1]) + k*ATR[j-1])
|
|
TP fisso tp0 invariato; horizon = max_bars invariato.
|
|
|
|
Logica: finche' il prezzo NON corre a favore, il rischio e' l'SL allargato (respiro:
|
|
si tollera un ritracciamento iniziale piu' ampio nella speranza che la fade rientri).
|
|
Appena il prezzo corre a favore, il chandelier sale sopra sl_w e protegge il
|
|
profitto come un trail normale. Differenza da EXIT-02 (che usa max(sl0, chand)):
|
|
qui il floor iniziale e' PIU' LARGO di sl0, quindi early il rischio per-trade e'
|
|
maggiore (peggiora i loser veloci) ma si salvano fade che con sl0 sarebbero state
|
|
stoppate giusto prima del rientro.
|
|
|
|
ANTI-LOOK-AHEAD: levels(j) usa SOLO dati <= j-1 (estremo favorevole su [i..j-1]
|
|
mantenuto incrementalmente fino a j-1; atr14[j-1]). after_bar non usato.
|
|
|
|
GRID: w in {1.5, 2.0} x k in {2.0, 3.0} (4 celle).
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from exit_lab import ExitPolicy, evaluate # noqa: E402
|
|
|
|
|
|
class WideSLTrail(ExitPolicy):
|
|
name = "wide_sl_trail"
|
|
|
|
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, w=1.5, k=2.0, **params):
|
|
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
|
|
self.w = float(w)
|
|
self.k = float(k)
|
|
self.high = ctx["high"]
|
|
self.low = ctx["low"]
|
|
self.atr = ctx["atr14"]
|
|
# SL iniziale ALLARGATO: piu' lontano dall'entrata (w>1)
|
|
if d == 1:
|
|
self.sl_w = entry - self.w * (entry - sl0)
|
|
else:
|
|
self.sl_w = entry + self.w * (sl0 - entry)
|
|
# estremo favorevole running (solo barre <= j-1); init = barra d'entrata i
|
|
self.run_hi = self.high[i]
|
|
self.run_lo = self.low[i]
|
|
self.last_seen = i
|
|
|
|
def _update_running(self, upto: int) -> None:
|
|
"""Incorpora le barre (last_seen, upto] nell'estremo favorevole. upto = j-1
|
|
-> NON tocca il bar j (anti-look-ahead)."""
|
|
while self.last_seen < upto:
|
|
self.last_seen += 1
|
|
if self.high[self.last_seen] > self.run_hi:
|
|
self.run_hi = self.high[self.last_seen]
|
|
if self.low[self.last_seen] < self.run_lo:
|
|
self.run_lo = self.low[self.last_seen]
|
|
|
|
def levels(self, j: int):
|
|
self._update_running(j - 1) # solo dati <= j-1
|
|
a = self.atr[j - 1]
|
|
if a is None or a != a: # NaN nei primi 14 bar -> usa l'SL allargato
|
|
return self.tp0, self.sl_w, 1.0
|
|
if self.d == 1:
|
|
chand = self.run_hi - self.k * a
|
|
sl = max(self.sl_w, chand) # il piu' protettivo (stop piu' alto)
|
|
else:
|
|
chand = self.run_lo + self.k * a
|
|
sl = min(self.sl_w, chand) # il piu' protettivo (stop piu' basso)
|
|
return self.tp0, sl, 1.0
|
|
|
|
|
|
GRID = [
|
|
{"w": w, "k": k}
|
|
for w in (1.5, 2.0)
|
|
for k in (2.0, 3.0)
|
|
]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
evaluate(WideSLTrail, GRID)
|