VIZANIXРазработка торгового ПО
Bybit APIWebSocket10 мин чтения

WebSocket Bybit: heartbeat, обрывы и состояние, которому нельзя верить

Оборванный WebSocket — это не ошибка для лога. Это момент, когда картина мира вашего бота и реальность тихо расходятся.

Инженеры Vizanix · об авторе

МАТЕРИАЛ
10 минвремя чтения
РАЗДЕЛ
Bybit API
ОПУБЛИКОВАНО
2026-08-28
ГЛАВ
6
ЧИТАТЬ ДАЛЬШЕ
3
ЯЗЫК
написано на русском
Инженерный разбор, а не пересказ документации.
WEBSOCKETHEARTBEATSEQUENCERESUBSCRIBESHARDING

Любой WebSocket-клиент рано или поздно переподключается. Вопрос, отделяющий продакшн-бота от скрипта, — что ему разрешено делать в первые секунды после того, как соединение вернулось.

Во время обрыва биржа продолжала торговать. Ордера исполнялись. Позиции менялись. Состояние бота в памяти теперь исторический документ. Бот, который сразу после переподключения возобновляет цикл стратегии, принимает решения по этому документу.

Heartbeat — это проверка живости, а не формальность

Bybit ждёт периодический ping и отвечает pong. Ценность не в протокольной вежливости, а в том, что TCP-соединение может оставаться открытым и при этом полностью мёртвым. Файрвол выбросил поток, сокет не выдал ошибку, и бот благополучно ждёт рыночных данных, которые никогда не придут.

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

python
# Живость измеряется по входящему трафику, а не по мнению сокета.
last_msg = time.monotonic()

async def watchdog(ws, idle_limit=30.0):
    while True:
        await asyncio.sleep(5)
        if time.monotonic() - last_msg > idle_limit:
            log.warning("нет данных %.1f с — принудительный reconnect", idle_limit)
            await ws.close()          # восстановлением займётся путь переподключения
            return

Номера последовательности существуют, чтобы понять, что вы пропустили

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

На разрыв последовательности есть ровно одна правильная реакция: выбросить локальный стакан и запросить свежий снимок. Интерполировать, игнорировать небольшие разрывы или надеяться, что «само пересинхронизируется», — это способы торговать против стакана, которого не существует.

Переподписка не происходит сама

Переподключение восстанавливает транспорт. Оно не восстанавливает ваши подписки. Обработчик, который открыл сокет и вышел, оставляет вас подключёнными к потоку, который ничего не шлёт, — а его затем справедливо убьёт watchdog выше, породив цикл переподключений, похожий на сетевую проблему и ею не являющийся.

Держите набор подписок явным состоянием и считайте переподписку частью процедуры подключения, а не чем-то, что случается после. Bybit ограничивает число аргументов в одном запросе подписки, так что большой универсум требует батчинга.

Шардируйте заранее

Один сокет на тысячу топиков — это единая точка отказа с долгим восстановлением: когда он падает, падает всё, а шторм переподписки случается ровно тогда, когда площадке и без того тяжело.

Наш конвейер свечей работает на десяти шардах. В устойчивом режиме это около 1850 топиков по 725 монетам, питающих 1450 буферов, при примерно 900 сообщениях в секунду. Когда падает один шард, девять остальных продолжают работать, и стратегия теряет десятую часть универсума на несколько секунд, а не весь.

Шардирование ещё и делает отказ читаемым. «Шард 7 лежит» — это утверждение, с которым можно что-то сделать. «WebSocket моргает» — нет.

Что бот обязан сделать до возврата к торговле

Именно этот шаг чаще всего пропускают. После переподключения, прежде чем циклу стратегии будет позволено выпустить хоть один ордер:

  1. Перечитать открытые ордера через REST и сверить с локальным состоянием.
  2. Перечитать позиции и сравнить с тем, что бот считал открытым.
  3. Перечитать баланс — маржа могла измениться по причинам, не связанным с этим ботом.
  4. Запросить свежие снимки стакана по каждому подписанному символу.
  5. И только затем разблокировать стратегию.

Сверка время от времени что-нибудь находит. Ордер, исполнившийся во время разрыва. Позицию, закрытую стопом. Частичное исполнение, изменившее среднюю цену. Любое из этого, обработанное по устаревшему состоянию, — это реальный убыток. И любое из этого невидимо для бота, который доверяет своей памяти.

Переподключения нормальны; незамеченные — нет

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

Считайте их. Частота переподключений, внезапно выросшая втрое, говорит вам что-то о сети, хосте или площадке — и говорит до инцидента, а не во время него. Этому место в том же health-выводе, что задержкам и reject rate; см. мониторинг торгового бота.

Статья описывает инженерную практику. Это не инвестиционная рекомендация. Vizanix разрабатывает программное обеспечение и не обещает торговую доходность.

Блог

Читать дальше

Эксплуатация · 7 мин

Мониторинг торгового бота: всё, кроме P&L

P&L рассказывает, что произошло. Он не рассказывает, исправна ли машина, которая это произвела, — а к моменту, когда P&L покажет сломанного бота, тот ломается уже давно.

Хотите такое у себя?

Мы пишем о том, что строим. Если нужно построить — напишите, разбор бесплатный.

Бриф

Получить оценку проекта

Четыре вопроса и контакт. Предоплата для разговора не нужна — если задача не наша, скажем сразу.

01Что вам нужно
02Биржа
03Рынок
04Стратегия
05Контакты

Проще написать напрямую? Telegram @vx_ceo

Обсудить систему