bb40e87d13
Quattro misure (r0909_*), nessun cambio a libro/pesi/config: - libro nei crolli: −0,48%/g nei 160 giorni ≤ −5%, positivo per finestra dal 2022 per la gamba short di SKH01 (108% dei guadagni); beta 0,0769 riprodotto (§46); il peso di SKH01 resta chiuso dal gate (in-sample). - crollo catturato 1-5/06/2026 a quote vere: f_net 0,74 = rally; put δ−0,10 1,92× il modello; a vol bassa e fuori dal gate di VRP01 → §3 non si riapre. - XRP terza gamba (harness r0822_sol_leg): hold-out −0,169 in 0/24, un anno buono. - universo Deribit: liquidi solo BTC/ETH/XRP/SOL; XS01 13/19; BTCDVOL future non negoziabile; PAXG non misurato. Revisione fable: due conclusioni smontate (MTM 2,6× era un artefatto di quote; «8/12 guadagna» era l'ordine delle classi). Debito §5.18: cblib.spot_series + asof guarda un'ora avanti (feed 1h etichettato all'apertura). Test Opus: 92 nuovi, suite 1008/1008; due difetti del verdetto XRP corretti. Docs: diario, RESULTS §74-77, CLAUDE.md, memoria 20/50, README; journal 07-08/09. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zJjHUS7mf4pnGE6pq9RTt
177 lines
15 KiB
Markdown
177 lines
15 KiB
Markdown
# Dati, feed e difetti trovati
|
||
|
||
> Estratto **verbatim** da `CLAUDE.md` il 2026-08-25 durante la compattazione.
|
||
> Difetti del dato scoperti e riparati, e la catena opzioni raccolta in proprio.
|
||
> Il testo non e' stato riscritto: e' la memoria originale, spostata.
|
||
|
||
---
|
||
|
||
- ⚠ **SPLIT NON AGGIUSTATI nel feed equity — difetto sul LIBRO LIVE, riparato (2026-07-25).**
|
||
`data/raw/eq_iwm_1d.parquet` ed `eq_efa_1d.parquet` avevano uno split non aggiustato il
|
||
**2005-06-09** (IWM 2:1 = −49.5%; EFA 3:1 = −66.5%); IB `ADJUSTED_LAST` non li aveva aggiustati.
|
||
**La certificazione non li vedeva per un punto cieco strutturale:** l'unica guardia era
|
||
`maxret > 50% → SPIKE?` e uno split 2:1 fa **esattamente −50%** → IWM passava a 49.5% con status
|
||
OK. **IWM e' una delle 6 gambe di GTAA01 in produzione.** Impatto: GTAA6 FULL Sh 0.61→**0.64**,
|
||
IS 0.49→**0.54**, OOS 2015+ e maxDD **INVARIATI** (artefatto nel 2005, fuori hold-out) → il
|
||
difetto SOTTOSTIMAVA lo sleeve, **nessuna decisione presa va rivista**. Discriminante
|
||
split-vs-crollo (riusabile): **non il rapporto** (SLV 2026-01-30 ha rapporto 1.3994, a 4bps da
|
||
1.4, ma e' un crollo vero: GLD −10.3% lo stesso giorno) ma il **RANGE INTRADAY** — lo split apre
|
||
gia' al nuovo livello con range normale (IWM: open 47.00, range 1.7%), il crollo si muove DENTRO
|
||
la barra (SLV: range 33%). Modulo `src/data/eq_splits.py` (`detect_unadjusted_splits` a 3
|
||
condizioni congiunte + `repair_splits` componibile), riparazione **in lettura** in
|
||
`src/portfolio/gtaa.py::_close` e `scripts/research/eqlib.py::load_eq`, status
|
||
**`SPLIT-NON-AGG`** in `fetch_ib_equities.certify()`, test `tests/test_eq_splits.py` (8 casi).
|
||
**Regola nuova: ogni soglia di certificazione tarata su un valore tondo va controllata contro il
|
||
difetto che genera esattamente quel valore** (una soglia a 50% non puo' sorvegliare gli split 2:1).
|
||
|
||
- ⚠️ **IL FEED EQUITY NON AVEVA UN CROSS-CHECK — buco trovato e chiuso (2026-07-26).**
|
||
`src/data/eq_crosscheck.py`. Nel crypto la certificazione incrocia sempre piu' venue
|
||
(`certify_feed.py` vs Coinbase USD); il feed equity aveva **solo controlli locali** (integrita',
|
||
gap, spike, split). Il primo veicolo estero ha trovato il buco alla prima estrazione: **CSPX
|
||
2012-01-13** con `open/high 112.740` in **USD** e `low/close 88.010` in **EUR** (fattore dai close
|
||
adiacenti **1.2797** = EURUSD di quel giorno) → −21.9% e poi +27.8% mentre SPY faceva −0.39%.
|
||
**La certificazione esistente non lo vedeva:** unica guardia `maxret > 50% → SPIKE?`, e una
|
||
contaminazione EUR/USD vale ~22-28% — **stesso schema dello split 2:1 del 25/07** (che valeva
|
||
*esattamente* −50%). **2ª conferma: una soglia tarata su una classe di difetto non sorveglia le
|
||
altre.**
|
||
**Perche' il GEMELLO e non una regola locale:** il discriminante del 25/07 (range intraday) qui
|
||
non funziona — anche un crollo vero ha range enorme (SLV 33%). Cio' che separa i casi e' che **un
|
||
evento di mercato lo fa anche il gemello**: nel *rapporto* i movimenti veri si cancellano.
|
||
Controprova su dati reali: la scansione sui **prezzi** segnalava IDTL 2020-03 (liquidazione
|
||
treasury) e IGLN 2013-04 (crollo oro); sul **rapporto** spariscono.
|
||
⚠️ **La soglia non era tarabile sulla deviazione** — rumore legittimo fino al **9.90%**
|
||
(2025-04-09: Londra chiude alle 11:30 di New York) contro un difetto del 21.4% → margine 2.2×,
|
||
sotto il 3× richiesto. **La risposta non e' accettare il margine ma CAMBIARE STATISTICA:**
|
||
`|dev| / movimento del gemello` (un disallineamento d'orario **non puo' superare il movimento del
|
||
mercato**) → rumore **8.1**, difetto **42.7**, **margine 5.3×**. Soglia 18.0, equidistante in
|
||
scala log. Tre condizioni congiunte: deviazione + non-spiegato + **rientro** entro 5 barre.
|
||
**Riparazione = SCARTARE la barra, non ricostruirla** (del prezzo vero non si sa nulla).
|
||
⚠️ **Limite dichiarato e chiuso sul DANNO, non sulla rilevabilita':** GBPUSD 1.27 → 21% sempre
|
||
rilevato; EURUSD 1.09 → 8.3% **dentro il rumore** e non tappabile senza falsi positivi. Misurato
|
||
invece il danno di una contaminazione non vista: **dSharpe mediano −0.003, peggiore −0.056,
|
||
|Δ|>0.05 nel 2%**. **REGOLA: quando un buco non si puo' chiudere senza generare falsi positivi,
|
||
si misura il DANNO del caso non rilevato** — un buco quantificato e innocuo e' un risultato, uno
|
||
taciuto e' un debito. Il limite e' congelato in un test (`test_limite_dichiarato_*`): se qualcuno
|
||
abbassa la soglia, il test dice cosa e' cambiato.
|
||
|
||
- **CATENA OPZIONI REALE — RACCOLTA PROPRIA dal 2026-07-30 (cerbero-bite ASSORBITO e dismesso).**
|
||
`/opt/docker/cerbero-bite` (progetto separato) accumulava dal 2026-06-09 la catena Deribit
|
||
**mainnet** BTC+ETH; **è stato ELIMINATO il 2026-07-30** (container, volume, immagine e cartella
|
||
rimossi, 12 GB liberati; codice conservato su Gitea `Adriano/Cerbero-Bite`, ultimo commit di
|
||
dismissione) **e la raccolta è passata dentro PythagorasGoal**:
|
||
- **raccolta:** `scripts/live/collect_chain.py`, cron **`25 * * * *`** (`scripts/cron_chain.sh`) →
|
||
`data/raw/cb_chain/YYYY-MM-DD.parquet`. Entrambe le ali, scadenze ≤95g, OI≥100, ~570 strumenti
|
||
a giro, ~3 min. **Minuto :25 scelto, non arbitrario:** :00 era la raffica di bite, :07 è
|
||
`cron_book` (feed 5m di SKH01, la cosa che non deve trovare l'IP occupato).
|
||
- **archivio ereditato:** `scripts/analysis/import_cb_archive.py` (una-tantum) →
|
||
`cb_chain/bite_archive.parquet` (1.23M righe, 2026-05-01+) e `cb_market_snapshots.parquet`
|
||
(17.402 righe, 2026-03-26+: DVOL, RV30, funding perp e cross, **dealer net gamma**, gamma flip,
|
||
**rischio liquidazioni**, giorni all'evento macro — dati che il progetto non ha altrove).
|
||
Snapshot sqlite integrale in `/opt/docker/backups/manual/cerbero-bite-20260730/` (SHA256).
|
||
- **certificazione:** `scripts/analysis/certify_cb_chain.py`; **harness** `scripts/research/cblib.py`
|
||
(`load_chain()` unisce archivio + raccolta, dedup su `(ts, strumento)`).
|
||
- **battuta di cuore:** ogni giro scrive `data/chain_collect/runs.jsonl`, sorvegliato da
|
||
`monitor_health` (cadenza 1h, `max_age_h=3`) — **un collettore fermo non produce niente, e il
|
||
niente si legge come "nessun dato quel giorno"**.
|
||
- **BACKUP (aggiunto 2026-07-30):** `data/raw/` è gitignored → la catena **non è in git**, e il
|
||
backup rotativo della VPS non copriva PythagorasGoal. Aggiunta `do_pythagoras` a
|
||
`/opt/docker/scripts/backup.sh` (daily 04:00, retention 7/28/185 g): salva **solo il dato non
|
||
ricostruibile** — catena + contesto, `data/paper_*` e `data/chain_collect` (serie forward-only
|
||
che alimentano i gate pre-registrati: **non sono ricalcolabili**), `data/options_daily`,
|
||
`data/live`, `venue_watch`, `fee_watch`, `config/live.json`. ~28 MB. **Esclusi di proposito**
|
||
i ~110 MB ricostruibili (`rebuild_history.py`, `fetch_dvol.py`, `fetch_hyperliquid.py`,
|
||
`fetch_ib_equities.py`, cache). La funzione **fallisce rumorosamente** se la catena è assente o
|
||
vuota, e verifica il tar prodotto (controllo positivo provato in entrambi i versi).
|
||
⚠️ `/opt/docker/scripts` **non è un repo git**: quella modifica vive solo su disco.
|
||
- **Dopo un riavvio della VPS la raccolta riprende da sola** (cron di sistema `enabled`+`active`,
|
||
nessuna dipendenza da docker o da cerbero-mcp: API pubblica Deribit diretta). Verificato con
|
||
`env -i` che il giro funzioni nell'ambiente nudo di cron. Finestra scoperta: fino al `:25`
|
||
successivo, **senza recupero** — un'ora persa resta persa (il collettore non fa catch-up).
|
||
**TRE DIFETTI DI BITE NON REPLICATI** (misurati il 30/07): (a) **una chiamata per strumento** —
|
||
`get_order_book?depth=3` dà già quote+greche+IV+OI+book+underlying, bite ne faceva due con
|
||
rischio di disallineamento; (b) **pacing** (token bucket 4/s + backoff) invece della raffica —
|
||
il carico non è mai stato il problema (~570 chiamate/ora = 0.16/s **distribuite**), bite le
|
||
sparava in ~26s (~44/s) auto-saturandosi il rate limit per-IP; misurato sul nostro giro:
|
||
**574 chiamate, 0 risposte 429**; (c) **`quote_status` esplicito** in {`ok`, `no_quote`, `error`}
|
||
— "book vuoto" (fatto di mercato) e "chiamata fallita" (fatto di infrastruttura) sono cose
|
||
diverse, e `book_depth_top3` è **NULL su errore, mai 0**. ⚠️ Le righe ereditate da bite hanno
|
||
`quote_status='unknown'`: bite non registrava il perché, e si dichiara l'ignoranza invece di
|
||
inventare uno stato.
|
||
🚨 **BUCO DI COLONNA nell'archivio ereditato, trovato il 2026-08-22 e mai registrato prima:**
|
||
`bite_archive` ha `index_price` e `underlying_price` **100% None (1.232.212/1.232.212)**. Il
|
||
sottostante esiste **solo dal 2026-07-30** (raccolta propria, 18,2% delle righe) e
|
||
`book_depth_top3` solo nel **67,2%**. **Chiunque calcoli moneyness o riprezzi sull'archivio
|
||
pre-30/07 sta usando una colonna che non c'è** — e il file si legge senza errori, quindi il
|
||
difetto è silenzioso.
|
||
✅ **Ed è CHIUDIBILE senza dato nuovo:** il forward si ricostruisce con la **parità put-call**
|
||
dalla catena stessa — verificato contro l'osservato su **6.578 coppie: |errore| mediano 0,023%,
|
||
p95 0,147%, corr 1,000000** → rende la superficie utilizzabile su tutti i **75 giorni** invece
|
||
che 23. (Lo **smile**, che non richiede il forward, esiste invece su **113 giorni dal 2026-05-01**;
|
||
la **superficie completa** solo da **2026-06-09**, perché prima bite raccoglieva una sola scadenza
|
||
per giro — misurato da **tre** agenti indipendenti.)
|
||
⚠️ La famiglia raccolta è quella **inverse** (`get_instruments?currency=BTC|ETH`): la superficie
|
||
**USDC-lineare non è nell'archivio**, e ogni conclusione su di essa nel progetto è oggi un
|
||
**controfattuale costruito sui mid inverse**, non una misura. Puntare il collettore anche su
|
||
`currency=USDC` costa ~~**+587 chiamate/giro (+90%)**~~ 🚨 **CORRETTO 2026-08-23 (§51): sono
|
||
+117 chiamate = +18%.** Il 587 era il conteggio **grezzo** (1.140 strumenti USDC ≤ 95g = +81%)
|
||
**senza il filtro OI≥100 che il collettore applica davvero**, e quel filtro taglia il 90% della
|
||
famiglia USDC: con gli stessi filtri del collettore vivo sono **113 strumenti** contro **649**
|
||
inverse (✅ verificato al venue da due percorsi indipendenti; replica esatta di §8 — su Deribit
|
||
USDC l'OI e la negoziabilità sono anti-correlati). Il giro passerebbe da 652 chiamate/163 s a
|
||
**769/192 s**, dentro la finestra del :25 e senza toccare `cron_book` al :07. Resta una decisione
|
||
sul rate-limit per-IP, che ha già causato un guasto il 29/07 — ma **di un ordine di grandezza
|
||
più piccola di come era stata scritta**, ed è un numero **di oggi** (cresce con la liquidità
|
||
USDC, va ri-misurato prima di accendere).
|
||
🚨 **LA RAGIONE PER RACCOGLIERLA E' CADUTA (2026-08-23, §64): le due superfici sono LA STESSA
|
||
SUPERFICIE** a strike appaiati — prezzo equo identico per costruzione, mezzo-spread Δ −0,21/−0,38 pp,
|
||
`f_venue` Δ +0,005/−0,011 ⇒ il `f` di VRP01 misurato sull'inverse **non e' «il numero della famiglia
|
||
sbagliata», e' lo stesso numero**. Resta vero che la lineare **non e' nell'archivio**; cade
|
||
l'argomento che la sua assenza falsi una misura gia' fatta.
|
||
**NON assorbito, e perché:** il motore credit-spread ETH (il progetto ha già la regola "niente
|
||
short-vol da modello in deploy"), la GUI, kill switch/dead-man/audit (PythagorasGoal ha
|
||
`venue_watch`/`edge_watch`/`monitor_health`/`fee_watch`), `dvol_history` (`fetch_dvol.py` ha
|
||
storia **più lunga**: 2020+ contro 2026-05), `decisions`/`positions` (59 righe a capitale $52,
|
||
0 posizioni). Test `tests/test_collect_chain.py` (11) + `tests/test_cb_chain_vrp.py` (13).
|
||
⚠️ **Prima di cancellare la sorgente** (verifiche nel diario `2026-07-30-assorbimento-cerbero-bite.md`):
|
||
snapshot **completo** e non solo integro (4 tabelle su 4 con conteggi identici al volume vivo e ai
|
||
parquet); i 10,6 GB di backup interni **non** contenevano dati unici (stessa riga più vecchia in
|
||
tutti gli snapshot + conteggi monotoni ⇒ nessuna potatura); zero dipendenze a runtime.
|
||
⚠️ **`cerbero-mcp` è un progetto DIVERSO e serve a PythagorasGoal** (Hyperliquid, percorso del
|
||
conto) — resta acceso; la rete `traefik` che condividevano è `external:` nel compose di bite,
|
||
quindi `down -v` non la tocca. **REGOLA: prima di cancellare una sorgente si verifica che la copia
|
||
sia COMPLETA, non che esista** — un hash prova che il file non è corrotto, non che contenga tutto.
|
||
**Perché si MEMORIZZA invece di interrogarla:** una catena opzioni non è ricostruibile a
|
||
posteriori — Deribit non serve book storici, un'ora non raccolta è persa per sempre, e non c'è un
|
||
secondo venue da cui recuperarla.
|
||
**Certifica 4 difetti:** quote vuote, book incrociato, premio non monotono nello strike,
|
||
`depth==0` (ambiguo **by design**: chiamata fallita e book vuoto danno lo stesso valore → si
|
||
riporta, non si ripara).
|
||
⚠️ **GUASTO IN CORSO dal 2026-07-29 05:00 UTC — status `QUOTE-VUOTE`.** Il collettore persiste la
|
||
riga anche quando il ticker fallisce (rate-limit Deribit **per-IP**: ~650 risposte 429 in ~26s a
|
||
ogni giro, **96% al minuto :00**, generate dalla spazzata full-chain che si auto-satura) →
|
||
`bid`/`ask`/`iv`/`delta` NULL e **conteggio righe INVARIATO** (13k/giorno prima e dopo). Tasso di
|
||
quote vuote per settimana: 0.4·0.7·2.2·1.5·0.5·0.4·0.3 → **22%**; giorno peggiore **51.7% BTC /
|
||
30.6% ETH**. ✅ **Risolto dal cambio di collettore** (30/07): la raccolta propria è paced e ha
|
||
fatto 574 chiamate con **0 risposte 429**. **REGOLA: una riga presente non è un dato presente** —
|
||
contare ciò che è QUOTATO, non ciò che è SCRITTO (3ª occorrenza dopo `paper_dvolspread` e
|
||
`fresh_5m`). **REGOLA: un guasto IN CORSO si misura al GIORNO PEGGIORE, non in media** — la prima
|
||
stesura confrontava "tutto" con "ultimi 7g" e diluiva un guasto di 2 giorni al 13.5%, commettendo
|
||
a 7 giorni lo stesso errore che dichiarava di evitare a 3 mesi. Diario `2026-07-30-vrp-quote-reali.md`.
|
||
|
||
- 🚨 **IL FEED 1h E' ETICHETTATO ALL'APERTURA, e `asof(ts)` guarda un'ora avanti (trovato in revisione
|
||
il 2026-09-09).** La barra 1h etichettata 20:00 chiude col 5m delle 20:55 (verificato: close 1h 20:00 =
|
||
close 5m 20:55 = 1603,5, mentre il 5m 19:55 fa 1572,95). Quindi `S.asof(ts)` su una serie indicizzata
|
||
con quell'etichetta restituisce la chiusura di **ts+1h**: un look-ahead di un'ora senza eccezioni e
|
||
senza NaN (D6, quarta occorrenza). Colpisce `cblib.spot_series` — cioe' il f 0,714 di §11 e ogni numero
|
||
di `cblib` con lo spot, compreso `ST = S.asof(exp)` che e' il prezzo di un'ora DOPO la scadenza.
|
||
`r0909_crash_catturato.spot_causale` sposta l'indice di +1h (chiusura = tempo in cui e' nota); `cblib`
|
||
**non e' riparato** (cambierebbe numeri pubblicati: va fatto con la rimisura di §11). Debito CLAUDE.md §5.18.
|
||
- **XRP** (`XRP/USDC:USDC`, dal 2022-03-16) ricostruito il 2026-09-09 con `rebuild_history --asset XRP` e
|
||
spostato in **`data/raw/alt_xrp_*.parquet`** (namespace di ricerca come SOL: fuori dal feed attivo, non
|
||
rinfrescato dal cron, `load_data("XRP")` fallisce, presidiato da `test_sol_leg` via `DERIBIT_INSTR`).
|
||
Certificazione per anno vs riferimento USD: **Coinbase non ha XRP fra 2021-01 e 2023-07** (delisting per
|
||
la causa SEC) → riferimento **Bitstamp** prima, Coinbase dopo; >1% 0,06% (2022) · 0,57% (2023) · ≤0,02%
|
||
(2024+); mediana 5-6 bps; **5m flat 27-61%** (BTC/ETH 0,1-2%, SOL 21%): il 5m e' illiquido. Cache del
|
||
riferimento in `data/_cache/` (gitignored, fuori backup: si riproduce con rete).
|
||
|