Files
Adriano Dal Pastro 14522262e6 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>
2026-06-19 15:20:59 +00:00

77 lines
3.1 KiB
Python

"""INVERTED_TP_SKIP (2026-06-16): un wick transitorio puo' far calcolare alla strategia
un tp dal lato SBAGLIATO dell'entry (es. donchian: segnale su barra wickata, entry al
prezzo recuperato gia' oltre il proprio tp). L'exit intrabar `bar_high>=tp` (long) /
`bar_low<=tp` (short) scatterebbe a bars_held=0 in PERDITA, con churn di fee e TP
reduce-only respinti. Verita' d'esecuzione, zero parametri: se il TP e' gia' sfondato
all'ingresso il segnale e' malformato -> NON si apre. TP dal lato giusto (o assente)
-> comportamento storico."""
from src.live.strategy_worker import StrategyWorker
from src.live.strategy_loader import load_strategy
from src.strategies.base import Signal
def _worker(tmp):
w = StrategyWorker(strategy=load_strategy("MR02_donchian_fade"), asset="BTC", tf="15m",
capital=1000.0, data_dir=tmp)
w._notify = lambda *a, **k: None
return w
def test_long_inverted_tp_skipped(tmp_path):
# long con tp SOTTO l'entry (caso reale 16-06: entry 66780, tp 66189) -> no entry
w = _worker(tmp_path)
sig = Signal(idx=119, direction=1, entry_price=66780.0,
metadata={"tp": 66189.25, "sl": 64218.21, "max_bars": 24})
w._open_position(sig, 66780.0, current_ts=1)
assert not w.in_position
assert w.tp == 0.0
def test_short_inverted_tp_skipped(tmp_path):
# short con tp SOPRA l'entry -> il TP intrabar `bar_low<=tp` scatterebbe subito -> no entry
w = _worker(tmp_path)
sig = Signal(idx=119, direction=-1, entry_price=100.0,
metadata={"tp": 105.0, "sl": 110.0, "max_bars": 24})
w._open_position(sig, 100.0, current_ts=1)
assert not w.in_position
def test_long_valid_tp_opens(tmp_path):
# controllo positivo: long con tp SOPRA l'entry -> apre normalmente
w = _worker(tmp_path)
sig = Signal(idx=119, direction=1, entry_price=100.0,
metadata={"tp": 103.0, "sl": 98.0, "max_bars": 24})
w._open_position(sig, 100.0, current_ts=1)
assert w.in_position
assert w.direction == 1
assert w.tp == 103.0
def test_short_valid_tp_opens(tmp_path):
# controllo positivo: short con tp SOTTO l'entry -> apre normalmente
w = _worker(tmp_path)
sig = Signal(idx=119, direction=-1, entry_price=100.0,
metadata={"tp": 97.0, "sl": 102.0, "max_bars": 24})
w._open_position(sig, 100.0, current_ts=1)
assert w.in_position
assert w.direction == -1
def test_no_tp_opens(tmp_path):
# segnale senza tp (strategie a orizzonte puro, es. SH01) -> il guard non si applica
w = _worker(tmp_path)
sig = Signal(idx=119, direction=1, entry_price=100.0, metadata={"max_bars": 12})
w._open_position(sig, 100.0, current_ts=1)
assert w.in_position
def test_inverted_skip_deduped_per_bar(tmp_path):
# stesso bar_ts -> un solo log INVERTED_TP_SKIP; non blocca un bar successivo valido
w = _worker(tmp_path)
sig = Signal(idx=119, direction=1, entry_price=66780.0,
metadata={"tp": 66189.25, "max_bars": 24})
w._open_position(sig, 66780.0, current_ts=1)
w._open_position(sig, 66780.0, current_ts=1)
assert not w.in_position
assert w._inverted_tp_ts == 1