Files
PythagorasGoal/docs/diary/2026-07-26-wave-esecuzione-dvolspread-xsr-equity.md
Adriano Dal Pastro 841f48c319 ops(live): cabla il forward-monitor DVOLSPREAD nel cron + gate pre-registrato
Chiude la lezione (c) dell'ondata 26/07: "un lead in forward-monitor senza
monitor e senza scadenza e' un lead perso" — DVOLSPREAD era in limbo da 35
giorni. Ora ha config congelata, monitor nel cron e gate con data.

Config congelata = la cella scelta IN-SAMPLE (zwin=180 k=2.0 lw=0.6 zw=1.1
tgt=0.17 svw=60), NON quella pubblicata dall'agente: quella era 83a/729
sull'hold-out ma 471a/729 in-sample e fallisce il deflated-Sharpe (0.947),
la congelata lo passa (0.953). Riusa make_book di r0726_dvolspread_gate,
nessuna reimplementazione.

Strumentazione specifica: il book va flat quando manca il DVOL, quindi 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), finestra misurata in barre ATTIVE, e guardia che esce 1 se
FROZEN diverge dallo stato salvato.

Gate pre-registrato: kill 2026-10-24 se Sharpe < -0.50; decisione 2027-01-24
solo se Sharpe>0 E marginale ADDS E deflated-Sharpe>=0.95 E weights_tilt_null;
veto d'integrita' se barre attive <80% (si estende, non si decide su dati
mancanti). La soglia su Sharpe e' debole di proposito: con ~180 barre
SE(Sharpe)~1.4, una soglia alta sarebbe finta precisione.

Inception 2026-07-25, apertura +0.184 = $111/gamba (cap $300).
Book/pesi INVARIATI. Suite 255 verdi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 20:05:30 +00:00

