Skip to content本文へ移動

Trading API & SDK · Placing Orders · 5/8

WebSocket Streams

Why WebSockets?

REST API polling is fine for one-off queries, but for real-time trading you need WebSockets:

Connecting

The SDK's Info.subscribe(subscription, callback) manages this connection for you (see basic_ws.py). To see the raw protocol, here is a minimal client using the websocket-client package:

import json
import threading
import websocket  # pip install websocket-client

WS_URL = "wss://api.hyperliquid.xyz/ws"

def on_message(ws, message):
    data = json.loads(message)
    print(data)

def on_open(ws):
    print("Connected!")
    # Subscribe to channels after connection
    subscribe_msg = {
        "method": "subscribe",
        "subscription": {"type": "l2Book", "coin": "BTC"}
    }
    ws.send(json.dumps(subscribe_msg))

ws = websocket.WebSocketApp(
    WS_URL,
    on_open=on_open,
    on_message=on_message,
)

# Run in a separate thread
ws_thread = threading.Thread(target=ws.run_forever)
ws_thread.daemon = True
ws_thread.start()

Subscription Types

L2 Order Book

{"method": "subscribe", "subscription": {"type": "l2Book", "coin": "BTC"}}

Each message is a full snapshot of the top levels (up to 20 per side), not an incremental diff. Snapshots are pushed on new blocks, no more than once every 0.5 seconds.

All Mid Prices

{"method": "subscribe", "subscription": {"type": "allMids"}}

Streams mid prices for all assets as {"mids": {coin: price}}. Useful for portfolio valuation. Add "dex": "xyz" to get mids for a HIP-3 dex.

Trades

{"method": "subscribe", "subscription": {"type": "trades", "coin": "BTC"}}

Every trade that occurs on the BTC market.

User Events

{"method": "subscribe", "subscription": {"type": "userEvents", "user": "0xYourAddress"}}

Fills, funding payments, liquidations and non-user cancels for an address. No signature is needed: user streams are public data for any address. Note that messages for this subscription arrive on the channel named "user". For fills alone, userFills is a simpler stream.

Candles

{"method": "subscribe", "subscription": {"type": "candle", "coin": "BTC", "interval": "1m"}}

Processing Messages

def on_message(ws, message):
    data = json.loads(message)

    if data.get("channel") == "l2Book":
        book = data["data"]
        bids = book["levels"][0]
        asks = book["levels"][1]
        if bids and asks:
            spread = float(asks[0]["px"]) - float(bids[0]["px"])
            print(f"BTC spread: ${spread:.2f}")

    elif data.get("channel") == "trades":
        for trade in data["data"]:
            side = "BUY" if trade["side"] == "B" else "SELL"  # side is "B" (buy) or "A" (sell/ask)
            print(f"{side} {trade['sz']} BTC @ {trade['px']}")

    elif data.get("channel") == "user":  # userEvents subscription
        event = data["data"]  # one object, e.g. {"fills": [...]} or {"funding": {...}}
        for fill in event.get("fills", []):
            print(f"Filled: {fill['coin']} {fill['sz']} @ {fill['px']}")

Best Practices

  1. Reconnection logic — The server may disconnect at any time without notice. Reconnect, resubscribe, and backfill gaps with the matching /info request.
  2. Heartbeats — The server closes a connection that has received nothing from it for 60 seconds. On quiet channels, send {"method": "ping"}; the reply is {"channel": "pong"} (docs).
  3. Message queuing — Process messages in a separate thread to avoid blocking the WebSocket.
  4. Error handling — Always handle connection errors and malformed messages gracefully.
  5. Limits — As of October 2026, each IP may hold up to 10 WebSocket connections and 1000 subscriptions, and send up to 2000 messages per minute (rate limits).

取引 API と SDK · 注文を出す · 5/8

WebSocket の配信

なぜ WebSocket か

1回きりの問い合わせなら、REST API を繰り返し呼ぶので十分です。ただ、リアルタイムで売買するなら WebSocket が必要です。

