Production-контур
Архитектурное решение
Устойчивое WebSocket-подключение к Hyperliquid требует трёх слоёв защиты: переподписки после reconnect на все каналы — книгу, trades, candles и user fills; проверки свежести данных по временной метке или sequence внутри сообщения, а не по факту наличия соединения; и разделения источников для решений об ордерах — критичные действия должны опираться на подтверждение через info endpoint, а не только на последний WebSocket-снимок. Документация указывает, что reconnect, повторную подписку и freshness-контроль обязан обрабатывать клиент. Без этого бот может действовать против цены, устаревшей на несколько секунд, особенно на волатильном рынке, где книга успевает сдвинуться за время разрыва соединения.
Что должна уметь система
Материал для разработчиков и трейдеров, которые строят автоматизированную торговлю или дашборд на Hyperliquid API и уже работают с perpetual, funding, subaccount и REST info endpoint, но хотят закрыть риск устаревших данных при realtime-подписках.
Зачем контролировать stale data именно на WebSocket-слое
WebSocket в Hyperliquid даёт realtime-подписки на книгу ордеров, trades, candles, user fills и состояние аккаунта. Слабое место схемы — постоянство соединения. Сеть роняет пакеты, провайдер перезапускает инстанс, биржа закрывает соединение по своим лимитам — и в этот момент клиент либо замечает разрыв и восстанавливает состояние, либо продолжает работать с последним снимком, считая его текущим.
Документация Hyperliquid указывает, что клиент обязан сам обрабатывать reconnect, повторную подписку и freshness-контроль по sequence или временной метке — это требование к архитектуре клиента, а не гарантия протокола.
Механика подписок: что нужно переподписать после разрыва
Подписка на WebSocket в Hyperliquid — не одно постоянное состояние соединения, а набор независимых каналов: книга по конкретному активу, поток trades, candles заданного интервала, user fills и состояние аккаунта. Каждый канал подписывается отдельным сообщением после установки соединения. Когда соединение разрывается и восстанавливается, все подписки нужно отправить заново — сервер не хранит список прежних подписок между сессиями.
Частая ошибка — переподписаться только на тот канал, разрыв которого заметили первым, и забыть остальные. Если бот держит подписку на книгу актива и на user fills для сверки исполнений, а после reconnect восстановил только книгу, он продолжит торговать вслепую относительно собственных исполнений: fills не придут, позиция в локальном состоянии разойдётся с реальной на аккаунте. Список активных подписок стоит хранить в явном виде в коде, а не восстанавливать по памяти в момент разрыва.
Конкретный сценарий: разрыв соединения во время открытой позиции
Бот на Hyperliquid держит открытую perpetual-позицию, подписан на книгу актива для стоп-логики и на user fills для подтверждения исполнений. В середине волатильного движения соединение обрывается на несколько секунд из-за сетевого сбоя, не связанного с биржей. За это время книга успевает сдвинуться, а один из ордеров бота мог исполниться частично.
Если бот не отслеживает момент разрыва явно, он продолжает использовать последний снимок книги как текущий, хотя рынок уже ушёл: стоп-логика, посчитанная на устаревшей цене, срабатывает с опозданием. Параллельно, если fills за время разрыва не получены, а переподписка не восстановила поток, локальное состояние позиции не совпадает с реальным — а именно на него опирается следующее решение об ордере.
Где WebSocket Hyperliquid даёт контекстное преимущество перед REST-опросом
Альтернатива WebSocket — постоянный опрос info endpoint через REST. У этого подхода есть предсказуемость: каждый запрос — самостоятельная транзакция с понятным ответом, без долгоживущего соединения. Но у REST-опроса есть потолок частоты, заданный weighted-лимитом запросов, и задержка между событием на рынке и моментом, когда бот его увидит, равна интервалу опроса.
WebSocket снимает этот потолок: обновления книги, trades и fills приходят по мере появления, а не по расписанию опроса. Но преимущество реализуется только если клиент сам поддерживает соединение живым и корректно восстанавливает подписки. Необработанный WebSocket не превосходит REST-опрос: соединение выглядит рабочим, а данные в нём уже могут быть устаревшими, тогда как REST при сбое вернул бы явный таймаут.
Реальные ограничения этого сценария
Документация задаёт для WebSocket лимиты на количество connections, subscriptions и inflight-сообщений наряду с weighted REST limit. Бот, который держит десятки подписок на одном соединении ради экономии ресурсов, может упереться в такие лимиты; документация не детализирует точный характер поведения при их превышении, поэтому стоит проверять подтверждение подписки на каждый канал отдельно, а не считать подписку успешной по умолчанию.
Второе ограничение задокументировано для info endpoint: agent wallet годится для подписи ордеров, но при обращении к account state через него часто возвращается пустой результат — для account-запросов, включая проверку позиции после разрыва, нужен master или subaccount адрес. Для WebSocket-подписки на состояние аккаунта это ограничение отдельно не задокументировано; предположение, что оно действует по аналогии, не подтверждено источником.
Типичные ошибки при работе с WebSocket-подписками
Открытое TCP-соединение может оставаться технически живым, пока сервер уже перестал присылать обновления по конкретному каналу. Freshness нужно проверять по временной метке или sequence внутри самих сообщений, а не по статусу сокета.
Переподписка без сверки с REST-снимком после длительного разрыва — ещё одна ошибка: если соединения не было несколько секунд и более, разумно после reconnect запросить актуальный снимок через info endpoint параллельно с восстановлением подписок, а не строить состояние только на первом WebSocket-сообщении, которое само может оказаться неполным сразу после переподключения.
Отдельная категория — путать канал user fills с гарантией доставки. Если во время разрыва произошло исполнение, сообщение о нём не ретранслируется автоматически после восстановления — его нужно восполнить явным запросом истории через info endpoint, иначе позиция в боте останется рассинхронизированной с реальной.
Условный числовой пример: как выглядит расхождение в цене
Ниже условные цифры для иллюстрации механики, а не рыночные данные. Mark price актива в момент t0 условно равна 42 000, стоп бота выставлен на 41 950. Соединение обрывается на пять секунд, за которые книга условно смещается на несколько уровней глубины, и к моменту реконнекта условная фактическая цена — 41 890. Если стоп-логика триггерится по локально сохранённому значению 42 000 без проверки freshness, она срабатывает уже после того, как рынок прошёл уровень 41 950: относительно этого уровня отклонение фактической цены составляет условно 0,14% ((41950-41890)/41950).
При условном размере позиции 50 000 USD notional это отклонение в процентах, умноженное на notional (0,14% × 50 000), даёт примерно 70 USD условной дополнительной издержки — это не прямой пересчёт разницы цен по факту исполнения, а иллюстративная оценка масштаба, без учёта проскальзывания при самом исполнении. Это издержка устаревших данных, а не проскальзывание исполнения: решение принято на основе снимка, который перестал соответствовать рынку до того, как об этом узнал бот. Величина такой издержки растёт пропорционально длительности разрыва, волатильности момента и размеру позиции — на спокойном рынке пятисекундный разрыв почти не даёт эффекта, на резком движении та же условная доля процента при крупном размере позиции превращается в заметную сумму.
Пошаговый план устойчивого WebSocket-клиента
Ниже — порядок действий для клиента, который должен переживать разрывы без потери контроля над данными.
Шаги плана: от разрыва до подтверждённого состояния
- Этап 1
Первый шаг — детектировать разрыв явно: не полагаться на исключение сокета, а держать таймер ожидания сообщений по каждому подписанному каналу и считать канал протухшим, если обновления не пришли дольше ожидаемого интервала.
- Этап 2
Второй шаг — хранить список активных подписок отдельной структурой в коде и при reconnect отправлять их все заново, а не только те, чей разрыв заметили первым.
- Этап 3
Третий шаг — после восстановления соединения параллельно с переподпиской запросить актуальный снимок через info endpoint: свежую книгу, баланс и открытые позиции по master или subaccount адресу, не через agent wallet.
- Этап 4
Четвёртый шаг — сверить полученный REST-снимок с локальным состоянием и явно запросить историю fills за период разрыва, чтобы восполнить исполнения, которые не были ретранслированы по WebSocket.
- Этап 5
Пятый шаг — до завершения этой сверки не принимать решений об ордерах на основе только WebSocket-данных, считая состояние временно недоверенным.
Вопросы и ответы
Частые вопросы
Как понять, что WebSocket-соединение Hyperliquid отдаёт устаревшие данные, если ошибки нет?
Открытый сокет не гарантирует свежесть: сервер может перестать присылать обновления по каналу, а TCP-соединение останется технически живым. Нужно проверять временную метку или sequence внутри каждого сообщения и сравнивать с ожидаемым интервалом обновлений.
Нужно ли восстанавливать все подписки после reconnect или только критичные?
Все — сервер не хранит список прежних подписок между сессиями соединения. Если восстановить только книгу и забыть про user fills, бот продолжит торговать вслепую относительно собственных исполнений, а локальная позиция разойдётся с реальной на аккаунте.
Почему agent wallet нельзя использовать для проверки позиции после разрыва?
Agent wallet предназначен для подписи ордеров от имени master или subaccount, но при чтении account state через info endpoint через него часто возвращается пустой результат. Для проверки реальной позиции, баланса и ордеров нужен адрес master или subaccount, а не agent wallet.
Что делать, если fills не пришли за время разрыва соединения?
Канал user fills не гарантирует ретрансляцию сообщений после восстановления соединения. Если во время разрыва произошло исполнение, его нужно явно восполнить запросом истории через info endpoint, иначе локальная позиция бота останется рассинхронизированной с реальной.
Чем WebSocket хуже REST-опроса, если reconnect не обработан?
REST-опрос при сбое вернёт явную ошибку таймаута, а необработанный WebSocket оставляет соединение выглядящим рабочим, хотя данные в нём уже устарели. Преимущество WebSocket в скорости реализуется только при полноценной обработке reconnect и freshness-контроле на стороне клиента.
Первичные источники
Полезные официальные ссылки
- Info endpoint
Hyperliquid Docs.
- WebSocket subscriptions
Hyperliquid Docs.
- Rate limits и user limits
Hyperliquid Docs.
- Nonces и API wallets
Hyperliquid Docs.
- Account abstraction modes
Hyperliquid Docs.
Полезные материалы
