cuscino_watch: riacquisto automatico di USDE con isteresi (ECCEDENTE), bande in config, escape HTML nel sink di notify
Decisione dell'operatore 10/09 («riportarla a quota in autonomia»). Verificato da revisione fable (10 segnalazioni, 9 applicate; loop numerico su usde_convert.piano: nessuna sequenza vendita→acquisto). - quarto stato ECCEDENTE: slack > cuscino_riacquisto_frac (0,40) x cuscino => acquisto di USDE fino allo stesso bersaglio della vendita, q* = 1 - 0,30 x (1 + cuscino_margine_frac 0,20) = 0,64. Isteresi [0 ; 0,40] x cuscino con bersaglio unico 0,20: per oscillare servono +-8,6% di equity USDC (~$380); un bonifico alza lo slack di 0,7 x importo e sopra ~9% dell'equity ricompra da solo. - le tre frazioni (preavviso/margine/riacquisto) in config/live.json sezione usde, lette da usde.bande_cuscino() che verifica l'ordine; quota_target 0,70 TOLTO (slack zero per costruzione). - notifier.notify: html.escape su titolo e valori — la prima allerta vera (13:53Z) era andata persa per un '<' nudo; allerta_errore registrato nel record (P3). - da ECCEDENTE un fallimento si ritenta ogni 24h (non 4 Telegram/giorno per sempre); bande fuori ordine => BLIND con motivo, non un traceback ingoiato dal cron. - CLAUDE.md §1/§4/§5.17, config _nota_usde/_nota_cuscino, diario. 0,64 e' una DERIVAZIONE dell'autore, non la quota decisa il 30/08 (0,70): dichiarato, da confermare. - test: 1070 (+8 netti). Fixes #7 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016kqvff47UBGeYfj1QeN4zE
This commit is contained in:
@@ -87,10 +87,10 @@ e' raggiungibile ne' ora ne' mai» (31/08) e' falsificato**; il tetto e' **spari
|
||||
20:58 dello stesso giorno avevo scritto qui «terza conferma della frazione» sulla base di *nessun rifiuto
|
||||
fino al 31,8%*, che dimostra ≥, non =. Non spiegato (D5): puo' tornare. `venue_cap_frac` → **null**,
|
||||
`quota_max_frac` → **0,85** (il valore che l'operatore aveva scelto il 30/08 per questo scenario).
|
||||
⚠️ **Nessuno sorveglia il cuscino USDC**: `usde_watch` allerta solo sulla quota; una perdita del libro
|
||||
(che si regola in USDC) fa salire la quota da sola — a −$58 di USDC il cuscino e' gia' scoperto, a −30%
|
||||
la quota passa il 98%. GATE USDE-01 in §4). ⚠️ **Ogni versamento abbassa la quota**: dopo un bonifico si
|
||||
rilancia `usde_convert --quota 0.70` (che si ferma al cuscino), non si aspetta che qualcuno se ne accorga. Autorita' dei parametri: sezione `usde` di `config/live.json`
|
||||
✅ **Il cuscino USDC e' sorvegliato dal 10/09** (`cuscino_watch`, §5.17): una perdita del libro (che si regola in USDC)
|
||||
fa salire la quota da sola, e sotto zero di slack il sorvegliante vende USDE; prima nessuno lo guardava — a −$58 di USDC
|
||||
il cuscino era gia' scoperto. GATE USDE-01 in §4). ⚠️ **Ogni versamento abbassa la quota**: dopo un bonifico si
|
||||
**dal 10/09 lo fa `cuscino_watch` da solo** (stato ECCEDENTE: slack > 40% del cuscino ⇒ ricompra USDE fino a quota **0,64**, issue #7); prima si rilanciava `usde_convert --quota 0.70` a mano, e il 04/09 nessuno l'aveva fatto. Autorita' dei parametri: sezione `usde` di `config/live.json`
|
||||
(haircut **5%** — ✅ divergenza chiusa il 31/08, la config diceva 10% ed era sbagliato (`r0831_margini_conto.py`); oggi comunque **non si applica**, vedi sopra — tetto ALLERTA quota 50%, soglie depeg 0,99/0,95 coi criteri in `_nota_usde`), letta
|
||||
da `src/live/usde.py` — shadow (sizing orario) e `usde_watch` (sorveglianza 12:35 UTC, cron
|
||||
proprio, sotto `monitor_health`) derivano entrambi da li'. ⚠️ Il difetto d'origine: `shadow._equity`
|
||||
@@ -251,7 +251,7 @@ sull'hold-out; cambiarne le soglie guardando l'esito, pure.
|
||||
|
||||
| gate | data | criterio | stato |
|
||||
|---|---|---|---|
|
||||
| **USDE-01 (eligibilita' reward)** | 2026-08-29 | ≥1 reward entro il 29/08 → IDONEO e si apre la decisione di QUOTA (dell'operatore; tetto allerta 50%, mai 100% — R1 emittente non recuperabile); zero → si riconverte e la pista si chiude | ✅ **CHIUSO IDONEO** il 2026-08-28 12:35Z: primo reward **+0,052055 USDE** rilevato per delta al netto dei trade, coi criteri pre-registrati il 26/08 PRIMA dell'esito. **QUOTA DECISA il 30/08** (l'operatore ha anticipato il rinvio: *"porta in usde tutto il capitale che non viene usato"*): bersaglio **70%**, `usde.quota_target` in config. Tasso a 4 finestre (30/08): **3,26% annuo, banda bootstrap [1,13% – 4,51%]** — 3/4 hanno pagato (0,00 · 3,80 · 4,51 · 4,51%), e la banda larga 3,4 punti **e' il risultato**: a n=4 il tasso non e' misurato. `usde_watch.rendimento()` lo stampa **col suo n**; `quota_da_decidere()` lo chiede ogni giorno da lunedi'. 🚨 **L'EV non puo' scegliere la quota** — e' lineare in q, quindi il suo argmax e' sempre un angolo (0% o 100%): ogni quota interna nasce da un criterio sulla **coda**, dichiarato non ottimizzato (M8). Il resto e' misurato (`r0830_usde_quota.py`, diario 30/08): **hazard di pareggio = l'APR** (EV-positiva sse Ethena sta sotto il 3,3%/anno, numero **assunto** come il `p` di Deribit) · l'haircut **non morde a nessuna quota** fino al 90%, nemmeno a leva 1,50x con USDE marcato a 0,95 (29× di cuscino): **il vincolo non e' il margine** · la resa di oggi vale **$16/anno**, meno di UN mese di versamento ⇒ la leva binding resta il **bonifico** · gia' a 24,2% l'evento emittente vale **3,1× il maxDD dell'intero libro**. 📌 **Aspettare costa $1,33**: alzare a 50% fra 4 settimane invece che subito lascia sul tavolo $1,33 di resa (conversione reversibile a ~6 bps) e porta il campione da **4 a 32 finestre**, stringendo la banda ~2,8×. 🚨 **DUE FATTI DEL 30/08 CHE CAMBIANO IL GATE** (diario `2026-08-30-usde-quota-tetto-venue`). **(a) TETTO DEL VENUE ≈31-32% dell'equity — e' una FRAZIONE, non un livello.** 🚨 **SUPERATO IL 06/09: il
|
||||
| **USDE-01 (eligibilita' reward)** | 2026-08-29 | ≥1 reward entro il 29/08 → IDONEO e si apre la decisione di QUOTA (dell'operatore; tetto allerta 50%, mai 100% — R1 emittente non recuperabile); zero → si riconverte e la pista si chiude | ✅ **CHIUSO IDONEO** il 2026-08-28 12:35Z: primo reward **+0,052055 USDE** rilevato per delta al netto dei trade, coi criteri pre-registrati il 26/08 PRIMA dell'esito. **QUOTA DECISA il 30/08** (l'operatore ha anticipato il rinvio: *"porta in usde tutto il capitale che non viene usato"*): bersaglio **70%**, `usde.quota_target` in config (📌 **dal 10/09 la quota e' DERIVATA dalle bande del cuscino, 0,64: §5.17**). Tasso a 4 finestre (30/08): **3,26% annuo, banda bootstrap [1,13% – 4,51%]** — 3/4 hanno pagato (0,00 · 3,80 · 4,51 · 4,51%), e la banda larga 3,4 punti **e' il risultato**: a n=4 il tasso non e' misurato. `usde_watch.rendimento()` lo stampa **col suo n**; `quota_da_decidere()` lo chiede ogni giorno da lunedi'. 🚨 **L'EV non puo' scegliere la quota** — e' lineare in q, quindi il suo argmax e' sempre un angolo (0% o 100%): ogni quota interna nasce da un criterio sulla **coda**, dichiarato non ottimizzato (M8). Il resto e' misurato (`r0830_usde_quota.py`, diario 30/08): **hazard di pareggio = l'APR** (EV-positiva sse Ethena sta sotto il 3,3%/anno, numero **assunto** come il `p` di Deribit) · l'haircut **non morde a nessuna quota** fino al 90%, nemmeno a leva 1,50x con USDE marcato a 0,95 (29× di cuscino): **il vincolo non e' il margine** · la resa di oggi vale **$16/anno**, meno di UN mese di versamento ⇒ la leva binding resta il **bonifico** · gia' a 24,2% l'evento emittente vale **3,1× il maxDD dell'intero libro**. 📌 **Aspettare costa $1,33**: alzare a 50% fra 4 settimane invece che subito lascia sul tavolo $1,33 di resa (conversione reversibile a ~6 bps) e porta il campione da **4 a 32 finestre**, stringendo la banda ~2,8×. 🚨 **DUE FATTI DEL 30/08 CHE CAMBIANO IL GATE** (diario `2026-08-30-usde-quota-tetto-venue`). **(a) TETTO DEL VENUE ≈31-32% dell'equity — e' una FRAZIONE, non un livello.** 🚨 **SUPERATO IL 06/09: il
|
||||
tetto non c'era piu'** — quota portata al **68,7%** con 39 ordini senza rifiuti, fermata dal cuscino di
|
||||
regolamento (§1). Quanto segue e' la misura del 30-31/08, vera allora, tenuta perche' il tetto puo' tornare. Ogni acquisto oltre il tetto e' rifiutato con `not_enough_funds_in_currency` pur avendo **$1.400 disponibili**: messaggio **fuorviante**, che ha fatto inseguire tre ipotesi sbagliate (taglia, cadenza, prezzo). Che sia un tetto e non un problema d'ordine e' provato a saldo neutro (BUY rifiutato → SELL OK → BUY riaccettato → BUY rifiutato); che sia una **frazione** e' provato il 31/08 lasciando 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%** (0,05pp di scarto, dentro il rumore dell'equity che oscilla ±$2-8/ora). ⚠️ **Ri-sondato il 31/08 dopo il passaggio a X:SM** (l'ipotesi era che il tetto dipendesse dal modello segregato): **[654,18-655,18) con equity $2.054,90 = 31,84-31,88%**. Il modello ENTRA nel tetto ma **non lo spiega** — ha comprato **+0,55pp = +11 USDE (~$11)**, non le centinaia che servirebbero. ⇒ **il tetto SCALA col conto**: la quota resta ~31% e il valore in dollari cresce col capitale, ma **il 70% non e' raggiungibile ne' ora ne' mai**. 🚨 **Deribit non lo documenta**: l'articolo ufficiale *Yield/reward bearing coins* descrive un **Cap ETHENA** che diluisce il **TASSO** a livello di exchange (`User APR = min(bal_exchange, cap)/bal_exchange × Ethena APR`) e **nessun limite sulle quantita' detenibili** da un conto. Ora e' in config (`usde.venue_cap_frac` 0.312, bordo basso dei bracket) e `usde_convert` **rifiuta il piano prima di sparare** invece di scoprirlo dal venue. **(b) L'USDC NON frutta SUL NOSTRO CONTO — misurato, e la premessa del gate e' RESTAURATA.** `public/get_currencies` dice USDC 3,4000% (USDE 4,1071%) e per qualche ora quel numero e' stato scritto qui come se fosse nostro: **era un listino del venue, non un accredito**. Deribit paga i reward USDC **una volta al MESE** («paid out as a single monthly payment early in the following month», accrual 00:00 UTC sulla **minima equity**) — non ogni giorno come l'USDE, ed e' per questo che una sorveglianza giornaliera non poteva vederli. Verificato sui **due confini di mese a libro FLAT**, dove `equity == balance == USDC` e ogni scalino sarebbe un accredito: **29/06→08/07 equity 598,06 costante, 237/237 ore ferme, 0 scalini** (attesi $0,45) e **31/07→03/08 equity 596,92 costante per 4 giorni** (attesi **$1,72 contro una risoluzione di $0,01, 172×**). **Zero misurato, non zero sotto soglia.** ⇒ il guadagno di tenere USDE e' il **tasso pieno ~4,1%**, non uno spread: **~$26/anno** sui $644. 🚨 **Il motivo ora e' DOCUMENTATO, e non e' MiCA come avevo ipotizzato**: l'articolo ufficiale elenca le giurisdizioni escluse dai reward USDC e **l'ITALIA c'e'** (con Canada e Giappone: non e' una lista MiCA, e' policy di giurisdizione Deribit). ⚠️ **E la finestra di pagamento e' piu' larga di quella che avevo controllato**: «within the **first two weeks** of the following month». Rifatta la verifica sulle due settimane vere: **luglio e' conclusivo** (atteso $1,72 contro un'escursione TOTALE dell'equity di **$0,48** in 1-16/08, zero scalini compatibili), **giugno NO** (il libro ha iniziato a operare a meta' mese e il rumore e' della taglia del segnale). Quindi: **una finestra conclusiva piu' la lista ufficiale**, non due finestre — il «172× la risoluzione» del 30/08 era sovra-affermato. 📌 **Un tasso pubblicato non e' un tasso incassato: si verifica sul CONTO** — ed e' costato una query su una serie che avevamo gia'. Strumento: **`scripts/live/balance_watch.py`** + `cron_balance.sh` (orario :42, sola lettura) registra il **balance a 8 decimali**, la serie che mancava. 📌 **Il vincolo che l'analisi del margine non aveva guardato**: P&L e funding dei perp USDC-lineari **si regolano in USDC**, quindi la quota massima difendibile non e' data dall'haircut ma dal **cuscino di regolamento** = disaster-SL sulla massima esposizione lorda (`n_asset × frac × disaster_sl_pct` = **30% dell'equity**), che lascia esattamente il **70%** — coincidenza per costruzione, zero slack (M8: non e' un argmax). 📌 **Il costo del NON averlo e' ora documentato e vale il criterio**: un'equity negativa in una valuta paga una *collateral fee* dello **0,05% AL GIORNO** — **18,25%/anno**, addebitata al secondo, **4,3× la resa USDE che si starebbe comprando** (fonte: KB *Cross collateral specifications*). Il ribilanciamento automatico NON salva: scatta solo a **$1M** assoluti o al **100% della cross equity**, soglie che a $2k non si toccano mai — si sanguina la fee e basta. Il 30/08 avevo scritto «Deribit lo finanzia a interesse» **senza il numero**: il numero e' questo, e rende il cuscino piu' giustificato, non meno. Attrezzo: **`scripts/live/usde_convert.py`** (dry-run di default, guardie proprie; NON passa da `execution.ALLOWED`, che resta ai soli due perp) |
|
||||
| **STATARB** | 2026-09-27 | soglie 24/07 (non toccate) + diagnostica statica sempre-short | ✅ monitor riparato e rigenerato il 26/08: la serie vera da' Sharpe **−1,61** a oggi → coi criteri invariati punta al **RITIRO**. Si legge il 27/09, non prima |
|
||||
@@ -447,13 +447,13 @@ d'ancora in modo diverso (nella differenza si cancella in parte, nel livello per
|
||||
Ora **`scripts/live/cuscino_watch.py`** (cron **:53**, orario, `cron_cuscino.sh`, sorvegliato da `monitor_health`)
|
||||
legge l'**EQUITY USDC** (decisione dell'operatore: e' quella che risponde del regolamento, il balance vede il buco
|
||||
solo a trade chiuso), deriva il cuscino da `usde.cuscino_richiesto_usd` — **la formula si e' spostata in
|
||||
`src/live/usde.py`, e `usde_convert` la importa da li'** (due lettori, una formula: P1) — e ha tre stati:
|
||||
OK · **PREAVVISO** (slack < 10% del cuscino, ⚠️ alla transizione) · **SCOPERTO** (slack < 0: 🚨 e
|
||||
`src/live/usde.py`, e `usde_convert` la importa da li'** (due lettori, una formula: P1) — e ha cinque stati:
|
||||
OK · **PREAVVISO** (slack < 10% del cuscino, ⚠️ alla transizione) · **ECCEDENTE** (sotto) · BLIND · **SCOPERTO** (slack < 0: 🚨 e
|
||||
**riconversione automatica** `usde_convert --quota usde.quota_ripristino(0,20) --esegui`, cioe' **0,64**, che lascia
|
||||
il cuscino piu' un 20% — il DOPPIO del preavviso, altrimenti ogni 🚨 sarebbe seguito da un ⚠️ per costruzione). Guardie: `execution_enabled` del libro (disarmare il libro disarma anche questo), niente
|
||||
vendita sotto `depeg_warn` (decide l'operatore), un tentativo ogni 6h, le guardie proprie di `usde_convert`;
|
||||
marcatore «gia' detto» = esito dell'invio (§5.2). **Primo giro (13:00Z): gia' PREAVVISO, slack +$26** su $1.335
|
||||
richiesti — la marcatura del libro dal 06/09 lo aveva consumato senza che nessuno lo vedesse. ⚠️ **Due limiti dichiarati** (revisione fable 10/09): (a) **a quota 0,70 lo slack e' ZERO per costruzione**, quindi PREAVVISO e' lo stato normale del conto a quota piena (allerta una volta); (b) **il ripristino e' un RATCHET verso il basso** — dopo una riconversione la quota resta a 0,64 e nessun automatismo la riporta a 0,70: ricomprare e' `usde_convert --quota 0.70` a mano, decisione dell'operatore (N9: va deciso se accettare il ratchet o autorizzare un riacquisto automatico quando lo slack torna sopra il margine). Il tetto del venue in `usde_convert.piano` ora vale **solo in acquisto**: bloccava anche la vendita, e con `venue_cap_frac` rimesso in config la riconversione sarebbe stata morta. `tests/test_cuscino_watch.py` (16).
|
||||
richiesti — la marcatura del libro dal 06/09 lo aveva consumato senza che nessuno lo vedesse. ✅ **Ratchet chiuso lo stesso giorno (issue #7, «riportarla a quota in autonomia»)**: quarto stato **ECCEDENTE** (slack > 40% del cuscino ⇒ **acquisto** di USDE fino allo stesso bersaglio 0,64). Le tre bande stanno in `config/live.json` (`cuscino_preavviso_frac` 0,10 · `cuscino_margine_frac` 0,20 · `cuscino_riacquisto_frac` 0,40, `usde.bande_cuscino` verifica l'ordine) e **`quota_target` 0,70 non esiste piu'**: a 0,70 lo slack era ZERO per costruzione e ogni ora in perdita avrebbe venduto. Isteresi [0 ; 0,40]×cuscino con bersaglio unico 0,20: per oscillare servono ±6% di equity di slack = **±8,6% di equity USDC (~$380)**, un giro costa ~6 bps sull'importo mosso; un bonifico alza lo slack di 0,7×importo e sopra ~9% dell'equity fa scattare il riacquisto da solo. Soglie dichiarate, non ottimizzate (M8). ⚠️ Trovato al primo giro vero (13:53Z): l'allerta PREAVVISO **non e' partita** — Telegram in HTML rifiuta un `<` nudo («(< 10%…)»); l'escape sta nel **sink** (`notifier.notify`, `html.escape` su titolo e valori: copre tutti i 45 chiamanti, incluso il campo `motivo` che la revisione ha trovato ancora scoperto), `allerta_errore` registrato nel record (P3). Un guasto persistente da ECCEDENTE (tetto del venue tornato, book illeggibile) si ritenta **una volta al giorno**, da SCOPERTO ogni 6h; una config con bande fuori ordine da' **BLIND con motivo**, non un traceback ingoiato dal cron. ⚠️ **0,64 e' una DERIVAZIONE dell'autore** (margine 0,20 sul cuscino), non una decisione dell'operatore: il bersaglio registrato il 30/08 era 0,70, e la differenza vale ~$10/anno di resa. Da confermare, o cambiare `cuscino_margine_frac` (0,10 ⇒ 0,67, al prezzo di un ⚠️ dopo ogni vendita). 📌 **Stato al 10/09 14:0xZ: quota 69,3%, PREAVVISO (slack +$30)** — sopra il bersaglio 0,64 ma sopra zero: il sorvegliante vende alla prima ora sotto zero; allinearlo subito e' `usde_convert --quota 0.64 --esegui` (237 USDE). Il tetto del venue in `usde_convert.piano` ora vale **solo in acquisto**: bloccava anche la vendita, e con `venue_cap_frac` rimesso in config la riconversione sarebbe stata morta. `tests/test_cuscino_watch.py` (24).
|
||||
|
||||
18. ✅ **RIPARATO (2026-09-09 sera).** `cblib.spot_series` + `asof(ts)` guardava **un'ora avanti** (feed
|
||||
1h etichettato all'apertura: verificato, chiusura 1h a T == chiusura 5m a T+55 nel 100% delle barre)
|
||||
@@ -698,7 +698,7 @@ uv run python scripts/live/trades_db.py --reconcile # incrocio dell
|
||||
uv run python scripts/live/journal.py # voce del giorno (numeri + lettura)
|
||||
uv run python scripts/live/analista.py --secco # analisi del giorno, senza salvare
|
||||
uv run python scripts/live/revisione.py --secco # taglia del materiale della revisione settimanale (niente modello)
|
||||
uv run pytest # test (1062, tutti verdi al 10/09)
|
||||
uv run pytest # test (1070, tutti verdi al 10/09)
|
||||
```
|
||||
|
||||
```python
|
||||
|
||||
Reference in New Issue
Block a user