WebSocket API
Hypercall のオプション取引向けリアルタイムデータストリーミングです。
ライブサンプルやスキーマの詳細を確認しやすい インタラクティブ WebSocket API リファレンス もご覧ください。
プログラムから利用する場合は AsyncAPI 仕様 をダウンロードしてください。
WebSocket のメッセージオブジェクトには、事前の告知なく新しいフィールドが追加されることがあります。クライアントは認識できないフィールドを無視する必要があります。Hypercall は既存のメッセージスキーマからフィールドを削除しません。
接続
wss://HOST/ws に接続します。
エンドポイント:
- 本番環境:
wss://api.hypercall.xyz/ws - ローカル:
ws://localhost:3000/ws
Hypercall がテストネット用の HYPE を追加で確保するまで、テストネットは一時的に無効化されています。
圧縮
/ws は RFC 7692 の permessage-deflate に対応しています。クライアントで有効にすると、マーケットデータの帯域幅を削減できます。本番環境で取得したトラフィックでは、個別に圧縮したフレームで約 45%、インデックス価格のバッチで約 70% サイズが小さくなりました。
- クライアントはアップグレードリクエストで拡張を提示します。例:
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits - サーバーが受け入れた場合、
101レスポンスにSec-WebSocket-Extensions: permessage-deflate; server_no_context_takeoverが含まれます。この場合、サーバーの各メッセージは共有スライディングウィンドウを使わずに個別に圧縮され、数百バイト未満のメッセージは引き続き非圧縮で送信されます。展開はライブラリが透過的に行います。 - レスポンスに
Sec-WebSocket-Extensionsヘッダーがない場合、すべてのフレームは非圧縮です。圧縮は環境ごとに有効化されるため、クライアントは両方のケースに対応する必要があります。どちらの場合も JSON メッセージの内容は同一です。本番環境はまだこの拡張を受け入れていないため、現時点で本番環境のフレームは非圧縮です。 - クライアントは送信するメッセージを圧縮しても構いません。サーバーはクライアントの各メッセージを最大 256 KiB まで展開し、それを超えるメッセージの場合は接続を切断します。
ブラウザは拡張を自動的にネゴシエートします。多くのライブラリでは変更は不要です。
Python(websockets はデフォルトで圧縮を有効にします):
import websockets
async with websockets.connect("wss://api.hypercall.xyz/ws", compression="deflate") as ws:
...
Node.js(ws):
import WebSocket from "ws";
const ws = new WebSocket("wss://api.hypercall.xyz/ws", { perMessageDeflate: true });
Rust: hypercall-client の WsClient はデフォルトで permessage-deflate をネゴシエートします(例: Rust クライアント を参照)。素の tungstenite および tokio-tungstenite はまだこの拡張を実装していないため、非圧縮で接続します。独自のソケットで圧縮を使う場合は、yawc など拡張を実装したクライアントを使用してください。
let url = "wss://api.hypercall.xyz/ws".parse()?;
let mut ws = yawc::WebSocket::connect(url)
.with_options(yawc::Options::default().with_low_latency_compression())
.await?;
ウォレットの識別
認証が必要なチャネル(注文、約定、ポートフォリオ)でデータを受信するには、接続後に Authenticate メッセージを送信してウォレットを識別します。
{"type": "Authenticate", "wallet": "0x1234..."}
サーバーは確認メッセージを返します。
{"type": "Authenticated", "wallet": "0x1234..."}
Authenticated を受信した後、認証が必要なチャネルを購読できます。ウォレットアドレスが無効な場合、サーバーは Error メッセージを返し、接続は維持されます。
?wallet= クエリパラメータは後方互換性のために引き続きサポートされていますが、非推奨であり、将来のリリースで削除されます。上記のメッセージベースの方式をご利用ください。
接続の死活監視
サーバーは WebSocket のハートビートを実施します。
- 20 秒ごとに
Pingコントロールフレームを送信します - 60 秒以内に対応する
Pongが返ることを期待します - クライアントが応答しなくなった場合、クローズコード
1008、理由pong timeoutで接続を切断します
ブラウザの WebSocket 実装は ping/pong を自動的に処理します。tungstenite や tokio-tungstenite を含む多くの Rust 製 WebSocket ライブラリも、コントロールフレームの ping/pong を自動で処理します。手動で Pong 処理を追加する前に、利用しているライブラリのドキュメントを確認してください。独自実装や生ソケットの実装では、Ping フレームに Pong で応答する必要があります。
低速コンシューマーからの復旧
サーバーは、設定されたメッセージ数、エンコード済みバイト数、キュー滞留時間、またはソケット書き込みの安全上限の範囲内で送信データを処理しきれない /ws 接続を切断します。接続がまだクローズフレームを受け取れる場合、サーバーはコード 1008 と、簡潔な JSON 形式の理由を送信します。
{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}
理由の各フィールドは次のとおりです。
| フィールド | 意味 |
|---|---|
class | 安全上限を超えたフレームの配信クラス。 |
cause | message_limit、byte_limit、message_age、または write_timeout。 |
recovery | 次に必要な対応。resubscribe、snapshot_resubscribe、portfolio_refetch、rest_reconcile など。 |
切断が発生した場合は、再接続し、必要に応じてウォレットを再度識別し、再購読したうえで、新しいイベントを処理する前に現在の状態を照合してください。順序付きの公開チャネルでは、新しいスナップショットが必要です。プライベートなイベントチャネルでは、カーソルによるリプレイがまだ利用できないため、正となる REST API を通じた照合が必要です。完全に停止した接続はクローズ理由を読み取る前に終了することがあるため、クリーンでない切断の場合もクライアントはこの復旧フローを使用する必要があります。
高頻度の公開マーケットデータと、認証が必要なコマンドやプライベートストリームには、別々の接続を使用してください。配信クラスによってメトリクスと復旧時の挙動が決まりますが、同じ接続上のフレームは単一の順序付きソケット書き込み経路を共有します。そのため、公開データの書き込みが停滞すると、書き込み期限により接続が切断されるまで、同じ接続上の後続のプライベートフレームも遅延する可能性があります。
チャネルの購読
購読するには JSON メッセージを送信します。
{"type": "Subscribe", "channel": "orderbook"}
購読を解除するには次のように送信します。
{"type": "Unsubscribe", "channel": "orderbook"}
確認メッセージが返されます。
{"type": "Subscribed", "channel": "orderbook"}
シンボルによるフィルタリング
order_updates および fills チャネルは、任意の symbols フィルタに対応しています。指定した場合、サーバーは原資産が指定シンボルのいずれかに一致するメッセージのみを送信します。
{"type": "Subscribe", "channel": "order_updates", "symbols": ["BTC"]}
原資産のみの指定("BTC")と、完全な銘柄名("BTC-20260131-100000-C")のどちらも指定できます。シンボルを追加するには、もう一度 Subscribe を送信します。特定のシンボルを除外するには次のように送信します。
{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}
symbols を指定しない場合、ご自身のウォレットに関するすべての更新が配信されます。
公開チャネルの orderbook、trades、indicative_market_data、indicative_market_data_v2 も symbols を受け付けますが、照合対象は原資産ではなく、銘柄シンボルの完全一致(大文字・小文字を区別しない)です。
{"type": "Subscribe", "channel": "orderbook", "symbols": ["BTC-20260131-100000-C"]}
symbols を指定しない場合、これらのチャネルはすべての銘柄を配信します。
オプションチェーンのフィルタリング
options_chain チャネルは、銘柄シンボル、満期日、オプションの種類によるフィルタリングに対応しています。
{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
| フィルタ | 値 | デフォルト |
|---|---|---|
symbols | 完全な銘柄シンボルの配列(例: ["BTC-20260131-100000-C"]) | すべての銘柄 |
expiry | 日付文字列 "YYYY-MM-DD"。各銘柄の満期の UTC 暦日と照合されます | すべての満期 |
option_type | "call"、"put"、"both"。省略すると両方 | 両方 |
バッチ配信
indicative_market_data_v2 は indicative_market_data と同じ行を、1 フレームに複数行まとめて配信します。
{"type": "Subscribe", "channel": "indicative_market_data_v2", "symbols": ["BTC-20260131-100000-C"]}
サーバーはバッチマーカー付きで確認を返します。
{"type": "Subscribed", "channel": "indicative_market_data_v2", "batch": true}
その後、サーバーは各行を最大で 1 バッチウィンドウ(デフォルトは 25 ms)保持し、そのウィンドウ内に発行された行を 1 つの IndicativeMarketDataBatch フレームとして送信します。バッチが 256 行に達した場合は、ウィンドウの終了を待たずに送信されます。
- 対応状況の確認:
"batch": true付きの確認を受け取った場合にのみ、サーバーがバッチ配信を行っています。このチャネルより前にリリースされたサーバーは、任意のチャネル名に対してマーカーなしで確認を返し、その後何も送信しません。現行のサーバーは未知のチャネルに対してunknown_channelエラー を返します。いずれの場合も、同じ接続上でindicative_market_data_v2の購読を解除し、indicative_market_dataを購読してください。 - レイテンシ: 行は
indicative_market_dataよりも最大 1 ウィンドウ分遅れて届きます。デフォルトのウィンドウで本番トラフィックを計測したところ、待機時間は平均 12 ms、最大でも 25 ms でした。個々のクォート更新に数ミリ秒以内で反応する必要がある場合は、v1 チャネルを使用してください。 - 帯域幅: バッチ化のみでは約 7% のバイト削減にとどまります。大きな削減効果は
permessage-deflateと組み合わせた場合に得られます。圧縮したバッチは、非圧縮の 1 行フレームと比べて、フィルタなしの購読で約 9.8 分の 1、単一のオプションチェーンで約 8.3 分の 1 のサイズになります。行を 1 つずつ圧縮した場合は約 1.8 分の 1 です。 - 順序:
updates内の行は発行順に並び、バッチも順番どおりに届きます。行は統合されないため、同じ銘柄が 1 つのバッチに複数回現れることがあります。行を順に適用すれば、v1 チャネルと同じ状態になります。 - スナップショット: 購読時のスナップショットもバッチフレームで届きます。
- フィルタ:
symbolsはindicative_market_dataと同様に機能します。フィルタを絞り込む、または購読を解除すると、旧フィルタのもとで保留中だった行がまず送信され、その後にUnsubscribedの確認が届きます。そのため、行の欠落や重複は発生しません。 - 独立したチャネル: 1 つの接続で、異なるフィルタを指定して両方のチャネルを購読できます。
indicative_market_dataに変更はありません。
利用可能なチャネル
| チャネル | 認証 | 説明 |
|---|---|---|
orderbook | 不要 | 全シンボルの L2 オーダーブック更新 |
trades | 不要 | 公開の約定フィード |
market_updates | 不要 | 銘柄の上場状況の変更(作成/削除/満期) |
options_chain | 不要 | オプションチェーンの差分更新(シンボル、満期、option_type でフィルタ可能) |
index_prices | 不要 | 全原資産のリアルタイムのスポット/インデックス価格 |
indicative_market_data | 不要 | 許可リスト制のクォートプロバイダー向けストリーム。一般提供はまだ開始していません |
indicative_market_data_v2 | 不要 | 同じストリームをバッチフレームで配信。バッチ配信 を参照 |
order_updates | 必要 | ご自身の注文ステータスの変更(シンボルでフィルタ可能) |
fills | 必要 | ご自身の約定(シンボルでフィルタ可能) |
portfolio | 必要 | ご自身のポジションと残高の更新 |
liquidation | 必要 | ご自身の清算状態の変更 |
rfq | 必要 | RFQ のクォート、ステータス更新、約定通知 |
experimental_order_updates, experimental_combo_fills | 必要 | 実験的なコンボ用チャネル。実験的コンボ API を参照 |
experimental_combo_trades | 不要 | 実験的な公開コンボ約定 |
コンペティションやリーダーボードのデータは、WebSocket・REST のいずれでも api.hypercall.xyz からは提供されません。廃止済みの competition または competition_engagement チャネルを購読すると Error が返されます。トレーディングアプリは、https://api-ui.hypercall.xyz のアナリティクスサービスから HTTP 経由でコンペティション情報を取得します。例: GET /v2/competitions、GET /v2/competitions/{id}、GET /v2/competitions/leaderboard、GET /v2/competitions/all-time/leaderboard。
メッセージの種類
注文の発注(認証必須)
WebSocket のコマンド経路で注文を発注します。
{
"type": "PlaceOrder",
"wallet": "0x1234...",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"size": "1",
"price": "100",
"tif": "gtc",
"route": "book_only",
"client_id": "my-order-1",
"nonce": 1780000000000,
"signature": "0x..."
}
上記の nonce は説明用の値です。注文ごとに、現在の Unix 時間(ミリ秒)から新しい値を生成してください(例: JavaScript の Date.now())。固定値をコピーして使うと、受付可能な範囲を外れて拒否されます。
| フィールド | 型 | 説明 |
|---|---|---|
wallet | string | 注文を保有するウォレットアドレス |
symbol | string | オプションのシンボル |
side | string | "Buy" または "Sell" |
size | string | 契約サイズ。署名した値と完全に一致する必要があります |
price | string | 指値価格。署名した値と完全に一致する必要があります |
tif | string | 任意の執行条件(time-in-force)。デフォルトは "gtc" |
route | string | "book_only" を使用してください。route を省略した場合も引き続き受け付けられますが非推奨であり、廃止予定日はすでに過ぎています。 |
client_id | string | 任意のクライアント注文 ID |
reduce_only | boolean | 任意。デフォルトは false。reduce-only 注文は PlaceOrderReduceOnly に署名し、route を明示的に指定する必要があります |
mmp_enabled | boolean | 任意。デフォルトは false |
builder_code_address | string | 任意のビルダーコード用ウォレット |
nonce | integer | 必須の署名用ノンス。現在の Unix 時間(ミリ秒)を指定します。現在時刻の 2 日前から 1 日後までの範囲内である必要があります。各ノンスは署名者ごとに 1 回のみ受け付けられ、REST と WebSocket の注文は同じノンス空間を共有します。リプレイされたフレームは拒否されます。 |
signature | string | EIP-712 の PlaceOrder 署名 |
接続で事前に Authenticate を送信している必要があります。送信していない場合、サーバーは {"type": "Error", "message": "Not authenticated"} を返します。署名者は wallet 本人、またはそのウォレットに承認されたエージェントである必要があります。
WebSocket の PlaceOrder は現在、オーダーブックに直接ディスパッチされます。この経路ではまだ RPI/RFQ ルーティングを実行しないため、WebSocket では route="best_execution" と route="rfq_only" は拒否されます。best_execution を使う場合は POST /order を使用してください。
受け付けられた注文には、同じ接続上で OrderResult が返されます。
{
"type": "OrderResult",
"order_id": 12345,
"status": "ACKED",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "100",
"size": "1"
}
注文が受け付けられなかった場合は reason が追加されます。バリデーション、署名、レート制限によるエラーは、message が Order placement failed: で始まる Error として送信されます。その後のステータス変更は order_updates で届きます。
オーダーブック更新
シンボルごとの L2 オーダーブックのスナップショット/更新です。
{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"option_token_address": "0x...",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
| フィールド | 型 | 説明 |
|---|---|---|
symbol | string | オプションのシンボル |
option_token_address | string? | オンチェーンのオプショントークンアドレス(判明している場合) |
bids | array | [price, size] タプル形式のビッドの板。サイズは人が読める単位の契約数です |
asks | array | [price, size] タプル形式のアスクの板。サイズは人が読める単位の契約数です |
timestamp | integer | Unix タイムスタンプ(ミリ秒) |
約定(公開)
公開の約定イベントです。
{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "Buy",
"timestamp": 1737331200000
}
| フィールド | 型 | 説明 |
|---|---|---|
symbol | string | オプションのシンボル |
price | string | USD 建ての約定価格 |
size | string | 契約数単位の約定サイズ |
side | string | アグレッサー側(Buy または Sell) |
timestamp | integer | Unix タイムスタンプ(ミリ秒) |
約定通知(認証必須)
ご自身の約定に関する通知です。
{
"type": "Fill",
"order_id": 12345,
"fill_id": 67890,
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "0.0523",
"size": "5.0",
"timestamp": 1737331200000,
"wallet_address": "0x1234...abcd",
"fee": "0",
"trade_id": 99999,
"is_taker": true,
"builder_code_address": null,
"builder_code_fee": null,
"instrument_type": "option"
}
| フィールド | 型 | 説明 |
|---|---|---|
order_id | integer | ご自身の注文 ID |
fill_id | integer | 約定 ID |
symbol | string | オプションのシンボル |
side | string | 取引におけるご自身のサイド(Buy または Sell) |
price | string | USD 建ての約定価格 |
size | string | 契約数単位の約定サイズ |
timestamp | integer | Unix タイムスタンプ(ミリ秒) |
wallet_address | string | ご自身のウォレットアドレス |
fee | string | 課された取引手数料。ローンチ期間中の取引所手数料が無効な間は 0 を返します |
trade_id | integer | 一意の取引 ID |
is_taker | boolean | ご自身がテイカーだったかどうか |
builder_code_address | string? | ビルダーコード用ウォレット(ある場合) |
builder_code_fee | string? | ビルダーコード手数料。ローンチ期間中の取引所手数料が無効な間は null を返します |
instrument_type | string | "option" |
ポートフォリオ更新(認証必須)
portfolio チャネルで、ポジション、残高、証拠金、グリークスについて送信されます。購読時にサーバーは Initial スナップショットを送信し、その後は差分更新を送信します。
各フレームの type は更新の種類です。
| 更新の種類 | timestamp 以外のフィールド |
|---|---|
Initial | positions |
PositionUpdate | position |
BalanceUpdate | total_margin_used |
MarginUpdate | span_margin, margin_summary, margin_mode, total_margin_used, available_balance |
GreeksUpdate | per_leg, aggregate |
portfolio フレームの timestamp は、他のチャネルのミリ秒単位のタイムスタンプとは異なり、Unix 秒です。
グリークス更新の例:
{
"type": "GreeksUpdate",
"timestamp": 1737331200,
"per_leg": [
{
"symbol": "BTC-20260131-100000-C",
"quantity": "2.0",
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
],
"aggregate": {
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
}
ポートフォリオが空の場合、グリークス更新は次の値になります。
per_leg: []aggregate: null
注文更新(認証必須)
注文ステータスの変更通知です。PARTIALLY_FILLED の更新も含まれます。
filled_size は、直近の約定数量ではなく、その注文の全約定にわたる累計約定数量です。
{
"type": "OrderUpdate",
"order_id": 12345,
"client_id": "my-order-1",
"request": {
"price": "0.0523",
"size": "10.0",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"tif": "gtc"
},
"status": "PARTIALLY_FILLED",
"filled_size": "0.75",
"timestamp": 1767225600000,
"reason": null,
"wallet_address": "0x0000000000000000000000000000000000000001",
"instrument_type": "option"
}
status は ACKED、OPEN、PARTIALLY_FILLED、FILLED、CANCELED、REJECTED のいずれかです。注文に client_id がない場合は省略されます。instrument_type は "option" または "perp" です。
マーケット更新
銘柄の上場状況の変更です。
銘柄の作成:
{
"type": "MarketUpdate",
"action": "Created",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1737331200000
}
銘柄の満期:
{
"type": "MarketUpdate",
"action": "Expired",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1738281600000
}
action は Created、Expired、Deleted(symbol と timestamp のみを含む)、または ComboCreated(実験的コンボ API を参照)のいずれかです。
オプションチェーン更新
銘柄の上場状況、または最良気配が変化したときに options_chain で送信されます。action は Upsert または Remove です。
{
"type": "OptionsChainUpdate",
"action": "Upsert",
"currency": "BTC",
"expiry": 1769846400,
"row": {
"strike": 100000.0,
"call": {
"symbol": "BTC-20260131-100000-C",
"bid_price_usd": 1520.0,
"ask_price_usd": 1580.0
}
},
"timestamp": 1737331200000
}
Upsert の行には、オプションチェーンのスナップショットと同じレッグフィールドを持つレッグ(call または put)が 1 つ含まれます。フィールドは symbol、option_token_address、ビッドとアスクの価格、IV、契約数単位のサイズと USD 建て想定元本、greeks_abs、greeks_cash です(上記の例は一部を省略しています)。利用できない値は null になり、更新に含まれない側のレッグは省略されます。Remove は、銘柄が削除された場合、満期を迎えた場合、または決済待ちになった場合に送信され、currency、expiry、strike、option_type、symbol、timestamp を含みます。expiry は Unix 秒です。
ポジションの満期(認証必須)
ご自身のポジションが満期で決済されたときに portfolio チャネルで送信されます。
{
"type": "PositionExpired",
"wallet_address": "0x1234...abcd",
"symbol": "BTC-20260131-100000-C",
"position_size": "10.0",
"settlement_price": "105000",
"settlement_value": "500.0",
"settlement_entry_price": "100.0",
"cost_basis": "1000.0",
"net_pnl": "-500.0",
"timestamp": 1738281600000
}
settlement_entry_price、cost_basis、net_pnl は、利用できない場合 null になります。
清算状態の変更(認証必須)
アカウントの清算状態が変化したときに liquidation チャネルで送信されます。
{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "healthy",
"new_state": "pre_liquidation",
"liquidation_mode": "partial",
"margin_mode": "standard",
"equity": "10000.0",
"mm_required": "10500.0",
"maintenance_margin": "-500.0",
"shortfall": "500.0",
"partial_liquidation": { "...": "..." },
"full_liquidation": null,
"timestamp": 1737331200000
}
| フィールド | 説明 |
|---|---|
previous_state, new_state | healthy、pre_liquidation、in_liquidation、liquidated のいずれか |
liquidation_mode | partial、full、または清算フローが進行していない場合は null |
margin_mode | standard または portfolio |
equity | アカウントの純資産 |
mm_required | 維持証拠金要件 |
maintenance_margin | 純資産から維持証拠金要件を差し引いた額 |
shortfall | アカウントが維持証拠金を下回っている額 |
partial_liquidation | 部分清算の進捗(開始時刻、目標純資産、エスカレーション期限、有効な清算注文、ボーナス)、または null |
full_liquidation | 全額清算オークションの詳細(オークション ID、開始時刻、必要証拠金、完了時には落札者、ボーナス、解決トランザクション)、または null |
各状態の意味については 清算 を参照してください。
インデックス価格更新
全原資産のスポット/インデックス価格をまとめて配信します。
{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50", "timestamp": 1737331200000},
{"underlying": "ETH", "price": "3200.00", "timestamp": 1737331199980},
{"underlying": "NVDA", "price": "182.40", "timestamp": 1737331199950}
],
"timestamp": 1737331199950
}
| フィールド | 型 | 説明 |
|---|---|---|
prices | array | 追跡中の各原資産について {underlying, price, timestamp} を持つエントリの配列 |
prices[].underlying | string | 原資産のシンボル(例: "BTC"、"ETH") |
prices[].price | string | USD 建ての現在のスポット/インデックス価格 |
prices[].timestamp | integer | この原資産のソース観測時刻(Unix ミリ秒) |
timestamp | integer | prices に含まれるソース観測時刻のうち最も古いもの(Unix ミリ秒) |
インディカティブ・マーケットデータ
登録済みのクォートプロバイダーから集約した最良ビッド/アスクを配信する、許可リスト制のクォートプロバイダー向けストリームです。このチャネルの一般提供はまだ開始していません。Hypercall がお客様の連携向けにクォートプロバイダーのストリーミングを有効化していない場合は、REST のマーケットデータと、認証が必要な注文/約定/ポートフォリオのチャネルをご利用ください。
{
"type": "IndicativeMarketData",
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"indicative_bid_size": "50.0",
"indicative_ask_size": "25.0",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
}
| フィールド | 型 | 説明 |
|---|---|---|
instrument | string | オプションのシンボル |
best_bid | string | 任意。集約された最良ビッド価格 |
best_ask | string | 任意。集約された最良アスク価格 |
bid_iv | number | 任意。最良ビッドのインプライド・ボラティリティ |
ask_iv | number | 任意。最良アスクのインプライド・ボラティリティ |
indicative_bid_size | string | 任意。全プロバイダー合計のビッドサイズ |
indicative_ask_size | string | 任意。全プロバイダー合計のアスクサイズ |
num_providers | integer | アクティブなクォートプロバイダーの数 |
rfq_provider_quotes | array | 任意。プロバイダーごとのクォート: wallet、bid_price、ask_price、max_bid_size、max_ask_size、updated_at |
published_at | integer | この行が発行された API クロック上の時刻(Unix ミリ秒)。rfq_provider_quotes の経過時間は、ローカルの時計ではなくこの値を基準に計測してください |
timestamp | integer | 最新のプロバイダークォートの時刻(Unix ミリ秒) |
インディカティブ・マーケットデータ・バッチ
indicative_market_data_v2 チャネルで送信されます(バッチ配信 を参照)。updates の各要素は、type を除いて IndicativeMarketData メッセージと同じフィールドを持ちます。
{
"type": "IndicativeMarketDataBatch",
"flushed_at": 1737331200025,
"updates": [
{
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
},
{
"instrument": "BTC-20260131-105000-C",
"best_bid": "0.0310",
"best_ask": "0.0322",
"num_providers": 2,
"published_at": 1737331200004,
"timestamp": 1737331200001
}
]
}
| フィールド | 型 | 説明 |
|---|---|---|
flushed_at | integer | バッチが送信された API クロック上の時刻(Unix ミリ秒)。flushed_at - published_at が各行のバッチ化による遅延です |
updates | array | ウィンドウ内に発行された行(古い順) |
RFQ クォート(認証必須)
ご自身が送信した RFQ に対して受け取ったクォートです。
{
"type": "RfqQuotes",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"quotes": [
{
"quote_id": "660e8400-e29b-41d4-a716-446655440001",
"net_premium": "52.30",
"expires_at": 1737331225000
}
],
"status": "quoted",
"taker_wallet": "0x1234...abcd"
}
RFQ ステータス更新(認証必須)
ご自身が送信した RFQ のステータス変更です。
{
"type": "RfqStatusUpdate",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "executed",
"taker_wallet": "0x1234...abcd"
}
クロック同期
任意の nonce 文字列を付けて ClockSync を送信すると、同じ接続上で API クロックのサンプルを取得できます。たとえば、伝送遅延の上限を見積もる際に利用できます。
{"type": "ClockSync", "nonce": "abc"}
{"type": "ClockSynced", "nonce": "abc", "server_at": 1737331200000}
server_at は Unix ミリ秒です。認証は不要です。
エラー
サーバーのエラーメッセージです。code がある場合は、message ではなく code で判定してください。
{
"type": "Error",
"message": "Unknown channel 'foobar'",
"code": "unknown_channel",
"channel": "foobar"
}
| フィールド | 型 | 説明 |
|---|---|---|
message | string | 人が読める形式の説明 |
code | string | 任意。安定した理由コード。unknown_channel: Subscribe で存在しないチャネルが指定されました |
channel | string | 任意。拒否された Subscribe で指定されたチャネル |
利用可能なチャネル に記載されていないチャネルへの Subscribe には unknown_channel エラーが返され、購読は作成されません。以前のサーバーは任意の名前に対して確認を返し、その後何も送信していませんでした。
その他のエラーは message のみを含みます。例: Authenticate の前に認証が必要なチャネルを購読した場合の Authentication required for this channel、Authenticate の前に PlaceOrder を送信した場合の Not authenticated、および Invalid wallet address: ...。
認証
認証が必要なチャネルでは、接続後にウォレット識別メッセージを送信する必要があります。
{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}
認証が必要なチャネルのメッセージは、ご自身のウォレットに関するデータのみが表示されるようフィルタされます。WebSocket 接続に署名は不要です。
例: Python クライアント
import asyncio
import websockets
import json
async def main():
uri = "wss://api.hypercall.xyz/ws"
async with websockets.connect(uri) as ws:
# Identify the wallet before subscribing to authenticated channels.
await ws.send(json.dumps({
"type": "Authenticate",
"wallet": "0xYourWallet"
}))
# Subscribe to orderbook
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "orderbook"
}))
# Subscribe to fills for BTC only
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "fills",
"symbols": ["BTC"]
}))
# Listen for messages
async for message in ws:
data = json.loads(message)
print(f"Received: {data['type']}")
asyncio.run(main())
例: TypeScript クライアント
const ws = new WebSocket("wss://api.hypercall.xyz/ws");
ws.onopen = () => {
ws.send(JSON.stringify({ type: "Authenticate", wallet: "0xYourWallet" }));
// Subscribe to channels
ws.send(JSON.stringify({ type: "Subscribe", channel: "orderbook" }));
// Subscribe to order updates filtered to BTC
ws.send(JSON.stringify({
type: "Subscribe",
channel: "order_updates",
symbols: ["BTC"],
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(`Received: ${msg.type}`);
if (msg.type === "OrderbookUpdate") {
console.log(`${msg.symbol}: ${msg.bids.length} bids, ${msg.asks.length} asks`);
}
};
例: Rust クライアント
hypercall-client クレートの WsClient は、ウォレットの識別、再接続後の購読の復元、サーバーからの ping への応答を自動で行います。デフォルトで permessage-deflate 圧縮を提示し、サーバーが受け入れない場合は非圧縮フレームにフォールバックします。どちらの場合も JSON メッセージは同一です。提示を止めるには with_permessage_deflate(false) を呼び出してください。
use hypercall_client::WsClient;
#[tokio::main]
async fn main() -> hypercall_client::Result<()> {
let ws = WsClient::new();
ws.connect("https://api.hypercall.xyz", None).await?;
ws.subscribe(vec!["orderbook", "index_prices"]).await?;
if let Some(msg) = ws.wait_for_message(|_| true, 5_000).await {
println!("Received: {msg:?}");
}
Ok(())
}