Откуда вообще возник вопрос
Почти все криптобиржи поддерживают и REST, и WebSocket. Начинающие разработчики, как правило, стартуют с REST: запрос — ответ, всё понятно. Но при первом же тесте на реальном рынке обнаруживают задержки в 150–300 мс на получение тикера и ограничение в 1200 запросов в минуту (Binance). Тогда и появляется вопрос: а стоит ли переходить на WebSocket?
Как работает REST в контексте торговли
REST (Representational State Transfer) использует стандартный HTTP: клиент отправляет запрос, сервер отвечает, соединение закрывается. Каждый раз — новое TCP-рукопожатие, TLS-хендшейк, DNS-резолв (если нет постоянного соединения).
Для получения цены это выглядит так:
import requests
def get_price(symbol: str) -> float:
url = f"https://api.binance.com/api/v3/ticker/price?symbol={symbol}"
resp = requests.get(url, timeout=3)
resp.raise_for_status()
return float(resp.json()["price"])
# Каждый вызов — новый HTTP-запрос
price = get_price("BTCUSDT")
Суммарная задержка складывается из RTT до сервера + время обработки + накладные расходы HTTP. На колокейшне рядом с серверами биржи это может быть 3–8 мс, из любой точки России — 50–200 мс.
Rate limits: главное ограничение REST
Биржи жёстко ограничивают количество запросов. Binance даёт 1200 запросов/мин по весу (каждый endpoint имеет вес от 1 до 50). При превышении лимита приходит HTTP 429, а при систематических нарушениях — бан IP на несколько часов.
Если вы хотите обновлять цену каждую секунду для 20 символов — это уже 1200 запросов в минуту. Лимит исчерпан полностью, и остальная логика бота (размещение ордеров, проверка баланса) просто не поместится.
Как работает WebSocket
WebSocket — это постоянное двунаправленное соединение поверх TCP. После одного HTTP-хендшейка (Upgrade) сервер сам толкает данные клиенту при каждом изменении. Никаких повторных соединений, никакого опроса.
import asyncio
import websockets
import json
async def stream_price():
url = "wss://stream.binance.com:9443/ws/btcusdt@trade"
async with websockets.connect(url) as ws:
while True:
msg = await ws.recv()
data = json.loads(msg)
# data["p"] — цена каждой сделки в реальном времени
print(data["p"])
asyncio.run(stream_price())
Задержка между изменением цены на бирже и получением сообщения — единицы миллисекунд (плюс сетевой RTT). Rate limits на стриминг существенно мягче или вовсе не применяются к входящим сообщениям.
Прямое сравнение
| Критерий | REST | WebSocket |
|---|---|---|
| Задержка получения данных | 50–300 мс (polling) | 1–10 мс (push) |
| Нагрузка на сеть | Высокая (заголовки HTTP на каждый запрос) | Минимальная (только payload) |
| Rate limits | Жёсткие (1200 req/min) | Мягкие / не применяются |
| Сложность реализации | Низкая | Средняя (реконнект, ping/pong) |
| Подходит для рыночных данных | ✗ при высокой частоте | ✓ |
| Подходит для ордеров | ✓ (POST /order) | ✓ (Binance WS API v3) |
| Stateful соединение | ✗ | ✓ (надо обрабатывать разрыв) |
Когда достаточно REST
- Вы запрашиваете данные реже одного раза в 3–5 секунд.
- Стратегия работает на дневных или часовых свечах.
- Вам нужна история (klines, trades) — только REST endpoint.
- Постановка ордеров и управление балансом — REST всегда надёжнее для исполнения.
- Прототип или MVP: скорость разработки важнее миллисекунд.
Когда необходим WebSocket
- Вам нужен каждый тик или каждая сделка (stриминг orderbook/trades).
- Стратегия реагирует на изменение цены быстрее 1 секунды.
- Вы отслеживаете 10+ символов одновременно.
- Арбитражный бот: разница в ценах живёт 50–200 мс, нельзя терять время на HTTP.
- Маркетмейкер: нужно видеть глубину стакана в реальном времени.
Особенности работы с WebSocket в production
Реконнект при разрыве
Биржи разрывают соединение каждые 24 часа (Binance) или при длительном отсутствии активности. Ваш код должен автоматически переподключаться и восстанавливать подписки.
import asyncio
import websockets
async def connect_with_retry(url: str, handler):
while True:
try:
async with websockets.connect(url, ping_interval=20) as ws:
await handler(ws)
except (websockets.ConnectionClosed, OSError):
await asyncio.sleep(5) # пауза перед реконнектом
Ping/Pong
Многие биржи требуют периодически отправлять ping-сообщения, иначе соединение признаётся неактивным. Библиотека websockets делает это автоматически через параметр ping_interval.
Множественные потоки
Binance позволяет объединять несколько стримов в одно соединение через /stream?streams=. Это снижает число соединений и упрощает управление:
url = "wss://stream.binance.com:9443/stream?streams=btcusdt@trade/ethusdt@trade"
Итог
Нет «лучшего» протокола — есть подходящий для задачи. Большинство production-систем используют оба: WebSocket для рыночных данных и REST для управления ордерами и аккаунтом. Если вы строите бота впервые — начните с REST, убедитесь в логике стратегии, потом переходите на стриминг.
Нужна готовая торговая система с оптимальной архитектурой? Опишите задачу — обсудим и оценим.