Files
PythagorasGoal/docs/diary/2026-07-25-mat01-statarb-generalization.md
T
Adriano Dal Pastro ec1501caa6 docs: diario ondata 2026-07-25 + CLAUDE.md — XSR01, 2 refutazioni, fix split equity
Diario docs/diary/2026-07-25-mat01-statarb-generalization.md (6 sezioni):
MAT01 scartato col null de-levering a pari volatilita'; STATARB-MULTI
(ETH/BTC non e' un outlier: 58° pctl) e STATARB-EQ (non si trasferisce alle
azioni, il lordo e' -0.17 e il resto e' turnover); lo split non aggiustato di
IWM/EFA con impatto quantificato su GTAA01; l'addendum pre-registrato al gate
del 27/09; e XSR01 col suo scettico e le sue tre debolezze dichiarate.

Registrati anche i due errori di metodo miei corretti in sessione (null statico
con look-ahead; null a fee piene contro un segnale permutato ad alto turnover):
entrambi avrebbero prodotto numeri piu' belli e sbagliati.

CLAUDE.md: nuove voci XSR01 (candidato in monitor, gate 2026-10-23), ondata
2026-07-25, e il difetto SPLIT-NON-AGGIUSTATI con la regola nuova — ogni soglia
di certificazione tarata su un valore tondo va controllata contro il difetto che
genera esattamente quel valore.

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

296 lines
18 KiB
Markdown
Raw 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-25 — Caccia a strategie nuove: MAT01 (trend multi-asset) + generalizzazione di STATARB, e uno SPLIT non aggiustato nel feed equity
Goal di sessione: **trovare nuove strategie**. Tre filoni scelti cercando i vuoti reali nella
mappa (89 diari, famiglie calendario/funding/VRP/CRT gia' dichiarate sature). Esito: **0 sleeve
nuovi**, 2 refutazioni pulite, 1 **difetto di dato che tocca il libro live** trovato e riparato,
1 addendum pre-registrato al gate STATARB del 27/09.
Book e pesi **INVARIATI**.
---
## (1) MAT01 — trend difensivo su 18 ETF multi-asset-class invece di 6 → **SCARTATO**
Script: `scripts/research/r0725_mat01_multiasset_trend.py`, `r0725_mat01b_regime.py`.
**Il vuoto.** GTAA01 gira su 6 ETF (SPY QQQ IWM TLT GLD HYG), 4 su 6 azionari US. I 12 ETF
multi-classe (DIA EFA EEM FXI EWJ AGG LQD IEF USO SLV DBC VNQ) sono su disco certificati dal
2026-06-22 con 9-30 anni di storia, ma erano stati usati SOLO per il test lead-lag crypto→X
(diario 2026-06-23-crossmarket-beyond-sp500), mai per un programma di trend. Il TSMOM
multi-asset-class e' l'anomalia meglio replicata della finanza quantitativa: valeva il test.
**Disciplina.** Meccanismo CONGELATO (import di `_exposure` da `src/portfolio/gtaa.py`: orizzonti
21/63/126/252, vol-target 12%, long-flat, EW, fee 2bps/lato). Cambia SOLO l'universo. L'universo
ALL18 e' definito a priori per classe d'attivo: **a k=18 la liberta' di selezione e' zero**
(esiste un solo sottoinsieme di 18 su 18), quindi il confronto ALL18-vs-GTAA6 non e' selezionabile.
**Risultati.**
| | Sh FULL | Sh IS<2015 | Sh OOS2015+ | maxDD OOS | vol |
|---|---|---|---|---|---|
| GTAA6 (incumbent) | 0.62 | 0.49 | **0.89** | 8.2% | 6.05% |
| MAT18 (candidato) | 0.56 | 0.43 | 0.80 | 6.9% | 4.62% |
| MAT18-CLS (per classe) | 0.57 | — | 0.73 | — | 4.38% |
corr(GTAA6, MAT18) = 0.91. Sostituzione nel book a peso invariato 20%: Sharpe FULL 2.22→2.19,
HOLD 2.36→2.38, DD 6.2%→6.6%. Corr→crypto praticamente identica (0.110 vs 0.116): **nessun
guadagno di diversificazione**, che era l'unica ragione plausibile per farlo.
**Perche' scartato — quattro ragioni indipendenti:**
1. **Finestre disgiunte: MAT18 perde 3/4** (1998-2004 0.28 vs 0.40; 2005-2011 0.63 vs 0.54 —
unica vittoria; 2012-2018 0.55 vs 0.72; 2019-2026 0.99 vs 1.13). Non e' regime-luck
dell'incumbent: GTAA6 vince anche nella finestra che contiene dot-com e GFC.
2. **A PARI VOLATILITA' il vantaggio di DD sparisce e si inverte**: MAT18 va scalato ×1.31 per
eguagliare la vol di GTAA6, e a quel punto maxDD 20.6% contro 15.4%. Il suo DD piu' basso
era **solo de-levering** — replicabile meglio abbassando `target_vol`.
**3ª occorrenza della stessa lezione** (overlay DD del VRP01 2026-07-03: 4/4 refutati dal
null de-levering; TP01×DVOL 2026-06-26: il taglio di DD era de-levering). Il null de-levering
e' ormai il primo test da fare su ogni claim di "meno drawdown".
3. Beta azionario e alpha quasi identici (GTAA6 beta 0.19 / alpha 1.56%; MAT18 0.14 / 0.97%):
MAT18 non e' meno "equity travestito", e' solo piu' piccolo.
4. Nei bear MAT18 e' migliore (GFC 3.0% vs 5.1%, 2022 3.2% vs 6.1%) ma paga quel conforto
con Sharpe piu' basso in ogni altro regime.
**Il risultato POSITIVO da conservare — l'ampiezza funziona, ma il soffitto e' gia' raggiunto.**
La curva di ampiezza (400 sottoinsiemi casuali per k, Sharpe OOS) e' monotona in 13/17 passi:
mediana **0.44 a k=1 → 0.80 a k=18**, DD mediano **16.0% → 6.9%**, satura verso k≈10-12.
Cioe': allargare l'universo di un trend difensivo *e' un meccanismo reale*. Ma GTAA6 sta al
**95° percentile dei 6-subset casuali** — e non perche' sia un best-of cherry-picked (contiene
TLT, il PEGGIORE dei 18 con Sh OOS 0.03): e' la sua composizione (equity US + oro + credito HY)
a stare sopra il soffitto d'ampiezza. **Non c'e' piu' ampiezza da raccogliere su questo sleeve.**
---
## (2) STATARB-MULTI — il meccanismo generalizza fuori da ETH/BTC? → **si', debolmente; nessuno sleeve nuovo**
Script: `scripts/research/r0725_statarb_multi.py`.
**Perche'.** STATARB-RESID e' il miglior lead del progetto e ha un gate di deploy al **2026-09-27**,
ma e' stato scoperto su UNA coppia dentro uno sweep. Test out-of-pair-sample: meccanismo congelato
(W=45, sgn=+1) su tutte le **50 coppie alt/BTC** di Hyperliquid, che non hanno partecipato alla
scoperta.
**Cosa regge:**
- **82% delle 50 coppie ha Sharpe netta > 0** (media 0.38, mediana 0.32).
- **0/50 coppie degeneri**: il segno del segnale e' quasi bilanciato (mono medio 53%) → NON e' la
scommessa statica "short alt vs BTC" travestita, che era il modo di fallire pre-registrato.
- p-permutazione a blocchi < 0.05 nel **18%** delle coppie (atteso 5% per caso).
- **ETH/BTC e' al rango 22/50, 58° percentile: la coppia scopritrice NON e' un outlier.** E'
l'informazione piu' utile per il gate del 27/09: l'ipotesi "fortuna di una coppia" non regge.
- Paniere EW delle 50 coppie: Sharpe 0.82, maxDD 6.0%, **corr a XS01 solo 0.207** (non ridondante).
**Cosa NON regge — e perche' non e' uno sleeve:**
- **Ampiezza effettiva ~4.5, non 50** (corr media fra coppie 0.204: condividono la gamba BTC).
- **Block-bootstrap sul paniere: IC95% [0.12, +1.72], t ≈ 1.31** → non distinguibile da zero su
2.6 anni. Il t cross-coppie apparente di 5.05 e' gonfiato dalla dipendenza.
- Contro il null **"sempre short alt vs BTC"** (a priori, nessun parametro stimato) l'uplift medio
e' **0.11** e solo il 40% delle coppie lo batte: una parte del rendimento e' beta di regime
2024-2026, non timing.
- Eseguibilita': 50 coppie = 51 gambe → STAT-MODE come XS01, fuori portata a $600.
**Correzione a un mio errore di metodo, dentro questa stessa sessione.** La prima stesura del
null statico usava `sign(mean(segnale))` sull'INTERO campione: un null che conosce gia' la
direzione giusta, cioe' look-ahead. Rifatto in due versioni oneste — (a) causale con media
espandente, (b) a priori sempre-short. L'uplift vs la versione causale e' mediana +0.10 / 58%
positivo (debolmente favorevole); vs sempre-short e' negativo. Il numero pubblicabile e' questo,
non quello della prima stesura.
---
## (3) STATARB-EQ — lo stesso meccanismo su coppie ETF con 20-30 anni di storia → **SCARTATO, e il crypto non ne esce rafforzato**
Script: `scripts/research/r0725_statarb_eq.py`.
**Perche'.** La debolezza di STATARB-RESID non e' il segno dei numeri, e' la statistica: 2.6 anni,
ampiezza effettiva 4.5. Le coppie ETF la attaccano frontalmente — 12 coppie definite **a priori
dentro la stessa classe d'attivo** (DIA/SPY, IWM/SPY, QQQ/SPY, EEM/EFA, EWJ/EFA, FXI/EEM, EFA/SPY,
SLV/GLD, IEF/TLT, HYG/LQD, LQD/AGG, USO/DBC), **28.5 anni**, ampiezza effettiva **9.9**, 4 regimi
completi. Nessun data-mining di cointegrazione: cercare le coppie piu' cointegrate sugli stessi
dati sarebbe selezione.
**Esito: il meccanismo NON si trasferisce.**
| | valore |
|---|---|
| Sharpe LORDA media / mediana | 0.17 / 0.16 (25% positive) |
| Sharpe NETTA media / mediana | 0.50 / 0.51 (8% positive) |
| paniere EW, 28.5 anni | Sharpe **1.00**, IC95% [1.36, 0.64], **t 5.33** |
| per decade | 0.56 / 1.61 / 1.83 / 0.78 — **negativo in 4/4** |
| p-permutazione < 0.05 | **0%** delle coppie |
| turnover | 0.40/giorno → drag di fee **0.33 Sharpe** |
| borrow 0 / 30 / 100 bps | 1.00 / 1.06 / 1.21 |
**La lettura corretta e' nella decomposizione lordo/netto, non nel netto.** La lorda e' 0.17, non
1.00: due terzi del disastro sono drag di turnover. Quindi **non esiste una "strategia specchio"
da girare**: sgn=1 avrebbe lorda ≈ +0.17 e netta ≈ 0.16, morta anch'essa sui costi. Il segno
lordo dice pero' una cosa vera e interessante: **sulle coppie azionarie il residuo REVERTE
debolmente, mentre sul crypto CONTINUA** (sgn=+1 vince). Il meccanismo di STATARB e' quindi
plausibilmente specifico del crypto, non universale.
**Onesta' sull'inferenza:** che non funzioni sulle azioni NON dimostra che non funzioni sul crypto
— gli indici azionari sono efficienti e le coppie alt/BTC hanno microstruttura e flussi diversi.
Il punto e' negativo in modo preciso: il gate del 27/09 **non puo' appoggiarsi** all'argomento
"e' un fenomeno universale, quindi e' reale". Non lo e'.
---
## (4) ⚠ DIFETTO DI DATO: split NON aggiustati nel feed equity — trovato, riparato, gate chiuso
Emerso mentre diagnosticavo ritorni giornalieri impossibili in (3) (min 99.9%, max +112%).
**Il fatto.** `data/raw/eq_iwm_1d.parquet` e `eq_efa_1d.parquet` avevano uno **split non aggiustato
il 2005-06-09** (tornata di split iShares): IWM 94.13→47.53 (49.5%, rapporto 1.981 ≈ **2:1**),
EFA 85.91→28.76 (66.5%, rapporto 2.987 ≈ **3:1**). IB `ADJUSTED_LAST` non li aveva aggiustati.
**Perche' la certificazione non li vedeva — ed e' un punto cieco strutturale, non sfortuna.**
L'unica guardia sui salti era `maxret > 50% → SPIKE?`. Uno split 2:1 non aggiustato produce
**esattamente 50%**: cade sul filo della soglia. IWM passava a 49.5% con status **OK**. La soglia
era tarata precisamente sul valore che il difetto piu' comune genera.
**Perche' importa: IWM e' una delle 6 gambe di GTAA01, sleeve in PRODUZIONE.** Impatto misurato:
| GTAA6 | FULL Sh | IS<2015 Sh | OOS2015+ Sh | maxDD |
|---|---|---|---|---|
| con difetto | 0.61 | 0.49 | 0.86 | 15.38% |
| riparato | **0.64** | **0.54** | 0.86 | 15.38% |
Il difetto **sottostimava** lo sleeve (l'artefatto e' nel 2005, fuori dall'hold-out) → **nessuna
decisione presa va rivista**, ma il dato e' ora corretto.
**Il discriminante split-vs-crollo (la parte riusabile).** Non basta il rapporto: SLV il
2026-01-30 ha fatto 28.5% con rapporto **1.3994**, a 4 bps da 1.4. Il discriminante e' il **range
intraday**:
- **SPLIT**: la barra APRE gia' al nuovo livello, range intraday normale. IWM 2005-06-09: open
47.00, range 1.7%. Un crollo del 50% con range 1.7% non esiste.
- **CROLLO VERO**: il movimento avviene DENTRO la barra. SLV: open 89.33, low 69.12, range 33%,
volume raddoppiato, e **GLD 10.3% lo stesso giorno**. Stessa verifica su EEM 2008-10-28 (+26%,
reale).
**Cosa e' stato fatto:**
- Nuovo modulo `src/data/eq_splits.py``detect_unadjusted_splits()` (tre condizioni congiunte:
|ret|>20% AND rapporto entro 1.5% da un fattore comune AND range intraday <5%) e
`repair_splits()` (riscala i prezzi precedenti; split multipli si compongono; volume opposto).
- Riparazione **in lettura** in entrambi i loader: `src/portfolio/gtaa.py::_close` (produzione) e
`scripts/research/eqlib.py::load_eq` (ricerca).
- Certificazione indurita: `fetch_ib_equities.certify()` ha ora lo status **`SPLIT-NON-AGG`** e
riporta gli split rilevati.
- Test `tests/test_eq_splits.py` (8 casi): i due split reali, il falso positivo SLV, un crollo
50% esatto con range grande, split multipli componibili, serie pulita invariata, ed end-to-end
sui parquet. **Suite completa: 180 passed.**
**Regola nuova:** ogni soglia di certificazione tarata su un valore tondo va controllata contro il
difetto che genera *esattamente* quel valore. Una soglia a 50% non puo' sorvegliare gli split 2:1.
---
## (5) Addendum PRE-REGISTRATO al gate STATARB del 27/09
Registrato **oggi, forward-day 26 di 90, 64 giorni prima della decisione** — pre-registrazione
vera, non selezione a posteriori. Motivo: il null "sempre short alt vs BTC" batte il segnale sul
60% delle coppie crypto, e su ETH/BTC (finestra HL 2024-2026) il pareggio e' quasi esatto
(segnale 0.46 vs statica 0.48).
`r0724_statarb_deploy_gate.py` ora calcola e riporta anche lo Sharpe della **statica sempre-short
a pari vol-target sulla stessa finestra forward**. **Le soglie pre-registrate il 2026-07-24
(Sharpe≥0.5, DD<10%, haircut<0.5pp) NON sono state toccate**: il benchmark e' una diagnostica
obbligatoria da leggere insieme, e la decisione se renderlo binding spetta all'operatore.
**Lettura di oggi (26 barre, da non sovrainterpretare):** STATARB **+5.70** contro benchmark
statico **4.98**. La posizione forward corrente e' LONG lo spread (+0.61), cioe' **opposta** alla
scommessa statica → la finestra forward sta testando il segnale in un modo che il beta di regime
non spiega. Prima lettura favorevole.
---
## (6) ✅ XSR01 — il candidato che e' uscito dal filone (2): **CROSS-SECTIONAL RESIDUAL**
Script: `r0725_statarb_basket_gate.py` (gate), `r0725_statarb_demean_skeptic.py` (scettico),
monitor `scripts/live/paper_xsr.py`, gate `r0725_xsr_deploy_gate.py`, test `tests/test_paper_xsr.py`.
Il paniere di coppie del punto (2) non era uno sleeve per un motivo **diagnosticato, non subito**:
ampiezza effettiva 4.5 invece di 50, perche' le 50 coppie **condividono la gamba BTC**. Da qui una
variante **pre-registrata per ragione strutturale** (prima di guardare i risultati): demeanare le
posizioni cross-sezionalmente ogni giorno. L'algebra dice cosa succede:
sum_i (p_i p̄)(r_i r_btc) = sum_i (p_i p̄) r_i perche' sum_i (p_i p̄) = 0
**la gamba BTC si annulla**, e con essa il fattore comune. Il risultato non e' piu' un paniere di
coppie: e' una strategia **cross-sectional dollar-neutral sui 50 alt** con pesi (p_i p̄)/N.
| | V1 ALL50 | V2 MAJ19 | **V3 DEMEAN** |
|---|---|---|---|
| Sharpe netta | 0.82 | 0.75 | **1.82** |
| maxDD | 6.0% | 8.1% | **2.6%** |
| ampiezza effettiva | 4.5 | 4.0 | **37.4** |
| marginale vs TP01 | ADDS | NOISE | **ADDS** |
| deflated-Sharpe | 0.701 | 0.660 | **0.985 PASS** |
**Gate superati.** Marginale **ADDS** con `robust_oos`, `beats_noise_null`, `is_hedge=False`,
`has_insample_edge=True`. **Deflated-Sharpe 0.985** (soglia 0.95) su 3 varianti pre-registrate — e
la config W=45/sgn=+1 viene da un altro studio, su questi dati non e' stata cercata.
**Correlazione ~0 a TUTTI e 5 gli sleeve attivi**: TP01 0.060, XS01 0.019, VRP01 0.001,
SKH01 0.001, GTAA01 0.071. Book a w=15%: HOLD 2.36 → **2.51**, DD invariato.
**Verifica avversariale** (`r0725_statarb_demean_skeptic.py`) — numeri cosi' puliti sono, in questo
progetto, il momento in cui di solito si trova l'artefatto. Quattro attacchi:
- **Tre null a fee-neutrale** (permutazione cross-sezionale delle etichette-asset; posizioni
casuali; permutazione temporale a blocchi 20g): tutti centrati a **~0.01** con p95 1.0-1.3, e il
candidato **LORDO 2.70 sopra il massimo di 300 estrazioni** → p < 0.004 su tutti e tre.
⚠ Correzione di metodo: la prima stesura confrontava a fee piene, e i null uscivano a 3.7/4.2
perche' permutare **fa esplodere il turnover** → il null perdeva per COSTO, non per assenza di
segnale, dando un p-value trionfale e falso. A fee zero il confronto isola l'informazione.
- **Lag**: 1.82 → 1.19 → 0.81 → 0.51 a +0/1/2/3 giorni. **Decadimento dolce = segnale lento reale;**
un look-ahead crollerebbe a zero al primo giorno di ritardo.
- **Ridondanza**: contro un momentum cross-sectional semplice sugli stessi 50 (che fa Sharpe
0.03/0.17/0.79 a L=30/45/90) la correlazione e' 0.29/0.17/0.10 → **non e' XS01 travestito**.
- **Struttura**: netto 2e17 (dollar-neutral esatto), 23.8 gambe long su 50 (bilanciato), lordo
14.4% del capitale.
**Le tre debolezze, dichiarate — e' per queste che va in MONITOR e non nel book:**
1. **Storia 2.6 anni, un regime solo**, e il rendimento e' **crescente** (Sharpe 2024 1.03 / 2025
1.98 / 2026 3.11): la maggior parte dell'edge e' recente.
2. **`weights_tilt_null` NON passa** (gate_pass=False a w=10% e 15%, delta_insample 0.004/0.007).
E' un effetto strutturale della storia corta — ma un gate fallito resta fallito.
3. **Margine di costo sottile**: 1.82 a 0.05%/gamba, **0.93 a 0.10%, NEGATIVA a 0.20%**. Turnover
38.5% del lordo al giorno su 50 alt fra cui illiquidi (GALA, BLUR, JTO, ORDI, WIF) e **slippage
non modellato**: e' il rischio numero uno.
**Eseguibilita' — il numero che serve davvero:** ticket medio per gamba $1.73 a $600 (**sotto il
min-order $5: STAT-MODE al capitale attuale**), $5.76 a $2000, **$14.41 a $5000**. Cioe' XSR01
diventa reale intorno ai **$5.000**, non ai $20.000 di XS01.
**Cablato come ogni lead del progetto:** `scripts/live/paper_xsr.py` (config CONGELATA, **tre**
libri paralleli MODELED $2000 / REAL $600 / REAL $5000 con min-order per gamba, stato append-only),
inserito in `cron_daily.sh`, test a 7 casi che bloccano config, dollar-neutralita', causalita' dello
step, min-order e la trappola dei timestamp. Gate di decisione pre-registrato oggi a forward-day 0:
**2026-10-23**, con soglia Sharpe ≥ 1.0 **E** una guardia di costo esplicita (haircut di
eseguibilita' a $5000 ≤ 40%, altrimenti RITIRO a prescindere dallo Sharpe).
⚠ Trappola pandas ri-pagata e ri-documentata: `astype("int64")` su `DatetimeIndex` tz-aware dava
epoche 1970 nel monitor. E' la gemella di quella dell'ondata 2026-07-01. Ora c'e' un test.
---
## Bilancio
- **1 candidato nuovo: XSR01**, il primo da molte ondate a superare marginale-ADDS, deflated-Sharpe
0.95, tre null avversariali e il test di lag, con corr ~0 a tutti e 5 gli sleeve. In
forward-monitor (NON nel book) per tre ragioni dichiarate: storia 2.6 anni, `weights_tilt_null`
fallito, margine di costo sottile. Gate pre-registrato al **2026-10-23**.
**Nota di onesta' su come e' nato:** non e' uscito da un'idea nuova, e' uscito dalla
DIAGNOSI di un fallimento — l'ampiezza effettiva 4.5 del paniere di coppie indicava un fattore
comune da togliere, e toglierlo era una mossa algebrica obbligata, non una ricerca di parametri.
- 2 refutazioni pulite con diagnostica riusabile: il soffitto d'ampiezza di GTAA01 e' gia'
raggiunto; STATARB non e' un fenomeno universale (non si trasferisce alle azioni).
- 1 difetto di dato sul **libro live** trovato, quantificato, riparato, testato e chiuso alla fonte.
- Il gate del 27/09 arriva alla decisione con **un'ipotesi alternativa in meno** (fortuna di una
coppia: refutata, 58° percentile) e **un benchmark in piu'** (beta statico, gia' favorevole).
- Due errori di metodo miei, trovati e corretti dentro la sessione: null statico con look-ahead
(STATARB-MULTI) e null a fee piene contro un segnale permutato ad alto turnover (scettico XSR01).
Entrambi avrebbero prodotto numeri piu' belli e sbagliati.
Script: `r0725_mat01_multiasset_trend.py`, `r0725_mat01b_regime.py`, `r0725_statarb_multi.py`,
`r0725_statarb_eq.py`, `r0725_statarb_basket_gate.py`, `r0725_statarb_demean_skeptic.py`,
`r0725_xsr_deploy_gate.py`; monitor `scripts/live/paper_xsr.py`; modulo `src/data/eq_splits.py`;
test `tests/test_eq_splits.py`, `tests/test_paper_xsr.py`.