Перейти к содержанию
Hyperliquid.guru

API и автоматизация · практический разбор

Rate limits, ошибки 429/422 и корректная retry-стратегия

Бот, который повторяет запрос при любой ошибке, на Hyperliquid рискует продублировать ордер или потерять reconciliation с книгой биржи. Разбираем разницу между ошибкой транспортного уровня и отказом по содержанию заявки, а также как строить retry на idempotency через client order id, backoff с jitter и проверке статуса через info endpoint.

Очередь API запросов с backoff, jitter и контролем ошибок. Иллюстрация к материалу «Rate limits, ошибки 429/422 и корректная retry-стратегия».
Rate limits, ошибки 429/422 и корректная retry-стратегия.

Редакционная визуализация практического сценария: очередь api запросов с backoff, jitter и контролем ошибок.

Production-контур

Архитектурное решение

Транспортная ошибка означает, что запрос упёрся в weighted лимит и не был обработан по существу — нужен backoff с jitter и повтор того же тела позже. Ошибка валидации означает, что запрос дошёл до биржи и отклонён по содержанию (некорректный asset id, нарушение условий ALO/IOC/GTC, margin) — тут нужно исправить параметры, а не повторять запрос. Главная опасность — повтор POST /exchange без проверки: если ответ не получен из-за таймаута, action мог уже быть принят биржей, и повторная отправка создаёт дубликат. Рабочая стратегия строится на client order id для сопоставления намерения с результатом и проверке статуса через info endpoint с master или subaccount адресом, а не с адресом agent wallet, перед любым повтором.

Что должна уметь система

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

Почему привычный retry опаснее, чем кажется

Типичная реализация: запрос упал — повторяем через фиксированную паузу. На Hyperliquid цена такой привычки выше, чем на бирже с идемпотентным REST. POST /exchange принимает подписанные actions, а исполнение action биржей и получение ответа клиентом — разные события во времени. Если соединение прервалось после того, как биржа приняла action, но до получения ответа, повтор с тем же намерением отправит второе действие — вместо восстановления связи бот создаёт дубликат ордера или лишнюю позицию.

Документация задаёт weighted REST limit и отдельные лимиты для WebSocket connections, subscriptions, inflight posts и сообщений. Ошибка может прийти не только из-за частоты ордеров, но из-за совокупного веса разных запросов: если бот параллельно опрашивает info endpoint и шлёт ордера, вес складывается. Retry-логика, не различающая тип запроса, оставляет исходную проблему нерешённой и добавляет новую — рассинхронизацию между тем, что бот думает об открытых позициях, и тем, что реально висит в книге.

Транспортная ошибка против ошибки валидации

Отказ нужно классифицировать до решения о повторе. Транспортная ошибка — отказ на уровне лимита или сети: запрос не был содержательно обработан биржей, а значит тело запроса валидно для повторной отправки после паузы. Ошибка валидации — отказ на уровне содержания action: биржа получила и разобрала запрос, но отклонила его по существу, например из-за некорректного asset id, нарушения условий ALO (add liquidity only, где пересекающая книгу заявка отменяется вместо taker-fill), IOC или несоответствия margin-требованиям.

Это различие определяет ветвление retry: при транспортном отказе тело запроса не меняется и отправляется повторно после паузы, при отказе валидации сначала исправляются параметры и формируется осознанно новый запрос. Повтор транспортной ошибки без изменений корректен и ожидаем; повтор ошибки валидации с тем же телом гарантированно повторит тот же отказ и лишь потратит вес rate limit.

Пошаговый алгоритм retry без дублирования ордеров

Классификация, идентификатор запроса, проверка состояния и пауза складываются в единый порядок действий при каждом отказе.

  1. Классифицировать отказ: transport, 429 или validation

    Если запрос не был содержательно обработан биржей из-за сети или превышения weighted лимита — это транспортный случай, включая 429. Если биржа разобрала action и отклонила его по существу (asset id, ALO/IOC, margin) — это ошибка валидации, требующая иной реакции.

  2. Зафиксировать client order id до отправки

    Каждому ордеру ещё до первой отправки присваивается уникальный client order id, который не меняется при повторных попытках того же намерения. Это единственная надёжная точка сопоставления того, что бот хотел сделать, с тем, что реально произошло на бирже.

  3. Проверить состояние через info endpoint с master или subaccount address

    Прежде чем что-либо повторно отправлять, нужно запросить фактический статус ордера или позиции через info endpoint, указав master или subaccount адрес. Запрос с адресом agent wallet для account queries часто возвращает пустой результат, даже если агент активно используется для подписи actions.

  4. Для transient/429 выдержать паузу с backoff и jitter

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

  5. Для 422/validation исправить параметры и создать новый request

    Если ошибка относится к содержанию action, тело запроса нужно изменить по существу — исправить asset id, тип ордера или margin-параметры — и отправить его как осознанно новый запрос, а не как повтор прежнего намерения с тем же client order id.

  6. Выполнить reconciliation перед следующим действием

    После ответа от info endpoint или обновления WebSocket-подписки состояние позиций и ордеров сверяется с реальным положением на бирже, и только затем бот принимает решение — повторить action, отменить его или оставить как есть.

Idempotency через client order id

Client order id, присваиваемый ордеру клиентом при отправке, — основной инструмент сопоставления намерения с результатом на Hyperliquid. Если ответ на POST /exchange не получен из-за обрыва соединения или таймаута, у клиента остаётся один надёжный способ узнать, был ли action фактически принят: запросить состояние по тому же client order id через info endpoint, а не отправлять новый ордер без проверки.

Источники не задают формат этого идентификатора, поэтому конкретную схему разработчик выбирает сам — это условный пример, а не предписание Hyperliquid. Важно другое: id остаётся неизменным при повторе одного и того же запроса и уникален для каждого нового намерения. Именно это постоянство превращает retry-цикл из источника дублей в безопасную операцию — ответ info endpoint по данному id однозначно покажет, принят action или нет.

Backoff с jitter без выдуманных чисел

После транспортной ошибки повтор откладывается на растущий интервал со случайным смещением (jitter), а не выполняется через фиксированную секунду. Jitter нужен, чтобы несколько параллельных запросов от одного или разных клиентов не ударили по лимиту синхронной волной сразу после сброса окна.

Документация Hyperliquid описывает сам принцип weighted лимита и необходимость backoff с jitter, но не публикует единую жёстко зафиксированную числовую формулу интервалов для всех типов запросов. Любые конкретные секунды или множители в реализации бота — условные параметры, которые разработчик подбирает сам и калибрует по фактическому поведению собственного трафика, а не переносит как готовое правило.

Проверка статуса через info endpoint перед повтором

POST /info возвращает market metadata и пользовательские данные, но для account queries требуется указывать master или subaccount address. Agent wallet (он же API wallet) подписывает actions от имени master или subaccount, но не является адресом для чтения account state: запрос к info endpoint с адресом agent часто возвращает пустой результат, даже если агент активно используется для отправки ордеров. После deregistration адрес agent повторно использовать не следует — это связано с жизненным циклом nonce state.

Перед retry-действием статус ордера или позиции нужно проверять запросом к info endpoint именно с master или subaccount адресом. Иначе бот получит пустой ответ, ошибочно решит, что предыдущий action не был принят, и повторит его без реальных оснований — то есть тот самый шаг проверки состояния, без которого весь алгоритм retry теряет смысл.

WebSocket-состояние после разрыва и порядок действий

WebSocket-подписки на user fills и состояние аккаунта дают более быстрый сигнал об изменениях, чем периодический опрос info endpoint, но клиент обязан сам обрабатывать reconnect, повторную подписку и проверку свежести данных по sequence или времени после разрыва соединения. Если бот полагается только на локальный кеш, накопленный до обрыва, retry-логика будет работать поверх устаревшей картины позиций и ордеров.

Последовательность закреплена алгоритмом выше: после сбоя — обновление состояния, и только затем решение о повторе, отмене или бездействии. Обратный порядок означает, что решение принимается вслепую до того, как известны факты.

Что не покрыто примерами из SDK

