"""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__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__1d.parquet (namespace dedicato). Universo per cross-sectional.") if __name__=="__main__": main()