Подписка на стакан Hyperliquid в реальном времени через WebSocket

6 мая 2026 г.
  • hyperliquid orderbook websocket

  • real time hyperliquid api

  • hyperliquid стакан в реальном времени

  • hyperliquid websocket подписка

  • hyperliquid l2 book

Стакан заявок — одна из ключевых структур данных любой биржи. Он в реальном времени показывает распределение всех неисполненных лимитных ордеров по ценам и объёмам. Для квант-ботов, арбитражных систем и аналитических панелей доступ к актуальному стакану с задержкой на уровне миллисекунд часто критичен: от этого зависит, насколько корректно стратегия видит рынок.

Hyperliquid предоставляет полноценный WebSocket API, через который можно получать снапшоты и инкрементальные обновления L2-стакана. Ниже разберём формат подписки, структуру сообщений, поддержку локального стакана, переподключение и другие инженерные детали, которые важны в продакшене. Если ты не хочешь поднимать собственную инфраструктуру ради торговли бессрочниками, в OneKey Perps уже есть готовое отображение рынка в реальном времени и удобный торговый workflow.

WebSocket или REST polling

Перед техническими деталями важно понять, почему для стакана обычно используют WebSocket, а не постоянный опрос REST API.

REST polling подходит для редких запросов: получить состояние рынка, проверить позицию, загрузить исторические данные. Но для стакана в реальном времени он быстро упирается в задержки, лимиты запросов и риск пропустить быстрые изменения ликвидности.

WebSocket держит постоянное соединение и позволяет серверу пушить обновления сразу после изменения стакана. Для сценариев, где важны bid/ask, спред, глубина и реакция на изменение ликвидности, WebSocket практически незаменим. Полные спецификации лучше сверять с официальной документацией Hyperliquid.

Установка WebSocket-соединения

Endpoint

WebSocket endpoint Hyperliquid, актуальность которого нужно сверять с официальной документацией:

wss://api.hyperliquid.xyz/ws

Базовый пример подключения

import asyncio
import json
import websockets

WS_URL = "wss://api.hyperliquid.xyz/ws"

async def connect_and_subscribe():
    async with websockets.connect(WS_URL) as ws:
        # Отправляем сообщение подписки
        subscribe_msg = {
            "method": "subscribe",
            "subscription": {
                "type": "l2Book",
                "coin": "BTC"
            }
        }

        await ws.send(json.dumps(subscribe_msg))

        # Постоянно принимаем сообщения
        async for raw_msg in ws:
            msg = json.loads(raw_msg)
            handle_message(msg)

asyncio.run(connect_and_subscribe())

Формат подписки

Подписка на L2-стакан

Подписка на L2-стакан BTC:

{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC"
  }
}

Hyperliquid позволяет подписываться на несколько торговых пар одновременно. Для этого достаточно отправить отдельное сообщение подписки по каждому инструменту: обновления будут приходить независимо.

Отписка

{
  "method": "unsubscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC"
  }
}

Типы сообщений: снапшот и инкрементальные обновления

Начальный снапшот

После подписки сервер сначала отправляет полный снимок стакана: все актуальные ценовые уровни и объёмы на них.

{
  "channel": "l2Book",
  "data": {
    "coin": "BTC",
    "time": 1714500000000,
    "levels": [
      [
        [{"px": "64000.0", "sz": "0.5", "n": 3}],
        [{"px": "64010.0", "sz": "0.3", "n": 2}]
      ]
    ]
  }
}
  • px — цена.
  • sz — совокупный объём заявок на этом уровне. Если значение равно 0, уровень считается очищенным.
  • n — количество заявок на ценовом уровне.

Bids обычно идут от высокой цены к низкой, asks — от низкой к высокой.

Delta-обновления

После снапшота сервер отправляет только изменившиеся ценовые уровни:

{
  "channel": "l2Book",
  "data": {
    "coin": "BTC",
    "time": 1714500000100,
    "levels": [
      [
        [{"px": "63990.0", "sz": "0.0", "n": 0}],
        [{"px": "64010.0", "sz": "0.8", "n": 4}]
      ]
    ]
  }
}

Если sz равен "0" или 0, значит все заявки на этом уровне были исполнены или отменены. Такой уровень нужно удалить из локального стакана.

Поддержка локального стакана

Главная сложность при работе с WebSocket-данными — корректно поддерживать локальное состояние стакана.

from sortedcontainers import SortedDict