Официальный репозиторий Python SDK содержит примеры Info client, Exchange client, подписи actions, размещения ордеров и базовой работы с WebSocket, но эти примеры демонстрируют механику вызовов, а не production-обвязку. Документация к SDK прямо указывает, что таймауты, idempotency и reconciliation остаются задачей разработчика поверх базовых примеров.

Копирование образца из репозитория без добавления слоя retry оставляет бота уязвимым к тем же проблемам: дублированию ордеров при обрыве соединения и работе поверх устаревшего состояния после сбоя. Слой idempotency, backoff и reconciliation нужно писать отдельно, ориентируясь на weighted rate limit и разделение ролей master/subaccount и agent wallet.

Как ошибка от параметров рынка проходит через тот же алгоритм

Например: margin table на конкретном рынке ужесточена, а бот отправляет ордер с прежним расчётом требуемой маржи — биржа разберёт action и отклонит его по существу. Это ошибка валидации из шага классификации, а не транспортный сбой. Такие изменения возникают из HIP-3 deployer actions — регистрация актива, oracle updates, funding multipliers, haltTrading, margin tables, OI caps — и способны привести к отказу по содержанию, даже если запрос технически сформирован корректно.

Реакция та же, что и для любой validation-ошибки: не повторять тело запроса, а запросить актуальные margin table и caps через perpetual metadata и asset contexts (сопоставление universe с contexts по позиции в массиве и DEX namespace), пересчитать параметры и отправить новый request. Официальный интерфейс торговли остаётся удобной точкой визуальной проверки на этапе отладки, но программная сверка через info endpoint нужна именно потому, что встраивается в тот же шаг классификации, который уже обрабатывает asset id, ALO/IOC и margin-отказы.

Вопросы и ответы

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

Чем транспортная ошибка отличается от ошибки валидации на Hyperliquid?

Транспортная ошибка означает, что запрос не был содержательно обработан биржей — например, превышен weighted rate limit, — и его тело можно безопасно повторить после паузы. Ошибка валидации означает, что запрос дошёл до биржи и отклонён по содержанию, например из-за некорректного asset id или нарушения условий ALO/IOC/GTC; повтор того же тела результата не изменит, нужно исправить параметры.

Почему нельзя просто повторить POST /exchange при таймауте?

POST /exchange принимает подписанные actions, и исполнение action биржей может произойти раньше, чем клиент получит ответ. Если соединение оборвалось после приёма action, но до получения ответа, повторная отправка без idempotency создаёт второй ордер с тем же намерением. Перед повтором нужно проверить фактический статус через info endpoint по client order id.

Почему проверка статуса через info endpoint иногда возвращает пустой результат?

Если запрос к info endpoint отправлен с адресом agent wallet, а не master или subaccount, результат для account queries часто оказывается пустым. Agent wallet подписывает actions от имени master или subaccount, но не предназначен для чтения состояния аккаунта, поэтому сверку статуса нужно выполнять именно с master или subaccount адресом.

Можно ли использовать фиксированную секунду ожидания между повторами?

Документация описывает необходимость backoff с jitter, а не фиксированного интервала. Растущая пауза со случайным смещением снижает риск того, что несколько параллельных запросов ударят по лимиту синхронно сразу после сброса окна. Единой числовой формулы Hyperliquid не публикует, поэтому конкретные секунды и множители — параметры, которые разработчик подбирает сам.

Нужно ли повторно использовать адрес agent wallet после его деактивации?

Нет, после deregistration адрес agent повторно использовать не следует. Это связано с жизненным циклом nonce state, привязанным к конкретному agent wallet: попытка задействовать деактивированный адрес заново способна нарушить логику проверки nonce и привести к отказам, не связанным напрямую с содержанием отправляемого action.

Hyperliquid.guru — независимый русскоязычный справочный сайт. Материал может содержать партнёрские ссылки; решение о торговле и размере риска пользователь принимает самостоятельно.

Автор: Редакция Hyperliquid.guru. Редактор: Редакционный контроль Hyperliquid.guru. Последняя проверка: 2026-08-28.