Files
PythagorasGoal/scripts/research/r0831_margini_conto.py
T
Adriano Dal Pastro 8d391ed29a margini: la pagina si ricostruisce dal gateway — e l'"IM %" non e' il margine delle posizioni
L'operatore ha incollato la riga CROSS col modello ATTIVO invece che proiettato:
Available $2.010,81 · IM 2,15% · MM 0,37%. Il gateway, letto allo stesso minuto, dice
available_funds = 2010,82299383. Scarto $0,01.

(a) LO SCREENSHOT NON SERVE PIU'. La riga CROSS della pagina E' `available_funds`, che
leggiamo da soli a ogni giro. Ieri quella schermata era l'UNICA fonte per l'haircut e per il
modello attivo, e per averla e' servito un passaggio dall'operatore e da Wasabi.
r0831_margini_conto.live() la ricostruisce.

(b) TERZA CONFERMA DEL 5%, E LA PRIMA ESATTA:
    1.400,71 + 0,95x654,176 + 0,20 dust - 11,553 IM = $2.010,82   contro pagina $2.010,81
Scarto $0,007. Il 10% della vecchia config non e' improbabile: invertendo la stessa riga da'
IM = -$21,16, aritmeticamente impossibile. Tre strade indipendenti, stesso numero.

(c) MIA LETTURA SBAGLIATA, CORRETTA. L'"IM %" della pagina e'
(margin_balance - available)/margin_balance, non il margine delle posizioni:
    haircut USDE  $32,71 = 1,592%   +   IM vera  $11,55 = 0,562%   =  2,153%
Il 74% di quella percentuale e' HAIRCUT. E' salita da 2,13% a 2,15% perche' abbiamo comprato
collaterale a rendimento — letta come rischio direbbe che ieri sera abbiamo alzato la leva
comprando USDE, l'opposto di quello che e' successo. La MM invece e' pulita ($7,60) e non puo'
contenere l'haircut, che da solo la renderebbe negativa: le due colonne hanno basi DIVERSE e la
pagina non lo dice. Regola: una percentuale letta da una schermata va INVERTITA nella sua
definizione prima di essere confrontata (P7 su superficie nuova).

(d) LA BOCCIATURA DI X:PM ESCE RAFFORZATA. La KB da' USDe al 5% sotto entrambi i modelli:
l'haircut si cancella e l'inversa da' il margine di POSIZIONE sulle stesse due posizioni,
stesso istante — X:SM $11,64 contro X:PM $88,23, 7,6x, e 9,3x la MM. Due misure pulite,
stesso verso. E la riga X:SM era una PROIEZIONE di un modello inattivo che oggi si riproduce
al centesimo: anche la riga X:PM era affidabile, quindi decidere senza provare era corretto.
Ora si sa perche', non solo che.

Suite: 800 passati.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BmkQty4a99pVmvwGfxAMQ9
2026-08-31 08:39:45 +00:00

139 lines
7.5 KiB
Python

