訂閱
本頁描述如何使用 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 對象應與訂閱該數據源時發送的原始訂閱消息一致。這樣伺服器才能識別你要取消訂閱的特定數據源。通過發送此取消訂閱消息,你告知伺服器停止發送該數據源的後續更新。
請注意,取消訂閱某個特定數據源不會影響你當時已激活的其他訂閱。要取消訂閱多個數據源,你可以發送多條取消訂閱消息,每條消息包含相應的訂閱詳情。