research: espandere universo XS01 a 52 asset DILUISCE (negativo) -> XS01 blindato sui 19 major

Esteso fetch_hyperliquid a 52 alt certificati (cross-venue vs Binance, flat 0%, 2024+; +gate
delistato per MKR/FXS). Ma il cross-sectional momentum sui 52 e' NEGATIVO (FULL -0.1..-0.6, k grande
non aiuta) vs +0.67/OOS0.91 sui 19 major (stessa finestra): i ~33 small-cap (WIF/JUP/ORDI/PYTH/TAO..)
sono idiosincratici/mean-reverting e rovesciano il momentum relativo. "Piu' asset = piu' robusto"
e' FALSO per l'XS momentum: la breadth utile e' quella dei major liquidi.

Fix: lo sleeve _xsec_returns usa XS_UNIVERSE esplicito (19 major), non glob-all (aggiungere parquet
certificati non lo rompe piu'). I 52 parquet restano su disco per ricerca futura, non per XS01.
Portafoglio ripristinato e invariato: TP01 70% + XS01 30%, FULL Sh 1.41 / HOLD 1.15. 12 test ok.
Diario 2026-06-19-xsec-universe-expansion.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-19 21:00:00 +00:00
parent 53d0134cb1
commit 8426d05f12
3 changed files with 65 additions and 12 deletions
@@ -0,0 +1,39 @@
# 2026-06-19 — Espandere l'universo XS01: PIÙ asset DILUISCONO (i 19 major sono il sweet spot)
Richiesta: aggiungere altri asset Hyperliquid certificati per rafforzare XS01 (cross-sectional
momentum). Fatto il lavoro, esito ONESTO: **non rafforza — diluisce.**
## Cosa ho fatto
- Esteso `fetch_hyperliquid.py` a ~54 candidati alt maggiori (mappa Binance auto SYM/USDT, k-prefissi
esclusi). **52 certificati** (cross-venue 4-11 bps vs Binance, flat 0%, storia 2024+): aggiunti
ATOM DYDX APE CRV LDO STX GMX SNX BCH COMP WLD UNI TRX FIL RUNE ENA ORDI JUP WIF PYTH FET AR ETC
ALGO GALA SAND AXS DOT BLUR JTO PENDLE ONDO TAO. Esclusi MKR (delistato HL 2025-09) e FXS
(migrazione Frax 2026-01) via nuovo gate "ultima barra recente".
## Il finding: il cross-section dei 52 è NEGATIVO; i 19 major sono positivi
Stessa finestra (2024-04 → 2026-06, 807g), mom L*/H10:
| Universo | k | FULL Sharpe (L30/L60/L90) |
|---|---|---|
| **52 asset** | 5 | 0.13 / 0.21 / 0.35 |
| **52 asset** | 8-12 | tutti negativi (k grande non aiuta) |
| **19 major** | 5 | +0.30 / +0.36 / **+0.67** (OOS 0.91) |
I ~33 small/new-cap aggiunti (WIF, JUP, ORDI, PYTH, TAO, GALA, AR, BLUR…) sono idiosincratici/
mean-reverting: il loro rumore **rovescia** il momentum relativo. Cross-sectional momentum su crypto
funziona fra i MAJOR liquidi, non sul long tail. Allargare l'universo NON è gratis.
## Azione
- **XS01 resta sui 19 major** (sweet spot già validato: plateau/fee/subset). Lo sleeve
`_xsec_returns` ora usa una **lista esplicita `XS_UNIVERSE` (19)**, non più glob-all (così
aggiungere parquet certificati non lo cambia/rompe — avevo inavvertitamente fatto vedere allo
sleeve 52 asset = negativo).
- I 52 parquet certificati restano su disco: dato valido per ricerca futura (uno strato diverso —
es. trend-following multi-asset, o un XS ristretto ai top-liquidità — potrebbe usarli), ma NON XS01.
- Portafoglio invariato e ripristinato: **TP01 70% + XS01 30%, FULL Sh 1.41 / HOLD 1.15.**
## Lezione
"Più asset = più robusto" è FALSO per il cross-sectional momentum: il long tail di alt piccoli
diluisce/inverte l'edge. La breadth utile è quella dei major liquidi (corr-strutturata), non il
numero grezzo. Per rafforzare XS01 servirebbe semmai una selezione per LIQUIDITÀ/qualità, non più
nomi. (Coerente con la disciplina: nessuna espansione senza che migliori il gauntlet.)
+12 -7
View File
@@ -18,12 +18,14 @@ import numpy as np, pandas as pd, requests, ccxt
RAW = PROJECT_ROOT / "data" / "raw"
START = "2024-01-01"; END = "2026-06-17"
# set liquido (volume recente alto + storia 2024); MATIC morto, HYPE 2025-only esclusi qui
SYMS = ["BTC","ETH","SOL","BNB","XRP","DOGE","AVAX","LINK","LTC","ADA","ARB","OP","SUI","APT","INJ","TIA","SEI","NEAR","AAVE"]
BINANCE = {"BTC":"BTC/USDT","ETH":"ETH/USDT","SOL":"SOL/USDT","BNB":"BNB/USDT","XRP":"XRP/USDT",
"DOGE":"DOGE/USDT","AVAX":"AVAX/USDT","LINK":"LINK/USDT","LTC":"LTC/USDT","ADA":"ADA/USDT",
"ARB":"ARB/USDT","OP":"OP/USDT","SUI":"SUI/USDT","APT":"APT/USDT","INJ":"INJ/USDT",
"TIA":"TIA/USDT","SEI":"SEI/USDT","NEAR":"NEAR/USDT","AAVE":"AAVE/USDT"}
# UNIVERSO ESTESO: alt liquidi noti su Hyperliquid (mappa Binance auto = SYM/USDT). Il gate di
# certificazione (cross-venue + liquidita' + flat) scarta i non-conformi. k-prefissi esclusi
# (scaling 1000x complica il cross-venue). MATIC morto escluso.
SYMS = ["BTC","ETH","SOL","BNB","XRP","DOGE","AVAX","LINK","LTC","ADA","ARB","OP","SUI","APT",
"INJ","TIA","SEI","NEAR","AAVE","ATOM","DYDX","APE","CRV","LDO","STX","GMX","SNX","BCH",
"COMP","MKR","WLD","UNI","TRX","FIL","RUNE","ENA","ORDI","JUP","WIF","PYTH","FET","AR",
"ETC","ALGO","GALA","SAND","AXS","DOT","FXS","BLUR","JTO","PENDLE","ONDO","TAO"]
BINANCE = {s: f"{s}/USDT" for s in SYMS}
def _h():
@@ -78,7 +80,10 @@ def main():
bps=(m["a"]-m["b"]).abs()/m["b"]*1e4
med=bps.median(); g1=(bps>100).mean()*100
else: med=g1=float("nan")
clean = (not np.isnan(med)) and med<60 and g1<3 and flat<5
# gate "delistato/migrato": l'ultima barra dev'essere recente (entro ~21g da END),
# altrimenti l'asset tronca l'universo cross-sectional (es. MKR fermo a 2025-09, FXS 2026-01).
recent = (pd.Timestamp(END, tz="UTC") - ts.iloc[-1]) <= pd.Timedelta("21D")
clean = (not np.isnan(med)) and med<60 and g1<3 and flat<5 and recent
v = "PULITO" if clean else "scarta"
print(f" {s:<6}{len(df):>7}{str(ts.iloc[0].date()):>12}{flat:>6.1f}%{med:>9.1f}{g1:>6.1f}%{v:>12}")
if clean:
+13 -4
View File
@@ -54,16 +54,25 @@ import glob as _glob
from pathlib import Path as _Path
XS_CFG = dict(L=30, H=10, k=5, mode="mom", target_vol=0.20)
_HL_DIR = _Path(__file__).resolve().parents[2] / "data" / "raw"
# UNIVERSO ESPLICITO = 19 ALT LIQUIDI MAJOR. NB (2026-06-19): allargare a 52 asset (incluso
# small-cap WIF/JUP/ORDI/PYTH/TAO...) DILUISCE l'edge -> momentum cross-section NEGATIVO sui 52.
# I major sono il sweet spot. NON usare glob-all (i parquet extra certificati servono ad altra
# ricerca, non a XS01). Vedi diario 2026-06-19-xsec-universe-expansion.md.
XS_UNIVERSE = ["BTC", "ETH", "SOL", "BNB", "XRP", "DOGE", "AVAX", "LINK", "LTC", "ADA",
"ARB", "OP", "SUI", "APT", "INJ", "TIA", "SEI", "NEAR", "AAVE"]
def _xsec_returns() -> pd.Series:
cols = {}
for p in sorted(_glob.glob(str(_HL_DIR / "hl_*_1d.parquet"))):
for sym in XS_UNIVERSE:
p = _HL_DIR / f"hl_{sym.lower()}_1d.parquet"
if not p.exists():
continue
d = pd.read_parquet(p)
cols[_Path(p).stem] = pd.Series(d["close"].values.astype(float),
cols[sym] = pd.Series(d["close"].values.astype(float),
index=pd.to_datetime(d["timestamp"], unit="ms", utc=True))
if not cols:
raise FileNotFoundError("universo Hyperliquid assente: gira scripts/analysis/fetch_hyperliquid.py")
if len(cols) < 10:
raise FileNotFoundError("universo Hyperliquid XS01 incompleto: gira scripts/analysis/fetch_hyperliquid.py")
C = pd.concat(cols, axis=1, join="inner").sort_index().dropna()
px = C.values; n, A = px.shape
L, H, k, mode, tv = XS_CFG["L"], XS_CFG["H"], XS_CFG["k"], XS_CFG["mode"], XS_CFG["target_vol"]