接続する

SDK の Info.subscribe(subscription, callback) が、この接続を代わりに管理します(basic_ws.py を参照)。ここでは生のプロトコルを見るために、websocket-client パッケージで最小のクライアントを書きます。

import json
import threading
import websocket  # pip install websocket-client

WS_URL = "wss://api.hyperliquid.xyz/ws"

def on_message(ws, message):
    data = json.loads(message)
    print(data)

def on_open(ws):
    print("Connected!")
    # Subscribe to channels after connection
    subscribe_msg = {
        "method": "subscribe",
        "subscription": {"type": "l2Book", "coin": "BTC"}
    }
    ws.send(json.dumps(subscribe_msg))

ws = websocket.WebSocketApp(
    WS_URL,
    on_open=on_open,
    on_message=on_message,
)

# Run in a separate thread
ws_thread = threading.Thread(target=ws.run_forever)
ws_thread.daemon = True
ws_thread.start()

購読の種類

L2 の板

{"method": "subscribe", "subscription": {"type": "l2Book", "coin": "BTC"}}

メッセージは毎回、上位の気配(片側20本まで)の完全なスナップショットです。差分ではありません。新しいブロックのたびに届きます。ただし間隔は0.5秒以上あきます。

すべての仲値

{"method": "subscribe", "subscription": {"type": "allMids"}}

全銘柄の仲値を {"mids": {coin: price}} の形で配信します。ポートフォリオの評価に便利です。HIP-3 の dex の仲値がほしいときは "dex": "xyz" を加えます。

売買

{"method": "subscribe", "subscription": {"type": "trades", "coin": "BTC"}}

BTC の市場で起きる売買がすべて届きます。

口座のイベント

{"method": "subscribe", "subscription": {"type": "userEvents", "user": "0xYourAddress"}}

あるアドレスの約定、資金調達料の支払い、清算、自分以外による取り消しが届きます。署名は要りません。口座の配信は、どのアドレスについても公開のデータです。この購読のメッセージは "user" という名前のチャンネルで届くので注意してください。約定だけがほしいなら、userFills のほうが簡単です。

ローソク足

{"method": "subscribe", "subscription": {"type": "candle", "coin": "BTC", "interval": "1m"}}

メッセージを処理する

def on_message(ws, message):
    data = json.loads(message)

    if data.get("channel") == "l2Book":
        book = data["data"]
        bids = book["levels"][0]
        asks = book["levels"][1]
        if bids and asks:
            spread = float(asks[0]["px"]) - float(bids[0]["px"])
            print(f"BTC spread: ${spread:.2f}")

    elif data.get("channel") == "trades":
        for trade in data["data"]:
            side = "BUY" if trade["side"] == "B" else "SELL"  # side is "B" (buy) or "A" (sell/ask)
            print(f"{side} {trade['sz']} BTC @ {trade['px']}")

    elif data.get("channel") == "user":  # userEvents subscription
        event = data["data"]  # one object, e.g. {"fills": [...]} or {"funding": {...}}
        for fill in event.get("fills", []):
            print(f"Filled: {fill['coin']} {fill['sz']} @ {fill['px']}")

よい作り方

  1. 再接続の処理: サーバーは予告なしに、いつでも接続を切ることがあります。つなぎ直して購読し直し、抜けた分は対応する /info のリクエストで埋めます。
  2. ハートビート: サーバーは、60秒間何も受け取らなかった接続を閉じます。静かなチャンネルでは {"method": "ping"} を送ります。返事は {"channel": "pong"} です(資料)。
  3. メッセージのキュー: メッセージの処理は別のスレッドで行います。WebSocket を止めないためです。
  4. エラーの処理: 接続のエラーや壊れたメッセージは、必ず適切に処理します。
  5. 上限: 2026年10月時点で、1つの IP が持てる WebSocket の接続は10本まで、購読は1000件までです。送れるメッセージは1分に2000件までです(レート制限)。