class LocalOrderBook:
    def __init__(self, coin):
        self.coin = coin
        self.bids = SortedDict(lambda x: -float(x))  # bids: цена от высокой к низкой
        self.asks = SortedDict(lambda x: float(x))   # asks: цена от низкой к высокой
        self.last_time = None

    def apply_snapshot(self, data):
        self.bids.clear()
        self.asks.clear()

        levels = data["levels"][0]

        for bid in levels[0]:
            if float(bid["sz"]) > 0:
                self.bids[bid["px"]] = float(bid["sz"])

        for ask in levels[1]:
            if float(ask["sz"]) > 0:
                self.asks[ask["px"]] = float(ask["sz"])

        self.last_time = data["time"]

    def apply_delta(self, data):
        levels = data["levels"][0]

        for bid in levels[0]:
            px, sz = bid["px"], float(bid["sz"])
            if sz == 0:
                self.bids.pop(px, None)
            else:
                self.bids[px] = sz

        for ask in levels[1]:
            px, sz = ask["px"], float(ask["sz"])
            if sz == 0:
                self.asks.pop(px, None)
            else:
                self.asks[px] = sz

        self.last_time = data["time"]

    @property
    def best_bid(self):
        return next(iter(self.bids.items()), None)

    @property
    def best_ask(self):
        return next(iter(self.asks.items()), None)

    @property
    def mid_price(self):
        bid = self.best_bid
        ask = self.best_ask
        if bid and ask:
            return (float(bid[0]) + float(ask[0])) / 2
        return None

    @property
    def spread(self):
        bid = self.best_bid
        ask = self.best_ask
        if bid and ask:
            return float(ask[0]) - float(bid[0])
        return None

Логика обработки сообщений

Нужно отличать начальный снапшот от последующих delta-обновлений и применять их к локальному состоянию.

order_book = LocalOrderBook("BTC")
is_initialized = False

def handle_message(msg):
    global is_initialized

    if msg.get("channel") != "l2Book":
        return

    data = msg["data"]

    if not is_initialized:
        order_book.apply_snapshot(data)
        is_initialized = True
        print(
            f"Стакан инициализирован: "
            f"{len(order_book.bids)} bid-уровней, "
            f"{len(order_book.asks)} ask-уровней"
        )
    else:
        order_book.apply_delta(data)

    # Печатаем текущий top of book
    print(
        f"Best bid: {order_book.best_bid}, "
        f"best ask: {order_book.best_ask}, "
        f"spread: {order_book.spread}"
    )

Переподключение при обрыве соединения

WebSocket-соединение может оборваться из-за сетевых проблем или действий сервера. В продакшене обязательно нужен автоматический reconnect.

import asyncio
import json
import websockets

async def subscribe_with_reconnect(coin, handle_fn, max_retries=None):
    retries = 0

    while max_retries is None or retries < max_retries:
        try:
            async with websockets.connect(
                WS_URL,
                ping_interval=20,
                ping_timeout=10
            ) as ws:
                retries = 0  # успешное подключение — сбрасываем счётчик
                is_initialized = False

                await ws.send(json.dumps({
                    "method": "subscribe",
                    "subscription": {"type": "l2Book", "coin": coin}
                }))

                async for raw_msg in ws:
                    handle_fn(json.loads(raw_msg))

        except (websockets.ConnectionClosed, ConnectionError, OSError) as e:
            retries += 1
            wait = min(2 ** retries, 60)  # exponential backoff, максимум 60 секунд
            print(f"Соединение разорвано ({e}), повтор через {wait} сек. Попытка #{retries}")

            is_initialized = False  # после reconnect ждём новый снапшот
            await asyncio.sleep(wait)

При переподключении нужно сбрасывать флаг is_initialized, потому что после нового соединения сервер снова отправит полный снапшот, а не продолжит поток delta-сообщений с места обрыва.

Timestamp и порядок сообщений

Сообщения WebSocket Hyperliquid содержат timestamp. Его можно использовать для базовой проверки порядка сообщений. В продакшене стоит делать следующее:

  • хранить timestamp последнего обработанного сообщения;
  • если новое сообщение старше уже обработанного, считать его устаревшим и отбрасывать;
  • если долго нет новых сообщений, отправлять ping или принудительно переподключаться;
  • для высокочастотных стратегий рассмотреть инфраструктуру с меньшей сетевой задержкой: более близкие узлы, стабильный канал, специализированный хостинг.

Подписка на несколько монет

Один WebSocket-канал может обслуживать несколько подписок. Обычно лучше переиспользовать одно соединение, чем создавать отдельный socket под каждую пару.

coins = ["BTC", "ETH", "SOL"]
order_books = {coin: LocalOrderBook(coin) for coin in coins}

async def multi_subscribe():
    async with websockets.connect(WS_URL) as ws:
        for coin in coins:
            await ws.send(json.dumps({
                "method": "subscribe",
                "subscription": {"type": "l2Book", "coin": coin}
            }))

        async for raw_msg in ws:
            msg = json.loads(raw_msg)

            if msg.get("channel") == "l2Book":
                coin = msg["data"]["coin"]
                if coin in order_books:
                    order_books[coin].apply_delta(msg["data"])

В реальной системе для каждой монеты также нужно отдельно отслеживать состояние инициализации, timestamp последнего сообщения и health checks.

Где используется стакан в реальном времени

