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>
109 lines
6.3 KiB
Markdown
109 lines
6.3 KiB
Markdown
# 2026-06-12 — Reconcile resting + guard feed↔book + epoca report (v1.1.27)
|
||
|
||
## Contesto: la notte ha validato (di nuovo) il tema osservabilità
|
||
|
||
Due eventi nelle 24h hanno motivato la tornata:
|
||
|
||
1. **MR02_BTC (06:00):** il TP resting LIMIT ha fillato sul **book reale** a 60481
|
||
nella notte (+6.55 USD reali) mentre il **feed sim** non è mai sceso sotto 63285
|
||
(−443 bps di divergenza, sim chiuso a time_limit con −1.25). Il disaster-SL è
|
||
risultato `order_not_found` alla cancel (probabile auto-cancel a posizione flat).
|
||
Caso SPECULARE del TP_PHANTOM: lì il feed stampa wick che il book non ha; qui il
|
||
book si muove e il feed non lo vede. Real-truth ha bookato il reale (corretto),
|
||
ma il sistema se n'è accorto solo ORE dopo, al close sim.
|
||
2. **Incidente venue (dalle ~09:47):** il conto Deribit testnet ha iniziato a
|
||
rifiutare ordini (`locked_by_admin`, `invalid_reduce_only_order`) e le posizioni
|
||
sul conto sono cambiate da sole (ETH LONG 0.141 con avg 1849.5 — prezzo vecchio
|
||
di settimane): **rollback/reset admin del testnet**, non un nostro bug. Difese OK:
|
||
`REAL_CLOSE_PARTIAL`, leg-fail con unwind, orfani registrati (ETH −0.026,
|
||
SOL +0.7), `sim_fallback` dichiarato. MA: il reconciler delle 11:40 è **morto in
|
||
silenzio** su un 502 — il guardiano che non suona è indistinguibile dal tutto-ok.
|
||
|
||
## Fatto
|
||
|
||
### 1. Reconcile degli ordini RESTING (cron :40, read-only)
|
||
|
||
- **cerbero-mcp 9a74052:** nuovo endpoint Deribit `get_open_orders`
|
||
(`private/get_open_orders_by_currency`; per i trigger untriggered interrogare
|
||
anche `type='trigger_all'` e merge per order_id). Pattern già presente per
|
||
Hyperliquid/IBKR. Rebuild + smoke su testnet (book vuoto == stato atteso).
|
||
- **`books.expected_resting()`:** TP/DSL attesi dai libri dei worker single-leg
|
||
in posizione reale (i pairs non hanno resting).
|
||
- **`reconcile_account.compute_resting_drift()`** — tre classi:
|
||
`FILLED_UNBOOKED` (atteso non in book + fill nel trade history col worker ancora
|
||
in posizione = il caso MR02), `MISSING` (atteso, non in book, zero fill — per il
|
||
DSL triggered il fill ha order_id NUOVO → appare qui e il drift posizioni
|
||
completa), `STALE` (in book con label di un nostro worker ma nessun libro:
|
||
fillerebbe a sorpresa). Anti-race come per le posizioni; alert `RESTING_DRIFT`.
|
||
- **`RECONCILE_FAIL`:** il main è ora guardato — su eccezione alert Telegram +
|
||
exit 2 (fix del crash silenzioso delle 11:40).
|
||
|
||
### 2. Guard FEED_BOOK_GAP nel runner
|
||
|
||
`_check_feed_book_gap`: ad ogni poll confronta il close della candela in corso col
|
||
**mark dello strumento d'ESECUZIONE** (USDC, `get_ticker_batch`, 1 chiamata);
|
||
oltre soglia (`overrides.feed_book_gap_bps`, default 150) → alert per episodio,
|
||
recovery con isteresi a soglia/2, fail-open su errori di rete. Le decisioni
|
||
restano sul feed (il sim è la verità che guida): questo dice solo QUANDO i fill
|
||
reali possono divergere dal sim. Avrebbe segnalato il caso MR02 in tempo reale.
|
||
|
||
### 3. Epoca v1.1.26 nell'hourly_report
|
||
|
||
I conteggi CHIUSI cumulativi erano inquinati dal churn TP-fantasma dell'11-06
|
||
17:32–17:58 (~24 giri pre-fix). Nuova riga `epoca v1.1.26+ (TP_PHANTOM attivo)`
|
||
da `EPOCH_V1126 = 2026-06-11T21:40` (deploy del gate): oggi legge **7/1** contro
|
||
il 18/17 storico — è il numero da confrontare col backtest da qui in poi.
|
||
|
||
## Test e deploy
|
||
|
||
`pytest` 121 passed (114 + 7 nuovi: `test_reconcile_resting.py`,
|
||
`test_feed_book_gap.py`). Deploy **v1.1.27** (runner nel container; reconciler e
|
||
hourly_report girano da host → già attivi). cerbero-mcp rebuildato (endpoint).
|
||
|
||
## Aperto / lezioni
|
||
|
||
- **Drift ETH +0.167 non spiegato** dal rollback testnet: quando il conto si
|
||
sblocca serve `reset_flatten` + riallineamento ledger (decisione utente).
|
||
- I **residui dei close single-leg falliti** (`REAL_CLOSE_PARTIAL`, es. MR07
|
||
0.102) NON finiscono in `orphan_legs` → il reconciler li vede come drift NON
|
||
spiegato. Estendere la registrazione orfani anche al single-leg è il naturale
|
||
passo successivo (punto in analisi sviluppi).
|
||
- Il testnet può **riscrivere il conto sotto i piedi** (lock + rollback): nessuna
|
||
invariante "il conto cambia solo per nostri ordini" è affidabile. Il reconciler
|
||
orario è l'unico rilevatore; valutare cadenza più fitta in presenza di
|
||
posizioni reali aperte.
|
||
|
||
## Addendum (pomeriggio, v1.1.28): orfani single-leg + circuit-breaker venue-lock
|
||
|
||
I due punti promossi dall'analisi sviluppi, entrambi figli dell'incidente di oggi:
|
||
|
||
1. **Orfani anche per i close single-leg.** `REAL_CLOSE_PARTIAL` ora registra la
|
||
quota residua in `StrategyWorker.orphan_legs` (stessa semantica dei pairs,
|
||
persistita in status.json, letta da `books.real_books`) → il reconciler vede
|
||
il drift come SPIEGATO invece che anomalo (il caso MR07 0.102 ETH delle 09:47
|
||
restava invisibile ai libri). Inoltre `_close_position` ora persiste lo stato
|
||
a fine booking (prima solo al save del tick: un crash li' in mezzo perdeva
|
||
capital e orfano). NB: nessun save a meta' chiusura — con `real_in_position`
|
||
ancora true l'orfano conterebbe doppio nei libri.
|
||
2. **Circuit-breaker venue-lock in `ExecutionClient`.** Dopo `lock_trip=3` reject
|
||
'locked' consecutivi (es. `locked_by_admin` di oggi) le APERTURE sono sospese
|
||
senza toccare l'API (Fill failed → path REAL_OPEN_FAIL/sim_fallback esistente;
|
||
per i pairs entrambe le gambe rifiutate localmente → niente leg parziali da
|
||
unwindare, niente fee sprecate). Le CHIUSURE si tentano SEMPRE (path gia'
|
||
sicuro: partial/orphan/netting) e un loro reject 'locked' rinfresca il
|
||
cooldown. Riarmo: dopo `lock_cooldown_s=900` la prossima apertura fa da probe.
|
||
Alert `VENUE_LOCK` al trip + RIENTRATO al primo ordine accettato.
|
||
|
||
Test: `test_single_leg_orphan.py`, `test_venue_lock_breaker.py` (126 passed).
|
||
|
||
## Chiusura incidente (13:05): testnet sbloccato, conto riallineato
|
||
|
||
Sequenza eseguita a venue sbloccato: stop runner → `reset_flatten` (chiusi i due
|
||
artefatti del rollback: ETH long 0.141 @1664.25, SOL long 0.7 @66.651, conto FLAT)
|
||
→ svuotati gli `orphan_legs` di ETH_SOL (le quote orfane non esistono piu' sul
|
||
conto post-flatten; edit a container fermo, altrimenti il worker li riscrive
|
||
dalla memoria) → restart. **Reconciler: OK — conto allineato ai libri** (posizioni
|
||
e resting), runner healthy, log puliti. Il ledger NON e' stato toccato: i booking
|
||
dell'incidente erano gia' dichiarati (`sim_fallback`/real) e l'equity (€2020.82)
|
||
resta la verita' contabile del paper.
|