이 페이지는 커뮤니티 번역으로 참고용이며, 내용은 영어 원문을 우선합니다.
영어 원문 보기 ↗

구독

이 페이지에서는 WebSocket API를 사용하여 데이터 스트림을 구독하는 방법을 설명합니다.

구독 메시지

특정 데이터 피드를 구독하려면 구독 메시지를 보내야 합니다. 구독 메시지 형식은 다음과 같습니다:

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

구독 ack는 시계열 데이터(예: 사용자 체결)에 대해 이전 데이터의 스냅숏을 제공합니다. 이러한 스냅숏 메시지는 isSnapshot: true로 태그되며, 이전 메시지를 이미 처리한 경우 무시할 수 있습니다.

subscription 객체에는 구독하려는 특정 피드의 세부 정보가 포함됩니다. 다음 구독 유형 중에서 선택하고 해당 속성을 제공하세요:

  1. allMids: * 구독 메시지: { "type": "allMids", "dex": "<dex>" } * 데이터 형식: AllMids * dex 필드는 mids를 가져올 무기한 선물(펍) dex를 나타냅니다. * dex 필드는 선택 사항입니다. 제공하지 않으면 첫 번째 무기한 선물(펍) 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 (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="\ 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 : 특정 사용자의 모든 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. 특정 사용자의 웹 데이터 구독:

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 피드 구독 해제

Hyperliquid WebSocket API에서 특정 데이터 피드를 구독 해제하려면 다음 형식의 구독 해제 메시지를 보내야 합니다:

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

subscription 객체는 피드를 구독할 때 보낸 원래 구독 메시지와 일치해야 합니다. 이를 통해 서버는 구독 해제하려는 특정 피드를 식별할 수 있습니다. 이 구독 해제 메시지를 보내면 지정된 피드에 대한 추가 업데이트 전송을 중단하도록 서버에 알리는 것입니다.

특정 피드의 구독 해제는 당시 활성화되어 있던 다른 구독에는 영향을 주지 않습니다. 여러 피드를 구독 해제하려면 각각 적절한 구독 세부 정보를 담은 여러 개의 구독 해제 메시지를 보낼 수 있습니다.

비공식 커뮤니티 번역입니다. 저작권은 Hyperliquid에 있으며 영어 원문을 우선합니다. 출처: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions