Страница переведена сообществом и носит справочный характер; актуальна английская версия.
Оригинал ↗

Подписки

Эта страница описывает подписку на потоки данных с помощью WebSocket API.

Сообщения подписки

Чтобы подписаться на определённые каналы данных, необходимо отправить сообщение подписки. Формат сообщения подписки следующий:

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

Подтверждение подписки (subscription ack) предоставляет снимок предыдущих данных для данных временных рядов (например, исполнений пользователя). Эти сообщения-снимки помечены isSnapshot: true и могут быть проигнорированы, если предыдущие сообщения уже были обработаны.

Объект subscription содержит детали конкретного канала, на который вы хотите подписаться. Выберите один из следующих типов подписки и укажите соответствующие свойства:

  1. allMids: * Сообщение подписки: { "type": "allMids", "dex": "<dex>" } * Формат данных: AllMids * Поле dex задаёт перп-декс, из которого берутся средние цены (mids). * Обратите внимание, что поле 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>" } * Поддерживаемые интервалы: "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 (5 уровней при fast, 20 уровней при slow) * Формат данных: 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="\ decoded: { "BTC": { "markPx": "97500.5" }, "ETH": { "markPx": "3650.25" }, "xyz:NVDA": { "markPx": "145.2" }}
    4. Первое сообщение является снимком, последующие сообщения содержат только обновившиеся монеты. Поля без обновлений опускаются.

Адрес пользователя

Чтобы подписаться на данные счёта, связанные с основным или суб-счётом, необходимо передать фактический адрес этого счёта. Распространённая ошибка — использование адреса агентского кошелька, что приводит к пустому результату.

Форматы данных

Сервер отвечает на успешные подписки сообщением, содержащим свойство 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 : Состояния клирингового дома по всем дексам для конкретного пользователя
  • WsAllDexsAssetCtxs : Контексты активов по всем дексам
  • WsOutcomeMetaUpdates : Изменения метаданных исходов

Для потоковых пользовательских конечных точек, таких как 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. Подписаться на веб-данные конкретного пользователя:

json { "method": "subscribe", "subscription": { "type": "webData3", "user": "<address>" } } 4. Подписаться на обновления свечей для конкретной монеты и интервала:

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

Чтобы отписаться от определённого канала данных в WebSocket API Hyperliquid, необходимо отправить сообщение отписки в следующем формате:

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

Объект subscription должен совпадать с исходным сообщением подписки, отправленным при подписке на канал. Это позволяет серверу определить конкретный канал, от которого вы хотите отписаться. Отправляя это сообщение отписки, вы сообщаете серверу прекратить отправку дальнейших обновлений для указанного канала.

Обратите внимание, что отписка от определённого канала не влияет на другие подписки, активные в этот момент. Чтобы отписаться от нескольких каналов, можно отправить несколько сообщений отписки, каждое с соответствующими деталями подписки.

Неофициальный перевод сообщества. Права на контент принадлежат Hyperliquid; актуальна английская версия. Источник: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions