Bybit V5 API: что на самом деле меняется при переезде бота
Одна модель аккаунта, один набор эндпоинтов и несколько деталей, которые тихо ломают ботов, перенесённых с прошлых версий.
Инженеры Vizanix · об авторе
- РАЗДЕЛ
- Bybit API
- ОПУБЛИКОВАНО
- 2026-08-28
- ГЛАВ
- 7
- ЧИТАТЬ ДАЛЬШЕ
- 3
- ЯЗЫК
- написано на русском
Bybit V5 свёл несколько параллельных API в одну поверхность. Для автора бота это в основном хорошая новость: одна схема подписи, одно пространство ошибок, одна модель аккаунта. Проблема в том, что при переезде ломается редко то, что видно на первом же запросе, — оно всплывает в три часа ночи, когда существует позиция, которую никто не планировал.
Сначала модель аккаунта
До первого запроса решите, с каким типом аккаунта работает бот. В Unified Trading Account спот, USDT-перпетуалы и опционы делят общий пул маржи. Это удобно — и это связность: убыточная позиция по перпетуалу уменьшает маржу, доступную всему остальному в аккаунте.
Для кода риска это принципиально. Бот, который считает доступную маржу как баланс кошелька минус мои собственные позиции, прав на выделенном аккаунте и не прав на едином, где человек может держать в том же пуле что-то ещё. Читайте баланс, который отдаёт биржа, а не восстанавливайте его.
Категория запроса — не косметика
Почти каждый эндпоинт V5 принимает параметр category: linear, spot, inverse, option. Он решает, в какой рынок попадёт запрос. Бот, у которого зашит linear, а потом его направляют на спотовый символ, не упадёт громко — он получит ошибку «инструмент не найден», похожую на опечатку в символе.
Держите категорию рядом с символом в реестре инструментов с самого начала. Выводить её потом из имени символа — гадание, которое ломается в первый же раз, когда площадка листит символ, существующий в двух категориях.
Подпись и двое часов
V5 подписывает строку, собранную из метки времени, ключа, recv-окна и тела запроса — именно в этом порядке. Два сценария дают большинство ошибок подписи:
- Сериализация при подписи и при отправке различается. Если подпись строится по одному JSON-дампу, а HTTP-библиотека сериализует тело заново, порядок ключей или пробелы могут разойтись — и подпись не сойдётся. Подписывайте ровно те байты, которые отправляете.
- Расхождение часов. Подпись несёт метку времени, и биржа отклоняет запросы за пределами
recv_window. Сервер, у которого часы уходят на секунду-две, работает прекрасно — ровно до того момента, когда перестаёт.
Второе стоит измерять, а не предполагать. В нашем исполнителе под Bybit расхождение локального времени с биржевым пишется на каждом ответе и выводится в health: в нормальной работе оно держится примерно в пределах ±40 мс. Дрейф, который начал расти, виден задолго до того, как превратится в отклонённый ордер.
# Подписываем ровно то, что собираемся отправить.
raw = json.dumps(payload, separators=(",", ":")) # одна каноническая форма
sign_payload = f"{ts}{api_key}{recv_window}{raw}"
signature = hmac.new(secret, sign_payload.encode(), hashlib.sha256).hexdigest()
resp = session.post(url, data=raw, headers={ # data=raw, а не json=payload
"X-BAPI-API-KEY": api_key,
"X-BAPI-TIMESTAMP": ts,
"X-BAPI-RECV-WINDOW": recv_window,
"X-BAPI-SIGN": signature,
"Content-Type": "application/json",
})Расширять recv_window, чтобы спрятать дрейф, — ловушка. Симптом действительно уходит, но заодно расширяется окно, в котором повторно отправленный запрос остаётся валидным. Чините часы: chrony или systemd-timesyncd ничего не стоят.
Фильтры инструмента решают, существует ли ваш ордер
У каждого символа есть фильтры: qtyStep, minOrderQty, tickSize, minNotionalValue. Объём, не прошедший любой из них, отклоняется. Обработать это легко и легко же ошибиться в мелочи:
- Округляйте количество вниз до
qtyStep, а не до ближайшего шага. Округление вверх может увести требуемую маржу за доступный баланс. - Округляйте цену до
tickSizeв консервативную для вашей стороны сторону: вниз для лимитной покупки, вверх для лимитной продажи. - Проверяйте
minNotionalValueпосле округления, а не до. Округление вниз может увести под минимум. - Обновляйте таблицу фильтров периодически. Площадки меняют лотность, и фильтр, закэшированный в день деплоя, со временем начинает врать.
Маржа резервируется вместе с комиссиями
Это удивляет тех, кто переносит бота, считавшего объём «на 100% свободных средств». Биржа держит начальную маржу плюс комиссию по номиналу. Поэтому реальный потолок — не свободный баланс, а примерно свободные / (1 + плечо × ставка_комиссии). На 10× это около 99% баланса, на 50× ближе к 96%.
Бот, который это игнорирует, получает 110004 недостаточно средств ровно на тех ордерах, которые больше всего хотел поставить, — на крупных. Наш исполнитель решает это лестницей повторов: взять свежий остаток, ужать объём, переставить — до пяти попыток, останавливаясь на минимальном лоте биржи. Жёсткий отказ превращается в позицию поменьше, а это почти всегда то, чего оператор и хотел.
Коды ошибок — это поток управления, а не строчка в логе
V5 возвращает числовой retCode. Считать всё ненулевое «ошибкой, надо повторить» — именно так боты создают дублирующие позиции. Коды делятся на группы, требующие разного поведения:
| Группа | Пример | Правильная реакция |
|---|---|---|
| Параметры и валидация | 10001, 170137 | Не повторять. Чинить запрос; алерт, если это неожиданно. |
| Авторизация и права | 10003, 10005, 10018 | Не повторять. Остановиться и позвать человека — обычно проблема в ключе или белом списке IP. |
| Лимит запросов | 10006 | Отступ с джиттером. Никогда не повторять в плотном цикле. |
| Баланс и риск-лимит | 110004, 110045 | Ужать объём и переставить либо отказаться от сигнала. |
| Идемпотентный no-op | 110043 плечо не изменено | Считать успехом. Нужное состояние уже достигнуто. |
| Таймаут и сервер | 10016 | Повторять только с клиентским ID ордера, затем сверяться. |
Последняя строка — самая важная. Таймаут это не отказ, это неизвестность. Запрос мог исполниться. Повтор без клиентского ID ордера — это то, как бот получает две позиции там, где стратегия просила одну. Более полную карту мы держим в справочнике ошибок Bybit API.
Что писать первым
- Реестр инструментов с фильтрами и категорией, обновляемый по расписанию.
- Функцию подписи с тестом, сверяющим подпись с известным вектором.
- Метрику расхождения часов, выведенную в health.
- Классификатор ошибок, отображающий
retCodeв одно из поведений выше. - И только потом — постановку ордеров.
Боты, написанные в этом порядке, скучны в эксплуатации. Боты, которые начинают с постановки ордера и добирают остальное под давлением, — это те, за которыми кто-то должен смотреть.
Статья описывает инженерную практику. Это не инвестиционная рекомендация. Vizanix разрабатывает программное обеспечение и не обещает торговую доходность.