a5a61ac7e3
Espansione universo (su input utente "storico da cerbero"): il Cerbero MCP col token MAINNET serve Hyperliquid (230 perp REALI, storia nativa dal 2024). fetch_hyperliquid.py certifica 19 alt liquidi a 1d (flat 0%, cross-venue 4-9 bps vs Binance) -> data/raw/hl_*_1d.parquet. Abilita le strategie CROSS-SECTIONAL (impossibili a 2 asset). XS01 = cross-sectional momentum market-neutral (long 5 forti / short 5 deboli su ret 30g, ogni 10g, vol-target 20%). Validato onesto: plateau (config/k/subset), fee-robusto (0.3% RT), scorrelato a TP01 (-0.06), positivo OGNI anno 2024-26, meccanismo complementare (lavora nella dispersione quando TP01 e' in cash). Diverso dal regime-luck RV bocciato (19 asset, plateau, ogni anno+). Contributo al portafoglio (outer-join + pesi rinormalizzati per sleeve a date diverse): TP01-solo FULL 1.30 / HOLD 0.31 -> TP01 70% + XS01 30%: FULL 1.41 / HOLD 1.15, DD giu', ~ogni anno+. -> XS01 BATTE il portafoglio esistente: inserito in active_sleeves. Caveat (documentati): storia XS ~2.5 anni; STAT-MODE (book 19 gambe non eseguibile a 2k -> ~20k), sleeve diagnostico/forward-monitor. portfolio.combine ora outer-join+renorm. 12 test passano. Diario 2026-06-19-hyperliquid-xsec.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
92 lines
4.3 KiB
Python
92 lines
4.3 KiB
Python
"""FETCH + CERTIFY universo Hyperliquid (Cerbero MCP MAINNET) — espansione cross-sectional.
|
|
|
|
Hyperliquid (via cerbero-mcp mainnet) offre ~230 perp liquidi, ma storia nativa REALE solo dal
|
|
2024 (pre-2024 = backfill, volume 0). Qui scarico un set liquido a 1d (2024+), e CERTIFICO ogni
|
|
asset come BTC/ETH: cross-venue vs Binance (realismo) + flat-bar (liquidita'). Scrivo SOLO i puliti
|
|
in data/raw/hl_<sym>_1d.parquet (namespace dedicato, NON mischiato col Deribit BTC/ETH).
|
|
|
|
Disciplina: Cerbero ci ha gia' bruciato (testnet) -> niente fiducia, solo certificazione.
|
|
|
|
uv run python scripts/analysis/fetch_hyperliquid.py
|
|
"""
|
|
from __future__ import annotations
|
|
import sys, time
|
|
from pathlib import Path
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
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"}
|
|
|
|
|
|
def _h():
|
|
env={}
|
|
for ln in open(PROJECT_ROOT/".env.mainnet"):
|
|
ln=ln.strip()
|
|
if ln and not ln.startswith("#") and "=" in ln: k,v=ln.split("=",1); env[k]=v.strip()
|
|
return {"Authorization":f"Bearer {env['CERBERO_TOKEN']}","X-Bot-Tag":env.get('CERBERO_BOT_TAG','fetch'),"Content-Type":"application/json"}
|
|
|
|
|
|
def fetch_hl(sym, H, interval="1d"):
|
|
r=requests.post("https://cerbero-mcp.tielogic.xyz/mcp/tools/get_historical",
|
|
headers=H, json={"exchange":"hyperliquid","instrument":sym,"interval":interval,
|
|
"start_date":START,"end_date":END}, timeout=60)
|
|
c=r.json().get("candles",[])
|
|
if not c: return pd.DataFrame()
|
|
df=pd.DataFrame(c)[["timestamp","open","high","low","close","volume"]]
|
|
return df.drop_duplicates("timestamp").sort_values("timestamp").reset_index(drop=True)
|
|
|
|
|
|
def binance_daily(sym_b, start_ms, end_ms):
|
|
ex=ccxt.binance({"enableRateLimit":True})
|
|
out={}; since=start_ms
|
|
while since<=end_ms:
|
|
try: r=ex.fetch_ohlcv(sym_b,"1d",since=since,limit=500)
|
|
except Exception: break
|
|
r=[x for x in r if x[0]>=since]
|
|
if not r: break
|
|
for x in r:
|
|
if start_ms<=x[0]<=end_ms and x[4]: out[int(x[0])]=float(x[4])
|
|
nxt=int(r[-1][0])+86400000
|
|
if nxt<=since: break
|
|
since=nxt
|
|
return pd.Series(out)
|
|
|
|
|
|
def main():
|
|
H=_h()
|
|
print("="*92); print(" FETCH + CERTIFY Hyperliquid 1d (Cerbero mainnet) — cross-venue vs Binance + liquidita'"); print("="*92)
|
|
print(f" {'sym':<6}{'barre':>7}{'start':>12}{'flat%':>7}{'med_bps':>9}{'>1%':>7}{'verdetto':>12}")
|
|
certified=[]
|
|
for s in SYMS:
|
|
df=fetch_hl(s,H)
|
|
if df.empty: print(f" {s:<6} vuoto"); continue
|
|
ts=pd.to_datetime(df["timestamp"],unit="ms",utc=True)
|
|
flat=((df.open==df.high)&(df.high==df.low)&(df.low==df.close)).mean()*100
|
|
# cross-venue vs Binance USDT (daily close)
|
|
ref=binance_daily(BINANCE[s], int(df["timestamp"].iloc[0]), int(df["timestamp"].iloc[-1]))
|
|
a=df.set_index("timestamp")["close"]
|
|
m=pd.concat([a.rename("a"),ref.rename("b")],axis=1,join="inner").dropna()
|
|
if len(m)>5:
|
|
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
|
|
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:
|
|
df.to_parquet(RAW/f"hl_{s.lower()}_1d.parquet", index=False); certified.append(s)
|
|
print(f"\n CERTIFICATI ({len(certified)}): {certified}")
|
|
print(" Scritti in data/raw/hl_<sym>_1d.parquet (namespace dedicato). Universo per cross-sectional.")
|
|
|
|
|
|
if __name__=="__main__":
|
|
main()
|