venue_news: sorvegliare cosa il venue ANNUNCIA — e due correzioni dalla KB

Nasce dall'annuncio sulla fine della Proof of Reserves. La notizia in se' vale
poco: si perde un segnale ad alta frequenza e DEBOLE (una PoR auto-pubblicata
prova che gli attivi esistono in un istante, non che coprano le passivita') e si
guadagna un audit annuale indipendente sotto VARA piu' il 90% degli attivi presso
Coinbase come custode. E non l'abbiamo mai sorvegliata: zero occorrenze nel
codice. Rinunciato di proposito a catturare l'ultimo dato — uno snapshot singolo
auto-riportato non regge lo standard di prova e non permetterebbe di stimare `p`.

CONSEGUENZA VERA: la decisione "100% Deribit fino a $20k" ha fra i suoi riapritori
"`p` che diventa stimabile invece che assunto". Dal 1/9 il segnale pubblico passa
da quotidiano ad ANNUALE: da una serie si stima, da un punto all'anno no. Quel
riapritore diventa praticamente irraggiungibile => la decisione e' ora gated SOLO
dal capitale.

TROVATO CERCANDO: esiste un feed RSS degli exchange-update, e conteneva quattro
annunci materiali che nessuno leggeva. Il caso che decide: le specifiche dei perp
USDC sono cambiate il 18/08, ANNUNCIATE IL 14/08. check_specs() e' nato da quella
svista e gira ogni ora, ma rileva la deriva DOPO; il feed l'avrebbe detta quattro
giorni PRIMA. La prima volta e' andata bene solo perche' i cambi erano RIDUZIONI.

Costruito scripts/live/venue_news.py (in cron_daily accanto a fee_watch):
  - NON interpreta: dice "e' uscito questo, guardalo". Nessun automatismo su un
    testo di marketing (P13). Classifica solo l'urgenza.
  - parole-chiave DERIVATE da deribit._CONTRACT e config/live.json, non
    ridichiarate (P1): chi aggiunge un asset allarga la sorveglianza da solo, ed
    e' il test che lo blinda.
  - primo giro semina senza allertare (P9); feed illeggibile -> exit 2, mai
    silenzio implicito (P5).
Debito #8 si RESTRINGE, non si chiude: il Rulebook non ha un feed.

Confermato due volte lo zero USDC: l'espansione del 31/07 non contiene l'Italia
ne' alcun paese UE, mentre San Marino e Citta' del Vaticano SONO idonei. Non
asserisco una causa (ci sono anche Canada e Giappone).

DUE CORREZIONI dalla KB "Cross collateral specifications":
(a) Il saldo negativo costa una collateral fee dello 0,05% AL GIORNO = 18,25%/anno,
    al secondo — 4,3x la resa USDE. Il 30/08 avevo scritto "lo finanzia a
    interesse" SENZA il numero: giusto e vuoto. Col numero, il criterio del
    cuscino di regolamento diventa aritmetica (-14 punti). E il ribilanciamento
    automatico non salva: scatta a $1M assoluti o al 100% della cross equity,
    irraggiungibili a $2k. Non veniamo ribilanciati: sanguiniamo la fee.
(b) L'haircut USDe ufficiale e' 5%, noi abbiamo 0.10 registrato come "verificato
    sul venue" il 26/08 senza traccia di come. NON riparato (P12/M28): si tiene
    0.10 perche' e' il lato conservativo, non e' sul percorso soldi e non morde
    fino al 90% di quota. Divergenza dichiarata in config.
Di lato: BUIDL haircut 2% (sarebbe stato il miglior collaterale del listino, se
si potesse comprare), stETH 7,5% (terza ragione indipendente per lasciarlo stare).
Nessuna fonte documenta un tetto sulle QUANTITA': il ~31,2% resta misurato e non
spiegato — e ora si sa che non e' una svista di lettura.

Suite: 800 passati (5 nuovi su venue_news).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-08-31 07:47:15 +00:00
parent 41f83b5dd8
commit 30286ea033
8 changed files with 424 additions and 6 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -10,7 +10,7 @@
"max_data_age_days": 2, "max_data_age_days": 2,
"_nota_skh_feed": "Freschezza del feed 5m usato per il segnale SKH01 (2026-07-26). fresh_5m ricade sul feed certificato IN SILENZIO se il fetch pubblico Deribit fallisce, e il certificato si rigenera 1x/giorno: senza controllo la latenza d'uscita di SKH01 passa da ~1h a ~1 giorno senza segnalazione. Sopra soglia book_execute ALLERTA e NON blocca (bloccare fermerebbe anche TP01, nettato sullo stesso strumento, per un guasto di rete). Diario 2026-07-26-t1-esecuzione-skh-live.md.", "_nota_skh_feed": "Freschezza del feed 5m usato per il segnale SKH01 (2026-07-26). fresh_5m ricade sul feed certificato IN SILENZIO se il fetch pubblico Deribit fallisce, e il certificato si rigenera 1x/giorno: senza controllo la latenza d'uscita di SKH01 passa da ~1h a ~1 giorno senza segnalazione. Sopra soglia book_execute ALLERTA e NON blocca (bloccare fermerebbe anche TP01, nettato sullo stesso strumento, per un guasto di rete). Diario 2026-07-26-t1-esecuzione-skh-live.md.",
"skh_feed_max_age_min": 30, "skh_feed_max_age_min": 30,
"_nota_usde": "Collaterale USDE a rendimento (test di eligibilita' 2026-08-26: 500 USDE, verdetto entro il 29/08 — diario 2026-08-26-usde-analisi). L'autorita' che LEGGE questa sezione e' src/live/usde.py; la usano shadow._collaterale_usde (equity oraria del book) e scripts/live/usde_watch.py (sorveglianza giornaliera 12:35 UTC). Criteri delle soglie, dichiarati (P6): depeg_warn 0.99 = fuori dalla banda operativa dello spot (~3 bps) e oltre il clamp +-0.5% per fonte dell'indice usde_usdc — a quel prezzo non e' rumore di book; depeg_crit 0.95 = meta' del buffer di haircut (10%) consumata. quota_target 0.70 = la quota DECISA dall'operatore il 2026-08-30 (la decisione di quota che il gate USDE-01 apriva; anticipata di un giorno sul rinvio al 31/08, su richiesta esplicita dell'operatore \"porta in usde tutto il capitale che non viene usato\"). Il 70% NON e' un argmax (M8): e' il massimo compatibile col CUSCINO DI REGOLAMENTO, cioe' il vincolo che r0830_usde_quota non aveva guardato — il P&L e il funding dei perp USDC-lineari si regolano in USDC, non nel collaterale, quindi a quota alta il saldo USDC va negativo alla prima perdita del libro e Deribit lo finanzia a interesse. Il cuscino richiesto e' il disaster-SL sulla massima esposizione lorda: n_asset x frac x disaster_sl_pct = 2 x 0.5 x 0.30 = 30% dell'equity, che lascia esattamente il 70%. quota_max_frac 0.50 = tetto di ALLERTA sulla quota USDE/equity totale (N4: la quota e' l'unica leva contro il rischio emittente, -100% = 25 anni di resa, non recuperabile). Alzato a 0.85 il 2026-08-30 in previsione della quota al 70% e RIMESSO A 0.50 lo stesso giorno: il 70% NON e' raggiungibile. 🚨 venue_cap_frac 0.312 = TETTO DEL VENUE sull'USDE, misurato e NON documentato da Deribit (l'articolo ufficiale 'Yield/reward bearing coins' descrive un Cap ETHENA che diluisce il TASSO a livello di exchange, e nessun limite sulle quantita' detenibili da un conto). Ogni acquisto oltre il tetto e' rifiutato con `not_enough_funds_in_currency` pur avendo $1.400 disponibili: messaggio FUORVIANTE, non c'entrano fondi/taglia/prezzo/liquidita'/cadenza. E' una FRAZIONE DELL'EQUITY TOTALE, non un livello fisso — provato il 31/08 facendo scendere l'equity di $8: il tetto e' sceso con lei (30/08 in [644,18·645,18) con equity $2.063,79 = 31,21-31,26%; 31/08 in [643,18·644,18) con equity $2.055,56 = 31,29-31,34%; i due bracket distano 0,05pp, dentro il rumore dell'equity che oscilla +-$2-8/ora). ⇒ **il tetto SCALA col conto**: la quota resta ~31% e il valore in dollari cresce col capitale, e il 70% di quota_target NON e' raggiungibile ne' ora ne' mai. Il valore 0.312 e' il bordo BASSO dei bracket, scelto per far fallire il piano PRIMA dell'ordine invece che dopo il rifiuto; va ri-sondato se cambia qualcosa sul venue. Con la quota reale al 31% il tetto d'allerta 0.50 e' di nuovo quello giusto e MORDE: allargarlo a 0.85 avrebbe disarmato la guardia per uno scenario che non si e' verificato. Se il tetto del venue si alzera', il criterio per 0.85 e' 'meta' del cuscino di regolamento consumata' (USDC sotto il 15% dell'equity). haircut 0.10 verificato sul venue il 26/08 (USDC 0%): il 90% dell'USDE fa margine.", "_nota_usde": "Collaterale USDE a rendimento (test di eligibilita' 2026-08-26: 500 USDE, verdetto entro il 29/08 — diario 2026-08-26-usde-analisi). L'autorita' che LEGGE questa sezione e' src/live/usde.py; la usano shadow._collaterale_usde (equity oraria del book) e scripts/live/usde_watch.py (sorveglianza giornaliera 12:35 UTC). Criteri delle soglie, dichiarati (P6): depeg_warn 0.99 = fuori dalla banda operativa dello spot (~3 bps) e oltre il clamp +-0.5% per fonte dell'indice usde_usdc — a quel prezzo non e' rumore di book; depeg_crit 0.95 = meta' del buffer di haircut (10%) consumata. quota_target 0.70 = la quota DECISA dall'operatore il 2026-08-30 (la decisione di quota che il gate USDE-01 apriva; anticipata di un giorno sul rinvio al 31/08, su richiesta esplicita dell'operatore \"porta in usde tutto il capitale che non viene usato\"). Il 70% NON e' un argmax (M8): e' il massimo compatibile col CUSCINO DI REGOLAMENTO, cioe' il vincolo che r0830_usde_quota non aveva guardato — il P&L e il funding dei perp USDC-lineari si regolano in USDC, non nel collaterale, quindi a quota alta il saldo USDC va negativo alla prima perdita del libro e Deribit lo finanzia a interesse. Il cuscino richiesto e' il disaster-SL sulla massima esposizione lorda: n_asset x frac x disaster_sl_pct = 2 x 0.5 x 0.30 = 30% dell'equity, che lascia esattamente il 70%. quota_max_frac 0.50 = tetto di ALLERTA sulla quota USDE/equity totale (N4: la quota e' l'unica leva contro il rischio emittente, -100% = 25 anni di resa, non recuperabile). Alzato a 0.85 il 2026-08-30 in previsione della quota al 70% e RIMESSO A 0.50 lo stesso giorno: il 70% NON e' raggiungibile. 🚨 venue_cap_frac 0.312 = TETTO DEL VENUE sull'USDE, misurato e NON documentato da Deribit (l'articolo ufficiale 'Yield/reward bearing coins' descrive un Cap ETHENA che diluisce il TASSO a livello di exchange, e nessun limite sulle quantita' detenibili da un conto). Ogni acquisto oltre il tetto e' rifiutato con `not_enough_funds_in_currency` pur avendo $1.400 disponibili: messaggio FUORVIANTE, non c'entrano fondi/taglia/prezzo/liquidita'/cadenza. E' una FRAZIONE DELL'EQUITY TOTALE, non un livello fisso — provato il 31/08 facendo scendere l'equity di $8: il tetto e' sceso con lei (30/08 in [644,18·645,18) con equity $2.063,79 = 31,21-31,26%; 31/08 in [643,18·644,18) con equity $2.055,56 = 31,29-31,34%; i due bracket distano 0,05pp, dentro il rumore dell'equity che oscilla +-$2-8/ora). ⇒ **il tetto SCALA col conto**: la quota resta ~31% e il valore in dollari cresce col capitale, e il 70% di quota_target NON e' raggiungibile ne' ora ne' mai. Il valore 0.312 e' il bordo BASSO dei bracket, scelto per far fallire il piano PRIMA dell'ordine invece che dopo il rifiuto; va ri-sondato se cambia qualcosa sul venue. Con la quota reale al 31% il tetto d'allerta 0.50 e' di nuovo quello giusto e MORDE: allargarlo a 0.85 avrebbe disarmato la guardia per uno scenario che non si e' verificato. Se il tetto del venue si alzera', il criterio per 0.85 e' 'meta' del cuscino di regolamento consumata' (USDC sotto il 15% dell'equity). haircut 0.10 registrato il 26/08 come 'verificato sul venue' (USDC 0%). 🚨 DIVERGENZA APERTA, non riparata (P12: fra due fonti che non concordano, una riparazione silenziosa e' un'invenzione): l'articolo ufficiale 'Cross collateral specifications' (Knowledge Base, aggiornato 2026-02-20) tabula USDe al **5%** — e con lui stETH 7.5%, PAXG 2.5/5%, USDT 2%, USYC 2%, BUIDL 2%, SOL 0/15%, e USDC/BTC/ETH a ZERO. Il 26/08 non ha lasciato traccia di COME fu verificato, e l'articolo e' ANTERIORE a quella data: non si sa quale delle due sia stale. Si TIENE 0.10 perche' e' il lato CONSERVATIVO (sottostima il margine utilizzabile) e perche' l'haircut non e' sul percorso soldi — non entra nel sizing, lo usa solo il report di usde_watch, ed e' gia' misurato che non morde a nessuna quota fino al 90%. Da chiudere leggendo la pagina margini del conto, che e' dove Deribit dice di guardare.",
"usde": { "usde": {
"index_name": "usde_usdc", "index_name": "usde_usdc",
"haircut": 0.1, "haircut": 0.1,
@@ -28,6 +28,13 @@ A quota ~99% resterebbero **$41 di USDC** contro un libro che, col disaster-SL a
esposizione, può perderne **~$619**: il saldo va negativo e Deribit lo finanzia a interesse, che si 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.** mangia la resa che si stava comprando. **Il vincolo non è il margine, ma non è nemmeno assente.**
> 📌 **Corretto e QUANTIFICATO il 31/08** (KB *Cross collateral specifications*): «*a collateral fee
> will be charged […] **default = 0.05% per day***», al secondo, sulla valuta negativa — cioè
> **18,25%/anno, 4,3× la resa USDE** che si starebbe comprando. Il ribilanciamento automatico non
> salva: scatta a **$1M** assoluti o al **100% della cross equity**, soglie irraggiungibili a $2k.
> Qui il 30/08 avevo scritto «lo finanzia a interesse» **senza il numero**: il numero rende il
> criterio del cuscino più giustificato, non meno.
Criterio dichiarato: cuscino USDC ≥ disaster-SL sulla massima esposizione lorda del libro = 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 `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%**. `config/live.json` e `src/live/book.py`, mai ridichiarato (P1). Che lascia esattamente **70%**.
@@ -129,10 +129,26 @@ per uno tutti i sospetti che sull'USDE avevano portato fuori strada:
> «**All Deribit users are permitted to buy and sell BUIDL tokens in the spot markets on Deribit, > «**All Deribit users are permitted to buy and sell BUIDL tokens in the spot markets on Deribit,
> with no extra requirements.**» — `insights.deribit.com/education/buidl-launches-on-deribit/` > with no extra requirements.**» — `insights.deribit.com/education/buidl-launches-on-deribit/`
Non per noi. Motivo plausibile e **non verificato**: BUIDL è un **titolo** (fondo BlackRock emesso Non per noi. **Il fatto misurato è il rifiuto, non il suo motivo** (stessa disciplina dello zero
via Securitize), e la sua distribuzione è ristretta per giurisdizione a monte dell'exchange — USDC). Le spiegazioni candidate sono due, e da fuori **non sono distinguibili**:
l'articolo di marketing non lo dice. *Il fatto misurato è il rifiuto, non il suo motivo* (stessa
disciplina dello zero USDC). - **(a) giurisdizione** — BUIDL è un **titolo** (fondo BlackRock emesso via Securitize), la cui
distribuzione è ristretta a monte dell'exchange. L'articolo di marketing non lo dice.
- **(b) limiti di spot per TIER DI CONTO** — la documentazione BUIDL, sezione *Limits and
Requirements*: «*Default non-margin spot order limits apply across assets. Check your account
tiers […] for specific maximum open order size configurations.*» Un tier che per questo asset
vale **zero** produrrebbe esattamente ciò che vediamo.
⚠️ Ma i nostri dati **restringono**: lo **spot USDE funziona** — ne abbiamo comprati 644 lo stesso
giorno, sullo stesso conto, con lo stesso codice. Quindi **non è un blocco generale sullo spot né
un limite di tier trasversale: è SPECIFICO DELL'ASSET.** Il che è compatibile con entrambe le
ipotesi (una giurisdizione per-asset, o un tier per-asset a zero) e non ne elegge nessuna.
*Restringere le ipotesi con l'evidenza che si ha vale più che sceglierne una con l'evidenza che
non si ha.*
Irrilevante per noi ma registrato: «*Deribit only supports the ERC-20 version of BUIDL on the
Ethereum blockchain*» — riguarda i trasferimenti on-chain, e la nostra uscita sarebbe comunque
una vendita sullo spot, non un prelievo.
📌 **Due affermazioni pubblicate di Deribit smentite dal conto in due giorni**: la APR USDC al 📌 **Due affermazioni pubblicate di Deribit smentite dal conto in due giorni**: la APR USDC al
3,40% (30/08) e ora «all users can buy BUIDL». Non è sfortuna, è una **regola**: 3,40% (30/08) e ora «all users can buy BUIDL». Non è sfortuna, è una **regola**:
@@ -0,0 +1,152 @@
# 2026-08-31 — Fine della Proof of Reserves, e il guardiano che mancava
L'operatore ha passato l'annuncio *Deribit to Discontinue Daily Proof of Reserves Publication*.
La notizia in sé vale poco per noi. Quello che è emerso cercandola vale molto di più.
## 1. La notizia: frequenza giù, sostanza su, per noi nulla cambia
Dal **1 settembre 2026** la pagina Proof of Reserves sparisce e gli aggiornamenti quotidiani
cessano. Al loro posto, sotto il regime **VARA** di Dubai: audit **annuale** indipendente delle
riserve, audit annuale del bilancio, obbligo di **copertura 100%** e **segregazione** degli attivi
dei clienti. E: «*approximately 90% of client assets have been migrated to Coinbase, which acts as
a custodian for Deribit*».
**Non è un peggioramento netto, ed è importante non raccontarlo come tale.** Si perde un segnale
**ad alta frequenza e debole** (una PoR auto-pubblicata prova che gli attivi esistono in un istante,
non che coprano le passività, ed è aggirabile attorno allo snapshot) e si guadagna un segnale **a
bassa frequenza e più forte** (audit indipendente obbligatorio invece di pubblicazione volontaria),
più un miglioramento **sostanziale** di custodia: 90% degli attivi presso un custode terzo regolato
invece che nei wallet dell'exchange.
**Per noi non cambia nulla di operativo**, e per una ragione che va detta: *la PoR non l'abbiamo
mai sorvegliata*. Zero occorrenze in tutto il codice. `venue_probe` legge se il venue **risponde**,
non cosa **dichiara**. Si perde un segnale che non stavamo usando.
Ho provato a catturare l'ultimo dato prima che la pagina sparisse — è la mossa giusta per un dato
non ricostruibile con una scadenza. **Rinunciato di proposito**: la pagina è una SPA e
`get_proof_of_reserves` non esiste come metodo API («Method not found»), ma soprattutto uno
snapshot singolo e auto-riportato non regge lo standard di prova di questo progetto e **non
permetterebbe comunque di stimare `p`**. Un dato che non cambierebbe una decisione non vale il
lavoro per prenderlo.
## 2. 📌 La conseguenza vera: il riapritore della decisione più grande si è ristretto
La decisione vincolante **«100% Deribit fino a $20k»** (26/07) ha come riapritori dichiarati:
*«**$20k**, o un cambio di piano, o `p` che diventa **stimabile** invece che assunto»*.
Dal 1 settembre il segnale pubblico di solvibilità passa da **quotidiano ad annuale**. Il terzo
riapritore non è formalmente chiuso — un audit indipendente è semmai evidenza più forte — ma
diventa **praticamente irraggiungibile**: da una serie giornaliera si può costruire una stima, da
un punto all'anno no. ⇒ **In pratica quella decisione è ora gated SOLO dal capitale**: si riapre a
$20k, o non si riapre. Non cambia la decisione di oggi (fu presa con `p` esplicitamente **assunto**,
non osservato), ma chiude l'unica uscita non-capitale che aveva.
## 3. 🚨 Quello che ho trovato cercando: quattro annunci materiali che nessuno leggeva
Il debito #8 dice, testuale: *«Resta scoperto il Rulebook vero e proprio: la sonda legge se il
venue RISPONDE, non cosa il venue ANNUNCIA»*. Esiste un feed RSS pubblico
(`insights.deribit.com/exchange-updates/feed/`) con 10 voci. Alla prima lettura:
| data | annuncio | perché ci tocca |
|---|---|---|
| 27/08 | Discontinue Daily Proof of Reserves | §1 e §2 di questo diario |
| **14/08** | **Contract Specifications change for Linear USDC Perpetuals** | **i nostri due strumenti** |
| 05/08 | New SM Margin Model On Deribit | leva per taglia, tiered |
| **31/07** | **USDC Rewards Available In More Countries** | tocca una conclusione viva |
| 29/06 | New Fee Schedule On Deribit | `fee_watch` esiste per questo |
**Il caso che decide la questione è il 14/08.** Le specifiche dei perpetual USDC sono cambiate il
**18/08**; l'annuncio è del **14/08**. Il codice lo racconta già con onestà: la tabella «*non se
n'era accorta […] è andata bene per la direzione del cambiamento, non perché ce ne fossimo
accorti*» — i cambi erano **riduzioni** (tick BTC 0,5→0,1, ETH 0,05→0,01, min/step ETH
0,001→0,0001) e un valore più grosso resta conforme. `check_specs()` è **nato da quella svista** e
oggi gira ogni ora. Ma rileva la deriva **dopo**; il feed l'avrebbe detta **quattro giorni prima**.
*Il giorno che Deribit ALZA un minimo, «dopo» significa ordini rifiutati.*
Il 31/07 chiude un cerchio aperto ieri: l'espansione delle giurisdizioni idonee ai reward USDC
**non contiene l'Italia**, né alcun paese UE — mentre **San Marino e Città del Vaticano** (i due
microstati europei fuori dall'UE) **sono idonei**. La lista che avevo letto (aggiornata 20/08) è
posteriore all'espansione: **la conclusione dello zero USDC è confermata due volte**. Il pattern
UE-fuori/microstati-dentro suggerisce un driver regolatorio, ma la lista contiene anche Canada e
Giappone: **non asserisco una causa**, il fatto è l'esclusione.
## 4. Costruito: `venue_news.py`
Sorveglianza giornaliera del feed, dentro `cron_daily.sh` accanto a `fee_watch` (suo parente
stretto). Scelte che contano:
- **NON interpreta.** Dice *«è uscito questo, guardalo»*. Nessun automatismo su un testo di
marketing: P13 — una guardia sui NUMERI non copre il RAGIONAMENTO, e la prosa si legge come
opinione di un lettore fallibile. L'unica cosa che classifica è l'**urgenza**.
- **Le parole-chiave sono DERIVATE, non ridichiarate** (P1, il difetto più ricorrente del
progetto): gli strumenti vengono da `deribit._CONTRACT`, la valuta di collaterale da
`config/live.json`. *Chi aggiunge un asset al book allarga la sorveglianza senza toccare questo
file* — ed è esattamente il test che lo blinda.
- **Primo giro semina senza allertare** (P9: l'allarme massimo non si spende per un arretrato di
10 voci, o non verrà letto il giorno che è vero).
- **Feed illeggibile → codice 2 e nessun silenzio implicito** (P5: «non vedo» non è «niente di
nuovo»).
5 test sulle funzioni pure. La rete no: `scarica()` ritorna `None` su qualunque errore, ed è quello
il contratto.
**Cosa NON copre**, e va detto: il **Rulebook** vero e proprio (ADL, perdita socializzata,
*emergency powers*, conti dormienti) non ha un feed. Il debito #8 si restringe, non si chiude.
---
## 5. La Knowledge Base risponde a due domande aperte — e corregge due cose mie
L'operatore ha passato anche *yield-generating-collateral-usde-buidl-and-more*, che **non** documenta
tetti né haircut ma rimanda alla Knowledge Base. Interrogata via API Zendesk
(`support.deribit.com/api/v2/help_center/articles/search.json`), l'articolo giusto è
**«Cross collateral specifications»** (aggiornato 2026-02-20).
### (a) 🚨 Il costo del saldo negativo: **0,05% al GIORNO**
> «*While the equity of a currency in an account remains negative, a **collateral fee** will be
> charged to that account. This fee is charged daily in the same currency as the negative balance
> (**default = 0.05% per day**). The fee is charged based on the amount of time the negative equity
> is held, down to a granularity of seconds.*»
**18,25% annuo**, cioè **4,3× la resa USDE** che si starebbe comprando tenendo meno USDC. Il 30/08
avevo scritto «Deribit lo finanzia a interesse» **senza il numero** — l'affermazione era giusta e
vuota. Con il numero il criterio del **cuscino di regolamento** smette di essere prudenza e diventa
aritmetica: scendere sotto il cuscino per tenere più USDE è **14 punti**.
E il ribilanciamento automatico **non salva**: scatta solo oltre **$1.000.000** assoluti o il
**100% della cross equity** (default tabulati), soglie che a $2k non si toccano mai. Non veniamo
ribilanciati: **sanguiniamo la fee**. *La cosa che sembrava un paracadute è, alla nostra taglia,
esattamente l'assenza di un paracadute.*
### (b) 🚨 Haircut USDe: la fonte dice **5%**, noi abbiamo registrato **10%**
| valuta | haircut X:PM | X:SM |
|---|---|---|
| BTC · ETH · **USDC** | — | — |
| USDT · USYC · **BUIDL** | 2% | 2% |
| PAXG | 2,5% | 5% |
| **USDe** | **5%** | **5%** |
| stETH | 7,5% | 7,5% |
| SOL | — | 15% |
`config/live.json` dice `haircut: 0.10`, e il diario del 26/08 lo dà per «verificato sul venue»
senza lasciare traccia di **come**. L'articolo è **anteriore** a quella data, quindi non si sa
quale delle due sia stale.
**Non l'ho riparato** (P12: fra due fonti che non concordano, una riparazione silenziosa è
un'invenzione; M28: la contraddizione è informazione). Si tiene **0,10** per tre ragioni dichiarate:
è il lato **conservativo** (sottostima il margine utilizzabile), **non è sul percorso soldi** (non
entra nel sizing — lo usa solo il report di `usde_watch`), ed è già misurato che **non morde a
nessuna quota fino al 90%**. Si chiude leggendo la pagina margini del conto, che è dove Deribit
stesso dice di guardare.
### (c) Un dato di lato che vale per il futuro
**BUIDL ha haircut 2%** — sarebbe stato il *miglior* collaterale a rendimento del listino (contro
il 5% dell'USDe), se solo lo si potesse comprare. E **stETH 7,5%**, il peggiore: terza ragione
indipendente per lasciarlo stare, dopo il tasso dimezzato e l'esposizione ETH.
📌 **Nessuna delle due fonti documenta un tetto sulle quantità detenibili.** Il ~31,2% sull'USDE
resta **misurato e non spiegato** — e ora si sa che non è una svista di lettura: non è scritto da
nessuna parte.
+6
View File
@@ -31,6 +31,12 @@ mkdir -p logs
# Schema fee Deribit (nuovo dal 2026-08-01, annunciato senza numeri): legge il tier BASE # Schema fee Deribit (nuovo dal 2026-08-01, annunciato senza numeri): legge il tier BASE
# dall'endpoint pubblico e applica la regola decisa in anticipo (<=5bps nulla, >10bps peso SKH01). # dall'endpoint pubblico e applica la regola decisa in anticipo (<=5bps nulla, >10bps peso SKH01).
uv run python scripts/live/fee_watch.py --quiet || true uv run python scripts/live/fee_watch.py --quiet || true
# Cosa il venue ANNUNCIA (debito #8: la sonda venue_probe legge se RISPONDE, non cosa dichiara).
# Feed RSS pubblico degli exchange-update. NON interpreta: classifica solo l'urgenza, su parole
# DERIVATE da deribit._CONTRACT e config/live.json. In una settimana quattro cambi di policy
# materiali erano arrivati a mano; le specifiche dei perp USDC cambiate il 18/08 erano annunciate
# il 14/08, e check_specs() se ne accorge solo DOPO.
uv run python scripts/live/venue_news.py --quiet || true
# f delle strutture VRP dalle quote REALI (canonico vs candidato bocciato dal gate 30/07). # f delle strutture VRP dalle quote REALI (canonico vs candidato bocciato dal gate 30/07).
# Criterio di sufficienza pre-registrato (>=40 coppie, IC95 <=0.12): avvisa da solo quando # Criterio di sufficienza pre-registrato (>=40 coppie, IC95 <=0.12): avvisa da solo quando
# il campione basta, invece di lasciare la misura appesa a un promemoria. # il campione basta, invece di lasciare la misura appesa a un promemoria.
+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/env python
"""venue_news.py — legge cosa il venue ANNUNCIA. SOLA LETTURA, non blocca mai nulla.
PERCHE' ESISTE (2026-08-31). Il debito #8 dice, testuale: *«Resta scoperto il Rulebook vero e
proprio: la sonda legge se il venue RISPONDE, non cosa il venue ANNUNCIA.»* Questa e' quella
meta'. In una settimana quattro cambi di policy Deribit materiali sono arrivati **a mano**, perche'
l'operatore ha incollato dei link — non perche' qualcosa li avesse visti:
* tetto sull'USDE (~31,2% dell'equity) * esclusione dell'Italia dai reward USDC
* permesso mancante su BUIDL * fine della Proof of Reserves quotidiana
E il caso che decide la questione: le **specifiche dei perpetual lineari USDC** sono cambiate il
18/08, annunciate il **14/08**. `check_specs()` rileva la deriva DOPO che e' avvenuta ed e' nato
proprio da quella svista; il feed l'avrebbe detto **quattro giorni prima**. Rilevare a posteriori e
sapere in anticipo non sono la stessa cosa: la prima volta e' andata bene solo perche' i cambi
erano RIDUZIONI (un valore piu' grosso resta conforme). Il giorno che Deribit ALZA un minimo, gli
ordini vengono rifiutati.
COSA E' E COSA NON E'. E' un promemoria che legge un feed RSS pubblico e dice *«e' uscito questo,
guardalo»*. **Non interpreta e non decide**: nessun automatismo su un testo di marketing (P13 — una
guardia sui NUMERI non copre il RAGIONAMENTO, e la prosa si legge come opinione di un lettore
fallibile). L'unica cosa che classifica e' l'URGENZA, e lo fa su parole DERIVATE dal codice
sorvegliato, non ridichiarate qui (P1): gli strumenti vengono da `deribit._CONTRACT`, le valute di
collaterale da `config/live.json`. Chi aggiunge uno strumento o una valuta allarga da solo la
sorveglianza, senza toccare questo file.
uv run python scripts/live/venue_news.py # report + allerta sui nuovi
uv run python scripts/live/venue_news.py --quiet # solo allerta (per il cron)
"""
from __future__ import annotations
import argparse
import html
import json
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from src.live.notifier import notify # noqa: E402
FEED = "https://insights.deribit.com/exchange-updates/feed/"
STATE = ROOT / "data" / "live" / "venue_news.jsonl"
# Parole che alzano un annuncio a 🚨. Le prime sono FISSE (categorie di rischio che ci toccano
# per costruzione); le altre si DERIVANO dal codice, sotto.
_CHIAVI_FISSE = (
"contract specification", "margin", "collateral", "fee", "delist", "discontinu",
"reserve", "maintenance", "liquidation", "settlement", "withdrawal", "reward",
"jurisdiction", "eligib", "insurance fund", "socialized", "adl", "rulebook",
)
def chiavi() -> list[str]:
"""Parole-chiave DERIVATE dal codice sorvegliato (P1), piu' quelle fisse."""
out = set(_CHIAVI_FISSE)
try:
from src.live.deribit import _CONTRACT
for nome in _CONTRACT: # BTC_USDC-PERPETUAL -> "btc", "usdc"
for pezzo in re.split(r"[_\-]", nome.lower()):
if len(pezzo) >= 3 and pezzo != "perpetual":
out.add(pezzo)
except Exception:
pass
try:
cfg = json.loads((ROOT / "config" / "live.json").read_text())
out.add(str(cfg.get("usde", {}).get("index_name", "")).split("_")[0].lower())
except Exception:
pass
return sorted(k for k in out if k)
def scarica(url: str = FEED, timeout: float = 20.0) -> str | None:
"""Feed RSS pubblico (tokenless). None se non leggibile. Mai solleva."""
try:
import requests
r = requests.get(url, timeout=timeout,
headers={"User-Agent": "PythagorasGoal/venue_news (+read-only)"})
return r.text if r.status_code == 200 else None
except Exception:
return None
def voci(xml: str) -> list[dict]:
"""PURA. Estrae (guid, titolo, data, link) dal RSS. Mai solleva."""
out = []
for blocco in re.findall(r"<item>(.*?)</item>", xml or "", re.S):
def campo(tag):
m = re.search(rf"<{tag}[^>]*>(?:<!\[CDATA\[)?(.*?)(?:\]\]>)?</{tag}>", blocco, re.S)
return html.unescape(m.group(1).strip()) if m else ""
g = campo("guid") or campo("link")
if g:
out.append({"guid": g, "titolo": campo("title"),
"data": campo("pubDate"), "link": campo("link")})
return out
def rilevante(titolo: str, ks: list[str]) -> list[str]:
"""PURA. Quali parole-chiave compaiono nel titolo."""
t = titolo.lower()
return [k for k in ks if k in t]
def gia_visti() -> set[str]:
if not STATE.exists():
return set()
out = set()
for riga in STATE.read_text().splitlines():
try:
out.add(json.loads(riga)["guid"])
except Exception:
pass
return out
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--quiet", action="store_true")
a = ap.parse_args()
xml = scarica()
if xml is None:
if not a.quiet:
print(" ✗ feed non leggibile — 'non vedo' non e' 'niente di nuovo' (P5)")
return 2
ks, viste, nuove = chiavi(), gia_visti(), []
primo_giro = not STATE.exists()
tutte = voci(xml)
STATE.parent.mkdir(parents=True, exist_ok=True)
with STATE.open("a") as f:
for v in tutte:
if v["guid"] in viste:
continue
v["match"] = rilevante(v["titolo"], ks)
v["visto_il"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
v["seed"] = primo_giro
f.write(json.dumps(v) + "\n")
nuove.append(v)
# Primo giro: si semina lo storico SENZA allertare (P9: l'allarme massimo non si spende
# per un arretrato di 10 voci, o non verra' letto il giorno che e' vero).
if not primo_giro:
for v in nuove:
if v["match"]:
notify("🚨 annuncio Deribit sul NOSTRO percorso",
{"titolo": v["titolo"], "tocca": ", ".join(v["match"][:6]),
"data": v["data"], "link": v["link"],
"azione": "leggerlo: questo sorvegliante NON interpreta"})
else:
notify("📌 nuovo annuncio Deribit",
{"titolo": v["titolo"], "data": v["data"], "link": v["link"]})
if not a.quiet:
print("=" * 78)
print(f" VENUE NEWS — {len(tutte)} voci nel feed, {len(nuove)} nuove"
+ (" (PRIMO GIRO: storico seminato, nessun allarme)" if primo_giro else ""))
print("=" * 78)
for v in tutte:
m = rilevante(v["titolo"], ks)
segno = "🚨" if m else ("·" if v["guid"] in viste else "📌")
print(f" {segno} {v['data'][:16]:17s} {v['titolo'][:70]}")
if m:
print(f" tocca: {', '.join(m[:8])}")
print(f"\n parole derivate dal codice: {', '.join(ks)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+64
View File
@@ -0,0 +1,64 @@
"""venue_news: il guardiano di cio' che il venue ANNUNCIA.
Si testano le funzioni PURE (parsing del feed, match, derivazione delle chiavi). La rete no:
`scarica()` ritorna None su qualunque errore ed e' quello il contratto — 'non vedo' non e'
'niente di nuovo' (P5).
"""
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts" / "live"))
import importlib.util
_spec = importlib.util.spec_from_file_location(
"venue_news", ROOT / "scripts" / "live" / "venue_news.py")
vn = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(vn)
_FEED = """<rss><channel>
<item><title><![CDATA[Contract Specifications change for Linear USDC Perpetuals]]></title>
<link>https://x/a</link><guid>https://x/?p=1</guid><pubDate>Fri, 14 Aug 2026 09:18:57 +0000</pubDate></item>
<item><title>Deribit Welcomes Orbit Markets</title>
<link>https://x/b</link><guid>https://x/?p=2</guid><pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate></item>
</channel></rss>"""
def test_estrae_le_voci_con_guid_titolo_e_data():
v = vn.voci(_FEED)
assert [x["guid"] for x in v] == ["https://x/?p=1", "https://x/?p=2"]
assert v[0]["titolo"] == "Contract Specifications change for Linear USDC Perpetuals"
assert v[0]["data"].startswith("Fri, 14 Aug 2026")
def test_feed_illeggibile_non_solleva_e_non_inventa_voci():
assert vn.voci("") == []
assert vn.voci("<rss>rotto") == []
def test_le_chiavi_sono_DERIVATE_dagli_strumenti_del_book():
"""P1: il bersaglio si deriva dal codice sorvegliato, non si ridichiara. Se un domani il book
prende un altro asset, la sorveglianza lo segue da sola."""
from src.live.deribit import _CONTRACT
ks = vn.chiavi()
for nome in _CONTRACT:
base = nome.split("_")[0].split("-")[0].lower()
assert base in ks, f"{base} (da {nome}) non e' fra le parole sorvegliate"
assert "usdc" in ks and "margin" in ks and "collateral" in ks
def test_riconosce_l_annuncio_che_ci_tocca_e_lascia_stare_gli_altri():
ks = vn.chiavi()
assert vn.rilevante("Contract Specifications change for Linear USDC Perpetuals", ks)
assert vn.rilevante("New SM Margin Model On Deribit", ks)
assert vn.rilevante("Deribit to Discontinue Daily Proof of Reserves Publication", ks)
assert vn.rilevante("USDC Rewards Available In More Countries", ks)
assert not vn.rilevante("Deribit Welcomes Orbit Markets to Block RFQ Platform", ks)
def test_il_match_e_case_insensitive_e_riporta_QUALI_parole():
m = vn.rilevante("New SM MARGIN Model On Deribit", vn.chiavi())
assert "margin" in m