Типичные сценарии применения L2-данных:

  • Торговые боты: динамическая перестановка лимитных ордеров с учётом спреда и глубины.
  • Арбитраж: мониторинг разницы цен между Hyperliquid и другими площадками, например dYdX или GMX.
  • Аналитические панели: визуализация глубины стакана, истории спреда и распределения ликвидности.
  • Риск-мониторинг: алерты при резком расширении спреда, исчезновении ликвидности или аномальном движении best bid / best ask.

OneKey Perps: без собственной инфраструктуры

Поднимать WebSocket-инфраструктуру, поддерживать локальные стаканы, следить за reconnection logic и хранить tick data — это отдельная инженерная задача. Если твоя цель не разработка квант-системы, а практичная торговля бессрочниками, проще использовать готовый интерфейс.

OneKey Perps даёт отображение рынка в реальном времени и торговые функции в одном workflow. В связке с аппаратным кошельком OneKey ты получаешь безопасное подписание транзакций и можешь сосредоточиться на торговом решении, а не на поддержке низкоуровневого data pipeline.

Если ты подключаешься к Web3-приложениям через WalletConnect, ориентируйся на документацию WalletConnect. OneKey поддерживает стандартный протокол WalletConnect и позволяет безопасно взаимодействовать с dApp, включая приложения экосистемы Hyperliquid.

Ненавязчивый следующий шаг: скачай или открой OneKey, подключи кошелёк и попробуй OneKey Perps на небольшом размере позиции, предварительно разобравшись с рисками плеча и бессрочных контрактов.

Частые вопросы

Q1: Есть ли лимиты на количество WebSocket-соединений?

Да, лимиты могут существовать. Актуальные ограничения нужно проверять в официальной документации Hyperliquid. На практике лучше не открывать слишком много соединений с одного IP: для нескольких пар обычно разумнее использовать одно WebSocket-соединение и несколько подписок внутри него.

Q2: Если потерять одно delta-сообщение, локальный стакан станет неправильным?

Да. Если delta-обновление потерялось из-за сети или сбоя обработки, локальный стакан может разойтись с реальным состоянием на сервере. Если ты видишь признаки рассинхронизации — например, аномальный спред, резкий скачок top of book или долгое отсутствие сообщений — лучше закрыть соединение и подписаться заново, чтобы получить свежий снапшот.

Q3: Можно ли использовать real-time стакан для бэктеста?

Напрямую — не очень удобно. Для бэктеста нужны исторические данные, а WebSocket даёт текущий поток. Рабочий подход — сохранять real-time данные как tick data, накапливать историю и затем использовать её для исследований. Для грубого первичного тестирования можно также комбинировать это с историческими K-line API Hyperliquid.

Q4: Как понять, что WebSocket-соединение здоровое?

Отслеживай как минимум два показателя:

  • сколько времени прошло с последнего полученного сообщения;
  • насколько адекватна ping/pong-задержка.

Если последнее сообщение было слишком давно, например больше заданного порога в 5 секунд, или ping/pong начинает деградировать, запускай принудительный reconnect.

Q5: OneKey-кошелёк увеличивает задержку торговли?

Подписание через аппаратный кошелёк OneKey обычно занимает сотни миллисекунд, и для большинства ручных или полуавтоматических стратегий это не является критичным фактором. Для ультравысокочастотных сценариев, где заявки отправляются десятки раз в секунду, можно разделять роли: горячий кошелёк или API Agent-субаккаунт для частых подписей, а основной капитал — под защитой OneKey.

Итоги

Подписка на стакан в реальном времени — базовый компонент качественной торговой или аналитической системы. WebSocket API Hyperliquid устроен достаточно понятно: ты подписываешься на l2Book, получаешь начальный снапшот, затем применяешь delta-обновления и следишь за корректностью локального состояния.

Если ты строишь маркет-мейкинг-бота, арбитражную систему или аналитический dashboard, этот подход даст хороший фундамент. Если же тебе нужен не backend для стаканов, а удобный вход в торговлю ончейн-бессрочниками, используй OneKey Perps: готовый интерфейс, real-time рынок и безопасное подписание через OneKey.

Риск-предупреждение: данные стакана отражают состояние рынка только в конкретный момент времени и не должны быть единственной основой для торгового решения. Автоматические стратегии на основе стакана могут привести к значительным убыткам из-за волатильности, технических сбоев, потери сообщений или ошибок в логике стратегии. Торговля бессрочными контрактами и использование плеча связаны с высоким риском, включая риск полной потери капитала. Этот материал предназначен только для технического ознакомления и не является инвестиционной, финансовой или юридической рекомендацией.

Защитите свое криптопутешествие с OneKey

View details for Магазин OneKeyМагазин OneKey

Магазин OneKey

Самый продвинутый аппаратный кошелек в мире.

View details for Загрузить приложениеЗагрузить приложение

Загрузить приложение

Предупреждения о мошенничестве. Поддержка всех монет.

View details for OneKey SifuOneKey Sifu

OneKey Sifu

Ясность в криптовалюте — на расстоянии одного звонка.