841f48c319
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>
256 lines
15 KiB
Markdown
256 lines
15 KiB
Markdown
# 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.
|