WebSocket API
Hypercall 期权交易的实时数据流。
请查看交互式 WebSocket API 参考,获得更好的浏览体验,包含实时示例和 Schema 详情。
下载 AsyncAPI 规范以供程序化使用。
WebSocket 消息对象可能会在不预先通知的情况下新增字段。客户端必须忽略无法识别的字段。Hypercall 不会从现有消息 Schema 中删除字段。
连接
连接到 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 尚未实现该扩展,因此会以未压缩方式连接。如需在自有 socket 上使用压缩,请使用实现了该扩展的客户端,例如 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。许多 Rust WebSocket 库,包括 tungstenite 和 tokio-tungstenite,也会为您处理控制帧 ping/pong。在添加手动 Pong 处理之前,请先查阅您客户端库的文档。自定义或原始 socket 实现必须以 Pong 帧回应 Ping 帧。
慢消费者恢复
如果 /ws 连接无法在配置的消息数、编码字节数、队列时长或 socket 写入安全上限内排空出站数据,服务器会关闭该连接。当连接仍能接收关闭帧时,服务器使用关闭码 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 接口进行对账,因为游标回放尚不可用。完全停滞的连接可能在读取关闭原因之前就已终止,因此客户端在非正常关闭时也必须使用此恢复流程。
请为高频公共行情数据与需认证的命令或私有流使用不同的连接。投递类别决定指标和恢复行为,但同一连接上的帧仍共享同一个有序的 socket 写入路径。因此,停滞的公共写入可能会延迟同一连接上后续的私有帧,直到写入截止时间触发关闭。
订阅频道
发送 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 相同的数据行,但每帧包含多行:
{"type": "Subscribe", "channel": "indicative_market_data_v2", "symbols": ["BTC-20260131-100000-C"]}
服务器以批量标记进行确认:
{"type": "Subscribed", "channel": "indicative_market_data_v2", "batch": true}
随后,服务器将每行最多保留一个批次窗口(默认 25 ms),并将该窗口内发布的数据行作为一个 IndicativeMarketDataBatch 帧发送。批次达到 256 行时也会提前发送。
- 检测支持: 只有带
"batch": true的确认才表示服务器进行批量推送。在该频道发布之前的服务器会对任何频道名称返回不带该标记的确认,随后不发送任何数据;当前服务器对未知频道会返回unknown_channel错误。无论哪种情况,请在同一连接上取消订阅indicative_market_data_v2并订阅indicative_market_data。 - 延迟: 与
indicative_market_data相比,每行最多晚一个窗口到达。在默认窗口下的生产流量中,数据行平均等待 12 ms,从未超过 25 ms。如果您需要在毫秒级内对单条报价更新做出反应,请使用 v1 频道。 - 带宽: 仅批量处理本身可节省约 7% 的字节。主要节省来自
permessage-deflate:对于无过滤订阅,压缩后的批次比未压缩的单行帧小约 9.8 倍;对于单个期权链则小约 8.3 倍;而逐行压缩仅小约 1.8 倍。 - 顺序:
updates中的行按发布顺序排列,批次也按顺序到达。数据行不会合并,因此同一合约可能在一个批次中出现多次。按顺序应用这些行,您将得到与 v1 频道相同的状态。 - 快照: 订阅时的快照同样以批量帧形式到达。
- 过滤器:
symbols的工作方式与indicative_market_data相同。缩小过滤范围或取消订阅时,会先发送旧过滤器下已待发送的数据行,然后发送Unsubscribed确认,因此不会丢失或重复任何数据行。 - 独立频道: 一个连接可以以不同的过滤器同时订阅两个频道。
indicative_market_data保持不变。
可用频道
| 频道 | 需要认证 | 描述 |
|---|---|---|
orderbook | 否 | 所有品种的 L2 订单簿更新 |
trades | 否 | 公共成交流 |
market_updates | 否 | 市场上市变动(创建/删除/到期) |
options_chain | 否 | 增量期权链更新(可按 symbols、expiry、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 | 否 | 实验性公共组合成交 |
api.hypercall.xyz 不通过 WebSocket 或 REST 提供竞赛和排行榜数据。订阅已停用的 competition 或 competition_engagement 频道会返回 Error。交易应用通过 HTTP 从位于 https://api-ui.hypercall.xyz 的分析服务读取竞赛数据,例如 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 | 可选的有效期类型,默认为 "gtc" |
route | string | 请使用 "book_only"。省略 route 目前仍被接受但已弃用,且其停用日期已过。 |
client_id | string | 可选的客户端订单 ID |
reduce_only | boolean | 可选,默认 false。只减仓订单签名 PlaceOrderReduceOnly,且需要显式指定 route |
mmp_enabled | boolean | 可选,默认 false |
builder_code_address | string | 可选的 builder code 钱包 |
nonce | integer | 必需的签名 nonce:当前 Unix 毫秒时间。它必须位于当前时间前两天至后一天的范围内。每个 nonce 对每个签名者只接受一次,REST 和 WebSocket 订单共享同一 nonce 空间。重放的帧会被拒绝。 |
signature | string | EIP-712 PlaceOrder 签名 |
连接必须先发送 Authenticate;否则服务器会返回 {"type": "Error", "message": "Not authenticated"}。签名者必须是 wallet 本身或其已批准的代理。
WebSocket PlaceOrder 目前直接分派到订单簿。route="best_execution" 和 route="rfq_only" 在 WebSocket 上会被拒绝,因为该路径尚未运行 RPI/RFQ 路由。如需 best_execution,请使用 POST /order。
被接受的订单会在同一连接上以 OrderResult 应答:
{
"type": "OrderResult",
"order_id": 12345,
"status": "ACKED",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "100",
"size": "1"
}
订单未被接受时会附加 reason。校验、签名和限流失败会以 Error 发送,其 message 以 Order placement failed: 开头。后续状态变化会通过 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 钱包(如有) |
builder_code_fee | string? | Builder code 费用。上线期间交易所手续费停用时返回 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),包含期权链快照中的腿字段: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 中的每个元素与 IndicativeMarketData 消息字段相同,但不含 type。
{
"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 时请依据 code 而非 message 进行匹配。
{
"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 crate 的 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(())
}