Il P&L di giornale era un delta di equity: la voce del 25/08 dichiarava +$1.414,57 di "giorno" quando $1.399,39 erano il deposito USDC, e il cumulato dall'arming avrebbe mentito per sempre. Nuova `movimenti_capitale()`: - soglia IMPORTATA da book.EQUITY_JUMP_ALERT, non ridichiarata (P1); - "movimento" solo se il salto supera di >2x il massimo che il mercato MISURATO (feed certificato, tetto di leva da config) poteva produrre fra le due letture; - altrimenti AMBIGUO: dichiarato con attenzione e NON scorporato (P12 -- un crash vero a tutta leva non deve diventare "prelievo"); idem a feed illeggibile (P5). Scansione dell'intera storia: 1 evento, esattamente il deposito (+209,6% contro mercato max 0,22%), zero falsi positivi. `concentrazione` ora lavora sul cumulato di TRADING; le regole sui movimenti stanno sopra l'early-return "nessun giro". Limite dichiarato (D5): un movimento sotto il 10% dell'equity resta nel P&L. 7 prove nuove (31 -> 37), incluso il controllo M15 al contrario. Voce del 25/08 rigenerata: giorno -> trading +$15,18; cumulato -> trading +$59,14. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
78 KiB
Produzione, sorveglianze e deploy
Estratto verbatim da
CLAUDE.mdil 2026-08-25 durante la compattazione. Cio' che gira con soldi veri: esecuzione, tripwire, monitor, libro di bordo, e i vincoli di deploy (PRIIPs/UCITS/broker). Il testo non e' stato riscritto: e' la memoria originale, spostata.
-
Ondata 2026-07-26 (3 filoni: esecuzione SKH01 / DVOLSPREAD / XSR01 fuori dal crypto) — 0 sleeve nuovi, 1 raccomandazione operativa aperta, 1 lead promosso, 1 falsificazione. Script
r0726_{skh_onbook,dvolspread_gate,xsr_equity}.py, testtests/test_wave_0726.py(11 casi), diario2026-07-26-wave-esecuzione-dvolspread-xsr-equity.md. Book/pesi/cron INVARIATI. (1) ⚠️ T1 — IL DEGRADO D'ESECUZIONE DI SKH01 ERA ANCH'ESSO FORTUNA D'ANCORA. Testato l'unico meccanismo che non e' un cron (ordini resting on-book: TP = limit al livello per costruzione + fee maker; SL = stop-market). A offset 0 l'on-book recupera il 94% del degrado — ma l'audit 02/07 aveva de-luckato i numeri headline di SKH01 e NON il degrado, misurato solo a off0. Sulla banda appaiata dei 23 offset il degrado massimo recuperabile e' +0.054 Sh di book, non −0.35 di sleeve. ⚠️ Errore di metodo mio, corretto in sessione: mediana(A)−mediana(B) fra offset e' sbagliato (confronta offset diversi) → serve la mediana delle DIFFERENZE appaiate; con quella il verdetto si RIBALTA. Esito: solo TP a limite = +0.054 FULL / +0.061 HOLD, positivo in 19/23 (FULL) e 21/23 (HOLD) offset; lo SL on-book PEGGIORA (contributo mediano −0.010, positivo in 11/23 = moneta) perche' cristallizza la perdita al livello mentre l'exit software ritardata incassa il rimbalzo — e sopra 0.50% di slippage l'on-book e' peggio del live. Meccanismo misurato: sulle uscite TP il fill orario batte il livello nel 42% dei casi (vantaggio medio −0.035%) → il limit TP converte una lotteria in certezza piu' che aggiungere ritorno; solo l'1% degli SL gappa davvero a 5m. RACCOMANDAZIONE NON ESEGUITA (decisione dell'operatore): TP come limit resting reduce-only, SL strategico NON on-book. E' un cambio di esecuzione (non passaweights_tilt_null) ma piccolo, da pesare contro ordini orfani/doppio fill. Il disaster-SL −30% on-book resta com'e'. ❌ T1 NON IMPLEMENTATO — e il perche' e' una CORREZIONE DI MODELLO (2026-07-26, diario2026-07-26-t1-esecuzione-skh-live.md). Leggendo il codice di produzione: TP01 e SKH01 tradano lo stesso strumento con una sola posizione netta Deribit → un ordine on-book al livello di SKH chiuderebbe anche quota TP01. Misurati i 2 ostacoli: (A) segno compatibile nel 97% dei trade che escono in TP (long 100%, short 94%) = risolvibile; (B) divergenza modello/live che sembrava bloccante (ritardo mediano 115 min, 70% dei TP con ≥1 cron dentro la finestra). ⚠️ MA (B) NON ESISTE:resample_5mNON scarta il bin 230m in corso (verificato: 21 barre 5m su 46 nell'ultimo bin) e_skyhook_positionsci itera dentro → il live rileva gia' SL/TP intra-barra, entro ~1h dal tocco. I docstring che dicevano "usa solo barre chiuse" / "latenza fino alla chiusura della barra 230m" erano FALSI e hanno guidato 3 analisi (02/07, 24/07, T1) — corretti sul posto. Conseguenza: la lentehourlysottostima il path live di +0.081 Sharpe FULL di book (23/23 offset, banda appaiata), il live vero sta sopra il canonical sul FULL, e il fix richiesto sarebbe un DECLASSAMENTO (+0.054 vs +0.081) in cambio di ordini parziali sul netto in un percorso con soldi veri. → non fatto, per misura, non per difficolta'. ✅ CABLATO INVECE il problema vero trovato per strada:fresh_5mfallisce in SILENZIO (fallback al feed certificato, rigenerato 1x/giorno) → la latenza d'uscita di SKH01 passa da ~1h a ~1 giorno senza che nulla lo segnali (conto online, posizione leggibile, e il gate di staleness guarda il feed di TP01: nessun controllo esistente scatta). Stesso schema del feed-freeze del 14/07, su un altro feed. Aggiunti:livefeed.feed_age_minutes(pura, eta' dalla CHIUSURA della barra,None=non misurata, clamp sugli skew),book_report.skh_feed_age_min(max fra gli asset), allerta Telegram inbook_executesopraskh_feed_max_age_min=30 min. Scelta dichiarata: ALLERTA, NON blocca — bloccare fermerebbe anche TP01 (nettato sullo stesso strumento) per un guasto di rete, e forzare SKH flat chiuderebbe posizioni buone su un glitch. Testtests/test_skh_feed_freshness.py(11 casi). Strategia/pesi/cadenza INVARIATI. ⚠️ SEGUITO 2026-07-29 — l'allerta ha funzionato, la sua CAUSA era una riga CABLATA. Diario2026-07-29-feed-skh-causa.md; test 11 → 16. Book/pesi/config/strategia INVARIATI. Il 29/07 (dopo il riavvio VPS delle 04:11) il feed e' ricaduto sul certificato in 6 giri orari su 8 fra le 05:00 e le 12:00: eta' 265→685 min (+60 a ogni giro = firma esatta del fallback) → latenza d'uscita SKH01 da ~1h a ~11h; book flat, nessuna posizione esposta. L'allerta ha segnalato 6/6 — poi ha stampato un perche' che non aveva misurato: la nota "fetch pubblico KO" era cablata, identica in ogni caso, compreso quello in cui la coda fresca E' attaccata e il vecchio e' il certificato stesso (= feed-freeze 14/07 in altra veste). E la causa vera non era recuperabile a posteriori per costruzione:_fetch_recent_5mingoia l'eccezione di pagina con unbreake a prima pagina fallita ritorna un frame vuoto, indistinguibile da "il venue non ha barre"; alle 12:14, a mano,fresh_5mrispondeva in 1.7s senza errori. ✅ Cablato:livefeed.last_fetch_error()(+_note_error, registra E logga nel punto in cui l'errore viene ingoiato) →book_report.skh_feed_errors(per asset) → allerta con la causa; e stesso buco chiuso sul ramo gemello "conto offline", che aveva gia' la ragione inmark_srce non la stampava mai. Tre guasti ora distinti: eccezione / risposta vuota / certificato vecchio con coda attaccata. Blindati anche il caso a meta' paginazione (coda parziale attaccata: la paginazione va in avanti → mancano le barre PIU' RECENTI) e la non-sopravvivenza della causa a una chiamata riuscita. ⚠️ La causa del 29/07 resta IGNOTA, e va citata cosi'. Solo circostanziale: giri falliti lunghi quanto i riusciti (16-46s → errore immediato, non timeout); finestra aperta col riavvio ma non chiusa da esso (11:00 ok, 12:00 no); stesso giorno il percorso del conto (rete diversa viacerbero-mcp, stesso venue a valle) davaReadTimeout/404/502; i due percorsi falliscono in alternanza, non insieme. Una prima stesura scriveva nei commenti "rate limit Deribit per-IP saturato da un altro progetto sulla stessa VPS" come fatto: rimossa — sarebbe stato lo stesso difetto che stavo correggendo, scritto meglio. Cron spostato0 * * * *→7 * * * *(ipotesi contesa al minuto tondo): ripiego da UNA osservazione, costo zero, dichiarato tale in testa acron_book.shperche' la riga di crontab vive fuori dal repo. ✅ SEGUITO 2026-07-30 — il MECCANISMO ipotizzato e poi rimosso e' ora MISURATO; il "perche' adesso" NO. Analizzando/opt/docker/cerbero-bite(stessa VPS, stesso IP pubblico): il suo collettore full-chain gira al minuto :00 e produce 12.186 risposte 429 in 26 ore, di cui 11.700 (96%) nel minuto :00 — ~770 chiamate ticker + ~770 orderbook in ~26s da un IP solo, senza backoff → si auto-satura il rate limit Deribit per-IP (ticker: 5.738 respinte su 20.029). Co-timing esatto con l'incidente: le sue quote passano da ~0.4% a ~50% vuote alle 05:00 del 29/07 e non sono ancora rientrate. ⚠️ Ma la stessa disciplina vale due volte: il carico di bite e' INVARIATO da settimane (6.100-6.400 righe BTC/giorno prima e dopo, immagine ferma al 09/06) e i log MCP non precedono il riavvio → le 429 spiegano come si perdono le chiamate, non perche' proprio quel giorno. La causa del cambiamento resta ignota. Nessuna azione:cron_booke' gia' a:07, fuori dalla finestra di ~26s. Diario2026-07-30-vrp-quote-reali.md. REGOLE: (a) una nota di diagnosi cablata e' peggio di nessuna nota — nessuna manda a guardare i dati, una sbagliata manda sulla pista sbagliata e sembra una misura; (b) se un errore si ingoia per non bloccare, si registra nel punto in cui lo si ingoia (non c'e' un secondo momento buono: quando la diagnosi serve, il guasto e' rientrato); (c) un'allerta risponde a due domande — cosa (decide) e perche' (ripara): misurare solo la prima costa un'intera occorrenza del guasto; (d) distinguere guasti diversi anche quando l'azione e' la stessa (tre cause → tre riparazioni); (e) una mitigazione da un'osservazione sola si applica pure, ma si scrive che lo e'. ✅ FOLLOW-UP CHIUSO 2026-07-26 — la misura dedicata sugli INGRESSI e' fatta: NON e' un difetto, il verso e' LASCIARLO.scripts/research/r0726_skh_partial_entry.py, testtests/test_skh_partial_entry.py(10), diario2026-07-26-skh-partial-entry.md. Confronto di due path identici in tutto (livelli, uscite intra-barra, cap, fee) tranne quando si valuta l'ingresso: LIVE = a ogni confine orario dentro il bin 230m (cio' che il cron fa oggi), BACKTEST = solo a chiusura di bin. ΔSharpe su 3 offset x 2 asset: −0.01/+0.04/+0.44/+0.32/+0.59/ +0.98 → 6/6 non negativi, mediana +0.38. All'offset 0 (l'ancora fortunata del backtest, 93-98° pctl) l'effetto e' ~0 sul FULL ma l'hold-out BTC fa 1.12 live vs 0.71 backtest. I falsi ingressi (segnale che evapora) sono ~5/anno/asset, e cannibalizzano il capmax_per_daysolo 2-3 volte in 7 anni (0.6-0.9% degli ingressi veri). Meccanismo: SKH01 e' un Donchian breakout — aspettare fino a 230 min la chiusura del bin fa pagare il movimento gia' avvenuto (ingresso 0.25-0.26% peggiore in media); e siccome i livelli sono percentuali sull'ingresso (long sl4%/tp10%, short sl2%/tp8%), lo stesso 0.26% vale il 6-13% della distanza dallo SL contro il 2.6-3.3% di quella dal TP → vantaggio asimmetrico a favore della sopravvivenza del trade (win rate +8pp ETH/+2pp BTC). Due attacchi superati: (a) il divario NON e' concentrato — togliendo i 5 giorni migliori si ALLARGA (ETH@460 35.6x vs 3.0x); e' il backtest il path concentrato (~39% del log-equity in 5 giorni contro 17-22% del live); (b) nessun look-ahead intra-bin — troncando i 5m alle sole barre gia' chiuse la risposta e' identica in 289/289 osservazioni intra-bin e il prezzo d'ingresso e' sempre l'ultimo close 5m disponibile (test permanentetest_nessun_lookahead_intra_bin; serviva perche' il self-check valida solo a chiusura di bin → un leak solo-intra-bin gli sarebbe invisibile per costruzione). ⚠️ La lettura che conta e' la seconda: live e backtest girano due strategie DIVERSE e la differenza non e' neutra. Ogni numero di SKH01 nel progetto (Sharpe standalone, peso 25%, audit d'ancora 02/07, conferma peso/cadenza 24/07) e' calcolato sul path a chiusura di bin, che non e' quello che gira. Sommato alla misura del 26/07 sulle uscite (+0.081 Sharpe FULL di book sottostimato), il path live di SKH01 e' stato modellato in modo sistematicamente pessimistico su ENTRAMBI i lati. Cio' che NON si conclude: che l'ingresso intra-bin sia un miglioramento validato — e' stato misurato sugli stessi 7 anni su cui SKH01 e' stato selezionato, non e' passato perstudy_family_honestne' per un deflated-Sharpe, e la taglia varia molto fra ancore. Ma non serve promuoverlo: e' gia' cio' che il live fa; l'azione e' smettere di trattare il numero del backtest come l'aspettativa del live, NON "riparare" il live verso un backtest peggiore. Book, pesi, cron, config INVARIATI. ⚠️ Regole nuove (due errori catturati in sessione, entrambi del tipo che passa i test pigri): (i) un self-check su eventi rari si campiona sugli EVENTI, non sulla popolazione — la prima stesura stampava "BTC 80/80 OK" mentre la ricostruzione era rotta da un off-by-one di confine (obs//MS_LTFa chiusura cade nel bin successivo, vuoto → segnale 0): con gli ingressi al ~2% dei bin confrontava zeri con zeri, potenza zero, e le 2 sole divergenze ETH erano gli unici 2 bin con segnale vero. (ii) un conteggio di eventi su segnale GREZZO non e' un conteggio di trade — la prima scansione dava 1361 falsi ingressi e un costo inventato di −3%/anno di sleeve perche' ignorava cap+non-overlap del live (sovrastima ~20x); la spia era 305 giorni con un falso ingresso a fronte di 663 "eventi", impossibile con cap 1/giorno. (2) ✅ T2 — DVOLSPREAD ESCE DAL LIMBO (era fermo dal 21/06, unico sopravvissuto del marginal scorer indurito, mai ripreso: non nel book, non in monitor, non rifiutato). Passato ai due gate che nel giugno NON esistevano. ⚠️ La griglia dichiarata dall'agente ("72 celle") ne contiene 729 (6 assi x 3) → valutate tutte, scelta conservativa (piu' trial = DSR piu' basso). Plateau REALE e larghissimo: 729/729 celle con hold-out positivo, FULL [0.60,0.71]. Selection-on-holdout confermata ma mite: la cella pubblicata e' 83ª/729 sull'hold-out ma 471ª/729 in-sample. Scegliendo onestamente in-sample: FULL 0.68 / HOLD 0.69 (non il 0.93 pubblicato — citare 0.69) e DSR 0.953 PASS, mentre la cella pubblicata FALLISCE (0.947). Marginale ADDS + robust_oos + multicut + non-hedge + insample_edge + beats_noise; corr +0.11, alpha +7.4%/a, dSharpe book +0.08 FULL / +0.17 HOLD a w=15%. PROMOSSO a forward-monitor con i parametri ONESTI (zwin=180 k=2.0 lw=0.6 zw=1.1 tgt=0.17 svw=60), NON nel book: campione ATTIVO 1949/2691 g (prima del 2021-03 non c'e' DVOL, book flat) con hold-out attivo 1.6 anni, margine DSR sul filo, eweights_tilt_nullmai affrontato. ✅ MONITOR CABLATO (stessa sessione):scripts/live/paper_dvolspread.pyincron_daily.shdopofetch_dvol.py, statodata/paper_dvolspread/(gitignored), testtests/test_paper_dvolspread.py(10 casi). Inception 2026-07-25, apertura +0.184 = $111/gamba (cap $300), 2 libri MODELED $2000 / REAL $600. ⚠️ Strumentazione specifica: il book va flat quando manca il DVOL → un feed rotto produrrebbe zeri che, contati come evidenza, direbbero "nessuna perdita" invece di "nessuna misura". Contabilita' a 3 stati (ATTIVE / flat-da-segnale / flat-senza-dato) e finestra misurata in barre attive, non giorni di calendario; guardia sulla config che esce 1 seFROZENdiverge dallo stato salvato. GATE PRE-REGISTRATO: kill 2026-10-24 se Sharpe forward < −0.50; decisione 2027-01-24 solo se TUTTE — (a) Sharpe>0 [debole di proposito: con ~180 barre SE(Sharpe)≈1.4, una soglia alta sarebbe finta precisione] (b) marginale ancora ADDS+robust_oos+insample_edge (c) deflated-Sharpe ricalcolato ≥0.95 [e' qui il peso: se lo 0.953 gia' sul filo NON migliora con piu' dati, l'edge non c'e'] (d)weights_tilt_null; veto d'integrita' se barre attive <80% → si ESTENDE, non si decide su dati mancanti. (3) ❌ T3 — XSR01 NON GENERALIZZA fuori dal crypto (meccanismo CONGELATO W=45/sgn=+1 su 9 settoriali SPDR 1998+ / 28 ETF 30 anni, residuo vs SPY, demean giornaliero, split IWM/EFA riparati, annualizzazione √252). Diverso dal test del 25/07: quello era a coppie, questo e' la versione DEMEANATA (quella vera di XSR01). Lordo +0.24 (SECT9, p=0.193) e −0.14 (ALL28, p=0.747) vs null di permutazione a fee zero; netto −1.6/−1.8 ovunque; per decennio stesso profilo nei 2 universi (neg. 1998-2005, debolmente pos. poi) = piu' cambio di regime che edge. Il risultato che conta non e' lo Sharpe ma l'AMPIEZZA: il demeaning porta l'ampiezza effettiva 4.5→37.4 (8x) sul crypto ma solo 5.3→6.2 / 8.4→11.3 (1.2-1.35x) sulle azioni. Spiegazione strutturale (e migliore descrizione di XSR01 di quella della sua scoperta): il residuo OLS rimuove gia' il beta al fattore comune; sul crypto alle gambe RESTA un enorme fattore comune (ampiezza 4.5 su 50 gambe) ed e' quello che il demean toglie — sulle azioni il residuo-vs-SPY e' gia' quasi indipendente, quindi non c'e' niente da togliere. Per il gate del 23/10: conferma e CHIUDE la scappatoia lasciata aperta dal test a coppie; XSR01 e' crypto-specifico. NON prova che sia falso. Soglie del gate NON toccate: resta appoggiato interamente su finestra forward + haircut di eseguibilita' a $5.000, come pre-registrato. LEZIONI: (a) se si de-lucka una strategia va de-luckato anche il suo DEGRADO — ogni Δ fra due varianti misurato su griglia ancorata eredita la fortuna dell'ancora; (b) su offset appaiati la statistica e' la mediana delle differenze, non la differenza delle mediane; (c) un lead "in forward-monitor" senza monitor e senza scadenza e' un lead perso (DVOLSPREAD: 35 giorni di limbo) → applicare ai lead la stessa disciplina dei candidati (config congelata + gate pre-registrato + cron); (d) il claim di multiple-testing di un agente va ricontato, non creduto (72 dichiarate, 729 reali); (e) quando un meccanismo non generalizza, chiedersi PERCHE' vale piu' del fatto che non generalizzi. -
✅ VENUE WATCH — tripwire di fallimento exchange, CABLATO LIVE (2026-07-26). Risposta alla domanda "trova un sistema di protezione da fallimento exchange" sotto il vincolo della decisione appena presa (100% Deribit fino a $20k): se non si puo' ridurre l'ESPOSIZIONE, l'unica leva e' il TEMPO. Script
r0726_venue_tripwire.py(segnale) +r0726_venue_response.py(costo della risposta); produzionesrc/live/venue_watch.py+scripts/live/venue_watch.pyincron_book.sh; testtests/test_venue_watch.py(37); diari2026-07-26-venue-tripwire.md,2026-08-19-venue-watch-disciplina-allarmi.md,2026-08-21-venue-taratura-tre-referenze.md. Book, pesi, config INVARIATI. (1) Il segnale: un venue che gata i prelievi rompe l'arbitraggio → il suo prezzo si stacca dal consenso e ci RESTA. Il segnale e' |scarto|, non il segno (Mt.Gox andava a premio, un venue in fuga a sconto: dicono la stessa cosa). Consenso = mediana di venue USD indipendenti (Coinbase, Bitstamp, e Kraken dal 19/08 — vedi sotto); mai USDT (depeg 2022 → falsi allarmi giganti). Deribit sta a 3 bps dal consenso in mediana su 8 anni — fondo di rumore bassissimo, ed e' cio' che rende possibile una soglia con margine. ⚠️ Le "65.043 ore BTC" citate qui fino al 21/08 erano le ore del consenso con bitfinex dentro, che la produzione non ha mai avuto: sull'insieme reale sono 69.633 (ETH 64.541 invariato). (2) Taratura CONGELATA = 100 bps persistenti 4h a segno costante. Criterio dichiarato prima, perche' i due ovvi sbagliano in versi opposti (provati entrambi): minimi bps → 25bps/24h consuma 24 delle ~72h che diede FTX; minime ore → 500bps/2h manca FTX (margine 0.6x). Regola adottata: (a) zero falsi allarmi su entrambi gli asset in 8 anni; (b) margine ≥3x sul caso storico piu' debole (FTX ~300bps) → soglia ≤100bps; (c) a quei vincoli, minima latenza. Margine finale 3x FTX / 5x QuadrigaCX / 10-20x Mt.Gox. ⚠️ CORREZIONE 2026-08-21 — la gamba (a) NON e' soddisfatta dalla configurazione che gira, e la frase "zero falsi allarmi inclusi crash COVID 2020-03" era FALSA: il falso allarme E' il COVID. Vedi il blocco (8) in fondo. Il punto (100 bps, 4h) resta, per economia e per la gamba (b). (3) ✅ CONTROLLO POSITIVO superato (obbligatorio: un rilevatore tarato per non segnalare e' indistinguibile da uno rotto). Puntato su Bitfinex 2018-19 (problemi bancari/Tether): 22 episodi, il piu' lungo 2.324 ore consecutive a +447bps di picco, altri a 1.151h/+663bps e 496h/+1136bps. 22 scatti dove il problema c'era, 1 solo su Deribit in 8 anni (era dichiarato 0 — vedi (8)). E la DURATA risponde alla domanda vera: un venue gated resta dislocato per settimane → 4h di latenza costano una frazione trascurabile del preavviso. (4) Economia della risposta: costo ATTESO di un falso allarme (flat 3 giorni, misurato sul book reale a ogni data d'inizio) = 0.248% di equity (coda p5 −2.065%); guadagno di un vero positivo = 100%. Break-even:p_annua > (falsi allarmi/anno) × 0.00248→ a 1 ogni 8 anni serve p > 0.031%, a 12/anno servirebbe p > 2.97%. Il valore sta nella SPECIFICITA', non nella sensibilita'. ⚠️ Errore mio corretto: il break-even si calcola sulla media, non sul p5 (con la coda esce 8.3x piu' severo e la conclusione si ribalta). (5) Tre stati, e il terzo NON e' il primo:OK/ALERT/BLIND(referenze irraggiungibili o in disaccordo fra loro → dopo 12h e' un allarme suo). "Non vedo" non e' "va tutto bene" — stessa lezione della contabilita' a 3 stati dipaper_dvolspread. ALLERTA, NON BLOCCA: l'azione a un vero positivo e' prelevare (manuale — una chiave API con permesso di prelievo sarebbe essa stessa un rischio), e bloccare non protegge il saldo, che e' a rischio anche stando flat. Runbook pre-deciso nel docstring del modulo (escludere guasto referenze →public/status→ prelievo di prova, unica evidenza diretta → flat + prelievo totale). (6) ⚠️ Cio' che NON copre, e non e' un argomento per riaprire il 26/07: un fallimento senza finestra (furto di chiavi, sequestro, exit-scam notturno) non lo prende nessun tripwire; quella parte dipresta scoperta e la sola difesa e' lo split. E il preavviso di 200-2.300 ore viene da un caso osservato: e' un'ancora, non una distribuzione. REGOLE: (a) un rilevatore tarato per non segnalare va validato su un controllo positivo; (b) una soglia si sceglie con un criterio dichiarato prima (i criteri ovvi sbagliano in versi opposti); (c) la persistenza richiesta e' latenza e va confrontata con la durata del fenomeno da rilevare; (d) un break-even si calcola sulla media, non sulla coda; (e) ⚠️ una diagnostica STAMPATA non e' un controllo — la prima corsa tronco' il campione da 8 anni a 29 giorni per un inner-join con Kraken (che serve solo ~700 candele) e la copertura era gia' a video: ora c'e' una guardia che ferma lo script (2ª occorrenza in un giorno dopo GTAA01 — l'outer-join con referenze di lunghezza diversa e' una trappola ricorrente); (f) un controllo positivo finito dentro il ramoelsenon gira mai (trovato in sessione: era esattamente il difetto che doveva prevenire). ✅ (7) DISCIPLINA DEGLI ALLARMI + TERZA REFERENZA + SPECIFICHE CONTRATTO (2026-08-19) — (bullet scritto il 21/08: la sessione era in un diario e in un commit e NON in memoria operativa, 2ª occorrenza dopoedge_watch). Nato da 4 🚨 identici il 18/08 per una manutenzione Deribit annunciata (14/08 per il 18/08 09:00 UTC, downtime dichiarato 15-30 min) che ha sforato fino alle 14:07 UTC. Il book si era comportato bene (astensione alle 09:07 e 10:07, "conto non leggibile → non eseguo a cieco"): il difetto era negli allarmi. (a) Il blocco piattaforma era unifsecco senza memoria, accanto a un rilevatore che allerta una volta per streak → ora passa dalock_step()pura: manutenzione entroMAINT_GRACE_HOURS=2 → ⚠️ una volta; che sfora → 🚨 una volta («ha SFORATO»); blocco senza manutenzione dichiarata → 🚨 subito; rientro annunciato una volta;public/statusilleggibile → NIENTE (dichiarare «e' rientrato» perche' non si e' riusciti a guardare sarebbe la bugia peggiore). Un allarme massimo speso per un evento atteso e' un allarme che non verra' letto il giorno che e' vero. (b) Il messaggio stampavalocked=truecablato mentre il parser accetta anchepartial→ dichiarava un valore che non aveva letto, e il runbook manda a controllare proprio quel campo; ora stampa e salva il grezzo. (c) ⚠️ Il difetto che poteva costare: il 18/08 Deribit ha cambiato tick e size dei perpetual lineari USDC (BTC tick 0.5→0.1, ETH 0.05→0.01, ETH min/step 0.001→0.0001) e la tabella_CONTRACTdideribit.py, cablata a mano, non se n'e' accorta. Nessun ordine rifiutato e non per merito nostro: erano riduzioni, e un valore piu' grosso resta conforme (costo effettivo: granularita', incremento minimo ETH $1.92 invece di $0.19). Il giorno che Deribit ALZA un minimo la stessa cecita' fa rifiutare gli ordini. Cablatocheck_specs()nel venue_watch orario, fuori dal percorso ordini: la tabella dichiarata resta l'AUTORITA' per costruire un ordine, il venue e' il controllore (prendere i valori dall'API dentro l'esecuzione renderebbe l'ordine dipendente da come ha risposto una GET = non ricostruibile). Verdetti:granularita'(dichiarato piu' grosso → conforme, ⚠️) vsrifiuto(dichiarato piu' fine → 🚨). Uno strumento non letto finisce innon_letti, non conta come «combacia». (d) Aggiunta Kraken come terza referenza: Coinbase ha comprato Deribit e una referenza che e' la casa madre non misura piu' se Deribit scolla dal mondo. ⚠️ (8) LA TARATURA RI-MISURATA (2026-08-21) — «zero falsi allarmi in 8 anni» non ha mai descritto la produzione, e il falso allarme e' il COVID. Scriptr0821_venue_refs.py, diario2026-08-21-venue-taratura-tre-referenze.md. Soglie, book, config INVARIATI. (i) Il numero pubblicato veniva dal consenso Coinbase+Bitstamp+Bitfinex dello script di ricerca; il sorvegliante live girava su Coinbase+Bitstamp. Due liste di referenze in due posti diversi, e nessun test poteva accorgersene. Sull'insieme reale: 1 falso allarme in 8 anni, il 2020-03-13 07:00-10:00 UTC, 4 ore a −418 bps di picco su BTC — cioe' proprio l'evento che questo bullet elencava come esempio di cio' su cui NON scattava. La soglia minima a zero falsi allarmi a 4h e' 150 bps (BTC), non 100. (ii) Kraken non lo ripara: su 8 anni porta un mese (tetto ~700 candele dell'endpoint pubblico, ri-verificato oggi: 704 barre su 70.286 richieste = 1,00%) → LIVE-post ≡ LIVE-pre sulla storia lunga, numeri identici. (iii) Perche' spariva a 3 referenze, ed e' il punto trasferibile: con bitfinex dentro 1 delle 4 ore diventa BLIND → lo streak si azzera e l'episodio non esiste, ma la dislocazione e' ancora li' (mediana −343 bps). Lo zero non veniva da un consenso piu' accurato, veniva da un'ora buttata (ore utilizzabili 93,4% contro 100,0%). (iv) La direzione dichiarata il 19/08 e' confermata, la sua TAGLIA dipende dal venue (confronto appaiato, stesse ore): con bitfinex le ore non-BLIND passano 99,95% → 86,04% = −13,91 pp; con kraken +0,00 pp (|scarto| mediano appaiato −0,04 bps). Non e' una proprieta' del numero tre: e' quanto la terza referenza e' d'accordo con le altre. (v) Controllo positivo intatto: Bitfinex 2018-19 → 22 episodi, il piu' lungo 2.324h, picco 1.136 bps = 11,4x la soglia. (vi) DECISIONE: (100 bps, 4h) NON si tocca, ma la giustificazione cambia. 1 falso allarme in 8 anni = 0,125/anno × 0,248% = 0,031%/anno di equity attesa contro il 100% che un vero positivo evita, e ognipplausibile (0,5-5%) e' 16-160x sopra il break-even; alzare a 150 bps porterebbe il margine su FTX da 3,0x a 2,0x, sotto la gamba (b) dichiarata prima di guardare i dati. Il numero da citare e' «1 in 8 anni» — che e' esattamente l'esempio gia' usato al punto (4): la memoria si contraddiceva da sola e la meta' giusta era quella dell'economia. REGOLE NUOVE: (g) un numero di taratura si etichetta con la CONFIGURAZIONE, non solo con la finestra — «zero falsi allarmi in 8 anni» era vero e inutile perche' descriveva un consenso che la produzione non ha mai avuto; (h) uno "zero" si legge accanto alla quota di campione utilizzabile: meno falsi allarmi perche' si vede meglio e meno perche' si vede di meno hanno lo stesso valore stampato e valore opposto; (i) quando due affermazioni della stessa memoria si contraddicono, la contraddizione e' informazione — una delle due e' stata scritta guardando i dati; (j) una nota che dichiara un debito puo' sottodimensionarlo: il 19/08 diceva «il numero non e' ri-misurato», e il numero era sbagliato prima della modifica che lo aveva fatto dichiarare. RESTA APERTO: il Rulebook Deribit del 12/08 (ADL, perdita socializzata, emergency powers, conti dormienti) non lo sorveglia nessuno;MAINT_GRACE_HOURS=2 presume gli annunci invece di leggerli (duelocked=truein 4 giorni: 18/08 ~4h, 21/08 ~1h); la terza referenza non e' validabile sulla storia. -
🚨 IL TRASPORTO DEGLI ALLARMI E' UN PUNTO SINGOLO DI GUASTO — misurato 2026-08-23, NON riparato (produzione, decisione dell'operatore). Registro
docs/research/RESULTS-0822.md(sezione NOTIFIER). Il progetto ha tarato il rilevatore (venue_watch: 1 falso allarme in 8 anni, controllo positivo su 22 episodi Bitfinex, margine 3x su FTX) e mai il trasporto.src/live/notifier.send()fa UN tentativourlopen(..., timeout=10),except Exception: return False, nessun retry;notify()ritornaboolescripts/live/venue_watch.py:80non lo guarda;logs/cron_book.logha 0 occorrenze di un qualsiasi esito d'invio → quando serve sapere se l'allarme e' arrivato, l'informazione non e' stata scritta (la regola del 29/07 — "se un errore si ingoia per non bloccare, si registra nel punto in cui lo si ingoia" — non e' mai stata applicata al notifier). 🚨 E lo stato e' marcato PRIMA dell'invio: invenue_watchla riganew.alerted = Truesta dentro la logica pura e viene persistita comunque; alle ore successivealready = st.alerted and st.sign == signfa tornare"WATCH"invece di"ALERT"→notifynon viene piu' chiamata per quell'episodio. Un 🚨 perso e' perso per l'episodio intero, e gli episodi storici durano 200-2.324 ore a segno costante: e' esattamente il caso in cui la ri-notifica non arriva mai. Taglia misurata: 6,9% di invii falliti (2/29, IC95 Wilson [1,9%, 22,0%]) sul digest giornaliero. ⚠️ Fonte dichiarata: e' il percorso del digest usato come proxy di quello d'allarme, che non ha dati propri — ed e' questo il punto; stessa funzione, stesso endpoint, stesso timeout. ⚠️ La nota stampata ("config Telegram assente o rete KO") conflazione due cause e la prima e' falsa: le chiavi sono presenti in.env(verificato) → manda a controllare il posto sbagliato, stessa forma del difetto codificato il 29/07, su un percorso diverso. Perche' conta piu' del suo numero: l'economia del 26/07 (falso allarme 0,248% di equity contro il 100% che un vero positivo evita, break-evenp > 0,031%) assume che l'allarme arrivi, e questa e' l'unica mitigazione rimasta dopo la decisione 100% Deribit fino a $20k contro un rischio prezzato a P(perso tutto) 10/18/34/64%. Riparazione in tre pezzi indipendenti, NON eseguita: (a) retry con backoff insend(); (b) registrare l'esito nel punto in cui l'eccezione viene ingoiata; (c) marcarealerted=Truesolo a invio riuscito. ⚠️ (c) cambia il comportamento — rende l'allarme ripetitivo finche' non passa: verso giusto per un 🚨, sbagliato per un ⚠️ → decisione dell'operatore, non un fix ovvio. REGOLA: un rilevatore si valida sul segnale E sul TRASPORTO — tarare la soglia e non misurare mai se il messaggio arriva lascia un punto singolo di guasto a valle di tutto il lavoro di taratura, e non produce numeri, quindi non si fa notare. -
❌ GTAA01 NON E' DEPLOYABILE — blocco PRIIPs CONFERMATO sul conto reale (2026-07-26). Nato da una domanda dell'operatore ("GTAA01 puo' essere in revolut?"), verificato lo stesso giorno tentando l'ordine. Il broker rifiuta: "Trading limitato — Questo prodotto non dispone di un KID in inglese o in una lingua approvata per il vostro Paese. I clienti retail possono negoziare prodotti retail preconfezionati solo se e' disponibile un KID appropriato." SPY/QQQ/IWM/TLT/GLD/HYG sono ETF domiciliati USA: gli emittenti non pubblicano il KID e i broker UE ne vietano l'acquisto al retail. ⚠️ Le quotazioni restano visibili — vedere i prezzi non e' poter comprare, ed e' esattamente cio' che rendeva l'assunzione invisibile. COSA CADE: lo sleeve cosi' com'e' non e' deployabile, e con esso il piano di attivarlo a ~$13k. Restano valide come ricerca e nulle come deploy: la validazione a 30 anni (22/06), il fix dei costi IB (25/07),
GTAA_MIN_CAPITAL, e il risultato del LOO (26/07) che lo indicava come l'unico sleeve positivo nel 100% delle estrazioni su tutte e tre le metriche. COSA NON CADE: tutte le traiettorie, i muri e le tabelle di rendita pubblicate usanobook_series(with_gtaa=0)= solo TP01+SKH01 su Deribit → nessun numero del piano va rifatto. E il book live non lo include. REGOLA: la negoziabilita' sul conto REALE va verificata quando lo sleeve entra in RICERCA, non quando entra nel book. Qui 5 settimane di misure poggiavano su un'assunzione mai controllata, e il controllo e' costato un ordine di prova. E' l'analogo azionario di cio' che il progetto fa gia' rigorosamente sul crypto (min-order, haircut small-cap, eseguibilita' a $600): la stessa disciplina non era stata applicata all'equity. -
✅ LA VIA D'USCITA UCITS E' APERTA E COSTA ~ZERO — misurata 2026-07-26 (domanda dell'operatore: "usiamo revolut o degiro"). E la premessa su cui era stata scartata era MIA e FALSA. Script
fetch_ib_ucits.py+r0726_gtaa_ucits.py; modulo nuovosrc/data/eq_crosscheck.py; testtests/test_eq_crosscheck.py(14) +tests/test_gtaa_ucits.py(10); diario2026-07-26-gtaa-ucits.md. Book/pesi/cron/config INVARIATI. (0) ⚠️ CORREZIONE: la nota diceva "storia UCITS piu' corta → si perde la validazione a 30 anni". FALSO per un motivo strutturale: il PRIIPs vieta di COMPRARE, non di GUARDARE. I prezzi dei 6 ETF USA restano leggibili (l'operatore li aveva sul terminale mentre l'ordine veniva rifiutato) → il segnale gira sui 30 anni per sempre, cambia solo il veicolo su cui si incassa. La storia corta serve solo a misurare la deviazione del veicolo, un drift lento. Regola: prima di dichiarare che un vincolo esterno distrugge un risultato, chiedersi cosa vincola esattamente — "non posso comprare" ≠ "non posso vedere". (1) Il cambio di veicolo NON costa. Tre lenti a un grado di liberta' per volta su 6.3 anni comuni: L0 (segnale USA + rend. USA, pubblicato) Sh 0.81 / CAGR 3.96%; L2 (segnale UCITS + rend. UCITS, deploy) Sh 0.84 / CAGR 4.08%. Drag del veicolo +0.10%/anno EW, coerente coi TER (controllo piu' netto: GLD 0.40% vs IGLN 0.12% → atteso +0.28%, misurato +0.36%); e la ritenuta USA 15% sui dividendi (~35bps) e' A FAVORE dell'UCITS e non e' nel drag misurato (ADJUSTED_LASTUSA e' al lordo). (Ipotesi fiscale dichiarata, fonte secondaria.) ⚠️ Lo stimatore ovvio da' la risposta sbagliata: la media delle differenze giornaliere dava −0.47%/anno su CSPX contro −0.06% vero. Le due serie seguono lo stesso indice ma sono campionate a orari diversi (Londra chiude 4h30 prima) → la differenza giornaliera e' dominata da uno sfasamento che si inverte il giorno dopo: SE ~7%/anno, 15× la quantita' stimata, piu' il drag di varianza. REGOLA: la deviazione fra due veicoli sullo stesso indice si misura sul RAPPORTO CUMULATO (e' una domanda sul drift), mai sulla media delle differenze. (2) ✅ IL VINCOLO NON E' IL BROKER, E' IL PREZZO DI UNA AZIONE — e quello e' una SCELTA. CSPX costa $802 e VUAA $144 sullo stesso S&P 500. Due insiemi: STORIA (CSPX/EQQQ/XRSU/ IDTL/IGLN/IHYU, finestra lunga, per misurare) e DEPLOY (VUAA/XNAS/R2US/IDTL/IGLN/IHYU, prezzo unitario basso, per eseguire). A $3.000 con esecuzione a azioni INTERE: STORIA tiene 4/6 gambe ed e' a mercato il 33% del tempo; DEPLOY tiene 6/6 al 65%, ΔSharpe −0.04. Il frazionamento del broker NON serve. Scartati benche' con piu' storia: RTWO (Russell 2000 quality), CSUSS (ESG), IDP6 (S&P 600) — equivalenza dell'INDICE prima della storia. ⚠️ Letto sulla colonna gambe vive + vol, non su Sharpe: il vincolo intero alza lo Sharpe a capitale piccolo perche' arrotonda in giu' e paga meno commissioni = null de-levering, 4ª occorrenza (VRP-DD, TP01×DVOL, MAT01). (3) Il costo per ordine. Col canonico lo sleeve fa 77 ordini/anno a $3k, 102 a $10k, 149 a $50k; soglia oltre cui non vale la pena (Sharpe<0.45) = $0.90/ordine a $3k, $2.23 a $10k, $7.62 a $50k. Listino proporzionale ≈ indifferente al capitale, listino fisso = tassa regressiva (regola 25/07 riconfermata su altro venue). ⚠️ Revolut/Degiro NON sbloccano gli ETF USA: il PRIIPs vale per ogni intermediario UE, IB e' anzi fra i piu' permissivi. -
✅ ADDENDUM 2026-07-27 — il numero di ordini e' un PARAMETRO, e con la banda giusta il costo smette di essere binding su qualunque broker UE. Nato dalla correzione dell'operatore "io ho gia' Revolut e Degiro e li uso da anni, IB sono solo iscritto": la raccomandazione del 26/07 ("restare su IB") poggiava su "il conto esiste gia'", che era falso. Il gateway IB serve solo per i dati del segnale (basta il paper), quindi il broker di esecuzione e' libero. Script
r0727_gtaa_broker.py, testtests/test_gtaa_broker.py(9). Book/pesi/cron/config INVARIATI. (a) I 77-149 ordini/anno sono la conseguenza diREBAL_EVERY=5/REBAL_BAND_USD=50, scelti il 25/07 per il listino IB su azioni USA e a una taglia sola. A cadenza settimanale allargare la banda non costa: Sharpe a costo zero 1.27 ($50) → 1.27 ($400) mentre gli ordini vanno 84 → 23. Rallentare la CADENZA invece costa (1.27 → 1.12 mensile). Meccanismo:_exposuree' la media di 4 indicatori binari, si muove a scatti di 0.25 ≈ $417 su una gamba da $1.667 → la banda filtra la deriva del vol-target, non il segnale di trend. ✅ Controllo fuori finestra: sui veicoli USA su 10 anni lo Sharpe a costo zero passa 0.98 → 0.96 mentre gli ordini calano del 74% (133 → 35) — non e' un artefatto della finestra corta UCITS (3.2a). (b) ⚠️ MA la banda in dollari ASSOLUTI e' la parametrizzazione sbagliata. A $3.000 una banda da $400 e' l'80% della gamba: 3 ordini/anno, a mercato il 45% del tempo invece del 66%. Lo Sharpe resta 0.71 — accettabile — su una strategia che ha smesso di seguire il proprio target. E' il null de-levering in veste nuova: non travestito da "meno drawdown" ma da "meno costi". REGOLA: quando un parametro di esecuzione e' espresso in valuta assoluta il suo effetto dipende dal capitale, e il controllo non e' lo Sharpe ma la QUOTA DI TEMPO A MERCATO. (c) Configurazione proposta: banda = 25% della gamba → 21 ordini/anno a OGNI capitale (invariante), esposizione 66% ovunque; soglia per ordine $5.65 a $3k / $18.90 a $10k / $47 a $25k contro i $2.08 a $3k del canonico. E' la differenza fra "serve un broker economico" e "va bene qualunque broker europeo". ⚠️ Proposta, non cambio di produzione: tarata su questa finestra, non passata perstudy_family_honestne' per un deflated-Sharpe — e GTAA01 non e' deployabile prima dei $20k, quindi c'e' tempo per validarla. (d) Cosa cercare sul proprio conto — per ISIN, non per ticker (da contract details IB; tutti domiciliati IE, quotati a Londra in USD): VUAAIE00BFMXXD54($143.80) · XNASIE00BMFKG444($65.74) · R2USIE00BJ38QD84($86.35) · IDTLIE00BSKRJZ44($3.09) · IGLNIE00B4ND3602($79.06) · IHYUIE00B4PY7Y77($94.12). Nessuna azione oggi (decisione venue: 100% Deribit fino a $20k). ⚠️ CORREZIONE 27/07 A QUESTO PUNTO. Avevo scritto "una linea in EUR aggiunge la conversione per ordine → prendere quella in USD". E' vero solo per un conto in USD. Per un conto in EURO (retail italiano su Revolut/Degiro) vale l'OPPOSTO: la linea USD costringe a convertire a ogni ordine, quella EUR no. L'esposizione economica e' identica (il fondo detiene attivi USD e nessuna delle due linee e' coperta): la valuta di quotazione non copre nulla, decide solo se serve una conversione. REGOLA GIUSTA: prendere la linea nella valuta del proprio saldo. Misurato (turnover lordo $13.655/anno su $10k, 21 ordini): 15bps −0.04 Sh/$20 a., 25bps −0.07 Sh/$34 a., 50bps −0.14/$68 → a 25bps equivale a ~$1.6 in piu' per ordine, piccolo rispetto alla soglia di $18.90. REGOLA: un costo di conversione non e' una proprieta' dello strumento ma della coppia strumento-CONTO. (f) Equivalenze e ripieghi, verificati su contract details IB (27/07). ZPRR (Xetra EUR) == R2US (Londra USD): stessa ISINIE00BJ38QD84, stesso fondo, stesso NAV → se un broker non quota la linea di Londra, quella di Xetra e' identica (e su conto in euro, migliore). REGOLA: si cerca per ISIN, non per ticker — lo stesso fondo ha ticker diversi su borse diverse. ⚠️ SPY4IE00B4YBJ215NON e' small cap ne' S&P 500: e' SPDR S&P 400 MID cap (l'S&P 500 e' SPY5IE00B6YX5C33). Misurato come ripiego della gamba small: su 6.5 anni Sharpe 0.86 vs 0.86, CAGR 4.26% vs 4.20%, corr fra i due sleeve 0.991, peggiore in 3/7 anni = moneta (sulla finestra corta di 3.2a sembrava −0.15: rumore) → ripiego accettabile, per ragione meccanica (small e mid USA correlano ~0.95 giornaliero, un TSMOM si accende negli stessi giorni). Non e' "validato": 6.5 anni non distinguono due gambe cosi' simili, ed e' esattamente perche' la scelta non conta. Se c'e' una linea Russell 2000, si usa quella. (g) ✅ DEGIRO HA TUTTE E SEI LE GAMBE — verificato sul conto reale (2026-07-27, screenshot watchlist "Pythagoras"). Era Revolut a non avere R2US. Su Degiro: VUAA e XNAS su Tradegate in EUR, R2US/IDTL/IGLN/IHYU su LSE in USD. ✅ Verifica indipendente che le linee EUR siano gli stessi fondi (dai dati, non dallo screenshot): il rapporto prezzo-IB/prezzo-Degiro dev'essere un solo cambio → VUAA 1.1341, XNAS 1.1315, scarto 0.23%; le altre 4 stanno a 0.993-0.998 (gia' USD). Due fondi diversi non darebbero lo stesso cambio. ⚠️ ERRORE MIO, dello stesso tipo che avevo appena codificato: per cercare le linee in euro delle altre 4 gambe ho interrogato IB per TICKER sulle borse tedesche → "nessuna linea EUR" su 4/4, falso. Cercando per ISIN ognuna ce l'ha: ZPRR (=R2US), IS04 (=IDTL), EGLN (=IGLN, Londra EUR), IS0R (=IHYU). Un "assente" da una ricerca per ticker su una borsa dove quel ticker non esiste NON significa "non esiste". Turnover per gamba a $10k (21 ordini/anno): IDTL 9 ordini / $6.257 = 46%, VUAA $2.289 (17%), IGLN $1.695 (12%), XNAS $1.614 (12%), IHYU $958 (7%), R2US $843 (6%) → il turnover e' concentrato, il 71% e' su gambe in USD ($9.752/anno, conversione $24/a a 25bps, $49 a 50bps = 6-12% del CAGR). Spostare la sola IDTL su IS04 copre il 64% del turnover convertibile. ⚠️ Non e' un risparmio netto (spread Xetra piu' larghi delle linee primarie di Londra + tariffa di connettivita' per borsa) e su $10k parliamo di decine di dollari l'anno in entrambe le direzioni: non e' una decisione importante, ed e' piu' utile dirlo che costruire una precisione finta. ⚠️ Il prompt W-8BEN di Degiro ("aliquota ridotta della ritenuta USA") non riguarda queste sei: sono fondi IRLANDESI, non titoli USA — la ritenuta 15% la subisce il fondo al proprio interno e nessun modulo dell'investitore la cambia. Stato: PREPARAZIONE, non azione (saldo Degiro €328,92; GTAA01 richiede ≥$3k e la decisione venue tiene tutto su Deribit fino a $20k). LEZIONE: una raccomandazione poggiata su un fatto non verificato sul conto reale vale quanto quel fatto — due volte in due giorni un'assunzione sul conto ha cambiato la conclusione (prima la negoziabilita' PRIIPs, poi quale conto e' davvero operativo). (e) "degiro ha api?" — NO, e costa −0.02 di Sharpe. DEGIRO non espone una API di trading ufficiale al retail; Revolut nemmeno (la sua e' per pagamenti); IB si'. I wrapper NON ufficiali degli endpoint interni girano su credenziali + seed 2FA e si rompono in silenzio a ogni cambio di front-end — e il progetto ha gia' pagato quel prezzo (fresh_5m, 26/07): un esecutore automatico che puo' rompersi senza dirlo e' peggio dell'esecuzione manuale. Misurato invece il costo di NON automatizzare: carico operativo 15 settimane/anno con ≥1 ordine (29% dei controlli, 1.4 ordini per volta); costo del ritardo su 10 anni 1g −0.02 (peggiora in 6/11 anni = moneta), 3g −0.13, 10g −0.27. ⚠️ Sulla finestra UCITS di 3.2 anni la curva NON e' monotona (5g −0.26, 10g −0.13) → il campione corto non risolve differenze di questa taglia, si legge la finestra lunga. Il costo non e' il ritardo tipico ma la CODA: il rischio e' la dimenticanza, e si copre con un ALLARME non con una API (gtaa_rebalance_planesiste gia' in produzione, nato per un esecutore; l'allerta Telegram c'e' gia' sul book live). ⚠️ Lato opposto, vero: il resto del book e' automatico, una gamba manuale aggiunge un modo di fallire che oggi non c'e' — argomento reale a favore di IB, che pero' richiede un secondo venue e quindi cade sotto la decisione venue ($20k). REGOLA: una capacita' mancante si valuta sul costo di non averla, non sulla sua assenza. -
📅 NUOVO SCHEMA FEE DERIBIT dal 2026-08-01 — misurata la CURVA, nessuna azione oggi (2026-07-26). Script
r0726_fee_sensitivity.py, testtests/test_fee_sensitivity.py(6), diario2026-07-26-fee-deribit.md. Book/pesi/cron/config INVARIATI. L'annuncio (taker piu' bassi, maker rebate piu' bassi, soglie VIP abbassate, nuovo VIP7, liquidation fee 1% su tutti i prodotti, spot a zero fino al collegamento con Coinbase) non contiene numeri e ⚠️ la tabella nell'articolo Insights e' un'IMMAGINE, non letta da fonte primaria → i valori indicativi (base ~5bps taker / 2bps maker, VIP7 2/0) vengono da un riassunto secondario e vanno etichettati come tali. Percio' e' misurata la curva:bps/lato %RT TP01 Sh SKH01 Sh BOOK Sh BOOK CAGR 0 0.00% 1.322 1.567 1.849 21.69% 3 0.06% 1.303 1.495 1.799 20.99% 5 0.10% 1.290 1.446 1.766 20.53% ← oggi 10 0.20% 1.258 1.324 1.682 19.39% 15 0.30% 1.226 1.200 1.597 18.26% Sensibilita' marginale del book: −0.017 Sharpe/bps, −0.23% CAGR/bps → anche un RADDOPPIO del taker costa 0.08 di Sharpe, meno della banda d'ancora dello stesso book (2.222 → 1.946). ⚠️ SKH01 e' ~4× piu' sensibile di TP01 (−0.69% vs −0.09% CAGR/bps: round-trip discreti vs posizione continua vol-targeted) → **se il taker salisse, il primo parametro da rivedere e' il peso 75/25**, non altro. **REGOLA DECISA IN ANTICIPO (per non decidere col numero davanti): taker ≤5bps/lato → non si tocca nulla; >10bps/lato → rivedere il peso di SKH01.** Punti irrilevanti e perche': maker — il book manda ordini market; tocca solo la raccomandazione T1 non implementata (TP resting per incassare il maker), che resta chiusa per il netting su strumento unico e il cui beneficio era quasi tutto "convertire una lotteria in certezza", non la fee. Liquidation fee 1% — live.jsonda' nozionale lordo max **1.00xl'equity** ( frac 0.5× 2 asset) con disaster-SL −30%: servirebbe un movimento avverso ~100%;⚠️ la conclusione poggia sul CAP, quindi e' cablata una guardia di decisione ( test_leva_massima_da_config_resta_sotto_o_uguale_a_1x): alzare il cap rompe il test.VIP/VIP7 — a $600 il volume 30g e' trascurabile, tier base a qualunque soglia. ✅ Cio' che il cambio non puo' rompere: tutti i backtest sono a 0.10% RT → se la fee scende diventano conservativi. AZIONE 1 agosto: leggere il tier reale in Account Settings e applicare la regola sopra. REGOLE: (a) a un annuncio senza numeri si risponde misurando la curva, non aspettando il numero; (b) dichiarare la qualita' della fonte (immagine non letta = dato secondario); (c) una conclusione che poggia su un parametro di config va legata a un test su quel parametro, o sopravvive al cambio che la rende falsa. -
✅ EDGE WATCH — criteri di kill del book LIVE, cablati (2026-07-26). (Bullet aggiunto il 27/07: era in cron dal 26/07 e NON stava in CLAUDE.md — il criterio di morte di cio' che gira con soldi veri non era nella memoria operativa.)
scripts/live/edge_watch.py(incron_daily.sh), taraturar0726_edge_death.py, testtests/test_edge_watch.py(11). Chiudeva l'asimmetria: gate di kill pre-registrati per i CANDIDATI, nessuno per il book. (A) RITORNO: Sharpe rolling 36m < −0.5 — falso kill 1.8% in 10 anni, riconosce l'edge morto nel 91% dei casi in ~3.8 anni. ⚠️ La lentezza non e' un difetto della regola, e' statistica: a 12 mesi la stessa regola ucciderebbe un edge VIVO nell'80% dei casi; a 12m il 56% dei casi "morto" e' indistinguibile da uno vivo. (B) PROTEZIONE: in un anno con DD buy&hold > 10%, il DD di TP01 deve restare sotto il 75% di quello — storico 8/8 anni di sinistro superati (protezione 1.8x-34.4x). Serve un criterio SEPARATO perche' il LOO misura il contributo hold-out di TP01 negativo nel 99.1% delle ancore: "non ha guadagnato" non e' evidenza di morte per uno sleeve difensivo — la sua morte e' non proteggere nel sinistro, e negli anni senza sinistro il criterio NON si valuta. Se (A) scatta il book non si spegne da solo: si riapreweights_tilt_null+ deflated-Sharpe sui dati nuovi. Se (B) fallisce 2 anni di sinistro consecutivi, il peso di TP01 va rimesso in discussione. Stato 27/07: Sharpe 36m +1.51, protezione 8/8. Diario2026-07-26-edge-death.md. -
✅ FEE WATCH + MONITOR HEALTH — due sorveglianze cablate (2026-07-27). Nessuna tocca l'esecuzione; entrambe in
cron_daily.sh. (1)scripts/live/fee_watch.py(test 13): il nuovo schema fee Deribit entra il 1° agosto e l'annuncio non ha numeri → invece di un promemoria, un sorvegliante. Legge il tier BASE dapublic/get_instrument(nessuna chiave; a $600 ogni soglia VIP e' fuori portata), oggi taker 5.00 / maker 0.00 / liquidazione 75-90 bps, applica la regola congelata (≤5bps nulla · >10bps rivedere il peso SKH01) e allerta su qualsiasi cambiamento dei tre.test_baseline_e_quella_dei_backtestlega la soglia al defaultfee_rt=0.001dibacktest_signals: se divergono, il test lo dice. ⚠️ CORREZIONE 2026-08-21 — sorvegliava lo STRUMENTO SBAGLIATO (test 13 → 17).INSTRUMENTSera la tupla cablata("BTC-PERPETUAL","ETH-PERPETUAL")= i perpetual INVERSE (regolati in BTC/ETH), mentre il book esegue sui LINEARI USDC (BTC_USDC-PERPETUAL). Due conseguenze: (a) il tier sorvegliato era di un prodotto mai tradato — oggi identico per caso (3.50/1.50 su entrambe le linee) ma la prova che si muovono in modo indipendente e' nel progetto: il cambio del 18/08 tocco' i SOLI lineari (inverse ancora tick 0.5/min 10.0, lineari 0.1/0.0001) → un aumento sulla sola linea lineare sarebbe stato invisibile e la regola ≤5/>10 bps applicata al numero sbagliato; (b) il cross-check sui trade reali non poteva misurare nulla per costruzione — chiedevatrade_historydi uno strumento con 0 fill e stampava «NON MISURATO» anche nei giorni con 4 esecuzioni (verificato: inverse 0 trade,_USDC3+1). OraINSTRUMENTSsi DERIVA dasrc.live.book.INSTRUMENT: la divergenza non e' un rischio da ricordare, e' impossibile. ⚠️ E non era un rename: le due famiglie hanno unita' DIVERSE — inverseamount=nozionale USD efeein valuta base; lineareamount=quantita' BASE efeegia' in USDC. Ripuntare senza correggerle avrebbe dato, su un fill vero (0.001 BTC @ 74.305,80, fee 0,02600703), ~2,6e8 bps invece di 3,50 — e senza sollevare nulla. Cablateconvenzione()(lineare/inverse/ignota: una famiglia non nota non si indovina) efee_bps_di_un_fill()pure; il cross-check ora gira e da' 3,50 bps effettivi = il tier esatto, e il report stampa lo scarto effettivo−tier con ⚠️ sopra 1 bps. REGOLA: un sorvegliante deve DERIVARE il proprio bersaglio dal codice sorvegliato, mai ridichiararlo — due liste in due file divergono in silenzio, e il giorno che divergono il sorvegliante continua a dire OK. 3ª occorrenza in un giorno della stessa forma (test dibook_livesenza potenza a libro flat, taratura divenue_watchmisurata con bitfinex mentre il live girava senza): un controllo puntato su una configurazione diversa da quella che gira passa sempre, e non sta controllando niente. (2)src/live/monitor_health.py+scripts/live/monitor_health.py(test 16): tre gate pre-registrati (STATARB 27/09, XSR01 23/10, DVOLSPREAD 24/10) si decidono su serie forward di cui una sola aveva una guardia d'integrita'. Un monitor fermo produce silenzio, e il silenzio in una serie di ritorni si legge come zero (stesso schema difresh_5me del feed-freeze 14/07). Misura due guasti, perche' uno solo non basta: coda (ultima barra vecchia) e buchi interni (copertura fra prima e ultima barra) — ⚠️ una serie bucata E fresca passa qualunque controllo di freschezza, ed e' il guasto che falsifica un gate senza farsi notare. Cadenze dichiarate per monitor (prevday e' orario, combo segue il calendario di borsa: sbagliarle = un falso allarme a settimana); soglia di copertura 0.80 riusata dal veto DVOLSPREAD perche' i gate restino confrontabili. Stati OK/FERMO/BUCATO/ASSENTE/NUOVO — "troppo giovane per un giudizio" non e' "sano". Controlli positivi obbligatori nei test. Stato 27/07: 6/6 giudicati, tutti OK (combo 96% per una festivita' chenp.busday_countnon conosce = limite dichiarato, conservativo). -
✅ BANDA GTAA01 AL 25% — VALIDATA, produzione NON toccata (2026-07-27).
r0727_gtaa_band_gate.py, testtests/test_gtaa_band_gate.py(13). Chiude il debito dichiarato il 27/07 ("tarata su questa finestra, non passata perstudy_family_honestne' per un deflated-Sharpe"). Griglia 30 celle (5 cadenze × 6 bande) su 29.9 anni del path di produzione, annualizzazione √252. (A) Selezione in-sample (cella scelta sui soli dati pre-2015, letta sul 2015+): proposta 4/30 in-sample, 5/30 hold-out → il rango NON migliora sull'hold-out, quindi non e' selection-on-holdout. La cella scelta al buio (cadenza giornaliera, banda 25%) vale +0.04 di Sharpe ma costa 250 controlli manuali/anno su un conto senza API → non e' una configurazione, e' un'ipotesi. (B) Deflated Sharpe 0.999 PASS (nullo 0.14). (C) ⚠️ il modo di fallire NON e' il de-levering: allargando la banda la vol non scende (0.99-1.10 del riferimento), si rompe il TRACKING (corr 0.951 a 25% → 0.907 a 40% → 0.859 a 60%) e lo Sharpe smette di migliorare insieme alla correlazione → nessuna zona premia il congelamento. Ma il 25% e' AL BORDO (0.951 contro soglia 0.95), non al centro di un plateau: citarlo cosi'. Invarianza: 25 ordini/anno a $3k/$10k/$50k (banda 25%, Sharpe 0.66/0.70/0.71) contro 65/92/134 (banda $50 fissa, 0.52/0.62/0.66) — ⚠️ 25 e non i 21 citati il 27/07: stimatore diverso (griglia dei controlli su 30 anni USA vs cambi di posizione sulla finestra UCITS di 3.2a); l'invarianza, che e' la proprieta' sotto esame, regge in entrambi. Impatto sul book: Sharpe FULL 2.221 → 2.221, maxDD 6.08% → 5.94% = zero (il book modella GTAA01 a $10k, dove la banda fissa gia' funziona) → il valore e' tutto al capitale piccolo (0.52 → 0.66 a $3k), cioe' al deploy.REBAL_BAND_USDNON cambiato: non sposta un numero pubblicato e lo sleeve non e' deployabile prima dei $20k → si applica al deploy, con questo gate come giustificazione. REGOLA: un parametro d'ESECUZIONE scelto guardando il risultato e' selezione come ogni altra e passa per gli stessi gate, anche quando "non tocca l'allocazione". ⚠️ CORREZIONE 2026-08-07 — il criterio (A) qui sopra e' RITIRATO: non misurava cio' che dichiarava, e il "4/30 in-sample, 5/30 hold-out" non e' un'evidenza. Il test lo aveva segnalato smettendo di passare (9ª/30 in-sample, 8ª/30 hold-out) senza che il codice fosse cambiato —data/raw/e' gitignored e il cron riscrive i parquet equity ogni notte conADJUSTED_LASTdi IB, che e' retroattivo. Misurato inr0807_gtaa_gate_resolution.py: (a) i due ranghi distavano 0.00116 di Sharpe su uno spread di griglia di 0.3124 (0.4%); (b) e soprattutto il criteriorank_in <= rank_ooslo passano 14/30 celle (47%) PER COSTRUZIONE — la somma dei ranghi e' la stessa nelle due finestre → e' una moneta, e il 27/07 la moneta era uscita bene. Contorno: spostamento tipico fra le due finestre 8 ranghi (max 25), Spearman IS/OOS +0.05. ✅ CRITERIO SOSTITUITO, e la proposta ne esce piu' forte di prima. La proposta e' una BANDA (la cadenza settimanale e' gia'REBAL_EVERY=5in produzione), quindi la domanda decidibile e' quale banda si sceglie a cadenza di produzione guardando solo il pre-2015: esce 25% = la proposta, con margine +0.0151 di Sharpe sulla seconda (13× il margine del vecchio criterio); chi avesse scelto sull'hold-out avrebbe preso 40% (controllo positivo: se coincidessero il gate non avrebbe potenza). Su tutta la griglia la cella al buio e' cadenza 1 / banda 25% — stessa banda. La proposta e' il CONTRARIO di una selezione-sull'hold-out. Regge identico sull'universo a 5 gambe (blind 25%, hold-out 40%, margine +0.0164). ⚠️ Il criterio dice da dove VIENE la scelta, non che sia la migliore sull'hold-out (con Spearman ~0 nessuna cella lo sarebbe): provenienza ≠ previsione. ⚠️ TROVATO PER STRADA, ed e' il difetto vero: TLT ha 13.5 ANNI DI STORIA IN MENO. Parte dal 2016-02-03 invece che dalla quotazione (2002-07-22) → GTAA01 gira su CINQUE gambe prima del 2016, e quella assente e' la gamba obbligazionaria, cioe' quella che diversifica. Non e' di oggi (cosi' fin dal primo giro nelcron_daily.log, 24/06 = prima della validazione del 27/07) e non e' un fetch da rifare: una richiesta retro esplicita a IB su questo conto ritorna 0 barre. Conseguenza metodologica: l'in-sample e l'hold-out di GTAA01 non sono la stessa strategia, e ogni confronto fra le due finestre su questo sleeve va letto cosi'. ✅ Guardia cablata (fetch_ib_equities.certify, testtests/test_eq_history_guard.py, 11):TRONCATO= storia persa rispetto al disco → il file NON viene sovrascritto (e neppure fuso:ADJUSTED_LASTe' ri-aggiustato all'indietro, incollare due vintage crea un salto sul giunto);STORIA-CORTA= parte >1 anno dopo la quotazione e non al tetto della richiesta (PRIMA_QUOTAZIONE, 6 simboli, fonte secondaria dichiarata). Controlli positivi obbligatori: giro normale, serie al tetto 30Y, ETF giovane, simbolo fuori tabella. REGOLE: (a) un criterio si misura sulla sua RISOLUZIONE prima che sul suo esito — se decide su una frazione di percento dello spread e' rumore anche quando passa; (b) un gate si valida contando quante volte lo passa un candidato a caso (qui 47%: il conto si poteva fare il 27/07 senza dati nuovi); (c) una certificazione che guarda solo DENTRO la serie non vede cio' che la serie ha PERSO — una serie troncata e' integra, senza gap, senza spike, senza duplicati, e passa tutto (3ª occorrenza dopo split 2:1 e contaminazione EUR/USD); (d) distinguere «giovane» / «al tetto della richiesta» / «troncato», o la guardia segnala sempre e viene ignorata; (e) un test che fallisce senza che il codice sia cambiato sta segnalando che i dati non sono versionati — si guarda sotto prima di toccarlo. Diari2026-08-07-crescita-fisco-etf-scelta.md§7 (scoperta) e2026-08-07-gate-gtaa-e-storia-troncata.md(risoluzione). -
📓 LIBRO DI BORDO — i trade allineati col tempo, il giornale e l'analista (2026-08-23).
src/live/{tradesdb,journal,analista}.py, CLI inscripts/live/, voci indocs/journal/, testtests/test_{tradesdb,journal,analista}.py(77). Strategia, pesi, config INVARIATI. 🚨 IL DIFETTO CHE L'HA FATTO NASCERE: i trade erano salvati e NON allineati col tempo.book_execute.pyscrivevats_utc = pd.Timestamp(r['last_data']), cioe' la data della barra di segnale: 19 righe su 19 a00:00:00, e un trade registrato SEI GIORNI prima di essere eseguito (ETH 0.04 @ 1.869,74: fill vero 2026-07-14T14:00, scritto 08/07). L'ora vera esisteva solo inlogs/cron_book.log— gitignored, fuori dal backup, ruotabile: la cronologia reale del libro live viveva in un file che una rotazione avrebbe cancellato senza che nessuno se ne accorgesse. Riparato alla sorgente (ts_utc= ora vera,bar_ts= barra) con un test di regressione sul sorgente: se qualcuno rimettelast_data, il test lo dice. 📌 IL DB (data/live/trades.db, dentro il perimetro del backup):fillscol contesto del segnale a quel giro (tp_frac, skh_sign, entry, target, posizione, equity),roundtripsderivati e ricalcolati da zero,equityoraria,journal. Sync orario incron_book. Le tre fonti si INCROCIANO e non si sovrascrivono: log (ora vera) x jsonl (i fill) x venue (autorevole ma TRONCA — 1 trade su BTC, 0 su ETH).reconcile()riporta le divergenze e non ripara niente da solo: fra due fonti che non concordano, una riparazione silenziosa e' un'invenzione. E' cosi' che il difetto dell'ora e' stato isolato invece che dedotto. 📌 QUATTRO LIVELLI IN PAGINA, SEPARATI PER PROVENIENZA — e la separazione E' il prodotto: numeri (feed + DB) · Lettura (12 regole dichiarate, ognuna con l'id stampato accanto alla riga che ha prodotto, ognuna con due test: uno che la accende e uno che la tiene spenta) · Analisi (prosa di un modello, firmata e datata) · Nota (l'operatore, mai riscritta da un ricalcolo). Un giornale che mescola misura e racconto, a sei mesi, non permette piu' di sapere quale delle due si stava leggendo. 🚨 L'ANALISTA SBAGLIA, E IL TRIPWIRE NON PUO' PRENDERLO.numeri_non_supportati()verifica che ogni cifra dell'analisi compaia in cio' che il modello ha ricevuto (oltre 3 numeri liberi: rifiutata), ma due errori su due giri con sonnet-5 non contenevano cifre nuove — una frase su un merge mai raccontato, e un round-trip corretto dichiarato inesistente con una spiegazione inventata per il proprio dubbio. Il modello e' stato portato aclaude-opus-5; il campione e' di due osservazioni, quindi e' un tentativo di abbassare un tasso, non una garanzia. REGOLA: una guardia sui NUMERI non copre il RAGIONAMENTO — l'analisi si legge come opinione di un lettore fallibile, mai come parte del registro. ⚠️ CICLO DI RETROAZIONE, trovato al primo giro reale: il modello leggeva la propria analisi del giorno prima e la commentava (aveva prodotto un paragrafo sull'avviso del tripwire che si era preso).senza_analisi()toglie la sua sezione dalla pagina prima di dargliela; laNotaresta, perche' il contesto dell'operatore serve. Nessun controllo automatico puo' distinguere il meta-commento da prosa valida: si vede solo LEGGENDO l'uscita. ✅ TELEGRAM, e due delle tre riparazioni al notifier finalmente fatte. L'analisi parte ogni giorno con una testata di numeri; se manca, il messaggio parte lo stesso dicendo perche' (il silenzio si legge come «non e' successo niente»). Il trasporto era il punto singolo di guasto gia' misurato (6,9% di invii persi, 2/29) = ~25 messaggi l'anno su una cadenza giornaliera: (a)send(text, tentativi=1)— retry opzionale, default invariato perche' alzarlo per tutti cambierebbe la latenza degli allarmi divenue_watchebook_executesu un percorso con soldi veri; (b)ultimo_errore()registra il motivo nel punto in cui veniva ingoiato e non sopravvive a un invio riuscito. (c)alerted=Truesolo a invio riuscito resta la decisione dell'operatore: cambia il comportamento degli allarmi. Esito nel DB in tre stati:inviata/non configurato/FALLITA — motivo. ⚠️ CINQUE difetti trovati dai test o leggendo l'uscita, nessuno a occhio: (1) il tetto di leva era RIDICHIARATO (0.5cablato) invece che letto daconfig/live.json— quinta occorrenza dello schema che il progetto paga da luglio; (2) l'IV-rank era il percentile a un anno etichettato col nome del gate di VRP01, che usa quello espandente: davano il verdetto opposto (0,52 «sopra» contro 0,18 «sotto», e il valore giusto combacia con «0/8 settimane passano il gate» misurato il 30/07); (3) il renderer cadeva inKeyErrorse mancava il blocco mercato; (4) «24 giri attesi» su un giorno in corso = allarme a ogni esecuzione; (5) libro e P&L leggevano due istanti diversi e la stessa pagina mostrava due equity. 📌 REGOLE: (a) un dato operativo non ricostruibile non puo' vivere in un file gitignored — si materializza dove il backup arriva; (b) una guardia piu' stretta del contratto produce allarmi che si impara a ignorare (il tripwire validava sulla sola pagina mentre il prompt include anche lo storico, e bocciava un'equity vera); (c) una regola che si accende su $2 di cumulato insegna a saltare la sezione: serve una soglia di rilevanza; (d) chi scrive in un registro va firmato, o il registro perde il suo valore probatorio.
Addendum 2026-08-25 — la voce del GIORNO IN CORSO si presentava come una giornata
(scritto 2026-08-25T08:59:12Z, ora letta da date -u)
cron_daily gira alle 00:30 UTC e faceva due chiamate al giornale: chiudeva IERI
(giorno completo, corretto) e apriva OGGI. La pagina di oggi nasceva quindi con ~30 minuti
di giornata dentro e nessuno la aggiornava fino alla notte dopo.
🚨 Il difetto non era il dato mancante, era che la pagina non lo diceva dove si legge. Aveva
tutte le sezioni di una pagina chiusa — Mercato, Libro, P&L, Salute, Lettura, Nota — quindi
passava ogni controllo di completezza e di freschezza; la parzialita' era dichiarata solo in
§Salute, quinta sezione su otto (giri di book_execute: 1/1 *(giorno in corso)*), mentre
titolo, P&L e le regole della Lettura parlavano al passato di una frazione di giornata.
E' la stessa famiglia gia' codificata due volte — "una riga presente non e' un dato presente",
"una barra presente non e' una giornata presente" — in una veste nuova: la pagina e'
presente, il giorno no.
📌 La taglia, misurata sul caso reale del giorno stesso (ed e' il motivo per cui non era un
difetto cosmetico): la pagina congelata alle 00:37 diceva "giorno: $+0.54 di equity (1 letture)"
e la regola [pnl] chiosava "senza operare: e' mark-to-market sulle posizioni gia' aperte".
Alle 08:54 dello stesso giorno il libro aveva fatto 3 fill, 2 round-trip chiusi e +$25.86 di
equity ($642.56 → $667.88). La pagina avrebbe raccontato una giornata ferma per tutta una
giornata operativa, e chi l'avesse letta — o un modello che se la fosse ritrovata nel prompt —
non aveva modo di accorgersene senza contare i giri.
✅ Riparato in due pezzi indipendenti:
- La pagina dichiara la propria parzialita' nel TITOLO e nella prima riga
(
src/live/journal.py::rendi_markdown):⚠️ PARZIALE (giorno in corso)+ copertura esplicita ("copre N giri su 24"), il fatto che non si aggiorna da sola, e quali numeri sono di quella frazione (giorno) e quali restano corretti (cumulati). - Il cron non la congela piu': tolta la seconda chiamata da
scripts/cron_daily.sh. Indocs/journal/restano solo giorni chiusi; chi vuole lo stato corrente lanciajournal.pya mano (e riceve una pagina marcata PARZIALE) o leggetrades.db, checron_booksincronizza ogni ora.
⚖️ Scelta dichiarata: NON si rigenera la voce di oggi ogni ora. Sarebbe l'altra soluzione
difendibile e costa una riga in cron_book, ma riscriverebbe un file tracciato da git 24
volte al giorno per un consumatore che oggi non esiste (l'analista legge il giorno chiuso).
Se un domani servisse la voce sempre fresca, la strada e' rigenerarla, non congelarla: e'
scritto nel commento del cron perche' chi ci torna non debba ri-derivarlo.
Prove (3, in tests/test_journal.py, 28 → 31): una accende la marcatura su un giorno in
corso e verifica titolo + copertura + "non si aggiorna da sola"; una la tiene spenta su un
giorno chiuso (una marcatura sempre accesa non si legge); la terza e' una guardia sul
SORGENTE di cron_daily.sh — ogni chiamata a journal.py deve avere --giorno esplicito,
perche' journal.py senza argomenti scrive OGGI. La guardia non vieta di rigenerare
spesso: vieta di scrivere la pagina una volta e lasciarla li'.
🚨 RIPARATO (2026-08-26): il P&L di giornale contava i VERSAMENTI come profitto.
Il «giorno» era un delta di equity fra letture: la voce del 25/08 dichiarava +$1.414,57 di
P&L quando $1.399,39 erano il deposito USDC dell'operatore, e il «cumulato dall'arming»
avrebbe mentito per sempre (e al prossimo versamento da $3.000 avrebbe stampato «+$3.000 di
giorno»). Riparazione in src/live/journal.py::movimenti_capitale con tre proprieta':
(1) la soglia e' importata da book.EQUITY_JUMP_ALERT, non ridichiarata (P1 — il rilevatore
di movimenti del progetto e' quello); (2) un salto e' movimento solo se supera di >2x il
massimo che il mercato misurato (feed certificato, tetto di leva da config) avrebbe potuto
produrre nell'intervallo fra le due letture; (3) altrimenti e' ambiguo: dichiarato e NON
scorporato (P12 — un crash vero a tutta leva non deve trasformarsi in "prelievo").
Scansione dell'intera storia reale: 1 evento, esattamente il deposito (+209,6% contro un
massimo di mercato di ±0,22%), zero falsi positivi. Anche la regola concentrazione ora
lavora sul cumulato di trading (il 25/08 leggeva "il 100% del P&L viene dagli ultimi 7
giorni" su un P&L che era il bonifico). Due scelte di design da non perdere: le regole sui
movimenti stanno sopra l'early-return "nessun giro di book" (un versamento in un giorno
senza giri esiste lo stesso: viene dal DB equity, non dal log del libro), e il limite e'
dichiarato (D5): un movimento sotto soglia — es. $150 su un conto da $2.000 — non si
distingue dal mercato e resta nel P&L, come nel rilevatore live. 7 prove nuove in
test_journal.py (31 → 37), incluso il controllo M15 al contrario: un crash −14% a tutta
leva resta AMBIGUO. Voce del 25/08 rigenerata: giorno +$1.414,57 di equity → trading
+$15,18; cumulato +$1.458,53 → trading +$59,14.
⚠️ Trovato girando la suite completa, NON riparato — e' un'altra cosa:
tests/test_wave_0726.py::test_t1_canonical_riproduce_il_backtest_ufficiale fallisce, e
falliva gia' prima di questa modifica (verificato con git stash: stesso fallimento sull'albero
pulito). Lo Sharpe hold-out di SKH01 canonical vale 1,9223 contro la banda cablata
1.3 < h < 1.9. Il codice non e' cambiato: sono cambiati i DATI — data/raw/ e' gitignored
e il cron lo ricostruisce ogni notte, quindi la finestra hold-out si allunga e il numero deriva
(verso l'alto, cioe' non e' un peggioramento). La banda NON e' stata allargata: e' la
lezione del 2026-08-07 ("un test che fallisce senza che il codice sia cambiato sta segnalando
che i dati non sono versionati — si guarda sotto prima di toccarlo"), e allargare una tolleranza
per far passare un test e' esattamente la manovra che quella lezione vieta. Resta aperto.
Addendum 2026-08-25 — La manutenzione del martedì: chi è rotto, e chi resta scoperto
Racconto completo in docs/diary/2026-08-25-manutenzione-deribit-e-resilienza-venue.md.
Qui restano i fatti citabili e i motivi, che valgono più degli esperimenti che li hanno prodotti.
I numeri, contati sui log (1.499 giri, 2026-06-23 → 2026-08-25)
| esito | n | % |
|---|---|---|
| manutenzione Deribit | 3 | 0,20% |
| traceback duro | 5 | 0,33% |
| giri senza esito utile | 26 | 1,7% |
Lo slot di release Deribit è il MARTEDÌ alle 09:00 UTC, 15-30 min annunciati. Quattro episodi,
tutti fra le 09:00 e le 09:07: 2026-07-21 (502 visto dal gateway), 11/08, 18/08 (giù anche
alle 10:07 → l'annuncio non è la durata), 25/08 (~20 min). Il cron al :07 ci cadeva
per costruzione.
🚨 Il punto singolo di guasto non è il venue, è NOSTRO. Dei 5 traceback, 4 sono
cerbero-mcp.tielogic.xyz: un 404 su get_positions, un 502, due ReadTimeout. Sostituire
Deribit non toccherebbe il guasto che ci ha davvero morso. E il gateway non è aggirabile: le
credenziali Deribit vivono solo lì dentro (§5.11).
I motivi — cioè la parte che chi riapre il tema deve battere
- Una nota di diagnosi cablata è peggio di nessuna nota (P4).
conto non leggibile (offline)copriva due guasti con azioni opposte. E il 18/08 il codice 11051 era già dentro il processo, nello stesso minuto, raccolto dalivefeed: non mancava il dato, mancava il trasporto del dato a chi decideva la gravità. - Declassare un allarme atteso (P9) è giusto, ma la finestra non è una prova.
venue_probedeclassa solo su evidenza della sonda (mai sull'orologio) e solo dentro la durata annunciata: oltre, RIALZA. Senza questi due paletti si costruisce il silenzio esattamente nell'ora in cui è più probabile che serva. naked≠place-failed(P5). Il primo è "ho tolto la protezione e non sono riuscito a rimetterla", il secondo "non sono riuscito a metterla". Solo uno lascia una posizione aperta senza stop on-book, e non è mai un evento atteso: 🚨 sempre.- Un guasto su un asset non deve togliere la rete all'altro. Il 21/07 il ciclo è morto su BTC e nel log ETH non compare: né ribilanciato, né verificato nella sua protezione. L'isolamento per asset è la riparazione; il costo di non averlo era un'ora di posizione non controllata.
- Riparato il silenzio, NON toccata la sequenza.
ensure_disaster_slcontinua a cancellare prima e piazzare dopo. Piazza-poi-cancella sembra più sicuro (due STOPreduce_onlydovrebbero essere innocui) ma "dovrebbe" non basta per cambiare il ciclo di vita dei bracket con soldi veri senza misurarlo. Chi lo riapre deve portare la misura, non l'intuizione. - Il vincolo del minuto
:07non era "il :07": era "fuori dai ~26s del minuto tondo" (il collettore catena si auto-satura il rate-limit per-IP — 12.186 risposte 429 in 26 ore, 96% nel minuto:00, misura del 30/07). Letto così, il vincolo lascia libero qualunque minuto ≠:00, e il:47soddisfa anche il secondo (fuori dallo slot di release). Una regola operativa va riletta nella sua ragione, non nel suo valore — altrimenti si difende un numero invece di un motivo.
Previsione dichiarata, da misurare (M12)
Sulle 4 finestre osservate 3 sono rientrate entro l'ora → il :47 ne avrebbe scavalcate 3 su 4.
Se al prossimo martedì il :47 becca comunque la manutenzione, la previsione è sbagliata e lo
slot non è quello descritto in venue_probe.RELEASE_*: rileggerlo prima di spostare ancora.
Cosa resta scoperto
- La sonda dice di chi è il guasto, non lo aggira. Col gateway giù il libro continua ad astenersi. Il fallback vero richiede chiavi API Deribit create dall'operatore — decisione, non refactor, con una superficie di rischio propria (§5.11).
- La sonda legge se il venue RISPONDE, non cosa il venue ANNUNCIA. Il Rulebook (ADL, perdita socializzata, emergency powers) resta non sorvegliato (§5.8).
Coda 2026-08-25 — Un test scriveva nel watermark VIVO (e ha mandato un allarme falso)
Lanciando la suite completa, data/live/equity_seen.json è passato da $667,68 a $5.000; il
giro del book alle 09:47 ha confrontato l'equity vera contro quel valore e ha spedito su Telegram
un 💰 USCITA DI FONDI: $5.000 → $667,68 (−86,6%) completamente falso.
Colpevole: test_book_live.py::test_la_formula_del_report_ha_potenza_anche_a_libro_flat — prende
solo monkeypatch (niente tmp_path), finge real_equity=5000.0 e chiama book.book_report(),
che come effetto collaterale scrive il watermark. Riprodotto isolando il singolo test.
🚨 Non era cosmetico. cap_fallback = min(cap_config, watermark × frac): con $5.000 dentro, il
cap sarebbe passato da $334 a $2.500/asset — fino a $5.000 di nozionale lordo su un conto da
$668, ~7,5x di leva. Il ramo che ci arriva (eq_fallback) allerta e NON blocca, per scelta
dichiarata. Lanciare i test poteva armare esattamente il pericolo che il watermark esiste per
impedire. Danno reale quel giorno: nessuno — alle 09:47 l'equity era leggibile, quindi il cap si
è calcolato sul vero. È andata bene per la direzione del caso, non per una protezione.
I motivi da non ri-derivare:
- Il perimetro di un test non è quello che il test dice di toccare: è quello che tocca il codice che chiama. Quel test non menziona il watermark, non lo importa, non lo asserisce — lo scrive passando per una funzione di produzione tre livelli sotto.
- La riparazione per-test non regge, ed è dimostrato tre volte. L'helper
_write_cfgnasce per questo il 26/07; il test colpevole è del 21/08 e non lo usa; oggi la stessa scommessa ha perso di nuovo. Quindi fixture autouse intests/conftest.py: vale anche per il test che qualcuno scriverà domani senza aver letto niente. Il monkeypatch esplicito di chi vuole davvero pilotare il watermark gira dopo e continua a vincere. - Una protezione mai vista fallire non è una protezione → guardia in
test_cap_watermark.pyche si accende se la fixture viene rimossa. - ⚠️ Resta il principio più largo: oggi è deviato solo il watermark.
data/live/trades.dbedata/live/book_executions.jsonlsono esposti allo stesso errore (§5.12).