research(exit-lab): 34 agenti su exit dinamiche → EXIT-16 close-confirm SL PROMOSSO a livello PORT06
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>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""EXIT-16 — close_confirm_sl: STOP-LOSS confermato in CHIUSURA (immune ai wick).
|
||||
|
||||
IDEA. Lo SL intrabar fisso stoppa anche su un wick transitorio che buca sl0 e
|
||||
poi rientra. Le fade sono mean-reversion: il movimento contrario e' spesso un
|
||||
overshoot momentaneo. Qui lo SL NON e' piu' un livello toccato intrabar
|
||||
(disattivato: sl=None nei livelli, l'engine non lo testa MAI sui low/high) ma
|
||||
una CONFERMA sul CLOSE del bar: si esce solo se il prezzo CHIUDE oltre sl0.
|
||||
|
||||
in levels(j): sl = None (no stop intrabar -> immune ai wick), TP fisso tp0.
|
||||
in after_bar(j):
|
||||
long (d=1): esci al close[j] se close[j] < sl0 - buffer*atr14[j]
|
||||
short (d=-1): esci al close[j] se close[j] > sl0 + buffer*atr14[j]
|
||||
|
||||
ONESTO. L'uscita avviene al CLOSE[j], che puo' essere PEGGIO di sl0 quando il
|
||||
bar gappa o sfonda di slancio (il backtest paga il close reale, non sl0). Questo
|
||||
e' il costo del "confermare": si rinuncia a fermarsi esatti a sl0 in cambio di
|
||||
non farsi cacciare dai wick. Il buffer*atr richiede uno sfondamento ulteriore in
|
||||
chiusura -> meno uscite ma piu' lontane da sl0 quando scattano.
|
||||
|
||||
ANTI-LOOK-AHEAD. levels(j) ritorna sl=None e tp0 (nessun dato del bar j). La
|
||||
decisione di uscita e' in after_bar(j), che PER CONTRATTO puo' leggere il bar j:
|
||||
close[j] e atr14[j] sono entrambi noti al close del bar j (atr14[j] = rolling
|
||||
mean di TR fino a j; TR[j] usa high/low/close[j] e close[j-1], tutti chiusi a j).
|
||||
Nessun dato > j entra nella decisione. -> contratto rispettato.
|
||||
|
||||
NB il HARD_CAP/horizon=max_bars resta: se ne' TP ne' close-confirm scattano, il
|
||||
trade scade al close a max_bars come la base. Quindi un trade puo' restare in
|
||||
posizione PIU' a lungo della base (la base poteva stopparlo intrabar prima):
|
||||
l'avg_bars puo' SALIRE -> il ret va pesato per l'esposizione.
|
||||
|
||||
GRID: buffer in {0.0, 0.25, 0.5} ATR (3 celle).
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
from exit_lab import ExitPolicy, evaluate # noqa: E402
|
||||
|
||||
|
||||
class CloseConfirmSl(ExitPolicy):
|
||||
name = "close_confirm_sl"
|
||||
|
||||
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
|
||||
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
|
||||
self.buffer = float(params.get("buffer", 0.0))
|
||||
self.close = ctx["close"]
|
||||
self.atr = ctx["atr14"]
|
||||
|
||||
def levels(self, j: int):
|
||||
# SL intrabar DISATTIVATO (immune ai wick): l'engine non testa low/high
|
||||
# contro lo stop. TP fisso tp0 intrabar invariato.
|
||||
return self.tp0, None, 1.0
|
||||
|
||||
def after_bar(self, j: int) -> bool:
|
||||
# Decisione sul CLOSE del bar j -> per contratto j e' leggibile.
|
||||
a = self.atr[j]
|
||||
if not np.isfinite(a):
|
||||
a = 0.0
|
||||
cj = self.close[j]
|
||||
if self.d == 1:
|
||||
# long: stop confermato se chiude SOTTO sl0 - buffer*atr
|
||||
return cj < self.sl0 - self.buffer * a
|
||||
else:
|
||||
# short: stop confermato se chiude SOPRA sl0 + buffer*atr
|
||||
return cj > self.sl0 + self.buffer * a
|
||||
|
||||
|
||||
GRID = [
|
||||
{"buffer": 0.0},
|
||||
{"buffer": 0.25},
|
||||
{"buffer": 0.5},
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
evaluate(CloseConfirmSl, GRID)
|
||||
Reference in New Issue
Block a user