fix(gtaa): costo IB reale (pavimento fisso) + esecuzione a banda — lo sleeve era cieco al capitale
DIFETTO. src/portfolio/gtaa.py modellava il costo come 2bps PROPORZIONALI e il modulo si
dichiarava "eseguibile a basso capitale, switch mensile/basso turnover". Entrambe false:
il vol-target e' CONTINUO (l'esposizione cambia ogni giorno, su 6 gambe) e IB non ha una
fee proporzionale ma un PAVIMENTO FISSO per ordine, min(max($0.35, $0.0035/az), 1% del
controvalore) = ~$530/anno indipendenti dal capitale.
Il modello vecchio era quindi CIECO AL CAPITALE: dava Sharpe 0.64 sia a $50.000 sia a $600.
Alla taglia grande era sostanzialmente giusto (0.64 vs 0.59-0.66 reali); a $600 la realta'
e' -0.55 di Sharpe e -3.5%/anno di CAGR. L'errore era tutto concentrato dove lo sleeve
verrebbe realmente deployato.
FIX. Il modulo ora:
* modella la commissione IB reale (ib_commission);
* esegue a BANDA + CADENZA (settimanale, $50/gamba) — config scelta sul PLATEAU del sweep
(weekly/monthly x banda 25-100 -> Sh 0.45-0.64 a ogni capitale), non sull'argmax
in-sample (banda $50 daily a $600 = cella isolata che crolla a banda 100);
* prende il CAPITALE allocato come parametro: gtaa_returns(capital=...);
* dichiara la soglia di deployabilita': GTAA_MIN_CAPITAL=$3.000 + gtaa_is_deployable();
* espone gtaa_rebalance_plan(held, capital) per l'esecutore — salta le gambe il cui
nozionale non supera la banda (un ordine da $12 costa $0.35 = 2.9%).
sleeves.py dichiara esplicitamente il capitale assunto (GTAA_DEFAULT_CAPITAL=$10.000 allocati
= book ~$50k al peso 20%) invece di nasconderlo.
IMPATTO SUL BOOK (misurato sostituendo la sola gamba GTAA, non citato):
GTAA01 standalone Sh 0.64 -> 0.61 CAGR 3.76% -> 3.65%
book 5 sleeve FULL 2.22 -> 2.22 HOLD 2.36 -> 2.38 maxDD 6.2% -> 6.0%
Trascurabile alla taglia assunta: il fix conta per il DEPLOY (a $600-2k passa da -3.5%/anno
a +3.0%/anno). PESI INVARIATI -> nessun weights_tilt_null richiesto.
CORREZIONE A UN ERRORE DI ANALISI DELLA SESSIONE. Il diario citava il modello vecchio a
"Sharpe 0.77 / CAGR 5.5%": artefatto di annualizzazione: la serie GTAA grezza ha ~252 barre
/anno (soli giorni di borsa) e metrics() annualizza a 365 con years=n/365.25 -> Sharpe x1.20
e CAGR x1.45. Le righe per-capitale erano gia' su calendario 365, quindi era falsata solo la
riga di riferimento. Corretti diario, CLAUDE.md e r0725_capcurve.py.
LEZIONE: una serie su giorni di borsa non si passa a metrics() senza to_daily().
Test: 221 pass (+4 in tests/test_gtaa_sleeve.py: pavimento non proporzionale, dipendenza dal
capitale + soglia, senza-banda-e-distruttivo, piano che salta le gambe sotto banda).
Smoke: scripts/live/paper_combo.py gira invariato.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,25 @@ Entrambe le cose sono false come codificate:
|
||||
|
||||
| capitale allocato a GTAA | CAGR reale | Sharpe reale | drag commissioni |
|
||||
|---|---|---|---|
|
||||
| $600 | **−3.5%** | **−0.55** | 9.0%/anno |
|
||||
| $2.000 | −0.7% | −0.09 | 6.2%/anno |
|
||||
| $5.000 | +1.5% | 0.28 | 4.0%/anno |
|
||||
| $50.000 | +3.4% | 0.59 | 2.1%/anno |
|
||||
| *modellato (2bps)* | *+5.5%* | *0.77* | — |
|
||||
| $600 | **−3.5%** | **−0.55** | 7.2%/anno |
|
||||
| $2.000 | −0.7% | −0.09 | 4.4%/anno |
|
||||
| $5.000 | +1.5% | 0.28 | 2.2%/anno |
|
||||
| $50.000 | +3.4% | 0.59 | 0.2%/anno |
|
||||
| *modello vecchio (2bps propor.)* | *+3.8%* | *0.64* | — |
|
||||
|
||||
⚠️ **Correzione a un errore MIO, trovata implementando il fix.** La prima stesura di questa
|
||||
sezione citava il modello vecchio a *Sharpe 0.77 / CAGR 5.5%*: era un **artefatto di
|
||||
annualizzazione** del mio script di analisi — metricavo la serie GTAA grezza (solo giorni di
|
||||
borsa, ~252/anno) con `metrics()`, che annualizza a 365 e calcola `years = n/365.25` → Sharpe
|
||||
gonfiato di √(365/252) = 1.20× e CAGR di ~1.45×. Le righe per-capitale erano già su calendario
|
||||
365 (reindex + weekend a zero), quindi **il confronto era falsato solo sulla riga di riferimento**.
|
||||
Valore corretto del modello vecchio: **0.64 / 3.8%**.
|
||||
|
||||
**La formulazione giusta del difetto cambia di conseguenza.** Non è "il modello sovrastimava lo
|
||||
Sharpe di 0.13": alla taglia grande il modello vecchio era sostanzialmente **giusto** (0.64 contro
|
||||
0.59-0.66 reali). Il difetto è che era **CIECO AL CAPITALE** — dava 0.64 sia a $50.000 sia a $600,
|
||||
mentre a $600 la realtà è **−0.55**. Un modello di costo proporzionale non può descrivere un
|
||||
pavimento fisso, e l'errore è tutto concentrato dove lo sleeve verrebbe realmente deployato.
|
||||
|
||||
**La banda lo salva.** Con costo fisso la banda ottimale non è il minimo eseguibile (come su
|
||||
Deribit) ma un valore molto più alto. Plateau robusto = **cadenza settimanale × banda $25-100**
|
||||
@@ -38,11 +52,24 @@ dà **Sh 0.52 / CAGR 3.0%** invece di −0.55/−3.5%. (La cella argmax a $600 e
|
||||
a 0.57, ma è isolata — crolla a 0.28 a banda 100 → scartata: il parametro è di costo, si sceglie
|
||||
sul plateau, non sull'argmax in-sample.)
|
||||
|
||||
**Due conseguenze.**
|
||||
1. Se GTAA01 va live su IB **deve** avere banda+cadenza cablate. Come sta ora, a $600-2k è un
|
||||
distruttore di capitale.
|
||||
2. Lo Sharpe **onesto** di GTAA01 è **~0.55-0.64, non 0.77** → i numeri headline del book a 5
|
||||
sleeve vanno citati con questo haircut (in aggiunta all'anchor-luck già documentato).
|
||||
**Conseguenza operativa: CABLATO** (stessa sessione, `src/portfolio/gtaa.py`). Il modulo ora
|
||||
modella il costo IB reale (`ib_commission`), esegue a **banda + cadenza** (settimanale, $50/gamba),
|
||||
prende il **capitale allocato** come parametro (`gtaa_returns(capital=...)`), dichiara la soglia
|
||||
di deployabilità (`GTAA_MIN_CAPITAL = $3.000`, `gtaa_is_deployable`) ed espone
|
||||
**`gtaa_rebalance_plan(held, capital)`** — il piano che l'esecutore deve usare per non ribilanciare
|
||||
ogni giorno per pochi dollari. `sleeves.py` dichiara esplicitamente il capitale assunto
|
||||
(`GTAA_DEFAULT_CAPITAL = $10.000` allocati ≈ book $50k al peso 20%) invece di nasconderlo.
|
||||
|
||||
**Impatto sul book, misurato prima/dopo** (non citato: ricalcolato sostituendo la sola gamba GTAA):
|
||||
|
||||
| | GTAA01 standalone | book 5 sleeve FULL | HOLD | maxDD |
|
||||
|---|---|---|---|---|
|
||||
| prima (2bps, continuo) | Sh 0.64 / CAGR 3.76% | 2.22 | 2.36 | 6.2% |
|
||||
| dopo (IB reale + banda) | Sh 0.61 / CAGR 3.65% | 2.22 | **2.38** | **6.0%** |
|
||||
|
||||
Alla taglia assunta l'impatto sul book è **trascurabile** — il fix non è cosmetico per i numeri
|
||||
storici, lo è per il **deploy**: è a $600-2.000 che cambia tutto (da −3.5%/anno a +3.0%/anno).
|
||||
Pesi **invariati** (nessun cambio pesi → nessun `weights_tilt_null` richiesto).
|
||||
|
||||
**Regola nuova (generale): il costo di un venue va modellato nella sua FORMA — fisso vs
|
||||
proporzionale — non solo nel suo livello.** Due venue con lo stesso "costo medio" danno
|
||||
|
||||
Reference in New Issue
Block a user