feat(portfolio): GTAA01 promosso a 5° sleeve @20% — FULL 2.12→2.24, HOLD 2.21→2.46, DD 7.8→6.2%
Il diversificatore strutturale validato il 2026-06-22 (trend difensivo equity 6-ETF su IB, 30y storia, OOS 2015+ indipendente dall'hold-out crypto, corr al book ~+0.10) era rimasto in paper_combo senza mai essere valutato come sleeve. Valutazione onesta (r0701_gtaa_5th_sleeve): uplift positivo in-sample e su TUTTE le finestre disgiunte (+0.05/+0.19/+0.25), multi-cut +0.21..+0.25, plateau monotono w10-30% — passa dove EW-STR era morto. Ingresso @20% (IS-best 30%, scelta strutturale dichiarata). Convenzioni: weekend equity=0 (capitale IB fermo, non riciclato), attivazione all'era book 2019-03. Il book live Deribit (TP01+SKH01) NON cambia. Suite 168/168. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -51,14 +51,22 @@ Prima ondata di ricerca onesta su BTC/ETH certificati (5 track, harness condivis
|
|||||||
monitor forward. NB il gate concentra XS nei regimi dispersi (2025-26 = hold-out alta-dispersione).
|
monitor forward. NB il gate concentra XS nei regimi dispersi (2025-26 = hold-out alta-dispersione).
|
||||||
Ricerca `scripts/portfolio/{xsec_research,xsec_blend,xsec_dispgate}.py`. Diari `2026-06-19-hyperliquid-xsec`
|
Ricerca `scripts/portfolio/{xsec_research,xsec_blend,xsec_dispgate}.py`. Diari `2026-06-19-hyperliquid-xsec`
|
||||||
/ `-xsec-blend` / `-xsec-dispgate` / `-xsec-universe-expansion` / `-trend-multiasset`.
|
/ `-xsec-blend` / `-xsec-dispgate` / `-xsec-universe-expansion` / `-trend-multiasset`.
|
||||||
- **PORTAFOGLIO ATTIVO = TP01 (41.25%) + XS01 (18.75%) + VRP01 (15%) + SKH01 (25%)** (`src/portfolio/sleeves.active_sleeves`):
|
- **PORTAFOGLIO ATTIVO = TP01 (33%) + XS01 (15%) + VRP01 (12%) + SKH01 (20%) + GTAA01 (20%)**
|
||||||
TP01+XS01 combinato **FULL Sharpe 1.55, HOLD-OUT 1.55, DD 4.4%**. Aggiunto **VRP01** (options
|
(`src/portfolio/sleeves.active_sleeves`): TP01+XS01 combinato **FULL Sharpe 1.55, HOLD-OUT 1.55,
|
||||||
short-vol, sotto): TP01+VRP01 da solo fa FULL Sh 1.30→1.44 / HOLD 0.31→0.40 a peso 20% (3-way da
|
DD 4.4%**. Aggiunto **VRP01** (options short-vol, sotto): TP01+VRP01 da solo fa FULL Sh 1.30→1.44 /
|
||||||
validare locale con dati HL). **Aggiunto SKH01-V2-DD @25% effettivo (2026-06-23, sotto):** i tre
|
HOLD 0.31→0.40 a peso 20%. **Aggiunto SKH01-V2-DD @25% effettivo (2026-06-23, sotto)**: 4-sleeve
|
||||||
preesistenti scalati nel restante 0.75 (rapporto 55:25:20). Il portafoglio a **4 sleeve** fa
|
**FULL Sharpe 1.68→2.13, HOLD-OUT 1.63→2.30, DD full 14.3%→7.8%** (Skyhook quasi-ortogonale,
|
||||||
**FULL Sharpe 1.68→2.13, HOLD-OUT 1.63→2.30, DD full 14.3%→7.8%** (Skyhook è quasi-ortogonale,
|
corr ~0.09). **Aggiunto GTAA01 @20% effettivo (2026-07-01, i 4 preesistenti scalati ×0.80):**
|
||||||
corr ~0.09). Report `scripts/portfolio/run_portfolio.py`. Sleeve a date d'inizio
|
trend difensivo equity 6-ETF su IB (`src/portfolio/gtaa.py`, ~30 anni storia, validato 2026-06-22
|
||||||
diverse → outer-join con pesi rinormalizzati (TP01/SKH01 dal 2019, VRP dal 2021, XS dal 2024).
|
su OOS equity 2015+ INDIPENDENTE dall'hold-out crypto, corr al book ~+0.10) → 5-sleeve
|
||||||
|
**FULL Sharpe 2.12→2.24, HOLD-OUT 2.21→2.46, DD full 7.8%→6.2%** (costo dichiarato: CAGR full
|
||||||
|
23.3→18.8%; 2022 unico anno con dSh−). Uplift positivo in-sample E su tutte le finestre disgiunte
|
||||||
|
(vs EW-STR refutato lo stesso giorno). Convenzioni: weekend/festivi equity = 0.0 (capitale IB
|
||||||
|
fermo, non riciclato); attivazione nel book all'era crypto 2019-03; **il book live Deribit
|
||||||
|
(`deribit_book_sleeves` TP01+SKH01 75/25) NON lo include** (GTAA in paper_combo dal 2026-06-23).
|
||||||
|
Test `tests/test_gtaa_sleeve.py`; diario `2026-07-01-strategy-wave-6threads.md` (addendum GTAA).
|
||||||
|
Report `scripts/portfolio/run_portfolio.py`. Sleeve a date d'inizio diverse → outer-join con pesi
|
||||||
|
rinormalizzati (TP01/SKH01/GTAA dal 2019*, VRP dal 2021, XS dal 2024; *GTAA troncato all'era book).
|
||||||
- **SKH01-V2-DD "Skyhook" — DIVERSIFICATORE quasi-ortogonale (research)** — `src/strategies/skyhook.SKH01_V2_DD`,
|
- **SKH01-V2-DD "Skyhook" — DIVERSIFICATORE quasi-ortogonale (research)** — `src/strategies/skyhook.SKH01_V2_DD`,
|
||||||
sleeve `src/portfolio/sleeves._skyhook_returns`. Sistema dual-TF (segnale 690m / exec 230m) regime
|
sleeve `src/portfolio/sleeves._skyhook_returns`. Sistema dual-TF (segnale 690m / exec 230m) regime
|
||||||
(BuzVola/BuzVolume tipo-Chande) AND pattern (Donchian breakout), NON trend-follower, L/S. Vincitrice
|
(BuzVola/BuzVolume tipo-Chande) AND pattern (Donchian breakout), NON trend-follower, L/S. Vincitrice
|
||||||
@@ -159,8 +167,8 @@ Prima ondata di ricerca onesta su BTC/ETH certificati (5 track, harness condivis
|
|||||||
l'edge è *deployabile* (2 gambe BTC/ETH perp). Altri LEAD: IVOL (idio-vol XS, STAT-MODE), DVOLSPREAD
|
l'edge è *deployabile* (2 gambe BTC/ETH perp). Altri LEAD: IVOL (idio-vol XS, STAT-MODE), DVOLSPREAD
|
||||||
(storia DVOL corta). Diario `2026-06-29-strategy-search-5threads.md`. Script
|
(storia DVOL corta). Diario `2026-06-29-strategy-search-5threads.md`. Script
|
||||||
`scripts/research/{xsec_v3_lowrisk,xsec_v3_momstruct,meta_allocation,orthogonal_signals,signal_inout_1leg}.py`.
|
`scripts/research/{xsec_v3_lowrisk,xsec_v3_momstruct,meta_allocation,orthogonal_signals,signal_inout_1leg}.py`.
|
||||||
- **Ondata 2026-07-01 (6 filoni multi-agente + scettico) — 0 nuovi sleeve, pesi CURRENT confermati,
|
- **Ondata 2026-07-01 (6 filoni multi-agente + scettico) — 0 edge nuovi dai filoni, 1 gate nuovo,
|
||||||
1 gate nuovo.** Filoni su angoli non coperti dalle ondate precedenti: (1) **funding time-series**
|
e 1 sleeve promosso DALL'ARCHIVIO (GTAA01, sotto nel bullet portafoglio).** Filoni su angoli non coperti dalle ondate precedenti: (1) **funding time-series**
|
||||||
BTC/ETH (posizionamento) = SCARTATO — FOLLOW è trend-beta ritardato, FADE shorta il toro, il gate è
|
BTC/ETH (posizionamento) = SCARTATO — FOLLOW è trend-beta ritardato, FADE shorta il toro, il gate è
|
||||||
TP01 travestito (DSR 0.215); **il filone funding è chiuso su 3 lati** (FC01 carry, price-clock, TS).
|
TP01 travestito (DSR 0.215); **il filone funding è chiuso su 3 lati** (FC01 carry, price-clock, TS).
|
||||||
(2) **breadth/internals alt** (51 HL) = SCARTATO ma unico NON-ridondante col trend (corr→TP01 0.40);
|
(2) **breadth/internals alt** (51 HL) = SCARTATO ma unico NON-ridondante col trend (corr→TP01 0.40);
|
||||||
@@ -267,7 +275,7 @@ src/strategies/indicators.py → indicatori condivisi (ema, atr, keltner, ...)
|
|||||||
src/strategies/trend_portfolio.py → TP01: strategia DIFENSIVA robusta (PORT LF1d, >=12h), causale
|
src/strategies/trend_portfolio.py → TP01: strategia DIFENSIVA robusta (PORT LF1d, >=12h), causale
|
||||||
src/portfolio/ → PORTAFOGLIO DI STRATEGIE estensibile (Sleeve + StrategyPortfolio)
|
src/portfolio/ → PORTAFOGLIO DI STRATEGIE estensibile (Sleeve + StrategyPortfolio)
|
||||||
portfolio.py → combina N sleeve per peso su griglia giornaliera; metriche FULL/hold-out/anno
|
portfolio.py → combina N sleeve per peso su griglia giornaliera; metriche FULL/hold-out/anno
|
||||||
sleeves.py → REGISTRY sleeve attivi: TP01 (55%) + XS01 (25%) + VRP01 (20%). Aggiungere = una riga
|
sleeves.py → REGISTRY sleeve attivi: TP01 33 / XS01 15 / VRP01 12 / SKH01 20 / GTAA01 20. Aggiungere = una riga
|
||||||
src/fractal/ → indicatori frattali (patterns.py, indicators.py, similarity.py)
|
src/fractal/ → indicatori frattali (patterns.py, indicators.py, similarity.py)
|
||||||
src/backtest/engine.py → engine di backtesting riusabile
|
src/backtest/engine.py → engine di backtesting riusabile
|
||||||
src/backtest/harness.py → harness ONESTO (load BTC/ETH, backtest_signals no-leakage, OOS)
|
src/backtest/harness.py → harness ONESTO (load BTC/ETH, backtest_signals no-leakage, OOS)
|
||||||
|
|||||||
@@ -72,3 +72,61 @@ reali di crescita restano (a) storia forward che promuova i lead (STATARB-RESID,
|
|||||||
anni), (b) capitale, (c) nuove fonti di dato (f di stress reale per VRP).
|
anni), (b) capitale, (c) nuove fonti di dato (f di stress reale per VRP).
|
||||||
|
|
||||||
**File dell'ondata:** `scripts/research/r0701_{funding_ts,breadth_internals,xs_residmom,portfolio_opt,portfolio_skeptic,vrp_refine,xs_seasonal}.py`; diari `2026-07-01-{funding-ts-signal,alt-breadth-internals,xs-residual-momentum,portfolio-weights-ddguard,vrp-refinement,xs-seasonality}.md`; gate in `src/portfolio/portfolio.py` + `tests/test_weights_tilt_null.py`.
|
**File dell'ondata:** `scripts/research/r0701_{funding_ts,breadth_internals,xs_residmom,portfolio_opt,portfolio_skeptic,vrp_refine,xs_seasonal}.py`; diari `2026-07-01-{funding-ts-signal,alt-breadth-internals,xs-residual-momentum,portfolio-weights-ddguard,vrp-refinement,xs-seasonality}.md`; gate in `src/portfolio/portfolio.py` + `tests/test_weights_tilt_null.py`.
|
||||||
|
|
||||||
|
## ADDENDUM (stessa sera) — GTAA01 promosso a 5° SLEEVE: il miglioramento c'era, ma era in casa
|
||||||
|
|
||||||
|
Il secondo passaggio sull'archivio (non sui dati!) ha trovato il candidato che l'ondata di *ricerca*
|
||||||
|
non poteva trovare: **EQ-GTAA01** (`src/portfolio/gtaa.py` — trend difensivo equity 6-ETF, vt12%,
|
||||||
|
~30 anni di storia, netto fee IB) era stato validato il 2026-06-22 come *"primo miglioramento
|
||||||
|
STRUTTURALE del rischio-aggiustato trovato in tutta la ricerca post-reset"*, messo in paper
|
||||||
|
cross-venue (`paper_combo`, nel cron dal 2026-06-23) e **mai valutato come 5° sleeve del
|
||||||
|
portafoglio attivo** (il giorno dopo arrivò SKH01 e il filone si fermò).
|
||||||
|
|
||||||
|
### Valutazione onesta (`r0701_gtaa_5th_sleeve.py`) — perché GTAA passa dove EW-STR è morto
|
||||||
|
|
||||||
|
| gate | EW-STR (refutato) | +GTAA01 (passa) |
|
||||||
|
|---|---|---|
|
||||||
|
| uplift IN-SAMPLE (pre-2025) | **−0.05** | **+0.09..+0.13** (2.134→2.23-2.26) |
|
||||||
|
| finestre OOS disgiunte | −0.12 / +0.06 / +0.14 | **+0.05 / +0.19 / +0.25** (tutte >0) |
|
||||||
|
| multi-cut (4 tagli) | solo annidate | **+0.21 / +0.21 / +0.22 / +0.25** |
|
||||||
|
| provenienza dell'edge | sleeve selezionati sull'hold-out crypto | validato su OOS equity 2015+, **indipendente** dall'hold-out crypto |
|
||||||
|
| corr al book | — | **+0.10** full, ~0.00 hold-out; is_hedge +0.30 (non-hedge) |
|
||||||
|
| plateau | gradiente generico anti-TP01 | **monotono su w 10-30%, ogni cella migliora IS/FULL/HOLD/DD** |
|
||||||
|
|
||||||
|
Convenzione di realismo cross-venue (nuova, cablata nello sleeve): nei giorni senza barra equity
|
||||||
|
(weekend/festivi US) il rendimento è **0.0** — capitale IB fermo, NON rinormalizzato sul crypto
|
||||||
|
(due conti reali non si travasano nel weekend). Numeri quasi identici alla versione outer-join
|
||||||
|
(differenze al 3° decimale) ma il modello è quello giusto. Attivazione nel book all'era crypto
|
||||||
|
(2019-03-14): senza troncatura l'outer-join farebbe partire il book nel 1996 con 23 anni di
|
||||||
|
solo-GTAA rinormalizzato al 100%.
|
||||||
|
|
||||||
|
### Decisione pesi
|
||||||
|
Cella IS-best = w=30% (bordo griglia), **ingresso @20%** per scelta strutturale dichiarata:
|
||||||
|
(a) cross-venue IB con paper operativo di soli 8 giorni — non diventa lo sleeve più grande del
|
||||||
|
book al day-one; (b) precedente: ogni sleeve nuovo è entrato ≤25% (SKH01 25%, VRP01 15%);
|
||||||
|
(c) costo CAGR (a 30%: 16.8% vs 18.8% a 20%) — e l'obiettivo €50/g vive di CAGR, non solo di
|
||||||
|
Sharpe. Tutte le celle 10-30% passano comunque ogni gate. Pesi nuovi: **TP01 33 / XS01 15 /
|
||||||
|
VRP01 12 / SKH01 20 / GTAA01 20** (i 4 preesistenti scalati ×0.80, rapporti conservati).
|
||||||
|
|
||||||
|
### Portafoglio 5-sleeve (run_portfolio, capitale 2k)
|
||||||
|
| | FULL Sh | FULL DD | FULL CAGR | HOLD Sh | HOLD DD | HOLD CAGR |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| 4-sleeve (baseline) | 2.12 | 7.8% | +23.3% | 2.21 | 3.5% | +16.0% |
|
||||||
|
| **5-sleeve (+GTAA01 20%)** | **2.24** | **6.2%** | +18.8% | **2.46** | **2.2%** | +14.6% |
|
||||||
|
|
||||||
|
Per-anno: tutti gli 8 anni positivi, 2022 +7.0% (era +11.6%: GTAA soffre il whipsaw 2022, unico
|
||||||
|
anno con dSh negativo −0.49 — dichiarato). Il trade-off è esplicito: −4.5pp di CAGR full per
|
||||||
|
+0.12/+0.25 di Sharpe e DD 7.8→6.2 / hold-out 3.5→2.2. A pesi research (XS/VRP/SKH modellati o
|
||||||
|
STAT-MODE) il CAGR era comunque di carta; lo Sharpe/DD del book è la metrica di verità.
|
||||||
|
|
||||||
|
### Cosa NON cambia
|
||||||
|
Il **book live Deribit** (`deribit_book_sleeves` TP01+SKH01 75/25, `book_execute`) è INTATTO —
|
||||||
|
GTAA è su IB, già tracciato forward da `paper_combo`. `paper_portfolio` da oggi traccia la
|
||||||
|
composizione a 5 (regime-break dichiarato qui). Test: `tests/test_gtaa_sleeve.py` (registry,
|
||||||
|
weekend-zero, attivazione, book live invariato) — suite 168/168.
|
||||||
|
|
||||||
|
### Lezione dell'addendum
|
||||||
|
Prima di una nuova ondata di *ricerca*, ri-leggere l'archivio dei **validati-ma-non-integrati**:
|
||||||
|
l'unico upgrade onesto del book in 3 ondate (104+5+6 filoni) era un edge già validato che
|
||||||
|
aspettava solo la valutazione da sleeve. La diversificazione strutturale (secondo mercato,
|
||||||
|
corr ~0.1) resta l'unica cosa che alza lo Sharpe del book senza nuovo alpha.
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
"""r0701_gtaa_5th_sleeve — EQ-GTAA01 come 5° sleeve del portafoglio attivo? Valutazione ONESTA.
|
||||||
|
|
||||||
|
Contesto (diari 2026-06-22/23): GTAA (trend difensivo equity, 6 ETF, vt12%, ~30y di storia, netto
|
||||||
|
fee IB 2bps/lato) fu validato come diversificatore strutturale del book crypto (corr ~0.17-0.21,
|
||||||
|
combo Sharpe 1.60->1.81) ma lasciato in paper cross-venue (paper_combo) e MAI valutato come 5°
|
||||||
|
sleeve del portafoglio attivo (il giorno dopo arrivo' SKH01). Qui: gate onesti per lo slot.
|
||||||
|
|
||||||
|
Metodo:
|
||||||
|
* pannello = 4 sleeve attivi + GTAA (to_daily), outer-join rinormalizzato (combine_outer);
|
||||||
|
* finestra di valutazione ancorata all'inizio del book crypto (TP01 start) — NO gonfiaggio
|
||||||
|
da 23 anni di solo-GTAA pre-2019;
|
||||||
|
* peso GTAA selezionato IN-SAMPLE (Sharpe pre-2025) su griglia {10..30%}, gli altri scalati
|
||||||
|
(1-w) — nessuna scelta sull'hold-out;
|
||||||
|
* verifica: hold-out 2025+, multi-cut (2023-01/2024-01/2024-07/2025-01), finestre DISGIUNTE,
|
||||||
|
per-anno, corr, is_hedge (corr tra Sharpe-anno del book e uplift-anno), plateau in w.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
sys.path.insert(0, str(ROOT))
|
||||||
|
|
||||||
|
from src.portfolio.portfolio import HOLDOUT, combine_outer, metrics, to_daily
|
||||||
|
from src.portfolio.sleeves import active_sleeves
|
||||||
|
from src.portfolio.gtaa import gtaa_returns
|
||||||
|
|
||||||
|
GRID_W = [0.10, 0.15, 0.20, 0.25, 0.30]
|
||||||
|
CUTS = [pd.Timestamp(c, tz="UTC") for c in ("2023-01-01", "2024-01-01", "2024-07-01", "2025-01-01")]
|
||||||
|
DISJOINT = [("2019-03-01", "2023-01-01"), ("2023-01-01", "2025-01-01"), ("2025-01-01", "2027-01-01")]
|
||||||
|
|
||||||
|
|
||||||
|
def sh(s: pd.Series, lo=None, hi=None) -> float:
|
||||||
|
v = s
|
||||||
|
if lo is not None:
|
||||||
|
v = v[v.index >= lo]
|
||||||
|
if hi is not None:
|
||||||
|
v = v[v.index < hi]
|
||||||
|
r = np.asarray(v.dropna().values, float)
|
||||||
|
return float(r.mean() / r.std() * np.sqrt(365.25)) if len(r) > 1 and r.std() > 0 else 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
sl = active_sleeves()
|
||||||
|
cols = {s.name: s.daily() for s in sl}
|
||||||
|
w_cur = {s.name: s.weight for s in sl}
|
||||||
|
g = to_daily(gtaa_returns())
|
||||||
|
lo_book = min(c.index.min() for c in cols.values()) # inizio era-crypto del book
|
||||||
|
cols5 = dict(cols, GTAA01=g)
|
||||||
|
|
||||||
|
base = combine_outer(cols, w_cur, lo=lo_book)
|
||||||
|
print(f"book start {lo_book.date()} | GTAA storia {g.index.min().date()}->{g.index.max().date()}"
|
||||||
|
f" | GTAA standalone: FULL {sh(g):.2f}, pre-2025 {sh(g, hi=HOLDOUT):.2f}, "
|
||||||
|
f"era-crypto {sh(g[g.index >= lo_book]):.2f}, HOLD {sh(g, lo=HOLDOUT):.2f}")
|
||||||
|
print(f"corr(GTAA, book) era-crypto: {g.reindex(base.index).corr(base):+.3f} | "
|
||||||
|
f"hold-out: {g.reindex(base.index).loc[HOLDOUT:].corr(base.loc[HOLDOUT:]):+.3f}")
|
||||||
|
print(f"\nBASE 4-sleeve : FULL {sh(base):.3f} IS {sh(base, hi=HOLDOUT):.3f} "
|
||||||
|
f"HOLD {sh(base, lo=HOLDOUT):.3f} DD {metrics(base)['maxdd']:.1%} "
|
||||||
|
f"CAGR {metrics(base)['cagr']:+.1%}")
|
||||||
|
|
||||||
|
# griglia peso GTAA — selezione IN-SAMPLE
|
||||||
|
rows = []
|
||||||
|
for w in GRID_W:
|
||||||
|
w5 = {k: v * (1 - w) for k, v in w_cur.items()} | {"GTAA01": w}
|
||||||
|
c5 = combine_outer(cols5, w5, lo=lo_book)
|
||||||
|
rows.append(dict(w=w, IS=sh(c5, hi=HOLDOUT), FULL=sh(c5), HOLD=sh(c5, lo=HOLDOUT),
|
||||||
|
DD=metrics(c5)["maxdd"], CAGR=metrics(c5)["cagr"]))
|
||||||
|
print(f" +GTAA {w:.0%}: IS {rows[-1]['IS']:.3f} FULL {rows[-1]['FULL']:.3f} "
|
||||||
|
f"HOLD {rows[-1]['HOLD']:.3f} DD {rows[-1]['DD']:.1%} CAGR {rows[-1]['CAGR']:+.1%}")
|
||||||
|
best = max(rows, key=lambda r: r["IS"])
|
||||||
|
w = best["w"]
|
||||||
|
print(f"\ncella IN-SAMPLE: w={w:.0%} (IS {best['IS']:.3f}); plateau IS: "
|
||||||
|
+ ", ".join(f"{r['w']:.0%}:{r['IS']:.2f}" for r in rows))
|
||||||
|
|
||||||
|
w5 = {k: v * (1 - w) for k, v in w_cur.items()} | {"GTAA01": w}
|
||||||
|
c5 = combine_outer(cols5, w5, lo=lo_book)
|
||||||
|
|
||||||
|
print("\nmulti-cut (Sharpe OOS dal taglio, book+GTAA vs book):")
|
||||||
|
for cut in CUTS:
|
||||||
|
print(f" {cut.date()}: {sh(c5, lo=cut):.3f} vs {sh(base, lo=cut):.3f} "
|
||||||
|
f"delta {sh(c5, lo=cut) - sh(base, lo=cut):+.3f}")
|
||||||
|
print("finestre DISGIUNTE:")
|
||||||
|
for a, b in DISJOINT:
|
||||||
|
la, lb = pd.Timestamp(a, tz="UTC"), pd.Timestamp(b, tz="UTC")
|
||||||
|
print(f" {a[:7]}..{b[:7]}: delta {sh(c5, lo=la, hi=lb) - sh(base, lo=la, hi=lb):+.3f}")
|
||||||
|
|
||||||
|
print("per-anno (ret book -> ret book+GTAA):")
|
||||||
|
ups, shs = [], []
|
||||||
|
for y in sorted(set(base.index.year)):
|
||||||
|
by, cy = base[base.index.year == y], c5[c5.index.year == y]
|
||||||
|
rb, rc = float((1 + by).prod() - 1), float((1 + cy).prod() - 1)
|
||||||
|
ups.append(sh(cy) - sh(by)); shs.append(sh(by))
|
||||||
|
print(f" {y}: {rb:+7.1%} -> {rc:+7.1%} dSh {sh(cy) - sh(by):+.2f}")
|
||||||
|
ih = float(np.corrcoef(shs, ups)[0, 1]) if len(ups) > 2 else float("nan")
|
||||||
|
print(f"is_hedge check — corr(Sharpe-anno book, uplift-anno): {ih:+.2f} "
|
||||||
|
f"(molto negativa = hedge, non alpha)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -277,6 +277,42 @@ def skyhook_sleeve(weight: float = 0.25) -> Sleeve:
|
|||||||
return Sleeve("SKH01_skyhook", weight, _skyhook_returns, pos_fn=_skyhook_positions)
|
return Sleeve("SKH01_skyhook", weight, _skyhook_returns, pos_fn=_skyhook_positions)
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------- GTAA01: trend difensivo equity multi-asset (IB) -----------------------------
|
||||||
|
# EQ-GTAA01 (src/portfolio/gtaa.py): TSMOM long-flat multi-orizzonte [21/63/126/252g] per-ETF,
|
||||||
|
# vol-target 12%, EW su SPY/QQQ/IWM/TLT/GLD/HYG, netto fee IB 2bps/lato. ~30 anni di storia
|
||||||
|
# (1996+), validato su OOS 2015+ PRIMA e INDIPENDENTEMENTE dall'hold-out crypto (diari
|
||||||
|
# 2026-06-22-equities-gtaa-and-crypto-combo / -deployable-combo-tp01-gtaa). Diversificatore
|
||||||
|
# STRUTTURALE del book crypto: corr ~+0.10 (hold-out ~0.00), is_hedge no (+0.30).
|
||||||
|
# Promosso a 5o sleeve il 2026-07-01 (diario 2026-07-01-strategy-wave-6threads.md, addendum GTAA):
|
||||||
|
# uplift positivo IN-SAMPLE (+0.13) e su TUTTE le finestre disgiunte (2019-23 +0.05, 23-24 +0.19,
|
||||||
|
# 25+ +0.25), multi-cut +0.21..+0.25, plateau monotono su w 10-30%. A differenza di EW-STR
|
||||||
|
# (refutato lo stesso giorno) NON e' selezione-sull'hold-out: l'edge di GTAA e' pre-esistente.
|
||||||
|
# CONVENZIONE CROSS-VENUE ONESTA: nei giorni senza barra equity (weekend/festivi US) il rendimento
|
||||||
|
# e' 0.0 (capitale IB fermo), NON rinormalizzato sugli altri sleeve: due conti reali non si
|
||||||
|
# travasano nel weekend. ESEGUIBILE a basso capitale (ETF frazionali, switch mensile, gia' in
|
||||||
|
# paper_combo dal 2026-06-23). CAVEAT: cross-venue = due conti (Deribit+IB); il book live Deribit
|
||||||
|
# (deribit_book_sleeves) NON lo include.
|
||||||
|
from src.portfolio.gtaa import gtaa_returns, gtaa_weights
|
||||||
|
|
||||||
|
# GTAA nel BOOK si attiva con l'era del book (inizio storia certificata BTC/ETH): senza troncatura
|
||||||
|
# l'outer-join farebbe partire il portafoglio nel 1996 con 23 anni di solo-GTAA rinormalizzato al
|
||||||
|
# 100%, distorcendo le metriche FULL. La storia 1996+ resta in gtaa.py per la ricerca.
|
||||||
|
GTAA_BOOK_ACTIVATION = pd.Timestamp("2019-03-14", tz="UTC")
|
||||||
|
|
||||||
|
|
||||||
|
def _gtaa_daily_returns() -> pd.Series:
|
||||||
|
r = gtaa_returns().dropna().sort_index()
|
||||||
|
if r.index.tz is None:
|
||||||
|
r.index = r.index.tz_localize("UTC")
|
||||||
|
days = pd.date_range(r.index.min().normalize(), r.index.max().normalize(), freq="1D", tz="UTC")
|
||||||
|
r = r.reindex(days).fillna(0.0) # weekend/festivi = capitale fermo (0), non riciclato
|
||||||
|
return r[r.index >= GTAA_BOOK_ACTIVATION]
|
||||||
|
|
||||||
|
|
||||||
|
def gtaa_sleeve(weight: float = 0.20) -> Sleeve:
|
||||||
|
return Sleeve("GTAA01_eq_trend", weight, _gtaa_daily_returns, pos_fn=gtaa_weights)
|
||||||
|
|
||||||
|
|
||||||
_TRADE_FREQ_CACHE = None
|
_TRADE_FREQ_CACHE = None
|
||||||
|
|
||||||
|
|
||||||
@@ -323,13 +359,17 @@ def active_sleeves() -> list[Sleeve]:
|
|||||||
"""Sleeve ATTIVI nel portafoglio (pesi rinormalizzati; sleeve a date diverse si attivano
|
"""Sleeve ATTIVI nel portafoglio (pesi rinormalizzati; sleeve a date diverse si attivano
|
||||||
quando parte la loro storia). Aggiungere qui SOLO strategie validate col gauntlet.
|
quando parte la loro storia). Aggiungere qui SOLO strategie validate col gauntlet.
|
||||||
|
|
||||||
SKH01 cablato @0.25 effettivo: i tre sleeve preesistenti scalati nel restante 0.75 mantenendo
|
SKH01 cablato @0.25 effettivo (2026-06-23): i tre preesistenti scalati nel restante 0.75
|
||||||
il loro rapporto 55:25:20 (-> 41.25/18.75/15), cosi' Skyhook pesa esattamente 25% del book."""
|
(rapporto 55:25:20 -> 41.25/18.75/15). GTAA01 cablato @0.20 effettivo (2026-07-01): i quattro
|
||||||
|
preesistenti scalati ancora x0.80 (-> 33/15/12/20). NB: la cella IS-best della griglia era
|
||||||
|
w=30% ma l'ingresso e' @20% per scelta STRUTTURALE dichiarata (cross-venue IB con paper_combo
|
||||||
|
giovane; precedente ingresso-sleeve <=25%; costo CAGR) — tutte le celle 10-30% passano i gate."""
|
||||||
return [
|
return [
|
||||||
tp01_sleeve(weight=0.4125), # trend difensivo, BTC/ETH, dal 2019 (l'unico deployable pieno)
|
tp01_sleeve(weight=0.33), # trend difensivo, BTC/ETH, dal 2019 (l'unico deployable pieno)
|
||||||
xsec_sleeve(weight=0.1875), # cross-sectional momentum Hyperliquid, dal 2024 (scorrelato, stat-mode)
|
xsec_sleeve(weight=0.15), # cross-sectional momentum Hyperliquid, dal 2024 (scorrelato, stat-mode)
|
||||||
vrp_sleeve(weight=0.15), # options short-vol (put credit spread + gate IV-rank), dal 2021 (lead modellato, scorrelato)
|
vrp_sleeve(weight=0.12), # options short-vol (put credit spread + gate IV-rank), dal 2021 (lead modellato, scorrelato)
|
||||||
skyhook_sleeve(weight=0.25), # dual-TF regime+breakout BTC/ETH, dal 2019 (quasi-ortogonale, exit %-asimmetrici, research)
|
skyhook_sleeve(weight=0.20), # dual-TF regime+breakout BTC/ETH, dal 2019 (quasi-ortogonale, exit %-asimmetrici, research)
|
||||||
|
gtaa_sleeve(weight=0.20), # trend difensivo equity 6-ETF (IB), dal 1996 (diversificatore strutturale, cross-venue)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
"""Lock del 5o sleeve GTAA01 (promosso 2026-07-01) e del registry a 5 sleeve.
|
||||||
|
|
||||||
|
Pin degli invarianti decisi nel diario 2026-07-01-strategy-wave-6threads.md (addendum GTAA):
|
||||||
|
* registry = 5 sleeve, pesi 33/15/12/20/20 (somma 1), GTAA01 presente @0.20;
|
||||||
|
* convenzione cross-venue: weekend/festivi = 0.0 (capitale IB fermo, NON rinormalizzato);
|
||||||
|
* attivazione nel book all'era crypto (2019-03-14) — niente 1996-2019 di solo-GTAA;
|
||||||
|
* il book live Deribit (deribit_book_sleeves) NON include GTAA (resta TP01+SKH01 75/25).
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
|
from src.portfolio.sleeves import GTAA_BOOK_ACTIVATION, _gtaa_daily_returns, active_sleeves, deribit_book_sleeves
|
||||||
|
|
||||||
|
|
||||||
|
def test_registry_5_sleeve_pesi():
|
||||||
|
sl = active_sleeves()
|
||||||
|
w = {s.name: s.weight for s in sl}
|
||||||
|
assert len(sl) == 5
|
||||||
|
assert w == {"TP01_trend_1d": 0.33, "XS01_xsec_hl": 0.15, "VRP01_shortvol": 0.12,
|
||||||
|
"SKH01_skyhook": 0.20, "GTAA01_eq_trend": 0.20}
|
||||||
|
assert sum(w.values()) == pytest.approx(1.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_gtaa_weekend_zero_e_attivazione():
|
||||||
|
r = _gtaa_daily_returns()
|
||||||
|
assert r.index.min() == GTAA_BOOK_ACTIVATION # niente storia pre-book nel registry
|
||||||
|
assert r.index.freqstr in ("D", "1D") or (r.index[1:] - r.index[:-1] == pd.Timedelta("1D")).all()
|
||||||
|
wknd = r[r.index.dayofweek >= 5] # sab/dom: capitale equity fermo
|
||||||
|
assert len(wknd) > 100 and float(np.abs(wknd.values).max()) == 0.0
|
||||||
|
wk = r[r.index.dayofweek < 5]
|
||||||
|
assert float(np.abs(wk.values).sum()) > 0 # nei feriali la strategia vive
|
||||||
|
|
||||||
|
|
||||||
|
def test_book_live_deribit_non_include_gtaa():
|
||||||
|
names = [s.name for s in deribit_book_sleeves()]
|
||||||
|
assert names == ["TP01_trend_1d", "SKH01_skyhook"] # esecuzione live invariata
|
||||||
Reference in New Issue
Block a user