research(vrp): buco del tenore chiuso col gate onesto — earns_slot_honest = False

Book, pesi, cron, config INVARIATI.

La griglia strutture del 03/07 si fermava a 10 giorni. Famiglia dichiarata nel
docstring PRIMA di guardare i numeri: 8 tenori (5-35g) x 3 delta corti x 3
lunghi = 72 celle, perche' riaprire il tenore riapre la struttura e i trial si
contano al rialzo.

study_family_honest e' cablato sui candidati direzionali (factory -> target_fn
via candidate_daily) e VRP01 non lo e': usati i suoi tre componenti reali —
selezione in-sample-only, altlib.deflated_sharpe, altlib.marginal_vs_tp01 —
importati e non riscritti (c'e' un test d'identita').

ESITO. Cella scelta al buio 10g -0.28/-0.05 (Sh IS 1.75 / FULL 1.55 / HOLD 1.01)
contro il canonico 7g (1.50/1.32/0.82; rango 17/72 in-sample). Batte il canonico
ma DSR 0.948 < 0.95 FAIL. marginal_vs_tp01 = ADDS per entrambe: il verdetto non
e' 'VRP01 e' rotto', e' che il vantaggio non sopravvive al conto dei trial.

IL BUCO SI CHIUDE SUL CONTENUTO, non sul gate: la regione mai esplorata PERDE.
Miglior cella >10g = 18g, rango 8/72, e solo 3/10 della top-10 sta oltre i 10
giorni -> lo studio conferma il 03/07 invece di ribaltarlo.

IL VINCITORE STA DOVE IL MODELLO SBAGLIA DI PIU': compra l'ala piu' lontana
(delta lungo -0.05), come 5/10 della top-10, cioe' la gamba che il 30/07 ha
misurato sottoprezzata ~2.3x. Sospetto motivato, non dimostrazione: il mediano
non separa -0.10 da -0.05, si separa la coda alta. Ma f non e' misurato fuori
dalla struttura canonica, e la sensibilita' a f uniforme e' la lente sbagliata
per una struttura il cui errore e' concentrato in una gamba sola.

ROBUSTEZZA DEL VERDETTO, PUBBLICATA: DSR 0.983 PASS a N=8, 0.948 FAIL a N=72,
0.909 a N=360. Il verdetto si ribalta col conteggio. La griglia era dichiarata
in anticipo e il conto fatto al rialzo, ma fallisce per 0.002: si cita come
tale, non come refutazione netta. Congelato in un test.

