perp-arbitrage/exchanges/hyperliquid.py

72 lines
2.9 KiB
Python
Raw Permalink Normal View History

2025-03-26 12:24:14 +00:00
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)