import asyncio import json import websockets import requests class HyperliquidPerpStream: def __init__(self, quote_filters): self.url = "wss://api.hyperliquid.xyz/ws" self.quote_filters = quote_filters self.symbols = self.get_symbols() def get_symbols(self): try: url = "https://api.hyperliquid.xyz/info" headers = {"Content-Type": "application/json"} payload = {"type": "metaAndAssetCtxs"} response = requests.post(url, headers=headers, json=payload) data = response.json() print("[HYPERLIQUID DEBUG] type:", type(data)) assets = data[0].get("universe", []) print("[HYPERLIQUID DEBUG] universe len:", len(assets)) symbols = [a["name"] for a in assets] print("[HYPERLIQUID SYMBOLS]", symbols[:10]) return symbols except Exception as e: print("[HYPERLIQUID REST ERROR]", e) return [] def normalize_symbol(self, symbol): return symbol + "/USD" async def stream(self): symbols = self.symbols print(f"[hyperliquid] Starting stream with {len(symbols)} symbols") while True: try: async with websockets.connect(self.url) as ws: chunk_size = 1 for i in range(0, len(symbols), chunk_size): chunk = symbols[i:i + chunk_size] await ws.send(json.dumps({ "type": "subscribe", "channels": [{"name": "l2Book", "symbols": chunk}] })) await asyncio.sleep(0.1) async for msg in ws: try: print(msg) data = json.loads(msg) if data.get("type") == "l2Book" and "impactPxs" in data: symbol = data.get("symbol") impact = data.get("impactPxs", []) if len(impact) < 2: continue bid = float(impact[0]) ask = float(impact[1]) yield { "exchange": "hyperliquid", "symbol": self.normalize_symbol(symbol), "bid": bid, "ask": ask, "bid_size": 0.0, "ask_size": 0.0 } except Exception as e: print("[HYPERLIQUID PARSE ERROR]", e) except Exception as e: print("[HYPERLIQUID WS ERROR]", e) await asyncio.sleep(5)