Seguito giusto = una MISURA, non un altro backtest: quanto vale f sul
10g/-0.05 sulle quote vere, ora che la catena la raccogliamo noi ogni ora.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-30 22:06:31 +00:00
parent 04cb572535
commit 36dc55748e
4 changed files with 598 additions and 0 deletions
+124
View File
@@ -0,0 +1,124 @@
# 2026-07-30 (4º filone) — il buco del tenore chiuso col gate onesto: nessun cambio a VRP01
**Richiesta dell'operatore:** *«chiudi il buco del tenore con study_family_honest».*
**Esito: `earns_slot_honest = False`. Book, pesi, cron, config INVARIATI.**
Script `scripts/research/r0730_vrp_tenor_gate.py`, test `tests/test_vrp_tenor_gate.py` (12 casi).
## Il buco, e perché era reale
La griglia strutture del 03/07 (`r0703_vrpimp_structgrid`) cercava su `TENOR_GRID = (3, 5, 7, 10)`:
**oltre i 10 giorni non è mai stato guardato.** Lo sweep del 30/07 sul profit-take aveva toccato
14/18/21/28g di passaggio e mostrato che il 18g *sembrava* battere il 7g in hold-to-expiry
(1.51 vs 1.32) — sei celle scelte sul campione pieno, cioè esattamente la selezione che questo
gate esiste per uccidere.
## Perché il gate è composto a mano, e non è una scorciatoia
`altlib.study_family_honest` è cablato sui candidati **direzionali**: vuole
`factory(tf=..., **params) -> target_fn` e passa da `candidate_daily`, che costruisce i rendimenti
da una serie di *posizioni* su BTC/ETH. VRP01 non è direzionale. Si usano quindi i suoi **tre
componenti reali**, nello stesso ordine e con le stesse soglie: selezione in-sample-only →
`altlib.deflated_sharpe` (importato, non riscritto — c'è un test che lo verifica) →
`altlib.marginal_vs_tp01` (importato).
**Famiglia dichiarata nel docstring PRIMA di guardare i numeri:** 8 tenori × 3 delta corti ×
3 delta lunghi = **72 celle**. Riaprire il tenore riapre la struttura, e il conteggio dei trial si
fa **al rialzo** — contarne meno gonfia il deflated-Sharpe.
## Il risultato
| | tenore | δ corto | δ lungo | Sh IS | Sh FULL | Sh HOLD | maxDD | CAGR |
|---|---|---|---|---|---|---|---|---|
| **scelta al buio** | 10g | 0.28 | 0.05 | **1.75** | 1.55 | 1.01 | 9.6% | 13.5% |
| VRP01 canonico | 7g | 0.28 | 0.10 | 1.50 | 1.32 | 0.82 | 10.5% | 10.5% |
Rango del canonico: **17/72 in-sample, 26/72 sul campione pieno**. La selezione al buio sceglie
un'altra cella, e quella cella batte il canonico sia in-sample sia full.
**Ma il gate si chiude sul deflated-Sharpe:**
| | DSR su 72 trial | esito |
|---|---|---|
| cella scelta | **0.948** | **FAIL** (soglia 0.95) |
| VRP01 canonico | 0.885 | FAIL |
`marginal_vs_tp01`**ADDS** a entrambe (corr +0.016, `robust_oos` True, `has_insample_edge`
True, `is_hedge` False). Quindi il verdetto **non** è «VRP01 è rotto» né «il tenore non conta»:
è che il vantaggio apparente non sopravvive al conto dei trial.
## Come il buco si chiude davvero: la regione nuova perde
Questo è il punto che rende la chiusura pulita, più del DSR:
| | cella | Sh IS | rango |
|---|---|---|---|
| miglior cella **≤10g** (già coperta dal 03/07) | 10g 0.28/0.05 | 1.75 | 1/72 |
| miglior cella **>10g** (territorio mai guardato) | 18g 0.28/0.05 | 1.56 | **8/72** |
Solo **3 celle su 10** nella top-10 in-sample stanno oltre i 10 giorni. **Si è aperta la regione
mai esplorata e la regione mai esplorata ha perso** contro celle che il 03/07 aveva già visto e
non promosso. Il buco non è "chiuso perché il gate boccia": è chiuso perché **guardandoci dentro
non c'è niente**.
## ⚠️ Il vincitore sta dove il modello sbaglia di più
La cella scelta compra l'ala **più lontana** (δ lungo 0.05), e 5 delle 10 celle migliori fanno lo
stesso. Il 30/07 ha **misurato** che il modello piatto sottoprezza proprio l'ala che si *compra*
(IV(lunga)DVOL **+7.5pp** contro +0.8pp della corta, ~**2.3×** il modello), e che l'errore cresce
con la distanza dallo strike. Una selezione che premia il δ lungo più piccolo sta plausibilmente
massimizzando **l'errore di modello**, non l'edge.
Onestà su questo punto: è un **sospetto motivato, non una dimostrazione**. Il *mediano* in-sample
non separa 0.10 da 0.05 (1.37 contro 1.37); a separarsi è la **coda alta** della griglia. Ma
basta a spostare l'onere della prova, perché `f` **non è misurato** fuori dalla struttura canonica.
⚠️ E la sensibilità a `f` non risolve: applicandolo uniformemente la cella scelta degrada *meno*
(f=0.73 → 0.84 contro 0.47 del canonico), ma **f uniforme è la lente sbagliata proprio per questa
struttura**, il cui errore è concentrato in una gamba sola. Un numero rassicurante ottenuto con lo
strumento sbagliato non è rassicurazione.
## ⚠️ Quanto è robusto il mio stesso verdetto
Il DSR dipende da quanti trial si dichiarano, e qui il verdetto **si ribalta**:
| conteggio | N | DSR | esito |
|---|---|---|---|
| solo gli 8 tenori | 8 | 0.983 | **PASS** |
| **la griglia dichiarata** | **72** | **0.948** | **FAIL** |
| 72 + 288 simulate del 03/07 | 360 | 0.909 | FAIL |
La griglia è stata dichiarata **prima** di guardare i numeri e il conteggio fatto al rialzo — ma il
verdetto va citato per quello che è: **fallisce per 0.002**, non è una refutazione netta. (L'ultima
riga usa trial *simulati* dalla distribuzione osservata, non le Sharpe vere del 03/07, che vengono
da un motore diverso: indicazione, non misura.) Congelato in
`test_il_verdetto_dipende_dal_numero_di_trial_dichiarati`, così che nessuno possa farlo passare
un domani restringendo il conteggio.
## Decisione
**Nessun cambio a VRP01**, per quattro ragioni in ordine di peso:
1. **Il gate pre-registrato fallisce.** Una soglia dichiarata in anticipo che poi si aggira non è
una soglia.
2. **La regione davvero nuova non vince** — quindi questo studio non ribalta il 03/07, lo conferma.
3. **Il vincitore sta nell'angolo dove abbiamo misurato che il modello è meno affidabile**, e lì
`f` non è misurato.
4. Niente di tutto questo è eseguibile prima di ~$2.6k, e a $3.000 VRP01 è **0 lotti** al peso di
book.
**Il seguito giusto non è un altro backtest, è una misura.** Se il 10g/0.28/0.05 interessa, la
domanda che decide è *quanto vale f su quella struttura sulle quote vere* — e da oggi la catena la
raccogliamo noi ogni ora. Serve però che il collettore accumuli abbastanza scadenze a 10 giorni:
oggi ci sono 15 osservazioni sul solo canonico.
## Regole
- **Quando si riapre un parametro si riapre la sua famiglia**, e i trial si contano al rialzo: il
deflated-Sharpe è l'unico posto dove barare è indolore e invisibile.
- **Dichiarare la griglia prima di guardare i numeri**, e pubblicare la sensibilità del verdetto al
conteggio — un gate che passa solo con la propria griglia preferita non è un gate.
- **Un buco si chiude meglio mostrando che dentro non c'è niente che bocciando il candidato**: qui
la frase che conta non è «DSR 0.948» ma «la regione mai esplorata è ottava».
- **Se la selezione converge dove un difetto di modello è già misurato, il sospetto vale più del
numero** — e si dice che è un sospetto.