cblib causale: spot +1h e DVOL +1 giorno (debito §5.18); §11 rimisurato 0,714 → 0,712, verdetti invariati
- cblib.causale(s, cadenza): spot_series e dvol_series escono causali (asof = ultima chiusura NOTA); il DVOL giornaliero era una seconda serie con lo stesso difetto (fino a 24h avanti), verificato contro l'API pubblica a 1h. Regolamento ST alle 08:00 invece delle 09:00. - §11 riprodotto al millesimo su worktree HEAD (0,714 [0,690-0,779], n=19, flag --al) e rimisurato: 0,712 [0,664-0,732]; solo spot 0,721, solo DVOL 0,693, DVOL orario di controllo 0,717. Mediana onesta BTC 1,45 → 2,12, fee 1,51x/1,87x. r0730: 0,73 → 0,71. §75: ETH pre 0,76, BTC durante 0,89 (orario 0,83). skew panel ≤0,005. vrp_f_watch: f canonico 0,732 → 0,706, differenza +0,097 [+0,042, +0,140]. - r0909 senza doppio shift, contesto sul DVOL del giorno; r0822 regime su date di calendario; r0901 join riallineato (bit-exact). Aperti con costo: DVOL orario (−0,04/+0,06 nel crollo), spot 5m (≤25 min). - test: +3 causalita' in test_cb_chain_vrp, anti-doppio-shift in test_r0909; suite 1011/1011. - revisione fable: 16 segnalazioni, tutte applicate (fra cui un «−1,8% in un'ora» che era +3,9%). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjj5vPEBoAJrB23P6RjKzs
This commit is contained in:
@@ -128,7 +128,7 @@ sono all'ancora fortunata; le stime oneste sono la **mediana della banda d'ancor
|
||||
| TP01 hold-out | 0,31 | **~+0,05** — il valore di TP01 e' il **taglio del DD ~6× vs buy&hold**, non il ritorno |
|
||||
| XS01 standalone | 1,50 / 1,71 / DD 11% | ensemble di fase **1,25 / 1,31 / 10,9%**; maxDD fuori campione **21%** |
|
||||
| SKH01 | i numeri di ammissione | de-luckato e' **il meno affidabile dei cinque** (l'ancora regala 2/3 del FULL) |
|
||||
| VRP01 | f = 1,00 | **f = 0,73** misurato sulle quote reali (IC95 [0,698; 0,780]) |
|
||||
| VRP01 | f = 1,00 | **f = 0,73** misurato sulle quote reali (IC95 [0,698; 0,780], 30/07); **0,71 [0,680; 0,756]** rigirando lo stesso `r0730` con `cblib` causale (09/09 sera, n=27, 0/27 ≥ 1) |
|
||||
| muro capitale-rendita | $272k (lordo) | **$313k** al netto di fisco **e** funding — banda **[$187k – $1,14M]** |
|
||||
| P(≥50 €/g), canale funded, 36 mesi | 42% | **2,6%** [1,5 – 4,7], P(zero) 40,3% |
|
||||
| XSR01 | Sharpe 1,82 (e' una **terza** lente, divisore fisso 50) | **1,79** alla scoperta / **1,56-1,63** a oggi — lente dei gate, sole barre chiuse. Citare sempre la coppia (lente, ultima barra chiusa) |
|
||||
@@ -161,8 +161,9 @@ con le classi nell'ordine dichiarato sono 4 + 6 immune. **La leva che aumentereb
|
||||
peso di SKH01** (37,5/62,5 batte 12/12 episodi ma maxDD 12,1% vs 9,4%): vincolato (§3), gate
|
||||
`weights_tilt_null` fallisce su una condizione **in-sample** (delta −0,0026, 26/07; cache segnali ferma
|
||||
al 25/07). **Crollo CATTURATO a quote vere (1-5/06/2026, archivio bite, `r0909_crash_catturato.py`)**:
|
||||
f_net del put credit spread **0,74 = 0,714 del rally**; put δ−0,10 costa **1,92×** il modello all'ask ma
|
||||
paga come il modello nel crollo (0,94-1,04); f al peggior MTM 1,08 (il 2,58 della prima stesura era un
|
||||
f_net del put credit spread **0,76 [0,71-0,86] = 0,712 del rally** (rimisurato la sera del 09/09 con spot e DVOL
|
||||
causali, debito 18; era 0,74 = 0,714); put δ−0,10 costa **1,98×** il modello all'ask ma paga come il modello nel
|
||||
crollo (0,99-1,04); f al peggior MTM 1,08 (il 2,58 della prima stesura era un
|
||||
artefatto di quote oltre la larghezza). **NON e' il f di stress della regola del 19/06**: crollo a vol
|
||||
BASSA (picco DVOL al 29°/46° percentile), gate IV-rank di VRP01 CHIUSO, famiglia INVERSE, 4 strutture.
|
||||
Diario `2026-09-09-crolli-opzioni-monete.md`.
|
||||
@@ -435,14 +436,29 @@ d'ancora in modo diverso (nella differenza si cancella in parte, nel livello per
|
||||
`usde_convert.cuscino_richiesto_usd`, P1) ogni ora e allerta sotto zero; e la riconversione USDE→USDC che
|
||||
ripristina il cuscino e' `usde_convert --quota <minore>`, che esiste ma non e' automatica.
|
||||
|
||||
18. ⚠️ **`cblib.spot_series` + `asof(ts)` guarda UN'ORA AVANTI** (trovato in revisione il 09/09): il
|
||||
feed 1h e' etichettato all'**apertura** (la barra 20:00 chiude col 5m delle 20:55), quindi
|
||||
`S.asof(ts)` restituisce la chiusura di ts+1h. Tocca ogni numero di `cblib` che usa lo spot
|
||||
(il f 0,714 di §11 compreso; anche `ST = S.asof(exp)` e' il prezzo di un'ora DOPO la scadenza).
|
||||
Nella misura del 09/09 e' innocuo (ambo le gambe ITM) e giocava contro l'autore; `r0909_crash_catturato`
|
||||
usa `spot_causale` (indice +1h). **Non riparato in `cblib`**: cambierebbe numeri pubblicati — va
|
||||
riparato con la rimisura di §11, dichiarando lo scarto. D6, quarta occorrenza dell'etichetta.
|
||||
|
||||
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)
|
||||
**e `dvol_series` fino a 24 ore avanti** (la riga DVOL del giorno D e' la chiusura delle 23:00 di D:
|
||||
verificato contro la risoluzione 1h dell'API pubblica) — seconda serie con lo stesso difetto, trovata
|
||||
riparando la prima (D6, quinta occorrenza). Ora `cblib.causale(s, cadenza)` rietichetta le chiusure
|
||||
all'istante in cui sono note e le due serie escono **gia' causali** (spot +1h, DVOL +1 giorno);
|
||||
`r0909` non ri-sposta. **§11 rimisurato allo stesso taglio (22/08, n=19)**: prima riprodotto al
|
||||
millesimo su worktree HEAD (0,714 [0,690-0,779]), poi **0,712 [0,664-0,732]** — le due correzioni
|
||||
hanno **segno opposto** (solo spot 0,721 · solo DVOL 0,693 · entrambe 0,712; M26) e un DVOL **orario**
|
||||
di controllo da' 0,717. Il verdetto di §11 non cambia; cambiano i numeri di contorno (Sharpe canonico
|
||||
BTC 32,58 → 29,61, mediana onesta 1,45 → **2,12**; ETH 3,90 → 7,64; fee 1,44×/1,80× → 1,51×/1,87×;
|
||||
il regolamento e' ora il prezzo delle 08:00, non delle 09:00: P&L +3,3%). Sul crollo (§75): ETH pre
|
||||
0,74 → **0,76 [0,71-0,86]**, BTC durante 0,79 → **0,89** (DVOL orario 0,83: nel crollo il DVOL
|
||||
giornaliero stantio vale −0,04/+0,06 di f). `vrp_f_watch` (cron): f canonico 0,732 → **0,706**, differenza
|
||||
col candidato +0,054 → **+0,097 [+0,042, +0,140]** — ora esclude lo zero e il criterio (b) e'
|
||||
soddisfatto, (a) no (28/40). ⚠️ **Resta aperto, con costo misurato**: il DVOL nel feed e' giornaliero,
|
||||
quindi causale = **stantio fino a 23 ore** (mediana 0,2 pt di vol, max 3 pt; nel crollo 0,06 di f):
|
||||
la via giusta e' un feed DVOL **orario** (API pubblica, gratuito, `resolution=3600`) con la sua riga
|
||||
in `cron_daily` — non fatto, e' una decisione sul feed; e lo spot causale resta **stantio ≤25 min** (snapshot
|
||||
al :25, chiusura al :00; il feed 5m certificato lo ridurrebbe a ≤5). Trovati in revisione altri due lettori:
|
||||
**`r0730_vrp_real_quotes`** (il f 0,73 di §2 → **0,71**, dichiarato in §2) e **`r0901_btc_collar`** (join
|
||||
per giorno: riallineato con `causale(·, "-1D")`, bit-exact a prima). `options_vrp_calibrate.spot_series`
|
||||
(copia propria, numeri del 20/06) **non toccato**. Diario `2026-09-09b-debito-18-cblib-causale.md`.
|
||||
---
|
||||
|
||||
## 6. Le regole di prim'ordine
|
||||
@@ -660,7 +676,7 @@ uv run python scripts/live/<script>.py --help # uso e flag (d
|
||||
uv run python scripts/live/trades_db.py --reconcile # incrocio delle 3 fonti sui fill
|
||||
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 pytest # test (1008, tutti verdi al 09/09)
|
||||
uv run pytest # test (1011, tutti verdi al 09/09 sera)
|
||||
```
|
||||
|
||||
```python
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
# 2026-09-09b — Debito §5.18 riparato: `cblib` causale (spot +1h, DVOL +1 giorno) e §11 rimisurato
|
||||
|
||||
**Richiesta dell'operatore:** *"ripara il debito §5.18 su cblib e rimisura §11"*. Revisione col modello
|
||||
`fable` (agente fresco), come da regola.
|
||||
|
||||
**Esito in una riga:** riparato in `cblib` — spot e DVOL escono **gia' causali** — e §11 rimisurato allo
|
||||
stesso taglio: **0,714 [0,690-0,779] → 0,712 [0,664-0,732]** (n=19). Il numero non si muove perche' le due
|
||||
correzioni hanno **segno opposto**; **nessun verdetto cambia**; riparando la prima serie ne e' uscita una
|
||||
**seconda con lo stesso difetto** (il DVOL giornaliero, fino a 24 ore avanti); il DVOL orario resta un
|
||||
passo aperto **con costo misurato**. Libro, config, cron: invariati. Nessun ordine.
|
||||
|
||||
## 0. Il difetto, verificato prima di ripararlo (D6: si controlla col lag, non si assume)
|
||||
|
||||
| serie | come e' etichettata | prova | look-ahead di `asof(ts)` |
|
||||
|---|---|---|---|
|
||||
| feed 1h certificato | all'**apertura**: la barra T contiene la chiusura di T+1h | chiusura 1h a T == chiusura 5m a **T+55** nel **100%** delle barre (BTC ed ETH, 1-5/06); a T−5 nell'1,7% / 0% | **+1 ora** |
|
||||
| `dvol_{asset}.parquet` (giornaliero, `fetch_dvol`, `resolution=86400`) | al giorno D contiene la **chiusura delle 23:00 di D** | API pubblica a risoluzione 1h, 1-4/06: `close` 1D del giorno D == `close` 1h delle 23:00 di D, e `open` 1D di D+1 == `close` di D | **fino a +24 ore** |
|
||||
|
||||
La seconda riga non era nel debito: e' uscita controllando la convenzione dell'altra serie di
|
||||
contesto che `cblib` legge con lo stesso `asof`. Il sleeve (`_vrp_weekly_asset`) **non ha il difetto**:
|
||||
lavora a cadenza giornaliera e accosta la chiusura del giorno D al DVOL del giorno D, che a quella
|
||||
cadenza e' coerente. Il difetto e' solo di chi entra **a un'ora** con una serie giornaliera.
|
||||
|
||||
## 1. La riparazione
|
||||
|
||||
`cblib.causale(s, cadenza)` sposta le **etichette** (mai i valori) dall'apertura all'istante in cui la
|
||||
chiusura e' nota. `spot_series` → `causale(·, "1h")`, `dvol_series` → `causale(·, "1D")`. Conseguenze:
|
||||
|
||||
- `asof(ts)` = ultima chiusura **conosciuta** a ts (prima della prima chiusura nota: NaN, non un valore).
|
||||
- il regolamento `ST = S.asof(exp)` alle 08:00 e' ora la chiusura della barra 07:00, cioe' **il prezzo
|
||||
delle 08:00** — prima era la chiusura della barra 08:00, cioe' il prezzo delle **09:00**, un'ora dopo la
|
||||
scadenza. Deribit regola su una TWAP dei 30 minuti prima delle 08:00: l'approssimazione e' ora dalla
|
||||
parte giusta dell'ora.
|
||||
- `r0909_crash_catturato` **non ri-sposta** (lo `spot_causale` locale della mattina e' rimosso: applicato
|
||||
due volte darebbe la chiusura di **due** ore prima — lo stesso errore col segno opposto). Test di
|
||||
non-regressione sul sorgente.
|
||||
- chi usa `cblib`: `r0822_vrp_real_quotes` (§11), `r0822_skew` (§5), `r0909` (§75), **`vrp_f_watch`**
|
||||
(cron giornaliero, `data/vrp_f_watch/state.json`), e — trovati dal revisore, non da me —
|
||||
**`r0730_vrp_real_quotes`** (il f 0,73 [0,706-0,805] di CLAUDE.md §2: rigirato stampa **0,71
|
||||
[0,680-0,756]**, n=27, 0/27 ≥ 1, f gamba lunga 1,66 → 1,49; verdetto invariato, numero dichiarato in §2)
|
||||
e **`r0901_btc_collar`** (join del DVOL **per giorno**: con la serie causale avrebbe accostato l'IV di D
|
||||
al DVOL di D−1 — riallineato con `causale(·, "-1D")`, bit-exact a prima, §71 non si muove).
|
||||
`options_vrp_calibrate.py` ha una **copia propria** di `spot_series` (numeri del 20/06): **non toccato**,
|
||||
dichiarato.
|
||||
- la sezione di REGIME di `r0822` (date di calendario: «ultimo giorno aperto», IV-rank per anno) e la
|
||||
tabella di contesto di `r0909` usano `causale(V, "-1D")`: li' serve il DVOL **del** giorno, non
|
||||
l'etichetta causale — altrimenti ogni data stampata slitta di un giorno (trovato dal revisore).
|
||||
- `r0822_vrp_real_quotes` ha ora il flag `--al <data>` (taglio delle scadenze) per riprodurre una misura
|
||||
a una data: senza, "riprodurre il 22/08" era impossibile perche' la catena cresce ogni ora.
|
||||
|
||||
## 2. Prima di pubblicare il numero nuovo, la macchina ha riprodotto quello vecchio (M23)
|
||||
|
||||
Worktree di HEAD (`git worktree add`, `data/raw` in symlink), stesso script con `--al 2026-08-22`:
|
||||
**pooled 0,714 (IC95 [0,690, 0,779], n=19)** — al millesimo, IC compreso. Poi lo stesso comando sul
|
||||
codice riparato.
|
||||
|
||||
## 3. Scomposizione: due correzioni di segno opposto (M26) e un controllo orario
|
||||
|
||||
| taglio | spot | DVOL | pooled f | IC95 | n |
|
||||
|---|---|---|---|---|---|
|
||||
| 22/08 | grezzo | grezzo (com'era) | **0,714** | [0,690, 0,779] | 19 |
|
||||
| 22/08 | causale | grezzo | 0,721 | [0,685, 0,758] | 19 |
|
||||
| 22/08 | grezzo | causale (giornaliero) | 0,693 | [0,670, 0,748] | 19 |
|
||||
| 22/08 | causale | causale (giornaliero) = **`cblib` oggi** | **0,712** | [0,664, 0,732] | 19 |
|
||||
| 22/08 | causale | causale **orario** (controllo, API pubblica) | 0,717 | [0,667, 0,732] | 19 |
|
||||
| 09/09 | grezzo | grezzo | 0,720 | [0,717, 0,952] | 23 |
|
||||
| 09/09 | causale | causale (giornaliero) | **0,712** | [0,677, 0,741] | 23 |
|
||||
| 09/09 | causale | causale orario | 0,726 | [0,680, 0,738] | 23 |
|
||||
|
||||
Il DVOL di fine giornata **alzava** f: nel rally la vol scende dentro il giorno, la chiusura di D sta
|
||||
**sotto** quella di D−1 (+1,05 pt di vol mediana su 19/19 trade, misura del revisore) → denominatore piu'
|
||||
basso → f piu' alto; causale: −0,021. Lo spot di un'ora dopo, invece, **non e' un meccanismo ma rumore**:
|
||||
lo scarto per trade ha segno misto (mediana −0,02% BTC / −0,11% ETH, banda −0,6…+0,9%) e sposta f fino a
|
||||
**±0,15 per trade** (lo spread δ−0,28/−0,10 ha delta netto ~0,18: 0,5% di spot vale 15-20% del credito
|
||||
modellato); il +0,007 netto e' la somma di 19 segni. ⚠️ Corollario: lo spot causale resta **stantio fino
|
||||
a 25 minuti** (snapshot al :25, chiusura nota al :00), cioe' ±0,05-0,10 di f per osservazione; il feed
|
||||
**5m certificato** lo porterebbe a ≤5 minuti. Non fatto: dichiarato in §6. Il DVOL giornaliero causale e' **stantio fino a
|
||||
23 ore** (agli ingressi delle 08:00: 8 ore): scarto mediano dall'orario **0,2 punti di vol**, max 1,1
|
||||
(22/08) / 3,0 (oggi). Su §11 vale 0,005 di f.
|
||||
|
||||
## 4. Cosa cambia in §11 (taglio 22/08, stesso campione)
|
||||
|
||||
| grandezza | prima | dopo | perche' |
|
||||
|---|---|---|---|
|
||||
| f pooled | 0,714 [0,690-0,779] | **0,712 [0,664-0,732]** | §3 |
|
||||
| f BTC / ETH | 0,706 / 0,715 | 0,720 / 0,692 | |
|
||||
| Sharpe canonico BTC (titolo, non citabile) | 32,58 | 29,61 | regolamento alle 08:00 |
|
||||
| **mediana onesta** BTC (9 ancore) | 1,45 | **2,12** | banda [−0,19, 29,61] (era [−0,35, 32,58]) |
|
||||
| Sharpe canonico ETH → mediana onesta | 3,90 → 2,41 | 7,64 → 3,35 | una settimana ETH cambia taglia: 26/06 −27,38 → −12,84 $ (BTC: 31/07 19,88 → 31,69, 14/08 12,94 → 8,68) |
|
||||
| media BTC fra le ancore | −1,35% → +11,22% | −0,66% → +11,44% | **cambia ancora segno**; sd 11,1× → 9,2× |
|
||||
| forfait fee vs listino | 1,44× / 1,80× | 1,51× / 1,87× | credito modellato a DVOL causale |
|
||||
| peggior mark: mediana / minimo / minimo fra le vincenti | −6,4% / −91,0% / −56,9% | −6,4% / −91,5% / −55,2% | |
|
||||
| P&L somma 19 settimane | $2.733 | $2.822 (+3,3%) | tutto dal regolamento |
|
||||
| sottostante nel campione | +25,1% / +44,2% | +21,1% / +40,1% | il vecchio regolamento del 21/08 era il prezzo delle **09:00**, che sta **+3,9%** sopra quello delle 08:00 (76.311 → 79.316): un numero a due estremi pesa un'ora intera. (La prima stesura diceva «−1,8%»: avevo letto l'ora dopo, 09:00 → 10:00. Corretto dal revisore) |
|
||||
|
||||
**Verdetto di §11: SCARTATO, per le stesse quattro ragioni** (il campione non contiene la strategia; il
|
||||
titolo non sopravvive all'ora d'ingresso; la famiglia con storia non e' quella eseguibile; lo spread e'
|
||||
il costo dominante). Nessuna delle quattro dipende da un'ora di spot. Il testo del verdetto nello script
|
||||
riporta i numeri nuovi con i vecchi accanto.
|
||||
|
||||
## 5. Effetti collaterali, misurati (tutto cio' che legge `cblib`)
|
||||
|
||||
**§75, crollo catturato** (`r0909`, rigirato): ETH pre-crollo f_net **0,74 [0,65-0,82] → 0,76
|
||||
[0,71-0,86]**; peggior MTM 1,08 [1,07-1,31] → 1,08 [1,06-1,27]; put δ−0,10 1,92× → 1,98×; al picco 0,94 →
|
||||
0,99; BTC durante **0,79 → 0,89 [0,74-1,05]**, ETH durante 0,71 → 0,78. Con il DVOL **orario** BTC durante fa **0,83**: nel crollo
|
||||
il DVOL sale di 5-6 punti al giorno, quindi il giornaliero di fine giornata (com'era) sottostima f e
|
||||
quello del giorno prima (causale) lo sovrastima — **−0,04/+0,06 di f e' il prezzo della stantiezza in un
|
||||
crollo**, ed e' l'argomento per il feed orario. DVOL "pre" 37,3 → **36,4** (BTC): il 37,3 era la chiusura
|
||||
del **primo giorno di crollo** (01/06, −3,5%), non del giorno prima — IV-rank pre 0,05 → 0,03. Picco e
|
||||
percentili **invariati** (49,1 / 69,2; 29° / 46°) dopo aver corretto la tabella di contesto (§7).
|
||||
Verdetto invariato.
|
||||
|
||||
**§5, skew** (`r0822_skew`, rigirato, 66 s): la scomposizione sul panel si muove di **≤0,005** per fattore
|
||||
(term 0,880 · skew 0,917 · spread 0,910 · fit 0,995 · f_tot 0,729); Q1/Q2 (lag prezzo/skew) **non si
|
||||
toccano** (serie proprie ancorate a `ts_max`). Agli ingressi il controllo `f_markfit` passa da 1,045 a
|
||||
**0,991** e le osservazioni che lo superano da 22/28 a **25/28**: l'ora di spot in piu' stava **nel
|
||||
controllo**, non nell'effetto — riparare ha reso il controllo piu' pulito, non il risultato diverso.
|
||||
|
||||
**`vrp_f_watch`** (sorvegliante in `cron_daily`, criteri pre-registrati il 30/07 e **non toccati**):
|
||||
|
||||
| | prima (state.json del 09/09 mattina) | dopo |
|
||||
|---|---|---|
|
||||
| coppie | 28 | 28 |
|
||||
| f canonico | 0,732 [0,702-0,784] | **0,706 [0,678-0,745]** |
|
||||
| f candidato | 0,803 [0,741-0,842] | 0,805 [0,771-0,840] |
|
||||
| differenza | +0,054 [−0,027, +0,105], 18/28 > 0 | **+0,097 [+0,042, +0,140]**, 21/28 > 0 |
|
||||
| ampiezza IC95 (b ≤ 0,12) | 0,131 — no | **0,098 — OK** |
|
||||
| coppie (a ≥ 40) | no | no |
|
||||
| `ready` | False | False |
|
||||
|
||||
Lo `state.json` e' stato **riscritto** dal mio lancio (21:14Z, senza `--quiet`; nessun Telegram: notifica
|
||||
solo a `ready`); il «prima» completo e' la colonna qui sopra (n_positive 18, `esclude_zero` False), e il
|
||||
cron lo rigenera domani. La differenza ora **esclude lo zero**. Non decide niente: (a) non e' soddisfatto e il candidato resta
|
||||
bocciato sul deflated-Sharpe, che non dipende da f. Si registra perche' fra un mese qualcuno leggera'
|
||||
"esclude lo zero" e deve sapere da quando e perche'.
|
||||
|
||||
## 6. Cosa resta aperto, col suo costo
|
||||
|
||||
| voce | costo di non farlo | costo di farlo |
|
||||
|---|---|---|
|
||||
| **DVOL orario** nel feed (`fetch_dvol --res 3600`, riga in `cron_daily`, `cblib` che lo legge) | su §11 0,005 di f; **su un crollo ±0,05**; ogni misura oraria su opzioni a DVOL giornaliero eredita lo scarto | un fetch pubblico gratuito (3.163 barre da maggio in 2 chiamate), una riga di cron, e una decisione: e' un feed nuovo dentro il perimetro (D1, certificazione, backup) |
|
||||
| **spot causale stantio ≤25 min** (snapshot :25, chiusura :00): ±0,05-0,10 di f per osservazione | `cblib.spot_series` sul feed **5m** certificato (`causale(·, "5m")`): cambia di nuovo ogni numero di `cblib`, quindi con rimisura dichiarata |
|
||||
| `options_vrp_calibrate.spot_series` (copia, 20/06) | i numeri del 20/06 (f 0,73) restano con l'ora in piu'; §11 li ha gia' sostituiti | riscriverlo su `cblib` |
|
||||
| la tabella pubblicata di §5 (x0,869 / x0,904 / x0,920) | ≤0,005 per fattore: sotto la risoluzione del campione (14+14 scadenze) | nulla: nota aggiunta |
|
||||
|
||||
## 7. Errori dell'autore in sessione
|
||||
|
||||
- **`asi8` in microsecondi** scrivendo il test della causalita' (pandas 3): i timestamp sintetici finivano
|
||||
nel 1970 e il test falliva per la fixture, non per il codice. E' la trappola del debito 1, ripagata
|
||||
scrivendo un test *sul* debito 18. Corretto con `(idx − epoch) // Timedelta(ms)`, la convenzione di
|
||||
`load_tf`.
|
||||
- **La tabella di contesto di `r0909` si e' spostata di un giorno** dopo la riparazione: mostrava il DVOL
|
||||
del giorno D−1 accanto al prezzo del giorno D, e il picco del crollo cambiava (69,2 → 68,3, 46° → 43°)
|
||||
non per una misura ma per un'etichetta. Trovato **col diff degli output**, non da un test: una tabella
|
||||
per umani non ha test. Ora il contesto usa la chiusura *del* giorno (`causale(V, "-1D")`, dichiarato
|
||||
nel commento) e `dvol_pre` / `ivr_pre` restano causali.
|
||||
- Il verdetto §7 di `r0822_vrp_real_quotes` era **prosa con numeri cablati**: sarebbe rimasto a 0,714 per
|
||||
sempre (N11 al contrario). Aggiornato con i vecchi accanto; il difetto di forma resta (i numeri del
|
||||
verdetto andrebbero calcolati, non scritti).
|
||||
|
||||
## 8. Revisione (`fable`, agente fresco) — 16 segnalazioni, verdetto «correggi e committa»
|
||||
|
||||
Ha **riverificato in proprio** la convenzione delle due serie (1h vs 5m su 120 barre: 100%; DVOL contro
|
||||
l'API oraria) e riprodotto ogni numero dei documenti lanciando gli script. Applicate: **#2** «−1,8% in
|
||||
un'ora» era falso (avevo letto 09:00 → 10:00; il fatto e' +3,9% 08:00 → 09:00) · **#3** due delle tre
|
||||
settimane «ETH» erano BTC · **#4** la parentesi sul DVOL era invertita (la chiusura di D e' piu' BASSA,
|
||||
non piu' alta) · **#5** lo spot non e' un meccanismo ma rumore, e resta stantio ≤25 min · **#6/#7** due
|
||||
lettori di `cblib` non dichiarati: `r0730` (0,73 → 0,71, ora in CLAUDE.md §2) e `r0901` (riallineato) ·
|
||||
**#8** le date di calendario di `r0822` §1 slittavano di un giorno · **#9** il test anti-doppio-shift non
|
||||
catturava `causale(spot_series, "1h")`: ora conta i `causale(` · **#10** ancora 0,74 → 0,76 nel test
|
||||
d'integrazione · **#11** teste di §75 e memoria 20 §5 con i numeri vecchi come correnti (M28) · **#12**
|
||||
«±0,05» → «−0,04/+0,06» · **#13** `state.json` riscritto: dichiarato · **#15** lo skew agli ingressi cambia
|
||||
piu' del panel (correlazioni che cambiano segno): dichiarato in §5. Non applicate: nessuna. Confermati
|
||||
senza rilievo (#1, #14, #16): verso e taglia degli shift, nessun doppio spostamento, `ST` alle 08:00
|
||||
coerente con la TWAP 07:30-08:00, tutti i numeri di §3-§5.
|
||||
|
||||
## 9. Test
|
||||
|
||||
`tests/test_cb_chain_vrp.py`: +3 (causale; `spot_series` causale sul feed 1h con controllo positivo sulla
|
||||
serie grezza; `dvol_series` causale sul giornaliero). `tests/test_r0909_crash_catturato.py`: il test dello
|
||||
shift locale diventa "lo script usa le serie di `cblib` senza ri-spostarle" (sorgente + controllo positivo
|
||||
su `cblib.causale`). Suite intera: **1011 passati, 0 falliti** (erano 1008), rilanciata dopo le correzioni della revisione: 1011/1011.
|
||||
@@ -701,7 +701,7 @@ chi lo riapre deve battere il motivo, non ripetere l'esperimento.
|
||||
**0,93** (alto) e **supera 1 in backwardation** mentre `f_skew` resta piatto -> **la parte maggiore
|
||||
del difetto si annulla proprio dove il gate fa tradare il sleeve**, quindi f=0,73 e' plausibilmente
|
||||
**conservativo li'**. Non misurato (0/22 ingressi passano il gate) e in un crash i due pezzi vanno
|
||||
in **direzioni contrarie**. **`VRP_CFG["f"]` NON cambiato.** Replica indipendente del f: **0,714**.
|
||||
in **direzioni contrarie**. **`VRP_CFG["f"]` NON cambiato.** Replica indipendente del f: **0,714** (0,712 dal 09/09 sera, `cblib` causale; il 0,73 del 30/07 stampa 0,71).
|
||||
📌 **(7) CHIUSURE DI FAMIGLIA.** **Il filone funding si chiude sul QUARTO lato** (affollamento):
|
||||
su **53.430 ore / 3 anni** non predice ne' direzione ne' volatilita'. E i futures datati **non sono
|
||||
un quinto lato**: il loro basis **E'** il funding del perp (+7,33% implicito contro **+6,48%**
|
||||
@@ -1532,7 +1532,7 @@ una maschera a caso della stessa frequenza**.
|
||||
−3,38%: crollo con TP01 a 0,505 (lo squeeze di §33 e' sulla lente hourly). 37,5/62,5 batte 12/12 episodi
|
||||
ma maxDD 12,1% vs 9,4%; gate fallisce in-sample (cache `skh_sigtab` ferma al 25/07). **(2) Crollo
|
||||
catturato**: l'archivio bite copre con bid/ask il 1-5/06/2026 (BTC −25%, ETH −30%), scadenza 19/06, inverse.
|
||||
ETH pre-crollo (4 strutture): f_net **0,74 = 0,714 del rally**; f a scadenza 1,04 ma **tautologico** (ambo le
|
||||
ETH pre-crollo (4 strutture): f_net **0,76 [0,71-0,86] = 0,712 del rally** (rimisurato la sera con `cblib` causale; era 0,74 = 0,714); f a scadenza 1,04 ma **tautologico** (ambo le
|
||||
gambe ITM ⇒ solo f_net); peggior MTM **1,08** dopo il taglio alla larghezza — la prima stesura diceva 2,58 con
|
||||
"IV corta esplosa a 108 per lo skew": **artefatto** (quote 158% di spread a T→0; la IV 108 e' del 18/06, a T→0);
|
||||
put δ−0,10 costa **1,92×** il modello (punto nuovo, sopra l'1,27 di §46) e paga come il modello (0,94-1,04);
|
||||
@@ -1544,7 +1544,8 @@ una maschera a caso della stessa frequenza**.
|
||||
Coinbase delisto' XRP 2021-01→2023-07, riferimento Bitstamp prima); 5m flat 27-61%. Dato in
|
||||
`data/raw/alt_xrp_*`. **(4) Venue**: 32 perp USDC, liquidi ≥$10M/g solo XRP/ETH/BTC/SOL; XS01 13/19 (APT
|
||||
inactive); `BTCDVOL_USDC` future esiste ma vol 0 / spread 12%; PAXG perp non misurato (9 mesi, $0,18M/g).
|
||||
**Debito nuovo (§5.18)**: `cblib.spot_series` + `asof` guarda un'ora avanti (feed 1h etichettato
|
||||
all'apertura). **Errori dell'autore smontati dal revisore `fable`**: il 2,6× (artefatto) e "8/12 GUADAGNA"
|
||||
**Debito §5.18** (`cblib.spot_series` + `asof` un'ora avanti) **riparato la sera stessa**, insieme al DVOL
|
||||
(fino a 24h avanti): §11 0,714 → 0,712, verdetti invariati; `vrp_f_watch` f canonico 0,732 → 0,706 e la
|
||||
differenza col candidato +0,097 [+0,042, +0,140] ora esclude lo zero (criterio (a) 28/40 ancora aperto). **Errori dell'autore smontati dal revisore `fable`**: il 2,6× (artefatto) e "8/12 GUADAGNA"
|
||||
(l'ordine delle classi era il verdetto: immune → POSITIVO da' 4+6). Nessun cambio a libro/pesi/config.
|
||||
|
||||
|
||||
@@ -164,8 +164,13 @@
|
||||
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.
|
||||
✅ **RIPARATO la sera stessa in `cblib`** (`causale(s, cadenza)`: spot +1h, e **anche il DVOL
|
||||
giornaliero, +1 giorno** — la riga del giorno D e' la chiusura delle 23:00 di D, verificato contro la
|
||||
risoluzione 1h dell'API pubblica: seconda serie con lo stesso difetto, quinta occorrenza di D6). §11
|
||||
riprodotto al millesimo su worktree HEAD e rimisurato: 0,714 → **0,712** (le correzioni hanno segno
|
||||
opposto; DVOL orario di controllo 0,717). Il DVOL causale da feed giornaliero e' **stantio fino a 23 ore**
|
||||
(0,2 pt mediana, 3 pt max; nel crollo ±0,05 di f): il feed DVOL orario e' il passo aperto. Diario
|
||||
`2026-09-09b-debito-18-cblib-causale.md`.
|
||||
- **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`).
|
||||
|
||||
@@ -197,6 +197,18 @@ lati contro il **93%** di BTC_USDC, e il suo miglior bid sta a **un tick**.
|
||||
DVOL alla mediana del 7°/11° percentile storico, sottostante +25%/+44%.
|
||||
- ✅ **Replica indipendente del f del 30/07 su campione piu' lungo: f = 0,714 pooled** (IC95
|
||||
[0,690, 0,779], **0/19 osservazioni >= 1,0**). Attraversare lo spread costa **~10% del credito**.
|
||||
✅ **RIMISURATO il 2026-09-09 sera** (debito §5.18: `cblib` dava lo spot di un'ora DOPO e il DVOL di
|
||||
fino a 24 ore DOPO l'ingresso): allo stesso taglio (22/08, n=19) **f = 0,712 [0,664, 0,732]** — le due
|
||||
correzioni hanno segno opposto (solo spot 0,721, solo DVOL 0,693) e un DVOL orario di controllo da'
|
||||
0,717; a oggi (n=23) 0,712 [0,677, 0,741]. **Il verdetto non cambia.** Cambiano i numeri di
|
||||
contorno: Sharpe canonico BTC 32,58 → 29,61 con mediana onesta **2,12** (era 1,45) e banda
|
||||
[−0,19, 29,61]; ETH 3,90 → 7,64 (mediana onesta 3,35); media BTC fra le ancore −0,66% → +11,44%
|
||||
(cambia ancora segno); forfait fee 1,51× (BTC) / 1,87× (ETH); il regolamento e' il prezzo delle
|
||||
08:00 e non delle 09:00 (P&L +3,3%); sottostante nel campione +21% / +40% (era +25% / +44%: il vecchio
|
||||
regolamento del 21/08 era il prezzo delle 09:00, **+3,9%** sopra quello delle 08:00 — quanto pesa un'ora su
|
||||
un numero a due estremi). Lo stesso `cblib` rigira anche `r0730`: il f 0,73 [0,706-0,805] del 30/07 stampa
|
||||
ora **0,71 [0,680-0,756]** (n=27, 0/27 ≥ 1).
|
||||
Diario `2026-09-09b-debito-18-cblib-causale.md`.
|
||||
- ⚠️ **Correzione a un numero pubblicato:** il forfait fee del sleeve sovrastima il listino vero di
|
||||
**1,44x (BTC) / 1,80x (ETH)**, non di "~2x". Il segno (conservativo) regge, la taglia no.
|
||||
- ⚠️ **Rischio sul MINIMO, non sulle chiusure:** peggior mark infra-settimana mediana −6,4% del
|
||||
@@ -374,6 +386,13 @@ nuovo: **va decisa PRIMA del 23/10, non quel giorno.**
|
||||
(il collettore li accumula da solo), revisione comunque **2027-02-22**.
|
||||
- ✅ Confound di modello **ESCLUSO e misurato**: `f_markfit` = **0,992** (la mark IV di Deribit
|
||||
riprezza i propri mid entro l'1%) -> RR/BF sono un fatto di **prezzo**, non l'output del fit.
|
||||
📌 **Rigirato il 2026-09-09 sera con spot e DVOL causali** (debito §5.18): la scomposizione sul panel si
|
||||
muove di **≤0,005** per fattore (term 0,880 · skew 0,917 · spread 0,910 · fit 0,995 · f_tot 0,729) e Q1/Q2
|
||||
non si toccano (serie proprie); agli **ingressi** il controllo `f_markfit` passa da 1,045 a **0,991** e
|
||||
le osservazioni che lo superano da 22/28 a **25/28** — l'ora di spot in piu' stava nel controllo, non
|
||||
nell'effetto. Agli ingressi (n=28) si muove di piu': f_term 0,910 → 0,875, f_tot 0,732 → 0,706, e le
|
||||
correlazioni `corr(f_tot_mid, rr7)` +0,21 → −0,06 e `atm7` +0,02 → +0,34 **cambiano segno/ordine** — sono
|
||||
22-25 punti, dichiarate (P12), non usate.
|
||||
- ✅ **Controllo positivo cablato nello script:** con l'ancora **assunta** a :30 invece del `ts_max`
|
||||
osservato compare un **falso lead** a +15m (0,102 contro 0,031) — *"e' l'errore che avrei
|
||||
pubblicato senza quel controllo"*.
|
||||
@@ -3997,7 +4016,7 @@ nuovo: quello che guadagna nei crolli e' gia' in produzione, e la leva che lo au
|
||||
|
||||
`scripts/research/r0909_crash_catturato.py`. **Nessun ordine.** L'archivio bite copre con bid/ask il crollo
|
||||
1-5/06/2026 (BTC −25%, ETH −30%; scadenza 19/06, 14-21 DTE, famiglia INVERSE); il campione di §11 partiva
|
||||
dal fondo. ETH, ingressi pre-crollo (286 snapshot = **4 strutture**): f_net **0,74 = 0,714 del rally**;
|
||||
dal fondo. ETH, ingressi pre-crollo (286 snapshot = **4 strutture**): f_net **0,76 [0,71-0,86] = 0,712 del rally** (era 0,74 = 0,714 prima della riparazione di §5.18, la sera stessa; put 1,98× e picco 0,99 idem);
|
||||
f a scadenza 1,04 ma **tautologico** nell'83% (ambo le gambe ITM ⇒ solo f_net); peggior MTM **1,08**
|
||||
dopo il taglio alla larghezza; put δ−0,10 costa **1,92×** il modello (punto nuovo sopra l'1,27 di §46)
|
||||
e paga come il modello (0,94-1,04); ingressi durante il crollo bimodali (perde il 46%). BTC pre-crollo
|
||||
@@ -4006,9 +4025,11 @@ IV-rank di VRP01 CHIUSO in tutte le ore. ⇒ la condizione di §3 e' soddisfatta
|
||||
sostanza: non si riapre**. Servono un crollo con IV-rank > 0,30 e la famiglia USDC-lineare.
|
||||
🚨 **Due conclusioni dell'autore smontate in revisione:** «MTM 2,58× per lo skew (IV 108)» era un
|
||||
artefatto (quote con 158% di spread a T→0 oltre la larghezza; la IV 108 e' del 18/06 a T→0); «f a
|
||||
scadenza 1,04 = il modello prezza bene» era una tautologia. **Debito nuovo (CLAUDE.md §5.18):**
|
||||
`cblib.spot_series` + `asof` guarda un'ora avanti (feed 1h etichettato all'apertura); qui corretto con
|
||||
`spot_causale`, in `cblib` no (toccherebbe il 0,714 di §11).
|
||||
scadenza 1,04 = il modello prezza bene» era una tautologia. **Debito §5.18 RIPARATO la sera stessa** in `cblib`
|
||||
(spot +1h, e anche il DVOL giornaliero, +1 giorno): ETH pre-crollo f_net **0,76 [0,71-0,86]** (era 0,74),
|
||||
BTC durante **0,89 [0,74-1,05]** (era 0,79; con DVOL orario 0,83 — nel crollo il DVOL giornaliero stantio
|
||||
vale −0,04/+0,06 di f), put δ−0,10 1,98× (era 1,92), DVOL pre 36,4 / 49,6 (il 37,3 di BTC era la chiusura del
|
||||
PRIMO giorno di crollo: contaminato). Picco e percentili invariati. Verdetto invariato.
|
||||
**VERDETTO: `CATTURATO, MA A VOL BASSA E FUORI DAL GATE: f_net NON CAMBIA COL REGIME`** — nessuna riapertura.
|
||||
|
||||
## 76 — XRP-TERZA-GAMBA (l'unica altra moneta liquida di Deribit, coi meccanismi congelati)
|
||||
|
||||
@@ -9,6 +9,9 @@ lontana, che il 30/07 aveva misurato sottoprezzata ~2.3x.
|
||||
piu' mispriced in RELATIVO (f_long 5.85 contro 2.23) ma pesa il **3.2%** del premio corto invece
|
||||
del **18.4%**, quindi sul credito NETTO l'effetto e' minore: f_net **0.852** contro **0.718**.
|
||||
Meccanismo giusto, segno della conclusione sbagliato.
|
||||
(Numeri del 30/07, misurati con `cblib` che leggeva spot e DVOL di UN'ORA / fino a 24 ORE dopo
|
||||
l'ingresso — debito §5.18, riparato la sera del 09/09: da allora la tabella stampata da questo
|
||||
script e' la fonte, e il f canonico e' passato da 0,732 a 0,706 sulle stesse 28 coppie.)
|
||||
|
||||
E' pero' una misura su **16 coppie**: la differenza appaiata e' **+0.109 con IC95
|
||||
[-0.047, +0.193]**, cioe' **compatibile con zero**. Serve piu' campione, e "quando ce ne sara'
|
||||
|
||||
@@ -13,6 +13,10 @@ Regola che vale per ogni misura fatta con questo modulo: il f della sola gamba c
|
||||
dello spread. Il modello sbaglia soprattutto sull'ala che si COMPRA (piu' OTM, IV piu' alta per
|
||||
skew, prezzata dal modello a vol ATM) -> misurare una gamba sola da' la risposta sbagliata con
|
||||
segno rassicurante.
|
||||
|
||||
Seconda regola (09/09, debito §5.18): spot e DVOL escono da qui gia' CAUSALI — `asof(ts)` da'
|
||||
l'ultima chiusura nota a ts. Chi costruisce una serie di prezzi altrove usi `causale()`, non
|
||||
l'indice del feed com'e' (etichettato all'apertura: D6).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -65,23 +69,48 @@ def puts(asset: str, df: pd.DataFrame | None = None) -> pd.DataFrame:
|
||||
return d[(d["asset"] == asset) & (d["option_type"] == "P")]
|
||||
|
||||
|
||||
def causale(s: pd.Series, cadenza: str) -> pd.Series:
|
||||
"""Rietichetta una serie di CHIUSURE dall'APERTURA della barra all'istante in cui la chiusura
|
||||
e' nota (apertura + cadenza), cosi' `s.asof(ts)` restituisce l'ultima chiusura CONOSCIUTA a ts
|
||||
e mai una futura. I valori non si toccano, solo le etichette.
|
||||
|
||||
🚨 Perche' esiste (debito §5.18, 09/09): i feed del progetto sono etichettati all'apertura —
|
||||
la barra 1h `20:00` chiude col 5m delle 20:55 (verificato: chiusura 1h a T == chiusura 5m a
|
||||
T+55 nel 100% delle barre) e la riga DVOL del giorno D e' la chiusura delle 23:00 di D
|
||||
(verificato contro la risoluzione 1h dell'API pubblica). Senza questo spostamento `asof(ts)`
|
||||
dava lo spot di UN'ORA dopo e il DVOL di FINO A 24 ORE dopo l'ingresso (D6, quinta occorrenza)."""
|
||||
out = s.copy()
|
||||
out.index = out.index + pd.Timedelta(cadenza)
|
||||
return out
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def spot_series(asset: str) -> pd.Series:
|
||||
"""Chiusure 1h del feed certificato, etichettate all'istante in cui sono NOTE (apertura + 1h).
|
||||
|
||||
`spot_series(a).asof(ts)` = ultima chiusura oraria conosciuta a `ts`. Conseguenza sul
|
||||
regolamento: `asof(exp)` alle 08:00 e' la chiusura della barra 07:00, cioe' il prezzo delle
|
||||
08:00 — prima era il prezzo delle 09:00, un'ora DOPO la scadenza."""
|
||||
from scripts.analysis.research_lab import load_tf
|
||||
px = load_tf(asset, "1h")
|
||||
s = pd.Series(px["close"].values.astype(float),
|
||||
index=pd.to_datetime(px["timestamp"], unit="ms", utc=True)).sort_index()
|
||||
s.index = pd.DatetimeIndex(s.index).as_unit("ns") # le quote bite hanno microsecondi
|
||||
return s
|
||||
return causale(s, "1h")
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def dvol_series(asset: str) -> pd.Series:
|
||||
"""DVOL giornaliero (chiusura), etichettato all'istante in cui e' NOTO (giorno + 1D).
|
||||
|
||||
`dvol_series(a).asof(ts)` = ultima chiusura giornaliera del DVOL conosciuta a `ts`: dentro il
|
||||
giorno D e' la chiusura di D−1, quindi vecchia fino a 23 ore. E' il prezzo della causalita'
|
||||
con un feed giornaliero; l'alternativa (DVOL orario dall'API pubblica) non e' nel feed."""
|
||||
d = pd.read_parquet(RAW / f"dvol_{asset.lower()}.parquet")
|
||||
s = pd.Series(d["close"].values.astype(float),
|
||||
index=pd.to_datetime(d["timestamp"], unit="ms", utc=True)).sort_index()
|
||||
s.index = pd.DatetimeIndex(s.index).as_unit("ns")
|
||||
return s
|
||||
return causale(s, "1D")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ prezzo
|
||||
|
||||
@@ -310,11 +310,15 @@ def boot_ci(x: np.ndarray, n: int = 4000, seed: int = 822) -> tuple[float, float
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--no-live", action="store_true", help="non interrogare il venue")
|
||||
ap.add_argument("--al", default=None,
|
||||
help="data di taglio UTC (riproduzione): esclude le scadenze >= questa data; default adesso")
|
||||
args = ap.parse_args()
|
||||
|
||||
print(__doc__.split("\n\n")[0])
|
||||
puts = load_puts()
|
||||
today = pd.Timestamp.now(tz="UTC")
|
||||
today = pd.Timestamp(args.al, tz="UTC") if args.al else pd.Timestamp.now(tz="UTC")
|
||||
print(f"\n taglio dei trade: scadenze < {today:%Y-%m-%d %H:%M}Z"
|
||||
+ (" (--al: riproduzione)" if args.al else " (adesso)"))
|
||||
venue = venue_read(not args.no_live)
|
||||
|
||||
# ------------------------------------------------------------ §1 REGIME
|
||||
@@ -323,7 +327,7 @@ def main() -> None:
|
||||
"misurato 4 volte). Se nel campione quel gate non scatta mai, il campione non contiene\n"
|
||||
"la strategia — contiene la sua astensione.\n")
|
||||
for a in ASSETS:
|
||||
V = CB.dvol_series(a)
|
||||
V = CB.causale(CB.dvol_series(a), "-1D") # calendario: il DVOL DEL giorno D (la serie di cblib e' causale: sta a D+1)
|
||||
win = V[(V.index >= puts["ts"].min()) & (V.index <= puts["ts"].max())]
|
||||
hist = V[V.index < win.index[0]].to_numpy(float)
|
||||
print(f" {a}: DVOL nel campione min {win.min():.1f} / mediana {win.median():.1f} / "
|
||||
@@ -372,7 +376,7 @@ def main() -> None:
|
||||
print(" Regola del 19/06: «rivalutare quando la catena cattura un crash». Un criterio senza\n"
|
||||
" numero non e' un criterio, quindi eccolo (IV-rank espandente causale, come nel sleeve):")
|
||||
for a in ASSETS:
|
||||
V = CB.dvol_series(a)
|
||||
V = CB.causale(CB.dvol_series(a), "-1D") # idem: date di calendario, non etichette causali
|
||||
vals = V.to_numpy(float)
|
||||
ivr = np.full(len(vals), np.nan)
|
||||
for i in range(1, len(vals)):
|
||||
@@ -753,13 +757,17 @@ def main() -> None:
|
||||
|
||||
# ------------------------------------------------------------ §7 VERDETTO
|
||||
hr("§7 VERDETTO")
|
||||
print(""" SCARTATO — su questi dati la domanda non e' decidibile. Quattro motivi, indipendenti
|
||||
print(""" (numeri della stesura del 22/08, RIMISURATI il 09/09 con spot e DVOL causali — debito §5.18:
|
||||
erano 0.714 [0.690, 0.779] · 32.58 / 1.45 / -0.35 · 3.90 -> 2.41 · -1.35% -> +11.22% · +25% / +44%.
|
||||
Il verdetto non cambia: le quattro ragioni non dipendono da un'ora di spot.)
|
||||
|
||||
SCARTATO — su questi dati la domanda non e' decidibile. Quattro motivi, indipendenti
|
||||
l'uno dall'altro: ciascuno da solo basterebbe.
|
||||
|
||||
1. IL CAMPIONE NON CONTIENE LA STRATEGIA. 0 settimane su 19 passano il gate IV-rank>0.30
|
||||
che E' l'alpha di VRP01 — il sleeve sarebbe stato FLAT per l'intero campione. La DVOL
|
||||
mediana sta al 7 (BTC) / 11 (ETH) percentile della storia 2021+, e il sottostante e'
|
||||
salito del +25% / +44%: vol implicita bassa E rialzo forte = il regime MIGLIORE
|
||||
salito del +21% / +40%: vol implicita bassa E rialzo forte = il regime MIGLIORE
|
||||
possibile per vendere put, non uno neutro. Le settimane sono 10 per asset, non 16
|
||||
(prima del 2026-06-09 l'archivio seguiva solo la finestra 13-20 DTE: quella 4-10 DTE
|
||||
non esiste). Esito: 10/10 vincenti su BTC, e la lente giusta non e' lo Sharpe ma la
|
||||
@@ -770,13 +778,13 @@ def main() -> None:
|
||||
regime di vol bassa persistente, non davanti a un muro.
|
||||
|
||||
2. IL TITOLO NON SOPRAVVIVE ALL'ORA D'INGRESSO. E' un max-of-k mai dichiarato, misurato
|
||||
qui per la prima volta su questa struttura: su 9 ancore lo Sharpe canonico BTC 32.58
|
||||
sta all'89 percentile, la MEDIANA ONESTA e' 1.45 e la banda tocca il NEGATIVO (-0.35).
|
||||
Su ETH 3.90 -> 2.41. Il numero da citare per BTC e' 1.45, non 32.58.
|
||||
qui per la prima volta su questa struttura: su 9 ancore lo Sharpe canonico BTC 29.61
|
||||
sta all'89 percentile, la MEDIANA ONESTA e' 2.12 e la banda tocca il NEGATIVO (-0.19).
|
||||
Su ETH 7.64 -> 3.35. Il numero da citare per BTC e' 2.12, non 29.61.
|
||||
⚠️ E il meccanismo non e' quello che avevo scritto prima di guardarlo. Non e' solo la
|
||||
vol campionaria a ballare: fra le ancore la MEDIA settimanale BTC va da -1.35% a
|
||||
+11.22% del rischio — CAMBIA SEGNO — e la deviazione standard di 11x (ETH: media 2.9x,
|
||||
sd 2.4x). Spostare l'ora d'ingresso cambia lo snapshot e quindi quali strike combaciano
|
||||
vol campionaria a ballare: fra le ancore la MEDIA settimanale BTC va da -0.66% a
|
||||
+11.44% del rischio — CAMBIA SEGNO — e la deviazione standard di 9.2x (ETH: media 2.1x,
|
||||
sd 3.2x). Spostare l'ora d'ingresso cambia lo snapshot e quindi quali strike combaciano
|
||||
col delta bersaglio: non e' lo stesso trade un'ora dopo, e' UN'ALTRA STRUTTURA. A 10
|
||||
settimane questo parametro di disturbo domina il segnale che si vorrebbe misurare.
|
||||
|
||||
@@ -793,7 +801,7 @@ def main() -> None:
|
||||
4. LO SPREAD E' IL COSTO DOMINANTE, E SULLA FAMIGLIA ESEGUIBILE E' PEGGIO. Attraversare
|
||||
il bid/ask costa ~10% del credito sugli INVERSE; nella regione di strike che serve lo
|
||||
spread relativo mediano e' 24-37% sugli inverse e 29-59% sulle USDC, con open interest
|
||||
~0. Il f del credito netto si replica indipendentemente a 0.714 (IC95 [0.690, 0.779],
|
||||
~0. Il f del credito netto si replica indipendentemente a 0.712 (IC95 [0.664, 0.732],
|
||||
0/19 osservazioni >= 1.0) — conferma dello 0.73 del 30/07 su un campione piu' lungo e
|
||||
con un percorso diverso.
|
||||
|
||||
|
||||
@@ -167,7 +167,8 @@ def calibra_catena() -> dict:
|
||||
skew[nm] = (np.array(xs), np.array(ys))
|
||||
|
||||
# struttura a termine: IV ATM a DTE t contro il DVOL 30g dello stesso istante
|
||||
dv = cblib.dvol_series("BTC")
|
||||
dv = cblib.causale(cblib.dvol_series("BTC"), "-1D") # join per GIORNO: il DVOL del giorno D — la serie di
|
||||
# cblib e' causale dal 09/09 sera (la chiusura di D sta a D+1); senza questo il join accosterebbe l'IV di D al DVOL di D−1
|
||||
a = q[q["ad"].between(0.45, 0.55)].copy()
|
||||
a["giorno"] = a["ts"].dt.floor("D")
|
||||
dvd = dv.copy()
|
||||
|
||||
@@ -33,8 +33,10 @@ Un episodio e' un episodio: da' la TAGLIA di f nello stress, non la sua distribu
|
||||
|
||||
DUE CORREZIONI DELLA REVISIONE (fable, 09/09), applicate:
|
||||
* il feed 1h e' etichettato all'APERTURA (la barra 20:00 chiude alle 21:00): `S.asof(ts)`
|
||||
guardava un'ora AVANTI. Qui lo spot e' `spot_causale` = chiusura dell'ultima barra chiusa a ts.
|
||||
⚠️ `cblib.spot_series` ha lo stesso difetto (e quindi il f 0,714 di §11): registrato, non toccato.
|
||||
guardava un'ora AVANTI. Corretto la mattina del 09/09 qui con uno `spot_causale` locale;
|
||||
la sera dello stesso giorno la riparazione e' entrata in `cblib` (`causale`, debito §5.18) e
|
||||
copre anche il DVOL giornaliero (fino a 24 ore avanti): questo script usa le serie di `cblib`
|
||||
COME SONO, senza ri-spostarle.
|
||||
* il costo di chiusura `(ask corta − bid lunga)·spot` puo' superare la LARGHEZZA dello spread
|
||||
(una quota da 158% di spread relativo a T→0): uno spread a rischio definito non costa mai piu'
|
||||
della larghezza per chiudere (si lascia regolare). Il MTM e' tagliato alla larghezza e le ore
|
||||
@@ -76,13 +78,6 @@ def leg_fee(prem_base: float, spot: float) -> float:
|
||||
return min(FEE_UNDERLYING * spot, FEE_PREMIUM_CAP * prem_base * spot)
|
||||
|
||||
|
||||
def spot_causale(S: pd.Series) -> pd.Series:
|
||||
"""Il feed 1h e' etichettato all'apertura: la chiusura della barra T e' nota a T+1h. Spostando
|
||||
l'indice di +1h, `asof(ts)` restituisce l'ultima chiusura CONOSCIUTA a ts, mai una futura."""
|
||||
out = S.copy(); out.index = out.index + pd.Timedelta(hours=1)
|
||||
return out
|
||||
|
||||
|
||||
def carica() -> pd.DataFrame:
|
||||
a = pd.read_parquet(ARCHIVIO)
|
||||
a["ts"] = pd.to_datetime(a["ts"], utc=True)
|
||||
@@ -213,7 +208,7 @@ def misura() -> dict:
|
||||
out = {"trades": {}, "contesto": {}, "sleeve": {}}
|
||||
for asset in ASSETS:
|
||||
seg = a[a["asset"] == asset]
|
||||
S, V = spot_causale(CB.spot_series(asset)), CB.dvol_series(asset)
|
||||
S, V = CB.spot_series(asset), CB.dvol_series(asset) # gia' causali (cblib, dal 09/09 sera)
|
||||
Q = Quote(seg, S, V)
|
||||
rows = []
|
||||
for ts in sorted(seg["ts"].unique()):
|
||||
@@ -227,17 +222,21 @@ def misura() -> dict:
|
||||
# contesto: DVOL, RV5 e RV1 sul crollo
|
||||
px = S[(S.index >= pd.Timestamp("2026-05-20", tz="UTC")) & (S.index <= EXP)]
|
||||
pd_ = px.resample("1D").last().dropna() # chiusura del giorno = ultima chiusura nota entro le 24:00
|
||||
hist_all = V[V.index < CROLLO[0]]
|
||||
# CONTESTO per giorno: la serie di cblib e' causale (la chiusura del giorno D sta a D+1);
|
||||
# qui si vuole "il DVOL DEL giorno D" accanto al prezzo del giorno D, quindi si toglie lo
|
||||
# spostamento SOLO per la tabella e per il picco del crollo. `dvol_pre` e `ivr_pre` restano
|
||||
# sulla serie causale: sono cio' che si sapeva alle 00:00 del primo giorno di crollo.
|
||||
dvg = CB.causale(V, "-1D")
|
||||
hist_all = dvg[dvg.index < CROLLO[0]]
|
||||
lr = np.log(pd_).diff()
|
||||
rv5 = lr.rolling(5).std() * np.sqrt(365.25) * 100
|
||||
dv = V[(V.index >= pd.Timestamp("2026-05-20", tz="UTC")) & (V.index <= EXP)]
|
||||
hist = V[V.index < CROLLO[0]]
|
||||
dv = dvg[(dvg.index >= pd.Timestamp("2026-05-20", tz="UTC")) & (dvg.index <= EXP)]
|
||||
out["contesto"][asset] = dict(
|
||||
spot=pd_, ret=lr, rv5=rv5, dvol=dv,
|
||||
dvol_max_crollo=float(dv[(dv.index >= CROLLO[0]) & (dv.index <= CROLLO[1])].max()),
|
||||
dvol_pre=float(V.asof(CROLLO[0])),
|
||||
pctl_picco=float((hist_all < V[(V.index >= CROLLO[0]) & (V.index <= CROLLO[1])].max()).mean()),
|
||||
ivr_pre=float((hist < V.asof(CROLLO[0])).mean()),
|
||||
pctl_picco=float((hist_all < dv[(dv.index >= CROLLO[0]) & (dv.index <= CROLLO[1])].max()).mean()),
|
||||
ivr_pre=float((hist_all < V.asof(CROLLO[0])).mean()),
|
||||
rv5_max=float(rv5[(rv5.index >= CROLLO[0]) & (rv5.index <= CROLLO[1] + pd.Timedelta(days=3))].max()),
|
||||
caduta=float(pd_[CROLLO[0]:CROLLO[1]].min() / pd_[:CROLLO[0]].iloc[-1] - 1.0),
|
||||
)
|
||||
|
||||
@@ -23,7 +23,8 @@ sys.path.insert(0, str(ROOT))
|
||||
sys.path.insert(0, str(ROOT / "scripts" / "research"))
|
||||
sys.path.insert(0, str(ROOT / "scripts" / "analysis"))
|
||||
|
||||
from cblib import bs_put, f_factors, pick_legs # noqa: E402
|
||||
import cblib # noqa: E402
|
||||
from cblib import bs_put, causale, f_factors, pick_legs # noqa: E402
|
||||
from certify_cb_chain import ( # noqa: E402
|
||||
crossed_rate, hollow_rate, monotonicity_violations, worst_day_hollow,
|
||||
)
|
||||
@@ -196,3 +197,61 @@ def test_nel_sleeve_f_moltiplica_il_credito_NETTO():
|
||||
assert SL.VRP_CFG["f"] == 1.0, (
|
||||
"il sleeve gira ancora a f=1.0: se cambia, aggiornare il diario 2026-07-30 e CLAUDE.md"
|
||||
)
|
||||
|
||||
|
||||
# ===========================================================================================
|
||||
# C. CAUSALITA' delle serie di contesto (debito §5.18, 09/09): `asof(ts)` non guarda avanti
|
||||
# ===========================================================================================
|
||||
|
||||
def test_causale_rietichetta_alla_chiusura_e_non_tocca_i_valori():
|
||||
"""Il feed e' etichettato all'APERTURA: la chiusura della barra T e' nota a T+cadenza.
|
||||
DEVE FALLIRE SE: qualcuno "semplifica" togliendo lo spostamento, o sposta i VALORI."""
|
||||
idx = pd.date_range("2026-06-01", periods=5, freq="h", tz="UTC")
|
||||
S = pd.Series([10.0, 11.0, 12.0, 13.0, 14.0], index=idx)
|
||||
Sc = causale(S, "1h")
|
||||
assert list(Sc.index) == list(idx + pd.Timedelta(hours=1))
|
||||
assert Sc.asof(idx[2]) == 11.0, "a 02:00 e' nota la chiusura della barra 01:00"
|
||||
assert S.asof(idx[2]) == 12.0, "il difetto che la funzione ripara (controllo positivo)"
|
||||
assert np.isnan(Sc.asof(idx[0])), "prima della prima chiusura nota non c'e' spot"
|
||||
assert list(Sc.values) == list(S.values), "i VALORI non si toccano, solo le etichette"
|
||||
|
||||
|
||||
def test_spot_series_e_causale_sul_feed_1h(monkeypatch):
|
||||
"""`cblib.spot_series(a).asof(ts)` = ultima chiusura ORARIA nota a ts. Controllo positivo:
|
||||
la serie grezza del feed (etichettata all'apertura) a ts da' la chiusura di ts+1h."""
|
||||
import scripts.analysis.research_lab as rl
|
||||
idx = pd.date_range("2026-06-01", periods=6, freq="h", tz="UTC")
|
||||
epoch = pd.Timestamp("1970-01-01", tz="UTC") # NON `asi8 // 10**6`: in pandas 3 e' in `us` (D6)
|
||||
px = pd.DataFrame({"timestamp": ((idx - epoch) // pd.Timedelta(milliseconds=1)).astype("int64"),
|
||||
"close": [100.0, 101.0, 102.0, 103.0, 104.0, 105.0]})
|
||||
monkeypatch.setattr(rl, "load_tf", lambda asset, tf: px)
|
||||
cblib.spot_series.cache_clear()
|
||||
try:
|
||||
S = cblib.spot_series("ZZZ")
|
||||
ts = idx[3] + pd.Timedelta(minutes=17) # 03:17: la barra 03:00 e' ancora aperta
|
||||
assert S.asof(ts) == 102.0, "a 03:17 l'ultima chiusura nota e' quella della barra 02:00"
|
||||
assert S.asof(idx[3]) == 102.0, "a 03:00 esatte la barra 02:00 e' appena chiusa"
|
||||
assert S.asof(idx[5] + pd.Timedelta(hours=1)) == 105.0, "l'ultima chiusura arriva un'ora dopo"
|
||||
grezza = pd.Series(px["close"].values, index=idx)
|
||||
assert grezza.asof(ts) == 103.0, "il difetto riparato: la serie del feed a 03:17 da' la chiusura delle 04:00"
|
||||
finally:
|
||||
cblib.spot_series.cache_clear()
|
||||
|
||||
|
||||
def test_dvol_series_e_causale_sul_feed_giornaliero(monkeypatch, tmp_path):
|
||||
"""La riga DVOL del giorno D e' la chiusura delle 23:00 di D: dentro D non e' ancora nota.
|
||||
`cblib.dvol_series(a).asof(ts in D)` deve dare la chiusura di D−1."""
|
||||
days = pd.date_range("2026-06-01", periods=4, freq="D", tz="UTC")
|
||||
epoch = pd.Timestamp("1970-01-01", tz="UTC")
|
||||
pd.DataFrame({"timestamp": ((days - epoch) // pd.Timedelta(milliseconds=1)).astype("int64"),
|
||||
"close": [36.0, 37.0, 43.0, 47.0]}).to_parquet(tmp_path / "dvol_zzz.parquet")
|
||||
monkeypatch.setattr(cblib, "RAW", tmp_path)
|
||||
cblib.dvol_series.cache_clear()
|
||||
try:
|
||||
V = cblib.dvol_series("ZZZ")
|
||||
ts = days[2] + pd.Timedelta(hours=10) # 03/06 10:00
|
||||
assert V.asof(ts) == 37.0, "dentro il 03/06 l'ultimo DVOL noto e' la chiusura del 02/06"
|
||||
assert V.asof(days[3]) == 43.0, "alle 00:00 del 04/06 e' nota la chiusura del 03/06"
|
||||
assert np.isnan(V.asof(days[0] + pd.Timedelta(hours=5))), "nel primo giorno non c'e' storia"
|
||||
finally:
|
||||
cblib.dvol_series.cache_clear()
|
||||
|
||||
@@ -8,7 +8,7 @@ numero con quel peso ha bisogno di guardie sul MECCANISMO, non solo sull'esito:
|
||||
nei casi degeneri (T≤0, sig=0 → intrinseco): se diverge, il denominatore di ogni `f` e' un
|
||||
altro modello e il rapporto non significa piu' niente;
|
||||
* **lo spot dev'essere CAUSALE.** Il feed 1h e' etichettato all'APERTURA: la barra 20:00 chiude
|
||||
alle 21:00, quindi `S.asof(ts)` guardava un'ora AVANTI. `spot_causale` sposta l'indice di
|
||||
alle 21:00, quindi `S.asof(ts)` guardava un'ora AVANTI. `cblib.causale` sposta l'indice di
|
||||
+1h. E' un look-ahead di un'ora dentro una misura di stress — piccolo e letale;
|
||||
* **il costo di chiusura si TAGLIA alla larghezza.** Uno spread a rischio definito non costa
|
||||
mai piu' della larghezza per chiudersi: si lascia regolare. Senza il taglio il "peggior MTM"
|
||||
@@ -96,25 +96,28 @@ def _trade(d_short: float, d_long: float, bid_s=0.030, ask_s=0.032, bid_l=0.010,
|
||||
|
||||
|
||||
# ===========================================================================================
|
||||
# spot_causale — il look-ahead di un'ora
|
||||
# lo spot e il DVOL arrivano da cblib GIA' causali: qui non si ri-spostano (doppio shift = un'ora
|
||||
# di RITARDO invece di un'ora di anticipo, stesso errore col segno opposto)
|
||||
# ===========================================================================================
|
||||
|
||||
def test_spot_causale_restituisce_l_ultima_chiusura_CONOSCIUTA():
|
||||
"""🚨 Il feed 1h e' etichettato all'APERTURA: la barra 01:00 chiude alle 02:00. Senza lo
|
||||
spostamento, `asof(02:00)` restituiva la chiusura delle 02:00 — cioe' un'ora di futuro
|
||||
dentro un ingresso. DEVE FALLIRE SE: qualcuno "semplifica" togliendo lo shift.
|
||||
|
||||
⚠️ `cblib.spot_series` ha ancora il difetto (e quindi il f 0,714 di §11): dichiarato nel
|
||||
docstring dello script, non toccato qui."""
|
||||
idx = pd.date_range("2026-06-01", periods=5, freq="h", tz="UTC")
|
||||
S = pd.Series([10.0, 11.0, 12.0, 13.0, 14.0], index=idx)
|
||||
Sc = C.spot_causale(S)
|
||||
|
||||
assert list(Sc.index) == list(idx + pd.Timedelta(hours=1))
|
||||
assert Sc.asof(idx[2]) == 11.0, "a 02:00 e' nota la chiusura della barra 01:00"
|
||||
assert S.asof(idx[2]) == 12.0, "il difetto che la funzione ripara (controllo positivo)"
|
||||
assert np.isnan(Sc.asof(idx[0])), "prima della prima chiusura nota non c'e' spot, non c'e' 10.0"
|
||||
assert Sc.iloc[0] == 10.0 and S.iloc[0] == 10.0, "i VALORI non si toccano, solo le etichette"
|
||||
def test_lo_script_usa_le_serie_di_cblib_senza_ri_spostarle():
|
||||
"""🚨 Il 09/09 mattina lo script riparava da solo il look-ahead con `spot_causale`; la sera la
|
||||
riparazione e' entrata in `cblib.spot_series` / `dvol_series` (debito §5.18). Applicare lo
|
||||
spostamento DUE volte darebbe la chiusura di due ore prima. DEVE FALLIRE SE: qualcuno
|
||||
reintroduce uno shift locale, o `cblib` smette di essere causale."""
|
||||
import inspect
|
||||
import cblib
|
||||
src = inspect.getsource(C.misura)
|
||||
assert "CB.spot_series(asset)" in src and "CB.dvol_series(asset)" in src
|
||||
assert "spot_causale" not in src and "Timedelta(hours=1)" not in src
|
||||
# l'UNICO `causale(` ammesso in misura() e' quello del contesto, e toglie un giorno al DVOL per la
|
||||
# tabella di calendario: un `causale(CB.spot_series(...), "1h")` sarebbe il doppio shift
|
||||
assert src.count("causale(") == 1 and 'CB.causale(V, "-1D")' in src
|
||||
assert not hasattr(C, "spot_causale"), "lo shift locale e' stato rimosso: vive in cblib.causale"
|
||||
# cblib e' causale (controllo positivo sul difetto che ripara)
|
||||
idx = pd.date_range("2026-06-01", periods=3, freq="h", tz="UTC")
|
||||
S = pd.Series([1.0, 2.0, 3.0], index=idx)
|
||||
assert cblib.causale(S, "1h").asof(idx[1]) == 1.0 and S.asof(idx[1]) == 2.0
|
||||
|
||||
|
||||
# ===========================================================================================
|
||||
@@ -327,7 +330,8 @@ def test_trade_CONTA_le_ore_tagliate_invece_di_nasconderle():
|
||||
|
||||
def test_f_net_e_il_credito_reale_su_quello_modellato():
|
||||
"""Il credito reale si incassa al BID della corta e si paga all'ASK della lunga: e' la
|
||||
convenzione conservativa di `cblib.f_factors`, e vale 0,74 su ETH nel crollo."""
|
||||
convenzione conservativa di `cblib.f_factors`, e vale 0,76 su ETH nel crollo (0,74 con lo spot
|
||||
e il DVOL non causali della mattina del 09/09: i due numeri vanno cambiati insieme)."""
|
||||
t = _trade(C.SHORT_D, C.LONG_D)
|
||||
assert t["cred_real"] == pytest.approx((0.030 - 0.012) * 2000.0)
|
||||
T = (C.EXP - TS0).total_seconds() / 86400.0 / 365.25
|
||||
@@ -477,7 +481,7 @@ def test_integrazione_la_misura_del_09_09_si_riproduce():
|
||||
|
||||
eth = s["ETH"]
|
||||
assert eth["n_pre"] > 200, "il campione pre-crollo si e' svuotato"
|
||||
assert eth["f_net"] == pytest.approx(0.74, abs=0.03)
|
||||
assert eth["f_net"] == pytest.approx(0.76, abs=0.03)
|
||||
assert eth["f_exp"] == pytest.approx(1.04, abs=0.03)
|
||||
assert eth["q_itm_pieno"] == pytest.approx(0.83, abs=0.10), (
|
||||
"la quota di trade a f_exp tautologico e' cambiata: cambia la lettura del 1,04")
|
||||
|
||||
Reference in New Issue
Block a user