8d391ed29a
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
139 lines
7.5 KiB
Python
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())
|