fill eseguito e poi eccezione (position_usd, flip): il fill manca da book_executions.jsonl e trades.db #23
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Revisione 2026-09-27 (goldrake): rilievo Opus 5.5, verifica avversariale fable. Sola lettura, nessun codice toccato.
Rilievo A4 [registro-falso]
FILE: PG:scripts/live/book_execute.py:272-290
COSA: i fill vengono stampati/loggati/notificati SOLO dopo
trader.position_usd(inst)(riga 273); se quella lettura (o il secondo ordine di un flip) solleva DOPO che un ordine e' stato eseguito, l'eccezione salta il ciclo di log -> fill reale assente da book_executions.jsonl, dalla riga "-> BUY ..." di cron_book.log e quindi da trades.db (tradesdb.parse_cron_log ricava i fill da quelle righe).SCENARIO: flip SKH: close() eseguito (fill reale), poi open() solleva (GuardrailError di A1 o 502) -> fills persi; oppure ordine eseguito e poi 502 su get_positions (i 502 sul gateway sono documentati, es. 21/07 09:00) -> nessuna traccia del fill, solo "asset fallito". Il TWR e il FIFO dei round-trip saltano un fill.
PROVA: VERIFICATO: lettura book_execute.py:270-290 (log dentro il for dopo newpos) e execution.py:158-182 (fills accumulati in lista locale, persa se open() solleva); src/live/tradesdb.py:180-224 parse dei fill dalle righe del log.
PROPOSTA: in rebalance_signed catturare l'eccezione dopo il primo fill e ritornare i fill con nota; in book_execute loggare ogni fill prima di leggere newpos (newpos in try separato, None se illeggibile).
Verifica fable A4 VERDETTO: CONFERMATO
GRAVITA': medio
PERCHE': book_execute.py:272-273
fills = trader.rebalance_signed(...)poinewpos = trader.position_usd(inst)PRIMA del for che stampa/logga/notifica (:274-289); position_usd -> _post ->raise_for_status()(deribit.py:207) solleva su 502 -> except :301 -> fill reale eseguito ma assente da book_executions.jsonl, dal log "-> BUY" e da trades.db. Nel flip, execution.py:158-182 accumula i fill in una lista locale che si perde se open() solleva (es. GuardrailError A1).CORREZIONE: ok.
ANALISI (passo 1, Opus) — unita' U2, ramo lavoro/goldrake-u2, repo gitea:Adriano/PythagorasGoal
RIF: #20 (A2), #21 (A3), #22 (A10), #25 (A6), #23 (A4)
FILE: src/live/shadow.py, src/live/book.py, scripts/live/book_execute.py, src/live/execution.py (SOLO rebalance_signed, per #23), tests/
Principio unico (dichiarato): quando il giro non sa QUANTO vale il conto o QUALE e' il segnale, NON manda ordini di ribilancio ma CONTROLLA LO STESSO il disaster-SL di ogni asset (la protezione dipende da posizione e mark, non da equity o segnale). Come gia' fa pos_error, ma senza saltare la protezione.
Implementazione: in _run una variabile
solo_protezione: str | None(motivo) calcolata dopo i gate esistenti (offline, pos_error, feed stantio restano come sono: return). Nel ciclo per asset: se solo_protezione, act = "HOLD (solo protezione: )" e niente rebalance; il blocco ensure_disaster_sl resta identico. Il riepilogo finale e l'exit code: exit 2 anche quando solo_protezione (giro degradato).a) execution.DeribitTrader.rebalance_signed: se dopo almeno un fill eseguito (es. flip: close fatto) un passo successivo solleva, sollevare
RebalanceParziale(fills, causa)(nuova eccezione in execution.py, sottoclasse RuntimeError, attributi .fills e .causa). Nessun'altra modifica a execution.py (U1 lavora su _submit/open_orders/position_usd nello stesso file: non toccarli).b) book_execute: estrarre la registrazione di un fill (print " -> SIDE ...", log_event, notify) in una funzione
_registra_fill(...); chiamarla per ogni fill SUBITO dopo rebalance_signed e PRIMA di leggere newpos; newpos letto in try separato (None se illeggibile: pos_after=None nel jsonl, e la riga "reconcile: pos" diventa "reconcile: pos illeggibile ()"). Su RebalanceParziale: registra i fill di e.fills, poi rilancia la causa nell'handler di isolamento esistente.⚠️ Il formato ESATTO delle righe stampate " -> BUY 0.0100 @ $84,000.0 fee 0.00000 (OK)" e "reconcile" e' letto da src/live/tradesdb.py (parse_cron_log, regex _RE_FILL ecc.): leggi quelle regex e NON cambiare il testo delle righe che parse legge. L'ordine delle righe per un giro normale deve restare: fill..., poi reconcile. Test che parse_cron_log legge un log prodotto dal nuovo codice (giro normale e giro con RebalanceParziale).
if hasattr(trader, "set_open_cap"): trader.set_open_cap(inst, r["cap_per_asset"] * r.get("scala", 1.0), mark). hasattr perche' U1 e U2 si uniscono dopo; un commento dice che l'hasattr si toglie al merge.TEST (tests/test_book_u2.py, pattern dei test esistenti in tests/test_book_live.py / test_book_resilienza_venue.py, tutto mockato):
Suite completa:
cd <worktree> && /opt/docker/PythagorasGoal/.venv/bin/python -m pytest -q -p no:cacheprovider(baseline 1098 passed, 3 skipped).NON TOCCARE: src/live/deribit.py; in execution.py tutto tranne rebalance_signed e la nuova eccezione; config/live.json; la sequenza e i testi dei gate offline/pos_error/feed stantio; /opt/docker/PythagorasGoal. Nessuna rete, nessun ordine.
ESITO: fatto sul ramo, non in produzione
RIF: gitea:Adriano/PythagorasGoal#23
COSA: correzione su lavoro/goldrake (pushato), analisi Opus, codice Sonnet, controllo finale Opus
FILE: commit
65a7f0dPROVA: /home/adriano/lavoro/PythagorasGoal pytest -q → 1166 passed, 3 skipped
MANCA: merge su main — richiede ok esplicito di Adriano (libro vivo). Chiusura con --soluzione dopo il merge.
PROSSIMO: ok di Adriano → merge lavoro/goldrake su main → git pull in /opt/docker/PythagorasGoal
Soluzione
src/live/execution.py RebalanceParziale(.fills,.causa); book_execute _registra_fill registra ogni fill prima di rileggere la posizione, che ha un try proprio.
COMMIT:
65a7f0d, su main dal 27/09/2026 (merge con ok di Adriano). Produzione aggiornata.