取引 API と SDK · 注文を出す · 5/8
WebSocket の配信
なぜ WebSocket か
1回きりの問い合わせなら、REST API を繰り返し呼ぶので十分です。ただ、リアルタイムで売買するなら WebSocket が必要です。
- 板の更新: ブロックが作られるたびに、新しい板のスナップショットが届きます
- 売買の配信: 売買が起きるたびに知らせが届きます
- 口座のイベント: 自分の約定、資金調達料の支払い、清算、自分以外による取り消しが届きます
- 遅延が小さい: メッセージごとに HTTP の手間がかかりません
接続する
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']}")
よい作り方
- 再接続の処理: サーバーは予告なしに、いつでも接続を切ることがあります。つなぎ直して購読し直し、抜けた分は対応する
/infoのリクエストで埋めます。 - ハートビート: サーバーは、60秒間何も受け取らなかった接続を閉じます。静かなチャンネルでは
{"method": "ping"}を送ります。返事は{"channel": "pong"}です(資料)。 - メッセージのキュー: メッセージの処理は別のスレッドで行います。WebSocket を止めないためです。
- エラーの処理: 接続のエラーや壊れたメッセージは、必ず適切に処理します。
- 上限: 2026年10月時点で、1つの IP が持てる WebSocket の接続は10本まで、購読は1000件までです。送れるメッセージは1分に2000件までです(レート制限)。