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:
Adriano Dal Pastro
2026-06-19 15:16:03 +00:00
parent 8401a280b9
commit 14522262e6
383 changed files with 1971 additions and 779 deletions
@@ -0,0 +1,61 @@
"""EXIT-15 — loser time-stop ("i loser muoiono giovani?").
Le fade tengono il trade fino a TP/SL fissi o max_bars. Qui aggiungiamo un
solo extra-exit CONDIZIONATO AL SEGNO della PnL: al k-esimo bar dopo l'entrata,
se il trade e' ancora in PERDITA sul CLOSE (unrealized < 0), chiudi il residuo
al close[j]. Se a quel bar il trade e' in profitto (o piatto), NON tocca nulla
e lascia correre verso TP/SL/max_bars come la base.
TP/SL fissi (tp0, sl0) INVARIATI; horizon = max_bars INVARIATO.
Differenza col time-stop semplice (gia' FALLITO il 2026-06-02, tagliava i
winner): qui non si esce per il solo passare del tempo, ma SOLO se la PnL e'
negativa. L'ipotesi e' che un trade ancora in rosso dopo k bar abbia bassa
probabilita' di recuperare e finisca per colpire lo SL (peggio) o scadere a
max_bars in perdita -> uscire prima limita la coda di perdite e libera capitale.
Anti-look-ahead: la decisione e' in `after_bar(j)`, che per contratto puo'
leggere il CLOSE del bar j (eseguibile al poll del tick). Confronto:
unrealized(j) = (close[j] - entry) * d (>0 = a favore)
Esce SOLO quando j - i == k (controllo una tantum al k-esimo bar). I livelli
TP/SL restano quelli base (nessun uso di dati futuri in levels()).
GRID: k in {4, 8, 12, 16} (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 LoserTimestop(ExitPolicy):
name = "loser_timestop"
def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
self.k = int(params.get("k", 8))
self.close = ctx["close"]
# livelli base, invariati (nessun look-ahead)
def levels(self, j: int):
return self.tp0, self.sl0, 1.0
def after_bar(self, j: int) -> bool:
# controllo una tantum al k-esimo bar dopo l'entrata
if j - self.i != self.k:
return False
unrealized = (self.close[j] - self.entry) * self.d
return unrealized < 0.0
GRID = [
{"k": 4},
{"k": 8},
{"k": 12},
{"k": 16},
]
if __name__ == "__main__":
evaluate(LoserTimestop, GRID)