14522262e6
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>
75 lines
3.0 KiB
Python
75 lines
3.0 KiB
Python
"""EXIT-22 — DIAGNOSTICA DEL VALORE DELLO SL sulle fade (MR01/MR02/MR07).
|
|
|
|
Le fade live escono con TP/SL FISSI decisi all'entrata (al close[i]) + max_bars.
|
|
Lo SL e' sl0 = entry -/+ k*ATR (per costruzione della strategia). Questa policy
|
|
NON cambia TP ne' horizon: tocca SOLO lo SL per misurare quanto lo SL ATTUALE
|
|
aggiunge/toglie a ret/DD/Sharpe per sleeve. Tre regimi:
|
|
|
|
mode = "none" -> sl = None (SL RIMOSSO: restano TP + max_bars). Il trade
|
|
puo' chiudere solo al TP o a scadenza horizon. Esposizione
|
|
al rischio di coda massima (nessun taglio della perdita).
|
|
mode = "wide2x" -> sl spostato a 2x la distanza entry->sl0 (stop piu' lasco):
|
|
sl = entry + 2*(sl0 - entry). Stoppa meno spesso.
|
|
mode = "tight05x" -> sl spostato a 0.5x la distanza (stop piu' stretto):
|
|
sl = entry + 0.5*(sl0 - entry). Stoppa piu' spesso, ma
|
|
perde di meno per stop.
|
|
|
|
La geometria col segno e' automatica: per long sl0<entry, per short sl0>entry;
|
|
scalare (sl0-entry) preserva il lato corretto in entrambi i casi.
|
|
|
|
ANTI-LOOK-AHEAD: il livello sl(j) dipende SOLO da {entry, sl0, mode}, tutti noti
|
|
all'ENTRATA (close[i]). Costante per tutto il trade, identico al baseline tranne
|
|
il fattore di scala. Nessun dato del bar j o futuro entra. TP = tp0 invariato.
|
|
-> contratto rispettato per costruzione (livello statico, come il baseline).
|
|
|
|
INTERPRETAZIONE (diagnostica, non per forza deployabile):
|
|
- se "none" >= base su ret E DD -> lo SL toglie valore (taglia winner che
|
|
sarebbero rientrati: la fade e' mean-reversion, il movimento avverso e'
|
|
spesso transitorio).
|
|
- se "tight05x" peggiora molto -> lo SL e' gia' sul filo: stringerlo morde i
|
|
rientri. se "wide2x" ~ "none" -> lo SL attuale e' quasi inerte (raramente
|
|
toccato) e il rischio di coda e' contenuto da max_bars/TP.
|
|
- DD e' la metrica chiave: lo SL serve a contenere la coda. Se "none" ha DD
|
|
simile o piu' basso, lo SL non sta proteggendo nulla di utile.
|
|
|
|
GRID: mode in {none, wide2x, tight05x} (3 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
|
|
|
|
|
|
_SCALE = {"none": None, "wide2x": 2.0, "tight05x": 0.5}
|
|
|
|
|
|
class NoSl(ExitPolicy):
|
|
name = "no_sl"
|
|
|
|
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
|
|
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
|
|
self.mode = str(params.get("mode", "none"))
|
|
if self.mode not in _SCALE:
|
|
raise ValueError(f"mode sconosciuto: {self.mode}")
|
|
scale = _SCALE[self.mode]
|
|
if scale is None:
|
|
self.sl = None
|
|
else:
|
|
# sl = entry + scale*(sl0 - entry): preserva il lato per long/short.
|
|
self.sl = entry + scale * (sl0 - entry)
|
|
|
|
def levels(self, j: int):
|
|
return self.tp0, self.sl, 1.0
|
|
|
|
|
|
GRID = [
|
|
{"mode": "none"},
|
|
{"mode": "wide2x"},
|
|
{"mode": "tight05x"},
|
|
]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
evaluate(NoSl, GRID)
|