本页面为社区翻译版本,仅供参考;内容以英文原版为准。
查看英文原版 ↗

订阅

本页描述如何使用 WebSocket API 订阅数据流。

订阅消息

要订阅特定的数据源,你需要发送一条订阅消息。订阅消息的格式如下:

{
  "method": "subscribe",
  "subscription": { ... }
}

订阅确认(ack)会为时间序列数据(例如用户成交)提供先前数据的快照。这些快照消息带有 isSnapshot: true 标记,如果之前的消息已被处理,则可以忽略。

订阅对象包含你要订阅的特定数据源的详细信息。从以下订阅类型中选择并提供相应的属性:

  1. allMids: * 订阅消息:{ "type": "allMids", "dex": "<dex>" } * 数据格式:AllMids * dex 字段表示从中获取中间价(mid)的永续合约 dex。 * 注意 dex 字段是可选的。如果未提供,则使用第一个永续合约 dex。现货中间价仅包含在第一个永续合约 dex 中。
  2. notification: * 订阅消息:{ "type": "notification", "user": "<address>" } * 数据格式:Notification
  3. webData3 : * 订阅消息:{ "type": "webData3", "user": "<address>" } * 数据格式:WebData3
  4. twapStates : * 订阅消息:{ "type": "twapStates", "user": "<address>", "dex": "<dex>" } * 数据格式:TwapStates
  5. clearinghouseState: * 订阅消息:{ "type": "clearinghouseState", "user": "<address>", "dex": "<dex>" } * 数据格式:ClearinghouseState
  6. openOrders: * 订阅消息:{ "type": "openOrders", "user": "<address>", "dex": "<dex>" } * 数据格式:OpenOrders
  7. candle: * 订阅消息:{ "type": "candle", "coin": "<coin_symbol>", "interval": "<candle_interval>" } * 支持的 K 线周期:"1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "8h", "12h", "1d", "3d", "1w", "1M" * 数据格式:Candle[]
  8. l2Book: * 订阅消息:{ "type": "l2Book", "coin": "<coin_symbol>" } * 可选参数:nSigFigs: int、mantissa: int、fast: boolean(fast 为 5 档,slow 为 20 档) * 数据格式:WsBook
  9. trades: * 订阅消息:{ "type": "trades", "coin": "<coin_symbol>" } * 数据格式:WsTrade[]
  10. orderUpdates:
    • 订阅消息:{ "type": "orderUpdates", "user": "<address>" }
    • 数据格式:WsOrder[]
  11. userEvents:
    • 订阅消息:{ "type": "userEvents", "user": "<address>" }
    • 数据格式:WsUserEvent
    • 注意:userEvents 消息的通道名为 "channel": "user"
  12. userFills:
    • 订阅消息:{ "type": "userFills", "user": "<address>" }
    • 可选参数:aggregateByTime: bool
    • 数据格式:WsUserFills
  13. userFundings:
    • 订阅消息:{ "type": "userFundings", "user": "<address>" }
    • 数据格式:WsUserFundings
  14. userNonFundingLedgerUpdates:
    • 订阅消息:{ "type": "userNonFundingLedgerUpdates", "user": "<address>" }
    • 数据格式:WsUserNonFundingLedgerUpdates
  15. activeAssetCtx:
    • 订阅消息:{ "type": "activeAssetCtx", "coin": "<coin_symbol>" }
    • 数据格式:WsActiveAssetCtx 或 WsActiveSpotAssetCtx
  16. activeAssetData:(仅支持永续合约)
    • 订阅消息:{ "type": "activeAssetData", "user": "<address>", "coin": "<coin_symbol>" }
    • 数据格式:WsActiveAssetData
  17. userTwapSliceFills:
    • 订阅消息:{ "type": "userTwapSliceFills", "user": "<address>" }
    • 数据格式:WsUserTwapSliceFills
  18. userTwapHistory:
    • 订阅消息:{ "type": "userTwapHistory", "user": "<address>" }
    • 数据格式:WsUserTwapHistory
  19. bbo :
    • 订阅消息:{ "type": "bbo", "coin": "<coin>" }
    • 数据格式:WsBbo
  20. spotState
    • 订阅消息:{ "type": "spotState", "user": "<address>", "isPortfolioMargin": bool }
    • 数据格式:WsSpotState
    • isPortfolioMargin 是可选参数
  21. allDexsClearinghouseState
    1. 订阅消息:{ "type": "allDexsClearinghouseState", "user": "<address>" }
    2. 数据格式:WsAllDexsClearinghouseState
  22. allDexsAssetCtxs
    1. 订阅消息:{ "type": "allDexsAssetCtxs" }
    2. 数据格式:WsAllDexsAssetCtxs
  23. outcomeMetaUpdates
    1. 订阅消息:{ "type": "outcomeMetaUpdates" }
    2. 数据格式:WsOutcomeMetaUpdates
  24. fastAssetCtxs
    1. { "method": "subscribe", "subscription": { "type": "fastAssetCtxs" } }
    2. 数据格式:base64 编码且压缩过的 WsFastAssetCtxs
    3. 读取数据请按顺序执行:\ 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" }}
    4. 第一条消息是快照,后续消息仅包含已更新的币种。没有更新的字段会被省略。

用户地址

要订阅与主账户或子账户关联的账户数据,你必须传入该账户的实际地址。一个常见的错误是使用代理钱包(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 格式,其用法与各自的订阅类型相对应。

示例

以下是用订阅消息订阅不同数据源的几个示例:

  1. 订阅所有中间价:

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 对象应与订阅该数据源时发送的原始订阅消息一致。这样服务器才能识别你要取消订阅的特定数据源。通过发送此取消订阅消息,你告知服务器停止发送该数据源的后续更新。

请注意,取消订阅某个特定数据源不会影响你当时已激活的其他订阅。要取消订阅多个数据源,你可以发送多条取消订阅消息,每条消息包含相应的订阅详情。

非官方社区镜像与翻译,内容版权归 Hyperliquid 所有,以英文原版为准。 来源: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions