open_orders ingoia gli errori: 'non letto' diventa 'nessun bracket' -> disaster-SL doppio o orfani #24
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 A5 [bug]
FILE: PG:src/live/deribit.py:252-267 (open_orders) usato da execution.py:220 (ensure_disaster_sl)
COSA: open_orders ingoia gli errori di entrambe le chiamate e ritorna [] : "non letto" diventa "nessun bracket".
SCENARIO: posizione long aperta, bracket esistente, get_open_orders 502 su entrambi i tipi -> brackets=[] -> si piazza un SECONDO stop reduce_only; giro dopo len==2 -> cancella entrambi e ripiazza (finestra scoperta). A posizione flat con lettura fallita i bracket orfani non vengono cancellati e il giro riporta "flat" come se fosse pulito.
PROVA: VERIFICATO: lettura deribit.py:257-266 (try/except: pass per tipo) ed execution.py:219-224.
PROPOSTA: se tutte e due le chiamate falliscono sollevare (o ritornare None) e in ensure_disaster_sl ritornare stato "unknown" senza piazzare.
Verifica fable A5 VERDETTO: CONFERMATO
GRAVITA': medio
PERCHE': deribit.py:257-266
try/except Exception: passper ciascun tipo -> [] anche se entrambe le chiamate falliscono; execution.py:219-224 tratta [] come "nessun bracket": a posizione aperta piazza un secondo stop; a flat con lettura fallita non cancella gli orfani e ritorna "flat". Danno contenuto: due stop reduce_only sono ridondanti e il giro dopo ricostruisce (finestra scoperta breve gestita danaked).CORREZIONE: ok (ritornare None/sollevare se tutte le chiamate falliscono; ensure_disaster_sl -> stato "unknown").
ANALISI (passo 1, Opus) — unita' U1, ramo lavoro/goldrake-u1, repo gitea:Adriano/PythagorasGoal
RIF: #17 (D1), #18 (A1), #24 (A5)
FILE: src/live/deribit.py, src/live/execution.py, tests/ (nuovo tests/test_execution_u1.py)
sizein abs() edirectiona parte.Nuova regola: s = float(size or size_currency or 0); dir = str(p.get("direction","")).lower();
dir in ("sell","short") -> -abs(s); dir in ("buy","long") -> abs(s); altrimenti (assente/"zero") -> s cosi' com'e' (compatibile con un gateway che un giorno mandi il segno).
Cercare con grep in src/ e scripts/live/ (escluso scripts/research, Old) ogni altro lettore di
positions(o di["size"]/.get("size")di una posizione e applicare la stessa regola SOLO se legge posizioni perp del libro; elencare nel rapporto quelli trovati.Verifica a valle: close() e ensure_disaster_sl() decidono lato e stop da
pos > 0: con il segno giusto uno short produce close BUY reduce_only e stop SOPRA il mark (disaster_stop_price long=False). Test che lo provano passando per positions() mockato (NON mockare position_usd).self._open_cap: dict[str, float] = {}; metodoset_open_cap(instrument, usd_cap, mark)-> amount_max = 1.10 * usd_cap / mark (usd_cap>0, mark>0 altrimenti ValueError)._submitsul ramo non reduce_only usaself._open_cap.get(instrument, MAX_AMOUNT[instrument]).trader.set_open_cap(inst, r["cap_per_asset"] * r["scala"], mark)prima di rebalance_signed). Scrivi nel rapporto la firma esatta.ensure_disaster_sl: la lettura di posizione+open_orders in try; su eccezione ritorna {"state": "unknown", "notes": ": "} SENZA cancellare ne' piazzare. Aggiornare il docstring (stati possibili).
Chiamanti di open_orders: grep; shadow.shadow_report lo chiama gia' dentro try/except (ok, non toccare shadow.py: e' di U2).
TEST (tutti in tests/test_execution_u1.py, client finto che sostituisce _post/positions, nessuna rete):
Suite completa:
cd <worktree> && /opt/docker/PythagorasGoal/.venv/bin/python -m pytest -q -p no:cacheprovider-> baseline 1098 passed, 3 skipped. Nessun test esistente deve rompersi; se uno esistente blinda il comportamento vecchio, aggiornalo e dillo.NON TOCCARE: scripts/live/book_execute.py, src/live/shadow.py, src/live/book.py (U2); config/live.json; tutto sotto /opt/docker/PythagorasGoal (produzione); nessuna chiamata di rete, nessun ordine.
ESITO: fatto sul ramo, non in produzione
RIF: gitea:Adriano/PythagorasGoal#24
COSA: correzione su lavoro/goldrake (pushato), analisi Opus, codice Sonnet, controllo finale Opus
FILE: commit
7c72308841d4c7PROVA: /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/deribit.py open_orders solleva su lettura fallita; ensure_disaster_sl -> stato unknown; book_execute: notify 'non verificabile', lista non_verificati, exit 2.
COMMIT:
7c72308841d4c7, su main dal 27/09/2026 (merge con ok di Adriano). Produzione aggiornata.