本文へ移動
レビューを依頼

取引 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件までです(レート制限)。