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,74 @@
|
||||
"""EXIT-13 — hurst_exit: TP condizionato al REGIME (rolling-Hurst causale).
|
||||
|
||||
IDEA. Le fade puntano alla MEDIA: in regime ANTI-PERSISTENTE (Hurst basso) la
|
||||
reversione tende a completarsi -> ha senso tenere il TP pieno tp0. In regime
|
||||
PERSISTENTE/trending (Hurst alto) la reversione spesso NON arriva fino in fondo
|
||||
(il movimento continua, lo stop-loss si concentra li': vedi loss-guard Hurst) ->
|
||||
conviene "prendere quel che c'e'": TP anticipato a meta' strada (entry+tp0)/2.
|
||||
|
||||
- H[j-1] < h_lo (anti-persistente): tp(j) = tp0 (reversione completa)
|
||||
- H[j-1] >= h_lo (persistente): tp(j) = (entry+tp0)/2 (TP a meta')
|
||||
|
||||
SL FISSO (sl0) e horizon (max_bars) invariati.
|
||||
|
||||
ANTI-LOOK-AHEAD. prepare() precalcola H = rolling_hurst(close, window=100, step=6)
|
||||
una volta sullo sleeve. rolling_hurst e' causale: H[k] usa returns[k-window:k] e
|
||||
returns[m]=diff(log(close))[m] dipende da close[m+1], quindi H[k] dipende solo da
|
||||
close <= k. In levels(j) leggo H[j-1] -> solo dati <= j-1. SL/horizon invariati.
|
||||
La decisione del regime e' fissata col bar precedente, il bar j tocca i livelli.
|
||||
|
||||
NB sul TP a meta'. Lo "step=6" significa che H e' costante a tratti di 6 barre; il
|
||||
regime e' ri-letto ogni bar (j-1) ma cambia valore ogni 6. Il TP a meta' strada
|
||||
e' SEMPRE >= breakeven per costruzione (e' fra entry e tp0, e tp0 e' gia' oltre il
|
||||
margine fee per come la fade lo fissa), quindi non maschera uscite in perdita.
|
||||
|
||||
GRID: h_lo in {0.45, 0.50, 0.55} (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
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[3]))
|
||||
from src.fractal.indicators import rolling_hurst # noqa: E402
|
||||
|
||||
|
||||
class HurstExit(ExitPolicy):
|
||||
name = "hurst_exit"
|
||||
|
||||
@classmethod
|
||||
def prepare(cls, ctx, **params):
|
||||
if "hurst100" not in ctx:
|
||||
c = ctx["close"]
|
||||
ctx["hurst100"] = rolling_hurst(c, window=100, step=6)
|
||||
|
||||
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
|
||||
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
|
||||
self.h = ctx["hurst100"]
|
||||
self.h_lo = float(params.get("h_lo", 0.50))
|
||||
self.tp_half = (entry + tp0) / 2.0 # TP a meta' strada (persistente)
|
||||
|
||||
def levels(self, j: int):
|
||||
# SOLO dati <= j-1
|
||||
hv = self.h[j - 1]
|
||||
if not np.isfinite(hv):
|
||||
return self.tp0, self.sl0, 1.0
|
||||
if hv < self.h_lo:
|
||||
tp = self.tp0 # anti-persistente: reversione completa
|
||||
else:
|
||||
tp = self.tp_half # persistente: prendi la meta'
|
||||
return tp, self.sl0, 1.0
|
||||
|
||||
|
||||
GRID = [
|
||||
{"h_lo": 0.45},
|
||||
{"h_lo": 0.50},
|
||||
{"h_lo": 0.55},
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
evaluate(HurstExit, GRID)
|
||||
Reference in New Issue
Block a user