256 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-07-26 — Ondata a 3 filoni: esecuzione SKH01, DVOLSPREAD, XSR01 fuori dal crypto
**Script:** `r0726_skh_onbook.py` · `r0726_dvolspread_gate.py` · `r0726_xsr_equity.py`
**Test:** `tests/test_wave_0726.py` (11 casi) · suite completa **245 verdi**
**Book / pesi / cron: INVARIATI.** Una raccomandazione operativa aperta (T1), nessuna modifica fatta.
Tre filoni scelti non per esplorare aree nuove — quelle sono in gran parte sature — ma perché
il progetto stesso aveva lasciato **tre questioni aperte e decidibili oggi**:
| filone | questione aperta | esito |
|---|---|---|
| **T1** | il degrado del path live di SKH01 (~0.35 Sh) è recuperabile? | ⚠️ **il degrado era a sua volta fortuna d'ancora**; metà del fix funziona, l'altra metà no |
| **T2** | DVOLSPREAD, in limbo dal 21/06, è sleeve o falso positivo? | ✅ **regge i gate che non esistevano allora** — promosso a forward-monitor con parametri onesti |
| **T3** | XSR01 regge fuori dal crypto e da 2.6 anni monoregime? | ❌ **no** — e si scopre *perché* |
---
## T1 — Il degrado d'esecuzione di SKH01 era anch'esso un artefatto d'ancora
### La domanda
Il book live gira SKH01 con cron orario e uscite **software**. Costo misurato (audit 02/07,
riconfermato il 24/07): sleeve FULL 1.46→1.19, HOLD 1.64→1.15, DD 18%→25%. È il buco singolo più
grande del progetto, e il 24/07 aveva già stabilito che **un cron più veloce non lo recupera**.
L'angolo mai testato è l'unico meccanismo che non è un cron: gli **ordini resting on-book**, dove
esiste un'asimmetria che nessuno aveva sfruttato:
- il **TP è un limit order**: se il prezzo ci arriva, il fill è al livello **per costruzione**
(sei il maker), e per giunta a fee maker invece che taker;
- lo **SL è uno stop-market**: al trigger diventa un ordine a mercato, e in un gap riempie peggio.
Ipotesi: il grosso del degrado sta sul lato TP, quindi è recuperabile senza rischio nuovo.
### Il risultato, e la trappola che ha nascosto
A **offset 0** — la griglia che gira davvero — il quadro sembrava trionfale: l'on-book completo
recupera il **94%** del degrado. Ma l'offset 0 è già noto essere al 93-98° percentile dei 23
offset a priori, quindi la lente onesta è la banda.
E qui c'è stato un mio errore di statistica, corretto in corso: avevo confrontato
**mediana(canonical) mediana(hourly)**, che confronta offset *diversi* fra loro. Gli offset sono
**coppie appaiate**: la statistica giusta è la **mediana delle differenze**. Con quella:
| modalità | ΔFULL mediana [min,max] | ΔHOLD mediana | migliora in |
|---|---|---|---|
| canonical (tetto teorico) | **+0.054** [0.05,+0.12] | +0.099 | — |
| **solo TP a limite** | **+0.054** [0.03,+0.07] | **+0.061** | **FULL 19/23 · HOLD 21/23 · DD 19/23** |
| TP + SL on-book | +0.024 [0.07,+0.11] | +0.031 | FULL 17/23 · HOLD 14/23 |
| *contributo del solo lato SL* | **0.010** [0.13,+0.08] | — | **11/23 = una moneta** |
**Due conclusioni, entrambe diverse da quella che cercavo.**
**(1) Il "0.35 del path live" è a sua volta un artefatto dell'offset 0.** L'audit del 02/07 aveva
de-luckato i numeri *headline* di SKH01 ma aveva misurato il **degrado** solo a offset 0. Sulla
banda appaiata il degrado massimo recuperabile è **+0.054 di Sharpe sul book**, non +0.35 sullo
sleeve. Il buco più grande del progetto era in buona parte fortuna d'ancora anche lui.
**(2) Lo stop on-book PEGGIORA.** Mettere lo SL sul book cristallizza la perdita al livello,
mentre l'uscita software ritardata a volte incassa il rimbalzo: contributo mediano **0.010**,
positivo in **11/23** offset = indistinguibile da una moneta. La sensibilità lo conferma: sopra
lo **0.50%** di slippage sullo stop l'on-book è **peggio del live di oggi**.
Il meccanismo è misurato, non ipotizzato: sulle uscite TP il fill orario batte il livello nel
**42%** dei casi (vantaggio medio 0.035%) — è quasi una moneta, quindi il limit TP **converte una
lotteria in una certezza** più che aggiungere ritorno. E solo l'**1% degli SL** gappa davvero
dentro la barra 5m: il gap-through dei crash è reale ma raro.
### Raccomandazione (NON eseguita)
> **Appoggiare il TP come limit resting reduce-only; NON mettere lo SL strategico sul book.**
> Guadagno atteso **+0.054 FULL / +0.061 HOLD** sul book, positivo in **19-21 offset su 23**,
> più il risparmio taker→maker su un quarto dei trade.
È un cambio di **esecuzione**, non di strategia, quindi non passa da `weights_tilt_null`. Ma è
piccolo, e va pesato contro il costo operativo vero: ordini orfani se il cron muore, gestione
del reduce-only, doppio fill. **Non l'ho implementato**: è una decisione dell'operatore, non un
fatto compiuto. Il disaster-SL on-book a 30% resta com'è (è un'altra cosa: protezione, non exit).
---
## T2 — DVOLSPREAD regge i gate che nel giugno non esistevano ✅
### Chi è, e perché era in limbo
`agent_14_dvol_spread` (onda ortho, 21/06) è **l'unico sopravvissuto** al marginal scorer
indurito: dei 18 book relative-value che facevano ADDS con lo scorer vecchio, l'indurito ne lasciò
in piedi **uno**, questo. Da allora non è mai stato ripreso — non è nel book, non è in un monitor,
non è stato rifiutato. Era semplicemente lì.
Il segnale: `log(DVOL_btc) log(DVOL_eth)`, tilt verso la gamba con **vol implicita più ricca**
(tesi VRP / fear-reversal), market-neutral per costruzione, eseguibile a $600.
Nel frattempo il progetto ha codificato **due gate che il 21/06 non c'erano**, ed erano proprio
quelli che colpivano le sue riserve dichiarate:
1. **`deflated_sharpe`** (29/06) — l'agente dichiara *da sé* uno sweep di celle. Nel giugno
"72/72 celle ADDS" si leggeva come robustezza; il DSR dice che sono anche 72 tentativi.
2. **`select_cell_insample`** (29/06) — il plateau dell'agente è descritto in termini di
**`uplift_hold`**, cioè la cella è stata guardata **sull'hold-out**. È la firma esatta che il
gate selection-on-holdout fu scritto per catturare.
### Esito
⚠️ **Prima osservazione: la griglia dichiarata è sbagliata.** Il docstring dice "72-cell sweep", ma
il plateau che descrive è 6 assi × 3 valori = **729** combinazioni. Le ho valutate tutte e 729 —
scelta **conservativa**, perché più trial abbassano il DSR.
**Il plateau è reale e larghissimo:** FULL in [0.60, 0.71], HOLD in [0.68, 0.97], e
**729/729 celle con hold-out positivo**. Non è una cella fortunata.
**La selection-on-holdout c'è, ma è mite.** La cella pubblicata è **83ª/729 sull'hold-out** ma
**471ª/729 in-sample** — la firma è inequivocabile. Solo che, essendo il plateau così piatto,
scegliere onestamente la cella in-sample costa poco:
| cella | FULL | IS | HOLD | DSR (729 trial) |
|---|---|---|---|---|
| scelta **IN-SAMPLE** (onesta) | 0.68 | 0.70 | **0.69** | **0.953 PASS** |
| scelta sull'hold-out (proibita) | 0.68 | 0.58 | 0.97 | — |
| **pubblicata dall'agente** | 0.66 | 0.57 | 0.93 | 0.947 **FAIL** |
Cioè: **l'hold-out onesto è 0.69, non il 0.93 pubblicato** — un haircut reale — ma resta
chiaramente positivo. E la cella onesta **passa il deflated-Sharpe (0.953)** mentre quella
pubblicata lo **fallisce (0.947)**, il che è di per sé una conferma che il gate fa il suo lavoro.
Marginale vs TP01 sulla cella onesta: **ADDS**, `robust_oos` ✓, `multicut_persistent` ✓,
`is_hedge` ✗, `has_insample_edge` ✓, `beats_noise_null` ✓; corr +0.11, alpha annua **+7.4%**,
beta a TP01 +0.117, jackknife_min_uplift **+0.069**; dSharpe sul book **+0.08 FULL / +0.17 HOLD**
a w=15%, **+0.11 / +0.25** a w=25%.
### Verdetto: promosso, ma non nel book
**DVOLSPREAD esce dal limbo e diventa un candidato in forward-monitor con parametri ONESTI**
(`zwin=180, k=2.0, lw=0.6, zw=1.1, tgt=0.17, svw=60` — la cella in-sample), non quelli pubblicati.
### ✅ Monitor CABLATO (stessa sessione)
`scripts/live/paper_dvolspread.py`, in `cron_daily.sh` dopo `fetch_dvol.py` (quindi con DVOL
fresco), stato in `data/paper_dvolspread/` (gitignored), test `tests/test_paper_dvolspread.py`
(10 casi). Inception **2026-07-25**, posizione d'apertura +0.184 → **$111/gamba** (cap $300).
**Strumentazione specifica di questo lead** — la ragione per cui non bastava copiare
`paper_statarb`: il book va **flat quando il DVOL manca**, quindi un feed rotto produrrebbe una
fila di zeri che, contati come evidenza, direbbero *"nessuna perdita"* invece di *"nessuna
misura"*. Il monitor tiene una contabilità a **tre stati** — ATTIVE / flat-da-segnale /
**flat-senza-dato** — e la finestra forward si misura in **barre attive**, non in giorni di
calendario. C'è anche una **guardia sulla config**: se `FROZEN` diverge dallo stato salvato il
monitor esce con codice 1 invece di continuare su una finestra non più valida (verificato; nel
cron non c'è `set -e`, quindi segnala senza rompere la catena).
**Gate pre-registrato (scritto oggi, prima di vedere qualsiasi barra forward):**
- **kill anticipato 2026-10-24 (~90g):** Sharpe forward < 0.50 → ritiro;
- **decisione 2027-01-24 (~180g):** promozione solo se *tutte e quattro* — (a) Sharpe > 0,
(b) marginale ancora ADDS + robust_oos + has_insample_edge, (c) deflated-Sharpe ricalcolato
sul campione esteso ≥ 0.95, (d) `weights_tilt_null` superato;
- **veto d'integrità:** barre attive < 80% → la finestra non conta, si **estende** invece di
decidere su dati mancanti.
⚠️ La soglia (a) è deliberatamente debole — **necessaria, non sufficiente**. Con ~180 barre attive
l'errore standard dello Sharpe è ≈1.4: una soglia più alta sarebbe finta precisione. Il peso della
decisione sta su (c) — se il margine 0.953, già sul filo, **non migliora** con più dati, l'edge
non c'è.
**Perché NON entra nel book, dichiarato:**
- **campione ATTIVO 1949 giorni su 2691** (72%): prima del 2021-03 non esiste DVOL e il book è
correttamente flat. L'**hold-out attivo è 1.6 anni**;
- **margine DSR sul filo** (0.953 vs soglia 0.95) — un passaggio, non un'assoluzione;
- non ha ancora affrontato `weights_tilt_null`, che ogni cambio di pesi deve superare;
- il numero headline che circolava (HOLD 0.93) era gonfiato dalla selezione: **va citato 0.69**.
---
## T3 — XSR01 non generalizza fuori dal crypto ❌ (e si capisce perché)
### La domanda
XSR01 ha superato tutto ciò che gli è stato chiesto, ma la sua debolezza numero uno è dichiarata:
**2.6 anni monoregime, con l'edge crescente nel tempo** (Sharpe 2024 1.03 / 2025 1.98 / 2026 3.11).
Con 2.6 anni non si distingue un meccanismo da un regime fortunato. L'unico modo di guadagnare
potenza senza aspettare è portare il meccanismo **congelato** su un pannello lungo decenni.
**Non è il test del 25/07.** `r0725_statarb_eq.py` aveva già scartato le azioni, ma testava il
meccanismo a **coppie**. XSR01 è la versione **DEMEANATA cross-sezionalmente**, ed è proprio il
demeaning ad aver creato l'edge (ampiezza effettiva 4.5 → 37.4). Testare il demean sulle azioni è
una domanda diversa, mai posta.
### Esito
Meccanismo congelato (W=45, sgn=+1, residuo OLS causale vs **SPY**, z-score, tanh, vol-target 20%,
demean giornaliero), split IWM/EFA riparati in lettura, annualizzazione a **√252** (giorni di borsa):
| universo | variante | ampiezza eff. | Sharpe **LORDA** | Sharpe netta | maxDD |
|---|---|---|---|---|---|
| **SECT9** (9 settoriali, 1998+, 26 anni) | coppie | 5.3 | 0.05 | 1.67 | 91% |
| **SECT9** | **DEMEAN (= XSR01)** | **6.2** | **+0.24** | 1.61 | 89% |
| **ALL28** (tutti gli ETF, 30 anni) | coppie | 8.4 | 0.20 | 1.61 | 92% |
| **ALL28** | **DEMEAN** | **11.3** | **0.14** | 1.82 | 91% |
| *XSR01 crypto (25/07, riferimento)* | *DEMEAN* | ***37.4*** | ***+2.70*** | *+1.82* | *2.6%* |
Null di permutazione cross-sezionale **a fee zero** (la lezione XSR01: permutare un segnale ne fa
esplodere il turnover, quindi a fee piena il null perderebbe per *costo* e regalerebbe un p-value
trionfale e falso): SECT9 candidato +0.24 vs null medio 0.00, **p = 0.193**; ALL28 0.14, **p = 0.747**.
Per decennio (DEMEAN, lordo): SECT9 0.88 / +0.49 / +0.29 / +0.74 · ALL28 0.88 / +0.46 / +0.38 / +0.05.
Stesso profilo nei due universi: fortemente negativo 1998-2005, debolmente positivo poi — il che
somiglia più a un cambio di regime che a un edge.
### Il risultato più interessante non è il Sharpe, è l'ampiezza
**Il demeaning non fa sulle azioni quello che fa sul crypto.** Sul crypto porta l'ampiezza
effettiva da 4.5 a 37.4 (**8×**); sulle azioni da 5.3 a 6.2 e da 8.4 a 11.3 (**1.2-1.35×**).
Il perché è strutturale, e spiega XSR01 meglio di quanto lo spiegasse la sua scoperta: il residuo
OLS **rimuove già** il beta al fattore comune. Sul crypto, dopo aver residualizzato su BTC, alle
gambe **resta** un enorme fattore comune (ampiezza 4.5 su 50 gambe = quasi una gamba sola) — ed è
quello che il demeaning toglie. Sulle azioni il residuo-vs-SPY è **già** quasi indipendente
(5.3 su 9 gambe), quindi il demeaning non ha molto da togliere e non c'è guadagno.
### Cosa significa per il gate del 2026-10-23
Il 25/07 aveva già scritto che *«il gate non può appoggiarsi all'argomento fenomeno universale»*.
Questo test **lo conferma e chiude la scappatoia** che il test a coppie lasciava aperta: nemmeno
la versione demeanata — quella vera di XSR01 — funziona sulle azioni.
**Onestà su cosa NON prova:** non prova che XSR01 sia falso. Prova che è **crypto-specifico**, e
suggerisce quale sia il meccanismo (l'esistenza di un fattore comune residuo che sopravvive alla
residualizzazione, cosa che le azioni non hanno). Il gate del 23/10 resta **interamente** appoggiato
sulla finestra forward e sull'haircut di eseguibilità a $5.000, come pre-registrato.
Nessuna soglia toccata.
---
## Lezioni da portare avanti
1. **Se si de-lucka una strategia, va de-luckato anche il suo DEGRADO.** L'audit del 02/07 ha
corretto i numeri headline di SKH01 per la fortuna d'ancora ma ha misurato il costo
d'esecuzione a offset 0 — e quel costo si è rivelato **fortunato quanto i numeri che
correggeva**. Ogni Δ fra due varianti misurato su una griglia ancorata eredita la fortuna
dell'ancora.
2. **Su una griglia di offset appaiati, la statistica è la mediana delle DIFFERENZE, non la
differenza delle mediane.** La seconda confronta offset diversi fra loro e qui ribaltava il
verdetto (faceva sembrare l'on-book completo migliore del solo TP, mentre è il contrario).
3. **Un lead lasciato "in forward-monitor" senza monitor e senza data di scadenza è un lead
perso.** DVOLSPREAD è stato in limbo 35 giorni. La disciplina che il progetto applica ai
candidati nuovi (config congelata + gate pre-registrato + cron) non era stata applicata a lui.
4. **Il claim di multiple-testing di un agente va ricontato, non creduto.** Il docstring diceva
72 celle; la griglia descritta ne contiene 729. Ricontare è conservativo e costa poco.
5. **Quando un meccanismo non generalizza, chiedersi PERCHÉ vale più del fatto che non generalizzi.**
Il fallimento di XSR01 sulle azioni ha prodotto la spiegazione migliore di come funziona sul
crypto: il demeaning vale quanto vale il fattore comune **residuo** dopo la residualizzazione,
ed è una proprietà dell'asset class, non del segnale.