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>
74 lines
3.2 KiB
Python
74 lines
3.2 KiB
Python
"""EXIT-14 — protezione GIVEBACK dal picco (trailing sul PROFITTO, non sul prezzo).
|
|
|
|
Idea: una fade puo' correre a favore quasi fino al TP (alla media) e poi
|
|
ritracciare prima di toccarlo, restituendo gran parte del guadagno gia' maturato.
|
|
Questa policy traccia l'high-water-mark (hwm) del PROFITTO non realizzato sul
|
|
CLOSE; quando il profitto corrente scende sotto (1-g)*hwm_profit -- cioe' si e'
|
|
restituita una frazione g del picco -- e il picco era gia' "significativo"
|
|
(hwm_profit > soglia * dist(entry, tp0)), esce al close del bar (after_bar).
|
|
Il TP fisso tp0 e lo SL fisso sl0 RESTANO invariati e prioritari intrabar.
|
|
|
|
Razionale: protegge il profitto maturato senza toccare i livelli; non e' un
|
|
ladder (ieri scartato perche' al TP/media il movimento e' esaurito) ma un
|
|
trailing sul drawdown del trade quando ha gia' fatto buona parte del lavoro.
|
|
|
|
ANTI-LOOK-AHEAD:
|
|
- levels(j) NON e' toccato (TP/SL fissi): nessun dato futuro.
|
|
- after_bar(j) decide sul CLOSE del bar j (eseguibile al poll). Aggiorna l'hwm
|
|
con il profitto a close[j] e poi confronta: tutto con dati <= j. Il bar j e'
|
|
lecito in after_bar per contratto. L'hwm e' un cliquet (non scende mai).
|
|
|
|
GRID: g in {0.4, 0.6} x arm_frac in {0.3, 0.5} della distanza al TP (4 celle).
|
|
- g = frazione del picco di profitto restituita che fa scattare l'uscita.
|
|
- arm_frac = il giveback e' armato solo quando hwm_profit ha superato
|
|
arm_frac * dist(entry, tp0): finche' il trade non ha "fatto strada"
|
|
(frazione del cammino verso la media) non interviene -> non taglia i trade
|
|
che partono storti, solo quelli che hanno gia' guadagnato e poi mollano.
|
|
"""
|
|
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 Giveback(ExitPolicy):
|
|
name = "giveback"
|
|
|
|
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
|
|
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
|
|
self.g = float(params.get("g", 0.4))
|
|
self.arm_frac = float(params.get("arm_frac", 0.3))
|
|
self.close = ctx["close"]
|
|
# distanza (in prezzo, sempre positiva) dall'entrata al TP iniziale
|
|
self.dist_tp = abs(self.tp0 - entry) if self.tp0 is not None else 0.0
|
|
self.arm_level = self.arm_frac * self.dist_tp
|
|
self.hwm_profit = 0.0 # high-water-mark del profitto a favore (cliquet)
|
|
|
|
def after_bar(self, j: int) -> bool:
|
|
if self.dist_tp <= 0.0:
|
|
return False
|
|
# profitto NON realizzato a favore, valutato sul close del bar j (lecito qui)
|
|
profit = (self.close[j] - self.entry) * self.d
|
|
if profit > self.hwm_profit:
|
|
self.hwm_profit = profit # aggiorna il picco (non scende mai)
|
|
# arma solo se il picco ha superato la soglia (trade gia' "in cammino")
|
|
if self.hwm_profit < self.arm_level:
|
|
return False
|
|
# esci se il profitto corrente ha restituito >= g del picco
|
|
if profit < (1.0 - self.g) * self.hwm_profit:
|
|
return True
|
|
return False
|
|
|
|
|
|
GRID = [
|
|
{"g": 0.4, "arm_frac": 0.3},
|
|
{"g": 0.4, "arm_frac": 0.5},
|
|
{"g": 0.6, "arm_frac": 0.3},
|
|
{"g": 0.6, "arm_frac": 0.5},
|
|
]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
evaluate(Giveback, GRID)
|