#!/usr/bin/env python
"""r0831_margini_conto.py — riconcilia la pagina margini del conto. Riproduce due numeri.
PERCHE'. Due domande erano rimaste aperte e nessuna era rispondibile dal gateway (debito #11:
`account_summary` filtrato a 8 campi, niente initial_margin, `extended` ignorato):
1. l'HAIRCUT sull'USDe: la KB ufficiale dice 5%, `config/live.json` diceva 10% "verificato sul
venue il 26/08" senza traccia di come;
2. quale MODELLO DI MARGINE e' attivo — che nessuno aveva mai chiesto.
Lo screenshot della pagina `Standard Margin` (2026-08-31 07:50:30 UTC, fornito dall'operatore) le
chiude entrambe. Qui la riconciliazione, perche' un numero pubblicato deve avere uno script che lo
riproduce (N11) e perche' l'haircut non si legge nella pagina: si RICAVA per differenza fra due
righe, ed e' un conto che va mostrato invece che asserito.
uv run python scripts/research/r0831_margini_conto.py
"""
from __future__ import annotations
# --- dalla schermata (2026-08-31 07:50:30 UTC) ---
SEG_USDC = 1400.86 # S:SM (ATTIVO) -> riga USDC, Available Balance. USDE NON e' in tabella.
CROSS_XSM = 2011.73 # X:SM -> riga CROSS, Available Balance
PX_INDICE = 0.9998 # prezzo mostrato in cima alla pagina
# --- dal conto, letti via gateway alle ~07:55 dello stesso giorno ---
USDC_EQ = 1412.281074
USDE_EQ = 643.175691
IM_MIS = 11.5530 # riservato in USDC = equity - available (misurato)
ETH_DUST_USD = 0.000078 * 2500 # riga ETH della schermata, ~$0.20
TOLL = 2.0 # $: sotto questo scarto due ipotesi non si distinguono
def haircut_implicito(cross: float, usdc: float, eth_dust: float, im: float,
usde: float, px: float) -> tuple[float, float]:
"""PURA. -> (contributo dell'USDE al cross in USD, haircut implicito).
L'haircut non e' scritto da nessuna parte nella pagina: si ricava perche' il CROSS conta
l'USDE scontato e il SEGREGATO non lo conta affatto. La differenza fra le due righe, tolto
cio' che e' comune, E' il contributo dell'USDE."""
contributo = cross - (usdc + eth_dust - im)
return contributo, 1.0 - contributo / (usde * px)
def main() -> int:
print("=" * 78)
print(" PAGINA MARGINI — riconciliazione (screenshot 2026-08-31 07:50:30Z)")
print("=" * 78)
atteso_seg = USDC_EQ - IM_MIS
print(f"\n [1] S:SM, il modello ATTIVO — solo il silo USDC")
print(f" USDC equity {USDC_EQ:,.2f} - IM {IM_MIS:,.2f} = {atteso_seg:,.2f}"
f" schermata {SEG_USDC:,.2f} scarto ${abs(atteso_seg-SEG_USDC):.2f}")
print(f" → l'USDE non compare in questa tabella: nel modello attivo NON fa margine.")
contrib, h = haircut_implicito(CROSS_XSM, USDC_EQ, ETH_DUST_USD, IM_MIS, USDE_EQ, PX_INDICE)
print(f"\n [2] X:SM — l'haircut si RICAVA per differenza")
print(f" contributo USDE al cross = ${contrib:,.2f} su ${USDE_EQ*PX_INDICE:,.2f} di valore")
print(f" → haircut implicito {h:.4%}")
for cand, nome in ((0.05, "KB ufficiale"), (0.10, "config al 30/08")):
att = USDE_EQ * PX_INDICE * (1 - cand)
ok = abs(att - contrib) < TOLL
print(f" {cand:.0%} ({nome:16s}) → atteso ${att:,.2f}, scarto ${abs(att-contrib):6.2f}"
f" {'TORNA' if ok else 'NON torna'}")
verdetto_h = "5%" if abs(USDE_EQ*PX_INDICE*0.95 - contrib) < TOLL else "indeterminato"
delta_modelli = CROSS_XSM - SEG_USDC
print(f"\n VERDETTO (calcolato a runtime, N11):")
print(f" haircut USDe = {verdetto_h} → `config/live.json` diceva 10%: SBAGLIATO")
print(f" modello attivo = SEGREGATO (S:SM) → l'USDE non e' collaterale del book")
print(f" passare a X:SM aggiungerebbe ${delta_modelli:,.2f} di margine utilizzabile")
print(f"\n{'=' * 78}")
live()
return 0
# --- 2026-08-31 08:34Z: X:SM e' ATTIVO. La pagina non serve piu': si RICOSTRUISCE. --------------
#
# L'operatore ha incollato la riga CROSS a X:SM attivo: Available $2.010,81, IM 2,15%, MM 0,37%.
# Il gateway, letto allo stesso minuto, dice `available_funds` = 2010.82299383 — **scarto $0,01**.
# ⇒ la riga CROSS della pagina E' `available_funds`, che leggiamo da soli. Lo screenshot che ieri
# era l'unica fonte per l'haircut e per il modello attivo NON e' piu' necessario a nulla.
PAG_AVAIL, PAG_IM_PCT, PAG_MM_PCT = 2010.81, 0.0215, 0.0037 # incollati dall'operatore, 08:34Z
GW_AVAIL, GW_MB = 2010.82299383, 2055.07348077 # gateway, stesso minuto
GW_USDC_EQ, GW_USDE = 1400.70809113, 654.175691
XPM_AVAIL = 1935.14 # riga X:PM della schermata delle 07:50 (proiezione, modello inattivo)
def im_di_posizione(avail: float, usdc_eq: float, usde: float, px: float, h: float,
dust: float = ETH_DUST_USD) -> float:
"""PURA. -> IM di POSIZIONE in USD, ripulita dall'haircut.
Inversa esatta della riga CROSS: available = usdc_eq + (1-h)*usde*px + dust - IM.
Serve perche' la percentuale stampata dalla pagina NON e' questa (vedi live())."""
return usdc_eq + (1 - h) * usde * px + dust - avail
def live() -> None:
print(" X:SM ATTIVO (2026-08-31 08:34Z) — la pagina si ricostruisce dal gateway")
print("=" * 78)
ric = GW_USDC_EQ + 0.95 * GW_USDE + ETH_DUST_USD - IM_MIS
print(f"\n [3] la riga CROSS, ricostruita con haircut 5%")
print(f" {GW_USDC_EQ:,.2f} + 0,95x{GW_USDE:,.3f} + {ETH_DUST_USD:.2f} dust"
f" - {IM_MIS:.3f} IM = ${ric:,.2f}")
print(f" pagina ${PAG_AVAIL:,.2f} · gateway ${GW_AVAIL:,.2f} → scarto ${abs(ric-PAG_AVAIL):.4f}")
for h in (0.05, 0.10):
im = im_di_posizione(GW_AVAIL, GW_USDC_EQ, GW_USDE, 1.0, h)
print(f" haircut {h:5.0%} → IM implicita ${im:9,.2f}"
f" {'coerente con gli $11,55 misurati' if im > 0 else 'IMPOSSIBILE: IM negativa'}")
print(" → terza conferma del 5%, ed e' la prima ESATTA. Il 10% non e' improbabile:"
"\n e' aritmeticamente impossibile.")
riserv = GW_MB - GW_AVAIL
hc = 0.05 * GW_USDE
print(f"\n [4] 🚨 l'\"IM %\" della pagina NON e' il margine delle posizioni")
print(f" (margin_balance - available)/margin_balance = {riserv/GW_MB:.4%}"
f" → la pagina stampa {PAG_IM_PCT:.2%}")
print(f" scomposta: haircut USDE ${hc:,.2f} ({hc/GW_MB:.3%})"
f" + IM vera ${IM_MIS:,.2f} ({IM_MIS/GW_MB:.3%})")
print(f" ⇒ il {hc/riserv:.0%} di quella percentuale e' HAIRCUT, non rischio.")
print(f" E' salita da 2,13% a 2,15% perche' abbiamo COMPRATO COLLATERALE A RENDIMENTO.")
print(f" La MM invece e' pulita: {PAG_MM_PCT:.2%} = ${PAG_MM_PCT*GW_MB:,.2f}, e non puo'"
f" contenere\n l'haircut (${hc:,.2f} da solo la renderebbe negativa):"
" le due colonne hanno basi DIVERSE.")
print(f"\n [5] X:PM — il confronto rifatto sulla misura pulita")
print(f" La KB da' USDe al 5% sotto ENTRAMBI i modelli: l'haircut si CANCELLA nel confronto.")
for nome, av in (("X:SM", CROSS_XSM), ("X:PM", XPM_AVAIL)):
im = im_di_posizione(av, USDC_EQ, USDE_EQ, PX_INDICE, 0.05)
print(f" {nome}: available ${av:,.2f} → IM di POSIZIONE ${im:6,.2f}")
im_sm = im_di_posizione(CROSS_XSM, USDC_EQ, USDE_EQ, PX_INDICE, 0.05)
im_pm = im_di_posizione(XPM_AVAIL, USDC_EQ, USDE_EQ, PX_INDICE, 0.05)
print(f" → PM chiede {im_pm/im_sm:.1f}x il margine iniziale sulle STESSE due posizioni,"
f"\n e {0.0343/PAG_MM_PCT:.1f}x la MM. Due misure pulite, stesso verso: SCARTATO confermato.")
if __name__ == "__main__":
raise SystemExit(main())