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,76 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user