Files
PythagorasGoal/docs/diary/2026-08-30-usde-quota-tetto-venue.md
T
Adriano Dal Pastro c250c04371 usde: l'USDC NON frutta sul nostro conto — misurato, e §6 di stasera era sbagliata
Domanda dell'operatore: "verifica se l'USDC frutta davvero sul nostro conto".

Sembrava dover aspettare: il gateway non espone il Transaction Log
(get_transaction_log, get_settlement_history, get_deposits, get_transfers,
get_interest_history: tutti 404 — debito #11) e l'unica serie storica e'
trades.db.equity, oraria ma arrotondata a 2 decimali e sporcata dal P&L non
realizzato (+-$2-8/ora a posizioni aperte), dove $0,13/giorno sparisce.

La fonte ufficiale Deribit ha spostato il problema dal rumore al calendario: i
reward USDC si pagano UNA VOLTA AL MESE ("paid out as a single monthly payment
early in the following month"), accrual alle 00:00 UTC sulla minima equity —
non ogni giorno come l'USDE. Ecco perche' una sorveglianza giornaliera non
poteva vederli. E un accredito mensile da qualche dollaro si vede benissimo
anche a 2 decimali, purche' il libro sia FLAT: allora equity == balance == USDC
e ogni scalino e' un accredito.

MISURA, due confini di mese entrambi a libro flat:
  29/06 -> 08/07  equity 598,06 costante, 237/237 ore ferme, 0 scalini  (attesi $0,45)
  31/07 -> 03/08  equity 596,92 costante per 4 giorni pieni             (attesi $1,72)
Il secondo e' decisivo: $1,72 contro una risoluzione di $0,01, 172x. Zero
MISURATO, non zero sotto soglia.

=> La premessa originale del gate USDE-01 e' RESTAURATA: il guadagno di tenere
USDE e' il tasso pieno ~4,1%, non lo spread 0,71 punti che avevo scritto poche
ore fa. Sui $644: ~$26/anno, non ~$4,6.

Cosa avevo sbagliato: ho letto `apr: 3.4` in public/get_currencies e l'ho
trattato come una proprieta' del NOSTRO CONTO. Era un listino del VENUE. La
"conferma indiretta" che invocavo provava che il listino e' reale per l'USDE e
non diceva nulla sull'idoneita' dell'USDC. Un tasso pubblicato non e' un tasso
incassato: si verifica sul conto — ed e' costato una query su una serie che
avevamo gia'.

Esclusione plausibile ma NON verificata: MiCA (USDC e' e-money token, USDe no);
Deribit dice solo "eligibility is based on their location". Il fatto misurato
e' lo zero, non il suo motivo.

Nuovo: scripts/live/balance_watch.py + scripts/cron_balance.sh (orario al
minuto :42, libero fra :25/:35/:47, sola lettura). Registra il BALANCE a 8
decimali per valuta — la serie che mancava — col conteggio dei fill dall'ultimo
campione e il nozionale lordo, cosi' una finestra sporca si riconosce invece di
essere mediata dentro. Etichetta PULITA le finestre a 0 fill e libro flat, dove
il delta USDC E' l'interesse, e ne stampa l'APR implicita.

Suite: 795 passati. L'ERROR di teardown e' il falso positivo dichiarato dalla
guardia stessa: il cron :47 ha scritto un fill reale (ETH BUY $+9, 23:47:19)
mentre la suite girava.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 23:48:52 +00:00

214 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-08-30 — "porta in USDE tutto il capitale che non viene usato": il venue dice 31%
**Richiesta dell'operatore**, verbatim: *"porta in usde tutto il capitale che non viene usato"*.
Arriva il 30/08, cioè **un giorno prima** della data a cui l'operatore stesso aveva rinviato la
decisione di quota (gate USDE-01, rinvio al 31/08). L'anticipo è esplicito e vale come decisione.
## 1. "Il capitale che non viene usato" non è una quantità piccola: è quasi tutto
Stato letto dal gateway alle 19:50Z: USDC **$1.563,09** (di cui **$11,36** impegnati a margine),
USDE 500,1757 → **$500,18**, totale **$2.063,26**, quota **24,2%**. Posizioni BTC $354,72 + ETH
$213,36 = **$568,08** lordi (0,275x).
Il margine consuma **$11 su $2.063**, e l'USDE è cross-collateral: convertirlo non lo toglie
dall'uso. Anche a piena esposizione del libro (lordo 1,0x) il margine sarebbe ~$41. Presa alla
lettera la richiesta è una quota **~99%** — il 100% che il gate esclude per nome ("mai 100%: R1
emittente non recuperabile"). Le due letture plausibili ("non a margine" e "non esposto dal libro")
convergono entrambe su ~97-99%: non è un'ambiguità che si risolve scegliendo, è una che si porta
all'operatore.
## 2. Il vincolo che `r0830_usde_quota` non aveva guardato: il cuscino di REGOLAMENTO
L'analisi del 30/08 aveva misurato il **margine** e concluso — correttamente — che l'haircut non
morde a nessuna quota fino al 90%, nemmeno a leva 1,50x con USDE a 0,95. Vero, e irrilevante:
il P&L e il funding dei perp **USDC-lineari si regolano in USDC**, non nel collaterale. Lo si vede
nel conto: `equity balance = $7,24` di floating, tutto nel secchio USDC.
A quota ~99% resterebbero **$41 di USDC** contro un libro che, col disaster-SL a 30% sulla massima
esposizione, può perderne **~$619**: il saldo va negativo e Deribit lo finanzia a interesse, che si
mangia la resa che si stava comprando. **Il vincolo non è il margine, ma non è nemmeno assente.**
Criterio dichiarato: cuscino USDC ≥ disaster-SL sulla massima esposizione lorda del libro =
`n_asset × frac × disaster_sl_pct` = 2 × 0,5 × 0,30 = **30% dell'equity** — tutto derivato da
`config/live.json` e `src/live/book.py`, mai ridichiarato (P1). Che lascia esattamente **70%**.
Non è un argmax (M8): la quota massima e il criterio coincidono per costruzione, e infatti il 70%
cade **esattamente sul limite, con zero slack**.
Tabella portata all'operatore (APR allora creduta 3,26% [1,13-4,51], n=4 — vedi §5, è sbagliata):
| quota | converti | USDC che resta | resa/anno | evento emittente vs maxDD libro |
|---|---|---|---|---|
| 24,2% (allora) | — | $1.563 | $16 | 3,1× |
| 50% | $531 | $1.032 | $34 | 6,3× |
| **70%** | **$944** | **$619** | **$47** | **8,8×** |
| ~99% | $1.522 | $41 | $66 | 12,3× |
**Scelta dell'operatore: 70%**, il massimo compatibile col cuscino.
## 3. Esecuzione: da 500 a 644 USDE, poi il muro
Nuovo attrezzo **`scripts/live/usde_convert.py`** (dry-run di default). Non passa da
`DeribitTrader`: `execution.ALLOWED` ammette solo i due perp del libro ed è il guardrail
anti-fat-finger del percorso soldi — **non si allarga** per farci entrare uno spot che col libro
non c'entra. Lo script porta le proprie guardie: banda prezzo [0,995 1,005], tetto HARD di quota
0,95, il cuscino di regolamento, dry-run.
Convertiti **+144 USDE** (500,1757 → **644,175691**), quota **24,24% → 31,21%**, tutti i fill a
1,0002-1,0003, **fee 0**. Poi ogni acquisto ha smesso di passare.
## 4. `not_enough_funds_in_currency` è un messaggio FUORVIANTE — la cronaca delle ipotesi sbagliate
Si tiene apposta, perché chi rilegge non deve rifare questo giro. Tre ipotesi, tutte plausibili,
tutte sbagliate:
1. **"È la taglia."** 943,98 rifiutato per `Invalid params` → vero: `min_trade_amount: 1` e
`contract_size: 1`, il passo è **intero** (confermato da `public/get_instrument`; il gateway
non espone quel tool, la risposta è arrivata dall'API pubblica). Quantizzato a intero: 933
rifiutato per **fondi**, con **$1.541 disponibili**. Falso indizio.
2. **"È il rate-limit."** 100 passava e 300 no; poi anche **1** rifiutato otto volte di fila.
Aggiunto backoff sul tempo fino a 90s: rifiutato lo stesso. Falso.
3. **"È il prezzo."** Diagnosi a tre ordini da 1 USDE: SELL @1,0000 OK, BUY **@1,0003 OK**,
BUY @1,0002 e BUY market rifiutati. Vero **in parte**: il book REST pubblico è in **ritardo**
sul matching engine, e un limite a `ask+1 tick` a volte non incrocia davvero. Difetto mio, e
istruttivo: prezzavo l'ordine sull'**indice** invece che sul **book**. Sono due prezzi con due
mestieri — l'indice **marca** il collaterale (`usde.valuta`, mediana multi-exchange: la lezione
Binance 10/10), il book **prezza** lo scambio. Corretto con 5 tick di margine e tetto duro
1,0010: il fill avviene al prezzo del libro, quindi il margine non si paga.
Ma corretto il prezzo, **200 e 800 continuavano a fallire con 4.552 di profondità all'ask**.
## 5. 🚨 Il fatto vero: un TETTO DEL VENUE sull'USDE, a 644,175691 (31,21%)
Esperimento **a saldo neutro**, quattro ordini di fila (20:14Z):
```
BUY 20 @1.0007 -> not_enough_funds_in_currency USDE 644.1757
SELL 20 @0.9996 -> OK USDE 624.1757
BUY 20 @1.0007 -> OK USDE 644.1757
BUY 5 @1.0007 -> not_enough_funds_in_currency USDE 644.1757
```
È un **tetto sul LIVELLO**: non taglia, non prezzo, non liquidità, non cadenza, non fondi
($1.408 disponibili). Lo stesso ordine che viene rifiutato passa subito dopo una vendita di pari
taglia. **La quota del 70% non è raggiungibile**, e nemmeno il 50%.
La formula del tetto **non è leggibile da qui**: `public/get_currencies` non espone un cap
(`in_cross_collateral_pool: true`, nient'altro), e il gateway non espone né `get_order_book`
`available_withdrawal_funds` — è il debito #11, il gateway è l'unico pezzo della catena che
possediamo e si ha solo quel che espone. Registrato come fatto misurato, non spiegato (D5: un buco
quantificato è un risultato, uno taciuto è un debito).
## 6. 🚨 E la resa non è quella che credevamo: **l'USDC paga 3,40%**
`public/get_currencies`, letta oggi:
| valuta | APR pubblicata |
|---|---|
| USDE | **4,1071%** |
| USDC | **3,4000%** |
I nostri reward USDE misurati (+0,052055 · +0,061815 · +0,061821 al giorno su 500 → **~4,5%/anno**)
**confermano** che la APR pubblicata di USDE è reale. Il che rende credibile anche l'altra riga.
Se l'USDC frutta già 3,40%, il guadagno del passaggio a USDE **non è il tasso: è lo spread**,
**0,71 punti**. Sui $644 che teniamo vale **~$4,6/anno**, non $21; sui $144 convertiti oggi,
**~$1,0/anno**. Il gate USDE-01 ha misurato con cura il reward dell'USDE e **non ha mai chiesto
cosa facesse l'USDC fermo**: è il controfattuale mancante — M1 in un'altra veste, si giudica il
**marginale**, non il livello. E cambia il verso della decisione: si prende un rischio emittente
**non recuperabile** (a 31,2% vale 3,9× il maxDD dell'intero libro) per **0,71 punti**.
⚠️ **Quello che NON è dimostrato:** che la APR USDC sia effettivamente accreditata *sul nostro
conto*. Sull'USDE l'abbiamo vista arrivare per delta; sull'USDC il P&L di trading copre $0,13/giorno
di interesse e il gateway non espone il Transaction Log. **Va verificato su un giorno senza trade
prima di trattarlo come misura** — qui è una APR pubblicata dal venue più una conferma indiretta,
non un reward osservato.
## 7. Cosa resta a terra
- **Conto**: USDC $1.419,61 · USDE 644,175691 ($644,18) · totale **$2.063,79** · quota **31,21%**.
Nessun ordine spot appeso (restano i due `tp01-disaster` reduce_only). Posizioni invariate.
Equity vista dal book **$2.063,86** ("mainnet USDC + USDE 644 @ 1.0000"): sizing corretto,
nessun falso "uscita di fondi".
- **`config/live.json`**: aggiunto `quota_target: 0.70` (la decisione dell'operatore, oggi bloccata
dal venue). `quota_max_frac` alzato a 0,85 e **rimesso a 0,50** nella stessa sessione: la soglia
larga presupponeva un 70% che non esiste, e lasciarla avrebbe **disarmato la guardia per uno
scenario che non si è verificato. Con la quota reale al 31%, il 50% morde di nuovo.**
- **Non fatto**: portare la quota al 70%. Il venue non lo consente. Non è una rinuncia
discrezionale, è un rifiuto misurato e riproducibile.
---
# APPENDICE (stessa sera, 23:40-23:55Z) — **l'USDC NON frutta sul nostro conto: §6 era sbagliata**
Richiesta dell'operatore: *"verifica se l'USDC frutta davvero sul nostro conto"*. Verificato.
**La risposta ribalta la §6 di questo stesso diario**, che va letta con questa appendice accanto.
## Perché la domanda sembrava dover aspettare, e invece no
Il gateway non espone il Transaction Log (provati `get_transaction_log`, `get_settlement_history`,
`get_deposits`, `get_transfers`, `get_interest_history`: **tutti 404** — debito #11). L'unica serie
storica del conto è `trades.db.equity`: **oraria ma arrotondata a 2 decimali**, e contiene il P&L
non realizzato, che a posizioni aperte oscilla di ±$2-8/ora. $0,13/giorno di interesse ci sparisce.
Poi la fonte ufficiale Deribit ha spostato il problema dal *rumore* al *calendario*:
> «Every day at 00:00 UTC, Deribit calculates the **minimum equity** of USDC that a user has been
> holding over the previous 24 hours. […] After the month is over, the rewards from each day are
> summed together and **paid out as a single monthly payment early in the following month**.»
> — `insights.deribit.com/education/usdc-rewards-now-paid-on-deribit/`
**I reward USDC si pagano UNA VOLTA AL MESE**, non ogni giorno come quelli USDE. Ecco perché non li
avevamo mai visti: guardavamo a cadenza giornaliera, dove l'USDE si vede e l'USDC per costruzione no.
E un accredito mensile da qualche dollaro **si vede benissimo anche a 2 decimali** — purché il libro
sia FLAT, perché allora `equity == balance == USDC` e ogni scalino è un accredito.
## La misura: due confini di mese, entrambi a libro flat
| finestra | punti orari | equity min | equity max | ore senza alcun movimento | scalini >1 cent | reward atteso se idoneo |
|---|---|---|---|---|---|---|
| **29/06 → 08/07** | 238 | **598,06** | **598,06** | **237 / 237** | **0** | $0,45 (8 gg dal 23/06) |
| **31/07 → 03/08** | 96 | **596,92** | **596,92** | **tutte** | **0** | **$1,72** (luglio intero) |
Il secondo è il caso decisivo: **$1,72 attesi contro una risoluzione di $0,01 — 172×** — e l'equity
non si muove di un centesimo per quattro giorni pieni, coprendo tutta la finestra "early in the
following month". Non è un'assenza sotto la soglia di rilevabilità: è uno zero misurato.
**Il conto NON riceve i reward USDC.** N=2 confini indipendenti, entrambi puliti per costruzione.
## Perché, e perché è coerente col fatto che l'USDE invece paga
Deribit: *«A user's eligibility to receive USDC is based on their location»*. L'ipotesi che spiega
entrambe le osservazioni è **MiCA**: USDC è un *e-money token* regolamentato, e a un residente UE
non se ne può corrispondere rendimento; **USDe non è un EMT**, e infatti i suoi reward arrivano
(li abbiamo visti per delta: +0,052055 · +0,061815 · +0,061821). ⚠️ *Questa è la spiegazione
plausibile, non una fonte normativa verificata* (P13/M27: una norma citata si verifica come un
numero). **Il fatto misurato è lo zero, non il suo motivo.**
## Cosa cambia (e cosa la §6 aveva sbagliato)
- **La premessa originale del gate USDE-01 è RESTAURATA.** Il guadagno di tenere USDE **non è lo
spread 0,71 punti: è il tasso pieno ~4,1%**, perché l'alternativa sul nostro conto rende **0**.
Sui $644 che teniamo: **~$26/anno** (e ~$29 al ritmo misurato di ~4,5%), non i ~$4,6 di §6.
- **Cosa avevo sbagliato, e la lezione.** Ho letto `apr: 3.4` in `public/get_currencies` e l'ho
trattato come una proprietà **del nostro conto**. È una proprietà **del venue**: un listino, non
un accredito. La conferma indiretta che invocavo ("i reward USDE misurati coincidono con la loro
APR pubblicata") provava che il listino è reale **per l'USDE**, e non diceva nulla sull'idoneità
dell'USDC. 📌 **Un tasso pubblicato non è un tasso incassato: si verifica sul CONTO, e la verifica
costava una query sulla serie che avevamo già.** È N10 in una veste nuova — la verifica a €0 va
fatta *prima*, e si fa **sul venue, non sul sito**; qui perfino il venue non bastava, serviva il
conto.
- Resta vero e non toccato: il **tetto del venue al 31,21%**, il **cuscino di regolamento** (30%
dell'equity, che lascia il 70%), e che a 31,2% l'evento emittente vale ~3,9× il maxDD del libro.
La decisione "tenere o no i $644" cambia però di segno rispetto a come l'avevo chiusa: si compra
**$26/anno**, non $4,6.
## Strumento lasciato in piedi
**`scripts/live/balance_watch.py`** + **`scripts/cron_balance.sh`** (orario al minuto **:42**, libero
fra :25/:35/:47; sola lettura). Registra il **balance a 8 decimali** per valuta — la serie che
mancava — con il conteggio dei fill dall'ultimo campione e il nozionale lordo, così una finestra
sporca si riconosce invece di essere mediata dentro. Etichetta PULITA le finestre a 0 fill e libro
flat, dove il Δ USDC **è** l'interesse, e ne stampa l'APR implicita accanto a quella attesa.
Serve a sorvegliare che lo zero resti zero (o che cambi, se l'idoneità cambia): l'inizio di
settembre è il prossimo confine di mese, ed è già strumentato.