chore(reset): v2.0.0 — storico certificato Deribit mainnet, ripartenza pulita
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>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""EXIT-08 — SL che si STRINGE linearmente col tempo (time-based stop tighten).
|
||||
|
||||
Lo stop iniziale sl0 si avvicina linearmente a un livello d'arrivo `target`
|
||||
man mano che il trade invecchia. TP fisso (tp0) e horizon=max_bars invariati.
|
||||
|
||||
frac(j) = clamp( (j - i) / (mb * stretch), 0, 1 )
|
||||
sl(j) = sl0 + frac(j) * (target - sl0)
|
||||
|
||||
target ("arrivo"):
|
||||
- "entry" -> entry (a fine corsa lo stop e' a breakeven)
|
||||
- "midpoint" -> (entry + sl0)/2 (a fine corsa lo stop e' a meta' strada)
|
||||
|
||||
Direzioni: il segno e' gestito dalla geometria di sl0 vs entry.
|
||||
long (d=1): sl0 < entry -> target >= sl0 -> lo stop SALE verso entry
|
||||
short (d=-1): sl0 > entry -> target <= sl0 -> lo stop SCENDE verso entry
|
||||
In entrambi i casi lo stop si stringe (avvicina al prezzo d'ingresso) col tempo.
|
||||
|
||||
stretch:
|
||||
- 1.0 : lo stop raggiunge `target` a max_bars (fine horizon).
|
||||
- 2.0 : lo stop raggiunge `target` a 2*max_bars -> stringe a META' velocita',
|
||||
quindi a max_bars e' solo a meta' del cammino sl0->target (piu' lasco).
|
||||
|
||||
ANTI-LOOK-AHEAD: sl(j) dipende SOLO da {i, j, mb, stretch, entry, sl0}, tutti
|
||||
noti all'ENTRATA (close[i]). Nessun dato del bar j o successivi entra nel livello
|
||||
attivo nel bar j. Il TP resta tp0. -> contratto rispettato per costruzione.
|
||||
|
||||
MECCANISMO ATTESO: stringere lo stop col tempo taglia prima i trade che ristagnano
|
||||
(non vanno al TP ne' allo SL iniziale e scadrebbero a max_bars vicino al BE/in
|
||||
perdita). Rischio: stoppa fuori trade che sarebbero rientrati verso il TP (la fade
|
||||
e' mean-reversion: il movimento contrario e' spesso transitorio) -> puo' alzare lo
|
||||
stop-rate effettivo e tagliare winner ritardatari.
|
||||
|
||||
GRID: stretch in {1.0, 2.0} x target in {entry, midpoint} (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 SlTighten(ExitPolicy):
|
||||
name = "sl_tighten"
|
||||
|
||||
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
|
||||
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
|
||||
self.stretch = float(params.get("stretch", 1.0))
|
||||
self.target_kind = str(params.get("target", "entry"))
|
||||
if self.target_kind == "entry":
|
||||
self.target = entry
|
||||
elif self.target_kind == "midpoint":
|
||||
self.target = 0.5 * (entry + sl0)
|
||||
else:
|
||||
raise ValueError(f"target sconosciuto: {self.target_kind}")
|
||||
self.denom = max(self.mb * self.stretch, 1e-9)
|
||||
|
||||
def levels(self, j: int):
|
||||
# frac dipende solo da i, j, mb, stretch -> noti all'entrata. No look-ahead.
|
||||
frac = (j - self.i) / self.denom
|
||||
if frac < 0.0:
|
||||
frac = 0.0
|
||||
elif frac > 1.0:
|
||||
frac = 1.0
|
||||
sl = self.sl0 + frac * (self.target - self.sl0)
|
||||
return self.tp0, sl, 1.0
|
||||
|
||||
|
||||
GRID = [
|
||||
{"stretch": 1.0, "target": "entry"},
|
||||
{"stretch": 1.0, "target": "midpoint"},
|
||||
{"stretch": 2.0, "target": "entry"},
|
||||
{"stretch": 2.0, "target": "midpoint"},
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
evaluate(SlTighten, GRID)
|
||||
Reference in New Issue
Block a user