本页由机器翻译。英文原文为权威版本。 阅读英文版
跳转到主要内容

WebSocket API

Hypercall 期权交易的实时数据流。

交互式参考

请查看 交互式 WebSocket API 参考文档,获得更好的浏览体验,包含实时示例和 schema 详情。

机器可读规范

下载 AsyncAPI 规范 以供程序化使用。

连接

连接至 wss://HOST/ws

端点:

  • 生产环境:wss://api.hypercall.xyz/ws
  • 本地:ws://localhost:3000/ws
测试网状态

测试网已临时禁用,直到 Hypercall 获取更多测试网 HYPE。

钱包身份识别

若要在需要身份验证的频道(订单、成交、投资组合)上接收数据,请在连接后通过发送 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 库,包括 tungstenitetokio-tungstenite,也会为您处理控制帧的 ping/pong。在添加手动 Pong 处理之前,请查阅您所用客户端库的文档。自定义或原始套接字实现必须以 Pong 回复 Ping 帧。

慢消费者恢复

如果某个 /ws 连接无法在配置的消息、编码字节、队列存活时长或套接字写入安全上限内排空待发送数据,服务器将关闭该连接。当连接仍能接受关闭帧时,服务器会使用关闭码 1008 和一段紧凑的 JSON 原因:

{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}

原因字段如下:

字段含义
class帧越过安全边界的投递类别。
causemessage_limitbyte_limitmessage_agewrite_timeout
recovery所需的后续操作,例如 resubscribesnapshot_resubscribeportfolio_refetchrest_reconcile

在任何断开连接之后,请重新连接,在需要时再次识别钱包,重新订阅,并在处理新事件之前对当前状态进行核对。有序的公共频道需要重新获取快照。私有事件频道需要通过权威的 REST 接口进行核对,因为游标回放功能尚不可用。完全停滞的连接可能在读取关闭原因之前就已终止,因此客户端对于非正常关闭也必须使用此恢复流程。

请为高速率的公共市场数据与需要身份验证的命令或私有流使用各自独立的连接。投递类别决定指标与恢复行为,但同一连接上的各帧仍共享一条有序的套接字写入路径。因此,停滞的公共写入可能会延迟该连接上后续的私有帧,直到写入截止时间将其关闭。

订阅频道

发送一条 JSON 消息以进行订阅:

{"type": "Subscribe", "channel": "orderbook"}

取消订阅:

{"type": "Unsubscribe", "channel": "orderbook"}

您将收到一条确认消息:

{"type": "Subscribed", "channel": "orderbook"}

标的过滤

order_updatesfills 频道支持一个可选的 symbols 过滤器。提供后,服务器仅发送其标的资产匹配指定标的之一的消息。

{"type": "Subscribe", "channel": "order_updates", "symbols": ["BTC"]}

既接受裸标的("BTC"),也接受完整合约名称("BTC-20260131-100000-C")。若要添加更多标的,请再发送一条 Subscribe。若要移除特定标的:

{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}

未指定 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"所有到期日
option_type"call""put",或省略以表示两者两者

可用频道

频道需要身份验证描述
orderbook所有标的的 L2 订单簿更新
trades公共成交流
market_updates市场挂牌变动(创建/删除/到期)
options_chain增量期权链更新(可按标的、到期日、期权类型过滤)
index_prices所有标的资产的实时现货/指数价格
indicative_market_data白名单报价方数据流。尚未普遍可用
order_updates您的订单状态变动(可按标的过滤)
fills您的成交(可按标的过滤)
portfolio您的持仓与余额更新
liquidation您的强制平仓状态变动
competition您的竞赛盈亏汇总、排名和最终统计数据
competition_engagement排名变动、与下一名的差距,以及最终排名
rfqRFQ 报价、状态更新和成交通知

消息类型

下单(需身份验证)

通过 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": 1000,
"signature": "0x..."
}
字段类型描述
walletstring拥有该订单的钱包地址
symbolstring期权标的
sidestring"Buy""Sell"
sizestring合约规模,须与签名值完全一致
pricestring限价,须与签名值完全一致
tifstring可选的有效期,默认为 "gtc"
routestring可选的路由。对于路由感知的 WebSocket 订单,请使用 "book_only"。省略路由在至少 2026 年 7 月 4 日之前仍受接受。
client_idstring可选的客户端订单 ID
nonceinteger唯一的签名 nonce
signaturestringEIP-712 PlaceOrder 签名

WebSocket PlaceOrder 目前直接分发至订单簿。route="best_execution"route="rfq_only" 在 WebSocket 上会被拒绝,因为此路径尚未运行 RPI/RFQ 路由。对于 best_execution,请使用 POST /order

订单簿更新

某个标的的 L2 订单簿快照/更新。

