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

Лимиты Bybit: очередь запросов, которая переживёт плохую минуту

Лимиты никогда не мешают на спокойном рынке. Они мешают в ту минуту, когда боту срочно надо снять ордер, — и проектировать надо именно под неё.

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

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

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

Представьте сценарий, который реально стоит денег. Цена прыгает гэпом. Три позиции одновременно достигают условий стопа. Поток рыночных данных захлёбывается. Логика котирования хочет обновить сорок ордеров. И где-то в этой очереди стоит отмена, защищающая позицию. Если очередь работает по принципу «первым пришёл — первым ушёл», эта отмена уйдёт после сорока обновлений котировок.

Два ведра, а не одно

Bybit считает лимиты не по одной оси: отдельно по IP и отдельно по UID аккаунта. Один глобальный счётчик внутри бота не моделирует корректно ни то, ни другое. Два бота на одном хосте делят бюджет IP; один бот с двумя ключами делит бюджет UID по каждому ключу, но не между ними.

Моделируйте как есть: ведро по IP и ведро по UID, и запрос обязан получить токен из обоих, прежде чем уйдёт. Это несколько десятков строк, и они убирают целую категорию загадочных отказов.

python
class Bucket:
    """Token bucket. Пополняется непрерывно, а не пачками по таймеру."""
    def __init__(self, rate_per_sec, burst):
        self.rate, self.capacity = rate_per_sec, burst
        self.tokens, self.ts = burst, time.monotonic()

    async def take(self, n=1):
        while True:
            now = time.monotonic()
            self.tokens = min(self.capacity,
                              self.tokens + (now - self.ts) * self.rate)
            self.ts = now
            if self.tokens >= n:
                self.tokens -= n
                return
            await asyncio.sleep((n - self.tokens) / self.rate)

async def send(req):
    await ip_bucket.take()      # оба бюджета, всегда
    await uid_bucket[req.key].take()
    return await http(req)

Приоритет — то, что действительно важно

Присвойте каждому запросу класс и обслуживайте очередь по классу, а не по времени поступления. Рабочий порядок:

ПриоритетЗапросПочему
0 — высшийОтмена, reduce-only, аварийное закрытиеСнижает риск. Не должен ждать ни за чем.
1Постановка stop-loss и take-profitЗащищает открытую позицию, у которой сейчас нет прикрытия.
2Ордера на входПропущенный вход стоит возможности, а не капитала.
3Обновление котировок, amendБольшой объём, малая ценность каждого.
4 — низшийОпрос баланса, позиций, инструментовЭто и так должно приходить из WebSocket.

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

Отступ с джиттером и с потолком

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

Добавьте потолок и алерт. Отступ, который удваивается уже две минуты, — это не временный сбой; что-то сломано структурно, и человек должен об этом знать. Тихий бесконечный повтор — это то, как бот остаётся «поднятым», ничего при этом не делая.

Повторам нужен клиентский ID ордера

Таймаут при постановке ордера — опасный случай: запрос мог пройти. Слепой повтор способен породить две позиции. Клиентский идентификатор ордера делает повтор идемпотентным: площадка распознаёт дубль и отклоняет его вместо исполнения.

Генерируйте идентификатор до первой попытки, сохраняйте его для всех повторов этого логического ордера и храните рядом с локальным состоянием, чтобы сверка после обрыва могла сопоставить по нему.

Пусть площадка сама скажет, где вы

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

Выводите остаток бюджета метрикой. Квота, которая в обычном режиме ползёт к нулю, сообщает, что следующая волатильная минута будет болезненной, — и сообщает заранее.

Лучше снизить нагрузку, чем лучше её планировать

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

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

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

Блог

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

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

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

Бриф

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

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

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

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

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