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>
5.3 KiB
2026-06-04 — Shadow execution: divergenza sim/reale misurata + TODO limit reduce-only
Deploy v1.0.6
Fix float deployata (74670da + release): _quantize_step con Decimal in
src/live/execution.py — 72*0.001 = 0.07200000000000001 causava Invalid params
su Deribit (1 REAL_OPEN_FAIL su MR07 il 2026-06-03). Resume pulito al restart.
Misura della divergenza sim vs reale (primi 7 close shadow)
Bilancio: PnL sim +11.85 USD vs reale +0.62 USD → delta −11.22 USD. Le fee NON sono il problema ($0.63 totali = 0.05%/lato, esattamente l'assunto del backtest). Il problema è tutto nel timing delle uscite.
- Aperture allineate: slippage da −8 a +27 bps, mediana ~±7 bps. OK.
- Chiusure take-profit: +235 bps di slippage medio (MR07 ETH short: +257/+267/+283/+333 bps). Causa strutturale, non liquidità: il sim esce al livello TP intrabar (come il backtest), il reale chiude a mercato solo al poll del tick, quando il prezzo è già rientrato (TP toccato a ~1790, fill reale a ~1840). Sim +3 USD a trade, reale ~0.
- Stop-loss: stessa meccanica ma a favore (MR02 SL: −0.68 reale vs −2.87 sim). Le fade però hanno più TP che SL → netto negativo.
- 2
REAL_CLOSEnon verificate (order_id null, fallback su stima sim). Venue flat (get_positions()=[]), nessuna posizione orfana — ma sorvegliare i prossimi close.
Implicazione onesta: l'edge di MR07 non sopravvive all'esecuzione market-on-poll. Il backtest assume il fill al livello TP; il reale incassa il prezzo post-rimbalzo.
TODO (richiesto, da implementare)
Nello shadow-execution (src/live/execution.py + StrategyWorker): all'apertura
della posizione reale piazzare su Deribit un LIMIT reduce-only appoggiato al
livello TP (e idealmente stop-market per lo SL), invece di chiudere a mercato al
poll — così il fill reale replica l'assunzione intrabar del backtest.
Dettagli da considerare:
- cancellare/aggiornare l'ordine resting se il sim esce per
max_barso al restart (resume); - i 3 fade BTC condividono lo strumento (posizioni nettate per conto): il limit
reduce-only deve coprire la SOLA quota del worker, come già fa
close_amount; - verificare il fill del resting order via
get_trade_history(order_id), come per i market.
IMPLEMENTATO (sera): LIMIT reduce-only al TP
Flusso nuovo. A ogni REAL_OPEN verificato il worker piazza subito un
limit reduce-only al livello TP (lato opposto, stesso amount della SOLA
quota del worker — strumento condiviso fra i 3 fade per coin) → evento
REAL_TP_RESTING (o REAL_TP_FAIL → si resta sul vecchio market-on-poll).
Alla chiusura sim, qualunque sia la ragione, _real_close ora:
- cancella il resting (innocuo se già fillato — e dopo il cancel nessun fill può più arrivare, niente race);
- riconcilia i fill (anche parziali) dal
get_trade_historyper order_id (stessa fonte autorevole dei market), con retry se il cancel risulta "già fillato" ma la history è in ritardo; - chiude a market reduce-only solo la quota residua (exit non-TP: stop_loss/time_limit, o TP non raggiunto sullo strumento d'esecuzione);
- ledger reale su prezzo d'uscita combinato (media pesata fill-TP +
market) e fee sommate.
REAL_CLOSEloggatp_order_id,tp_filled_amount,market_amount.
Dettagli del TODO coperti:
max_bars/stop_loss→ il cancel è il passo 1 di ogni chiusura;- restart →
real_tp_order_idè persistito instatus.json: al resume il resting resta in book e la prima chiusura lo riconcilia normalmente; - quota del worker → il limit usa lo stesso
amountdell'apertura (maiclose_position); il residuo è ri-quantizzato allo step (Decimal) dentroclose_amount(niente artefatti float tipo0.072-0.024); - prezzi limit quantizzati al tick dello strumento (
quantize_price, BTC_USDC 0.5 / ETH_USDC 0.05 — Deribit rifiuta prezzi off-tick).
SL: niente stop-market, decisione deliberata. (a) Su Deribit un trigger
order, quando scatta, genera l'ordine eseguito con un nuovo order_id → il
fill non sarebbe verificabile via get_trade_history per order_id (il
requisito di verifica); (b) la misura di stamattina mostra che sul SL il
market-on-poll lavora a favore (il rimbalzo riduce la perdita). Lo SL resta
quindi market-on-poll.
Bonus fee. Quando il TP filla da resting il fill è maker (~0% su Deribit) invece di taker 0.05% — il reale farà meglio dell'assunto 0.10% RT sulle uscite TP.
Verifica. live_shadow_smoke.py esteso ai due percorsi e passato su
testnet: (A) resting in book → exit time_limit → cancel + market fallback,
conto flat; (B) TP già crossato → fill immediato del limit, chiusura
riconciliata dalla history senza ordine market (market_amount=0),
prezzo persino migliore del TP (+48 bps, taker sul cross). 54 test pytest OK.
Caveat residuo onesto. Se il processo muore DOPO il fill del resting e
PRIMA della chiusura sim, il worker al resume riconcilia al prossimo exit sim
(corretto); ma nell'intervallo la quota reale è già chiusa mentre il sim la
crede aperta — finestra breve e solo contabile. Inoltre il TP del sim è sul
feed (BTC-PERPETUAL inverse) mentre il limit vive sul lineare USDC: la base
fra i due può far fillare/non fillare il limit a cavallo del livello — il
fallback market copre il caso.