{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
字段类型描述
symbolstring期权标的
bidsarray买价档位,格式为 [price, size] 元组,size 以人类可读的合约数计
asksarray卖价档位,格式为 [price, size] 元组,size 以人类可读的合约数计
timestampintegerUnix 时间戳(毫秒)

成交

公共成交事件。

{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "buy",
"timestamp": 1737331200000
}
字段类型描述
symbolstring期权标的
pricestring以美元计的成交价
sizestring以合约数计的成交规模
sidestring主动方(buysell
timestampintegerUnix 时间戳(毫秒)

成交(需身份验证)

您的成交通知。

{
"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
}
字段类型说明
order_idinteger您的订单 ID
fill_idinteger成交 ID
symbolstring期权代码
sidestring交易方向(buysell
pricestring成交价格(美元)
sizestring成交数量(合约张数)
timestampintegerUnix 时间戳(毫秒)
wallet_addressstring您的钱包地址
feestring收取的交易费用。在启动场所费用停用期间返回 0
trade_idinteger唯一交易 ID
is_takerboolean您是否为吃单方
builder_code_addressstring?构建者代码钱包(如有)
builder_code_feestring?构建者代码费用。在启动场所费用停用期间返回 null

投资组合更新(需认证)

针对持仓、余额、保证金及希腊字母指标的投资组合流更新。

希腊字母指标更新示例:

{
"type": "PortfolioUpdate",
"timestamp": 1737331200000,
"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

竞赛盈亏摘要(需认证)

用于页眉/页脚盈亏显示的竞赛流更新。

{
"type": "CompetitionPnlSummary",
"wallet_address": "0x1234...abcd",
"lifetime_realized_pnl": "1250.50",
"active_competition": {
"competition_id": 7,
"competition_name": "Spring Sprint",
"competition_state": "active",
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null
},
"timestamp": 1737331200000
}

当没有正在进行的竞赛时,active_competitionnull

订单更新(需认证)

订单状态变更通知。

{
"type": "OrderUpdate",
"order_id": 12345,
"client_order_id": "my-order-1",
"status": "filled",
"filled_size": "10.0",
"remaining_size": "0",
"avg_fill_price": "0.0523"
}

市场更新

市场挂牌变更。

市场已创建:

{
"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
}

持仓到期(需认证)

当您的持仓在到期时结算时的通知。

{
"type": "PositionExpired",
"wallet_address": "0x1234...abcd",
"symbol": "BTC-20260131-100000-C",
"position_size": "10.0",
"settlement_price": "105000",
"settlement_value": "500.0",
"timestamp": 1738281600000
}

强制平仓状态变更(需认证)

您账户的强制平仓状态变更。

{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "Normal",
"new_state": "Warning",
"equity": "10000.0",
"mm_required": "9500.0",
"shortfall": "0",
"auction_id": null,
"timestamp": 1737331200000
}
状态说明
Normal账户状况健康
Warning接近追加保证金通知
Liquidating强制平仓拍卖进行中

指数价格更新

所有标的资产的批量现货/指数价格。

{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50"},
{"underlying": "ETH", "price": "3200.00"},
{"underlying": "HYPE", "price": "28.50"}
],
"timestamp": 1737331200000
}
字段类型说明
pricesarray每个跟踪标的资产的 {underlying, price} 条目数组
prices[].underlyingstring标的资产代码(例如 "BTC""ETH"
prices[].pricestring当前现货/指数价格(美元)
timestampintegerUnix 时间戳(毫秒)

指示性市场数据

来自已注册报价提供方的白名单报价提供方流,包含聚合的最优买价/卖价。此频道尚未普遍开放。除非 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,
"timestamp": 1737331200000
}
字段类型说明
instrumentstring期权代码
best_bidstring可选的最优聚合买价
best_askstring可选的最优聚合卖价
bid_ivnumber可选的最优买价隐含波动率
ask_ivnumber可选的最优卖价隐含波动率
indicative_bid_sizestring可选的各提供方买单总量
indicative_ask_sizestring可选的各提供方卖单总量
num_providersinteger活跃报价提供方数量
timestampintegerUnix 时间戳(毫秒)

竞赛排名变更(需认证)

当您在正在进行的竞赛中的排名发生变化时的通知。

{
"type": "CompetitionRankChange",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"from_rank": 15,
"to_rank": 12,
"delta_places": 3,
"pnl": "420.25",
"timestamp": 1737331200000
}

竞赛差距更新(需认证)

与您上方下一名次之间的距离。

{
"type": "CompetitionGapUpdate",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"next_rank": 11,
"gap_metric_value": "50.00",
"timestamp": 1737331200000
}

竞赛最终排名(需认证)

在竞赛结束时发送,包含您的最终成绩。

{
"type": "CompetitionFinalStanding",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null,
"timestamp": 1737331200000
}

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"
}

错误

服务器错误消息。

{
"type": "Error",
"message": "Invalid channel: foobar"
}

认证

认证频道在连接后需要发送一条钱包身份识别消息:

{"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`);
}
};