订阅
本页描述如何使用 WebSocket API 订阅数据流。
订阅消息
要订阅特定的数据源,你需要发送一条订阅消息。订阅消息的格式如下:
{
"method": "subscribe",
"subscription": { ... }
}
订阅确认(ack)会为时间序列数据(例如用户成交)提供先前数据的快照。这些快照消息带有 isSnapshot: true 标记,如果之前的消息已被处理,则可以忽略。
订阅对象包含你要订阅的特定数据源的详细信息。从以下订阅类型中选择并提供相应的属性:
allMids: * 订阅消息:{ "type": "allMids", "dex": "<dex>" }* 数据格式:AllMids*dex字段表示从中获取中间价(mid)的永续合约 dex。 * 注意dex字段是可选的。如果未提供,则使用第一个永续合约 dex。现货中间价仅包含在第一个永续合约 dex 中。notification: * 订阅消息:{ "type": "notification", "user": "<address>" }* 数据格式:NotificationwebData3: * 订阅消息:{ "type": "webData3", "user": "<address>" }* 数据格式:WebData3twapStates: * 订阅消息:{ "type": "twapStates", "user": "<address>", "dex": "<dex>" }* 数据格式:TwapStatesclearinghouseState:* 订阅消息:{ "type": "clearinghouseState", "user": "<address>", "dex": "<dex>" }* 数据格式:ClearinghouseStateopenOrders: * 订阅消息:{ "type": "openOrders", "user": "<address>", "dex": "<dex>" }* 数据格式:OpenOrderscandle: * 订阅消息:{ "type": "candle", "coin": "<coin_symbol>", "interval": "<candle_interval>" }* 支持的 K 线周期:"1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "8h", "12h", "1d", "3d", "1w", "1M" * 数据格式:Candle[]l2Book: * 订阅消息:{ "type": "l2Book", "coin": "<coin_symbol>" }* 可选参数:nSigFigs: int、mantissa: int、fast: boolean(fast 为 5 档,slow 为 20 档) * 数据格式:WsBooktrades: * 订阅消息:{ "type": "trades", "coin": "<coin_symbol>" }* 数据格式:WsTrade[]orderUpdates:- 订阅消息:
{ "type": "orderUpdates", "user": "<address>" } - 数据格式:
WsOrder[]
- 订阅消息:
userEvents:- 订阅消息:
{ "type": "userEvents", "user": "<address>" } - 数据格式:
WsUserEvent - 注意:
userEvents消息的通道名为"channel": "user"
- 订阅消息:
userFills:- 订阅消息:
{ "type": "userFills", "user": "<address>" } - 可选参数:
aggregateByTime: bool - 数据格式:
WsUserFills
- 订阅消息:
userFundings:- 订阅消息:
{ "type": "userFundings", "user": "<address>" } - 数据格式:
WsUserFundings
- 订阅消息:
userNonFundingLedgerUpdates:- 订阅消息:
{ "type": "userNonFundingLedgerUpdates", "user": "<address>" } - 数据格式:
WsUserNonFundingLedgerUpdates
- 订阅消息:
activeAssetCtx:- 订阅消息:
{ "type": "activeAssetCtx", "coin": "<coin_symbol>" } - 数据格式:
WsActiveAssetCtx或WsActiveSpotAssetCtx
- 订阅消息:
activeAssetData:(仅支持永续合约)- 订阅消息:
{ "type": "activeAssetData", "user": "<address>", "coin": "<coin_symbol>" } - 数据格式:
WsActiveAssetData
- 订阅消息:
userTwapSliceFills:- 订阅消息:
{ "type": "userTwapSliceFills", "user": "<address>" } - 数据格式:
WsUserTwapSliceFills
- 订阅消息:
userTwapHistory:- 订阅消息:
{ "type": "userTwapHistory", "user": "<address>" } - 数据格式:
WsUserTwapHistory
- 订阅消息:
bbo:- 订阅消息:
{ "type": "bbo", "coin": "<coin>" } - 数据格式:
WsBbo
- 订阅消息:
spotState- 订阅消息:
{ "type": "spotState", "user": "<address>", "isPortfolioMargin": bool } - 数据格式:
WsSpotState isPortfolioMargin是可选参数
- 订阅消息:
allDexsClearinghouseState- 订阅消息:
{ "type": "allDexsClearinghouseState", "user": "<address>" } - 数据格式:
WsAllDexsClearinghouseState
- 订阅消息:
allDexsAssetCtxs- 订阅消息:
{ "type": "allDexsAssetCtxs" } - 数据格式:
WsAllDexsAssetCtxs
- 订阅消息:
outcomeMetaUpdates- 订阅消息:
{ "type": "outcomeMetaUpdates" } - 数据格式:
WsOutcomeMetaUpdates
- 订阅消息:
fastAssetCtxs- { "method": "subscribe", "subscription": { "type": "fastAssetCtxs" } }
- 数据格式:base64 编码且压缩过的
WsFastAssetCtxs - 读取数据请按顺序执行:\
1. base64 解码为字节\
2. 解压缩:原始 DEFLATE 流(RFC 1951)——没有 zlib(RFC 1950)或 gzip(RFC 1952)包装。Python 用
zlib.decompress(b, wbits=-15),浏览器用new DecompressionStream("deflate-raw"),Node 用\fflate.inflateSync\ 3. UTF-8 解码并解析为 JSON\ 4. 用于测试你的实现的示例\ payload:"q1ZyCnFWsqpWyk0syg6oULJSsjQ3NTDQM1Wq1VFyDfFAkTI2MzXQMwJLVVRWWfmFuTiiyBuamOoZKdXWAgA="\ 解码后:{ "BTC": { "markPx": "97500.5" }, "ETH": { "markPx": "3650.25" }, "xyz:NVDA": { "markPx": "145.2" }} - 第一条消息是快照,后续消息仅包含已更新的币种。没有更新的字段会被省略。
用户地址
要订阅与主账户或子账户关联的账户数据,你必须传入该账户的实际地址。一个常见的错误是使用代理钱包(agent wallet)的地址,这会导致返回空结果。
数据格式
服务器会以包含 channel 属性为 "subscriptionResponse" 的消息响应成功的订阅,其中 data 字段提供原始订阅内容。随后服务器将开始发送 channel 属性为相应订阅类型(例如 "allMids")的消息,data 字段提供所订阅的数据。
data 字段的格式取决于订阅类型:
AllMids:所有中间价。- 格式:
AllMids { mids: Record<string, string> } Notification:通知消息。- 格式:
Notification { notification: string } WebData3:用户的汇总信息,主要用于前端。- 格式:
WebData3 WsTrade[]:成交更新数组。- 格式:
WsTrade[] WsBook:订单簿快照更新。- 格式:
WsBook { coin: string; levels: [Array<WsLevel>, Array<WsLevel>]; time: number; } WsOrder:用户订单更新。- 格式:
WsOrder[] WsUserEvent:非订单更新的用户事件- 格式:
WsUserEvent { "fills": [WsFill] | "funding": WsUserFunding | "liquidation": WsLiquidation | "nonUserCancel": [WsNonUserCancel] } WsUserFills:成交快照,随后是流式成交WsUserFundings:资金费用快照,随后是整点时的资金费用WsUserNonFundingLedgerUpdates:不包含资金费用的账本更新:提币、充值、划转和清算WsBbo:仅在某个区块上 bbo 发生变化时发送的 bbo 更新WsSpotState:现货状态更新。WsAllDexsClearinghouseState:特定用户在所有 dex 上的清算所状态WsAllDexsAssetCtxs:所有 dex 上的资产上下文WsOutcomeMetaUpdates:outcome 元数据的变更
对于 WsUserFills、WsUserFundings 等流式用户端点,第一条消息带有 isSnapshot: true,后续的流式更新带有 isSnapshot: false。
数据类型定义
以下是 WebSocket API 中使用的数据类型定义:
interface WsTrade {
coin: string;
side: string;
px: string;
sz: string;
hash: string;
time: number;
// tid is 50-bit hash of (buyer_oid, seller_oid).
// For a globally unique trade id, use (block_time, coin, tid)
tid: number;
users: [string, string] // [buyer, seller]
}
// Snapshot feed, pushed on each block that is at least 0.5 since last push
interface WsBook {
coin: string;
levels: [Array<WsLevel>, Array<WsLevel>];
time: number;
}
interface WsBbo {
coin: string;
time: number;
bbo: [WsLevel | null, WsLevel | null];
}
interface WsLevel {
px: string; // price
sz: string; // size
n: number; // number of orders
}
interface Notification {
notification: string;
}
interface AllMids {
mids: Record<string, string>;
}
interface Candle {
t: number; // open millis
T: number; // close millis
s: string; // coin
i: string; // interval
o: number; // open price
c: number; // close price
h: number; // high price
l: number; // low price
v: number; // volume (base unit)
n: number; // number of trades
}
type WsUserEvent = {"fills": WsFill[]} | {"funding": WsUserFunding} | {"liquidation": WsLiquidation} | {"nonUserCancel" :WsNonUserCancel[]};
interface WsUserFills {
isSnapshot?: boolean;
user: string;
fills: Array<WsFill>;
}
interface WsFill {
coin: string;
px: string; // price
sz: string; // size
side: string;
time: number;
startPosition: string;
dir: string; // used for frontend display
closedPnl: string;
hash: string; // L1 transaction hash
oid: number; // order id
crossed: boolean; // whether order crossed the spread (was taker)
fee: string; // negative means rebate
tid: number; // unique trade id
liquidation?: FillLiquidation;
feeToken: string; // the token the fee was paid in
builderFee?: string; // amount paid to builder, also included in fee
}
interface FillLiquidation {
liquidatedUser?: string;
markPx: number;
method: "market" | "backstop";
}
interface WsUserFunding {
time: number;
coin: string;
usdc: string;
szi: string;
fundingRate: string;
}
interface WsLiquidation {
lid: number;
liquidator: string;
liquidated_user: string;
liquidated_ntl_pos: string;
liquidated_account_value: string;
}
interface WsNonUserCancel {
coin: String;
oid: number;
}
interface WsOrder {
order: WsBasicOrder;
status: string; // See https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-order-status-by-oid-or-cloid for a list of possible values
statusTimestamp: number;
}
interface WsBasicOrder {
coin: string;
side: string;
limitPx: string;
sz: string;
oid: number;
timestamp: number;
origSz: string;
cloid: string | undefined;
}
interface WsActiveAssetCtx {
coin: string;
ctx: PerpsAssetCtx;
}
interface WsActiveSpotAssetCtx {
coin: string;
ctx: SpotAssetCtx;
}
type SharedAssetCtx = {
dayNtlVlm: number;
prevDayPx: number;
markPx: number;
midPx?: number;
};
type PerpsAssetCtx = SharedAssetCtx & {
funding: number;
openInterest: number;
oraclePx: number;
};
type SpotAssetCtx = SharedAssetCtx & {
circulatingSupply: number;
};
interface WsActiveAssetData {
user: string;
coin: string;
leverage: Leverage;
maxTradeSzs: [number, number];
availableToTrade: [number, number];
}
interface WsTwapSliceFill {
fill: WsFill;
twapId: number;
}
interface WsUserTwapSliceFills {
isSnapshot?: boolean;
user: string;
twapSliceFills: Array<WsTwapSliceFill>;
}
interface TwapState {
coin: string;
user: string;
side: string;
sz: number;
executedSz: number;
executedNtl: number;
minutes: number;
reduceOnly: boolean;
randomize: boolean;
timestamp: number;
}
type TwapStatus = "activated" | "terminated" | "finished" | "error";
interface WsTwapHistory {
state: TwapState;
status: {
status: TwapStatus;
description: string;
};
time: number;
}
interface WsUserTwapHistory {
isSnapshot?: boolean;
user: string;
history: Array<WsTwapHistory>;
}
// Additional undocumented fields in WebData3 will be removed on a future update
interface WebData3 {
userState: {
agentAddress: string | null;
agentValidUntil: number | null;
serverTime: number;
cumLedger: number;
isVault: boolean;
user: string;
optOutOfSpotDusting?: boolean;
dexAbstractionEnabled?: boolean;
};
perpDexStates: Array<PerpDexState>;
}
interface PerpDexState {
totalVaultEquity: number;
perpsAtOpenInterestCap?: Array<string>;
leadingVaults?: Array<LeadingVault>;
}
interface LeadingVault {
address: string;
name: string;
}
interface ClearinghouseState {
dex: string;
user: string;
clearinghouseState: InnerClearinghouseState;
}
interface InnerClearinghouseState {
assetPositions: Array<AssetPosition>;
marginSummary: MarginSummary;
crossMarginSummary: MarginSummary;
crossMaintenanceMarginUsed: number;
withdrawable: number;
}
interface MarginSummary {
accountValue: number;
totalNtlPos: number;
totalRawUsd: number;
totalMarginUsed: number;
}
interface AssetPosition { type: "oneWay"; position: Position }
interface OpenOrders {
dex: string;
user: string;
orders: Array<Order>;
}
interface TwapStates {
dex: string;
user: string;
states: Array<[number, TwapState]>;
}
interface WsSpotState {
user: string;
spotState: SpotState;
}
interface SpotState {
balances: Array<UserBalance>;
}
interface UserBalance {
coin: string;
token?: number;
hold: string;
total: string;
entryNtl: string;
}
interface WsAllDexsClearinghouseState {
user: string;
clearinghouseStates: Array<[string, InnerClearinghouseState]>;
}
interface WsAllDexsAssetCtxs {
ctxs: Array<[string, Array<PerpsAssetCtx>]>;
}
type WsOutcomeMetaUpdates = [WsOutcomeMetaUpdate];
type WsOutcomeMetaUpdate =
| { outcomeCreated: OutcomeSpec }
| { outcomeSettled: number }
| { questionUpdated: QuestionSpec }
| { questionSettled: number };
type OutcomeSpec = {
outcome: number;
name: string;
description: string;
sideSpecs: [OutcomeSideSpec, OutcomeSideSpec];
};
type OutcomeSideSpec = {
name: string;
};
type QuestionSpec = {
question: number;
name: string;
description: string;
fallbackOutcome: number;
namedOutcomes: number[];
settledNamedOutcomes: number[];
};
type FFastAssetCtx = {
markPx?: number;
midPx?: number | null;
};
type WsFastAssetCtxs = Record<string, FFastAssetCtx>;
WsUserNonFundingLedgerUpdates
interface WsUserNonFundingLedgerUpdate {
time: number;
hash: string;
delta: WsLedgerUpdate;
}
type WsLedgerUpdate =
| WsDeposit
| WsWithdraw
| WsInternalTransfer
| WsSubAccountTransfer
| WsLedgerLiquidation
| WsVaultDelta
| WsVaultWithdrawal
| WsVaultLeaderCommission
| WsSpotTransfer
| WsAccountClassTransfer
| WsSpotGenesis
| WsRewardsClaim;
interface WsDeposit {
type: "deposit";
usdc: number;
}
interface WsWithdraw {
type: "withdraw";
usdc: number;
nonce: number;
fee: number;
}
interface WsInternalTransfer {
type: "internalTransfer";
usdc: number;
user: string;
destination: string;
fee: number;
}
interface WsSubAccountTransfer {
type: "subAccountTransfer";
usdc: number;
user: string;
destination: string;
}
interface WsLedgerLiquidation {
type: "liquidation";
// NOTE: for isolated positions this is the isolated account value
accountValue: number;
leverageType: "Cross" | "Isolated";
liquidatedPositions: Array<LiquidatedPosition>;
}
interface LiquidatedPosition {
coin: string;
szi: number;
}
interface WsVaultDelta {
type: "vaultCreate" | "vaultDeposit" | "vaultDistribution";
vault: string;
usdc: number;
}
interface WsVaultWithdrawal {
type: "vaultWithdraw";
vault: string;
user: string;
requestedUsd: number;
commission: number;
closingCost: number;
basis: number;
netWithdrawnUsd: number;
}
interface WsVaultLeaderCommission {
type: "vaultLeaderCommission";
user: string;
usdc: number;
}
interface WsSpotTransfer = {
type: "spotTransfer";
token: string;
amount: number;
usdcValue: number;
user: string;
destination: string;
fee: number;
}
interface WsAccountClassTransfer = {
type: "accountClassTransfer";
usdc: number;
toPerp: boolean;
}
interface WsSpotGenesis = {
type: "spotGenesis";
token: string;
amount: number;
}
interface WsRewardsClaim = {
type: "rewardsClaim";
amount: number;
}
请注意,上述数据类型为 TypeScript 格式,其用法与各自的订阅类型相对应。
示例
以下是用订阅消息订阅不同数据源的几个示例:
- 订阅所有中间价:
json
{ "method": "subscribe", "subscription": { "type": "allMids" } }
2. 订阅特定用户的通知:
json
{ "method": "subscribe", "subscription": { "type": "notification", "user": "<address>" } }
3. 订阅特定用户的 web 数据:
json
{ "method": "subscribe", "subscription": { "type": "webData3", "user": "<address>" } }
4. 订阅特定币种和周期的 K 线更新:
json
{ "method": "subscribe", "subscription": { "type": "candle", "coin": "<coin_symbol>", "interval": "<candle_interval>" } }
5. 订阅特定币种的订单簿更新:
json
{ "method": "subscribe", "subscription": { "type": "l2Book", "coin": "<coin_symbol>" } }
6. 订阅特定币种的成交:
json
{ "method": "subscribe", "subscription": { "type": "trades", "coin": "<coin_symbol>" } }
取消订阅 WebSocket 数据流
要取消订阅 Hyperliquid WebSocket API 上的特定数据源,你需要发送如下格式的取消订阅消息:
{
"method": "unsubscribe",
"subscription": { ... }
}
subscription 对象应与订阅该数据源时发送的原始订阅消息一致。这样服务器才能识别你要取消订阅的特定数据源。通过发送此取消订阅消息,你告知服务器停止发送该数据源的后续更新。
请注意,取消订阅某个特定数据源不会影响你当时已激活的其他订阅。要取消订阅多个数据源,你可以发送多条取消订阅消息,每条消息包含相应的订阅详情。