position_usd legge uno SHORT come LONG: size arriva in valore assoluto, direction ignorata #17
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 D1 [bug-critico]
FILE: TB:src/live/deribit.py:291-297 (identico in PG:src/live/deribit.py:238-243); forma da TB:src/gateway/deribit.py:307-324 (e cerbero-mcp exchanges/deribit/client.py:381)
COSA: position_usd() restituisce
sizeche il gateway (e cerbero-mcp) mette in abs(), ignorandodirection: una posizione SHORT si legge POSITIVA.SCENARIO: tp_frac=0, skh_sign=-1 -> book_net_target = 0.5eq(-0.25) ≈ -$560 (eq $4.5k). Giro 1: flat -> SELL $560, posizione vera -560. Giro 2: position_usd=+560 -> crossing -> close() manda SELL reduce_only (verso sbagliato: su uno short e' rifiutato/no-op) poi apre SELL -> short cresce ogni ora. Disaster-SL (execution.py:219-225): long = pos>0 -> stop SOTTO il mark lato sell reduce_only -> lo short resta SCOPERTO. Idem nel replay/confronto: l'ombra registra posizione_usd>0.
PROVA: VERIFICATO: lettura gateway positions()
"size": abs(size), "direction": ...; position_usd legge solo p.get("size"); book_net_target (book.py:226-227) ammette net<0. Mai accaduto finora: 0 righe con net<0 in PG data/live/book_executions.jsonl (166) e in TB data/live/ombra.jsonl (335) — il caso non e' ancora stato esercitato, non e' smentito. Nessun test passa una posizionedirection: shortattraverso position_usd (i test mockano position_usd direttamente).PROPOSTA: in position_usd:
s = float(p.get("size") or 0); return -abs(s) if str(p.get("direction","")).lower() in ("short","sell") else abs(s); test che attraversa gateway.positions -> DeribitRead.position_usd con size negativa. Da correggere in PG PRIMA che SKH01 vada short a TP01 flat, e in TB prima della promozione.Verifica fable D1 VERDETTO: CONFERMATO
GRAVITA': critico
PERCHE': cerbero-mcp sorgente /opt/docker/cerbero-mcp/src/cerbero_mcp/exchanges/deribit/client.py:376-382 e IMMAGINE IN ESECUZIONE (
docker exec cerbero-mcp grep-> /app/src/cerbero_mcp/exchanges/deribit/client.py:381) restituiscono"size": abs(size), "direction": "long"|"short"; tools.py:277 e routers/deribit.py:90 passano la lista senza trasformarla. TB src/gateway/deribit.py:307-320 identico (abs + direction). PG src/live/deribit.py:238-243position_usdlegge solosize-> uno short si legge positivo; execution.py:117,177,180,226 decidono side e verso del disaster-SL dapos > 0. Nessun short reale finora: logs/cron_book.log 0 righenet $-/pos $-su 2296 giri, book_executions.jsonl 0 ordini sell non reduce_only; il tp_frac minimo visto conSKH -1e' 0.399 (serve tp < 1/3 perche' net vada sotto zero: 0.75*tp < 0.25), ma tp_frac=0 con SKH aperto e' uno stato raggiungibile (tp_frac 0.0 registrato il 18/07, 05/08, 19/08). Nessun test attraversa positions()->position_usd con direction short.CORREZIONE: ok (usare
direction; nota:sizearriva in USD notional anche per i lineari — verificato empiricamente: pos_after 756.27 = 0.2807 ETH * 2694.26 — quindi la conversione resta com'e', cambia solo il segno). Aggiungere anche il casosize_currencynel ramo (mai usato per i lineari).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#17
COSA: correzione su lavoro/goldrake (pushato), analisi Opus, codice Sonnet, controllo finale Opus
FILE: commit
2bf4f9cPROVA: /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 position_usd: segno da direction (sell/short -> negativo), non dal solo size che cerbero manda in abs().
COMMIT:
2bf4f9c, su main dal 27/09/2026 (merge con ok di Adriano). Produzione aggiornata.