Внимание: данное руководство охватывает только публичные рыночные данные Bybit V5 API. Убедитесь, что ваше использование соответствует Условиям обслуживания Bybit и применимому законодательству. Не скрейпьте приватные или аутентифицированные эндпоинты без явного разрешения.
Скрейпинг Bybit V5 Market API через ротационные прокси — это техника сбора публичных рыночных данных (стаканы, тикеры, свечи, последние сделки) с эндпоинтов api.bybit.com/v5/market/* при помощи пула residential-IP, которые ротируются между запросами для обхода IP-based rate limit и geo-блокировок. В этом руководстве мы разберём маппинг эндпоинтов, формат ответа, лимиты, блокировки и дадим минимум пять runnable-примеров на Python и Node.js.
Карта публичных эндпоинтов Bybit V5 Market API
Bybit V5 API объединяет spot, linear и inverse рынки под единым базовым URL api.bybit.com. Все рыночные эндпоинты находятся под префиксом /v5/market/ и не требуют аутентификации. Ключевой параметр — category, который принимает значения spot, linear или option.
| Эндпоинт | Метод | Ключевые параметры | Назначение |
|---|---|---|---|
/v5/market/orderbook | GET | category, symbol, limit (25/50/100/200/500) | Снимок стакана заявок |
/v5/market/tickers | GET | category, опционально symbol | Список тикеров с lastPrice, volume24h и т.д. |
/v5/market/kline | GET | category, symbol, interval, limit, cursor | Исторические свечи (OHLCV) |
/v5/market/recent-trade | GET | category, symbol, limit (max 1000) | Последние сделки |
Все ответы V5 API используют единый конверт. Поле retCode равно 0 при успехе; ненулевое значение означает ошибку, текст которой находится в retMsg. Данные — в result. Всегда проверяйте retCode перед обработкой result, иначе можно silently получить пустой результат.
Пример 1: curl с raw-прокси — снимок стакана
curl -x http://user-country-DE:pass@gate.proxyhat.com:8080 \
"https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=50"
Параметр -country-DE в username указывает ProxyHat выдать немецкий residential-IP. Порт 8080 — стандартный HTTP-шлюз. Ответ содержит b (bids) и a (asks) — массивы пар [цена, размер].
Rate limit и IP-баны: почему bursts на orderbook опасны
Bybit применяет IP-based rate limit на каждый эндпоинт. Для /v5/market/orderbook лимит составляет примерно 50–120 запросов в секунду на IP (точное значение зависит от категории и нагрузки). При превышении API возвращает HTTP 403 или 429, а при повторных нарушениях IP может попасть в бан на ~10 минут.
Проблема усугубляется тем, что orderbook — самый «жадный» эндпоинт: разработчики часто опрашивают его в цикле с малым интервалом для построения локального стакана. Burst из 200+ запросов за секунду с одного IP почти гарантированно вызывает 403. Решение — ротация IP между запросами через residential-прокси, чтобы каждый запрос шёл с нового IP с собственным rate budget.
Пример 2: Python requests с raw-прокси — тикеры
import requests
proxy_url = "http://user-country-DE:pass@gate.proxyhat.com:8080"
proxies = {"http": proxy_url, "https": proxy_url}
resp = requests.get(
"https://api.bybit.com/v5/market/tickers",
params={"category": "linear"},
proxies=proxies,
timeout=10,
)
data = resp.json()
if data["retCode"] != 0:
raise Exception(f"Bybit error: {data['retMsg']}")
print(f"Tickers returned: {data['result']['tickerCount']}")
for t in data["result"]["list"][:3]:
print(t["symbol"], t["lastPrice"])
Geo-блокировки: 403 и CloudFront
Bybit ограничивает доступ из ряда юрисдикций, включая США, Великобританию и другие регионы. Запросы из заблокированных IP получают HTTP 403 или блокируются на уровне CloudFront (AWS CDN), который Bybit использует для защиты. Это значит, что datacenter-IP из США почти всегда получит 403, даже если rate limit не превышен.
Residential-прокси решают эту задачу: запрос маршрутизируется через реальный домашний IP из разрешённой страны (например, Германия или Япония). ProxyHat поддерживает geo-таргетинг через username-флаг -country-XX. Для город-уровня используйте -country-DE-city-berlin. Подробнее о доступных локациях — на странице локаций ProxyHat.
Пример 3: Node.js (axios) с ротацией IP через ProxyHat SDK
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { ProxyHat } = require('@proxyhat/sdk');
const ph = new ProxyHat({ username: 'user', password: 'pass' });
const symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT'];
async function fetchTicker(symbol) {
// Каждый вызов getHttpUrl выдаёт новый residential-IP
const proxyUrl = ph.getHttpUrl({ country: 'DE' });
const agent = new HttpsProxyAgent(proxyUrl);
const { data } = await axios.get(
'https://api.bybit.com/v5/market/tickers',
{
params: { category: 'spot', symbol },
httpsAgent: agent,
proxy: false,
timeout: 10000,
}
);
if (data.retCode !== 0) throw new Error(data.retMsg);
return data.result.list[0];
}
(async () => {
for (const sym of symbols) {
try {
const t = await fetchTicker(sym);
console.log(sym, t?.lastPrice);
} catch (e) {
console.error(sym, e.message);
}
await new Promise(r => setTimeout(r, 200)); // soft pacing
}
})();
Здесь каждый символ запрашивается с нового IP. Задержка 200ms — мягкий pacing для вежливого скрейпинга; при использовании ротационных прокси её можно сократить, но не убирать полностью.
Sticky-сессии для пагинации kline
Эндпоинт /v5/market/kline поддерживает пагинацию через параметр cursor, возвращаемый в result.nextPageCursor. Для консистентности пагинации полезно сохранять один IP на всю серию запросов — это даёт sticky-сессия через флаг -session-ID в username ProxyHat.
Пример 4: Python — пагинация kline со sticky-сессией
import requests
import time
def fetch_klines_paginated(symbol, interval="60", max_pages=5):
session_id = f"kl-{symbol}-{int(time.time())}"
proxy_url = (
f"http://user-country-DE-session-{session_id}:pass@gate.proxyhat.com:8080"
)
proxies = {"http": proxy_url, "https": proxy_url}
all_candles = []
cursor = None
for page in range(max_pages):
params = {
"category": "spot",
"symbol": symbol,
"interval": interval,
"limit": 1000,
}
if cursor:
params["cursor"] = cursor
resp = requests.get(
"https://api.bybit.com/v5/market/kline",
params=params,
proxies=proxies,
timeout=10,
)
data = resp.json()
if data["retCode"] != 0:
raise Exception(f"API error: {data['retMsg']}")
result = data["result"]
all_candles.extend(result["list"])
cursor = result.get("nextPageCursor")
if not cursor:
break
time.sleep(0.15)
return all_candles
candles = fetch_klines_paginated("BTCUSDT")
print(f"Fetched {len(candles)} candles")
Sticky-сессия гарантирует, что все страницы пагинации идут с одного residential-IP, что снижает риск рассинхронизации данных и уменьшает количество уникальных IP в логах Bybit.
Production-паттерны: retries, backoff, rate budgeting
В продакшене нужен комплексный подход: экспоненциальный backoff при 429/5xx, per-endpoint rate budget, circuit breaker при серии 403 и логирование. Ниже — класс на Python с интеграцией urllib3 Retry и ручным rate budget для orderbook.
Пример 5: Python — retries, backoff, per-endpoint rate budget
import requests
import time
import logging
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("bybit-scraper")
class BybitScraper:
BASE_URL = "https://api.bybit.com"
ORDERBOOK_BUDGET = 0.25 # 4 req/s per IP
def __init__(self, proxy_user, proxy_pass, country="DE"):
self.proxy_url = (
f"http://{proxy_user}-country-{country}:{proxy_pass}"
f"@gate.proxyhat.com:8080"
)
self.proxies = {"http": self.proxy_url, "https": self.proxy_url}
self.session = requests.Session()
retry = Retry(
total=5,
backoff_factor=1.5,
status_forcelist=[429, 500, 502, 503],
allowed_methods=["GET"],
)
adapter = HTTPAdapter(max_retries=retry)
self.session.mount("https://", adapter)
self.session.mount("http://", adapter)
self._last_ob_ts = 0.0
def _rate_limit(self, budget):
elapsed = time.time() - self._last_ob_ts
wait = budget - elapsed
if wait > 0:
time.sleep(wait)
self._last_ob_ts = time.time()
def get_orderbook(self, symbol, category="spot", depth=50):
self._rate_limit(self.ORDERBOOK_BUDGET)
resp = self.session.get(
f"{self.BASE_URL}/v5/market/orderbook",
params={"category": category, "symbol": symbol, "limit": depth},
proxies=self.proxies,
timeout=10,
)
if resp.status_code == 403:
logger.warning("403 — IP ban or geo-block, rotate proxy")
raise Exception("IP blocked")
data = resp.json()
if data["retCode"] != 0:
raise Exception(f"retCode={data['retCode']}: {data['retMsg']}")
return data["result"]
scraper = BybitScraper("user", "pass", country="DE")
ob = scraper.get_orderbook("BTCUSDT")
print(f"Bids: {len(ob['b'])}, Asks: {len(ob['a'])}")
Ключевые моменты: backoff_factor=1.5 даёт задержки 1.5s, 2.25s, 3.375s и т.д. ORDERBOOK_BUDGET = 0.25 ограничивает частоту до ~4 запросов в секунду на IP — безопасно ниже лимита Bybit. При 403 логируется предупреждение и поднимается исключение для rotation на уровне вызывающего кода.
REST-снимки vs WebSocket orderbook.50
REST-эндпоинт /v5/market/orderbook возвращает снимок стакана на момент запроса. Для live-обновлений Bybit предоставляет публичный WebSocket wss://stream.bybit.com/v5/public/spot с топиком orderbook.50.BTCUSDT, который пушит дельты стакана в реальном времени. WebSocket не подвержен IP-based rate limit на эндпоинты REST, но соединение всё равно может быть geo-заблокировано.
| Аспект | REST /v5/market/orderbook | WebSocket orderbook.50 |
|---|---|---|
| Тип данных | Полный снимок | Дельта + периодические снапшоты |
| Задержка | ~100–300ms на запрос | <50ms (push) |
| Rate limit | IP-based, ~50–120 req/s | Ограничение на подписки/сообщения |
| Geo-блок | Да, 403/CloudFront | Да, на уровне соединения |
| Использование прокси | HTTP-прокси (8080) | SOCKS5 (1080) для ws:// |
Пример 6: WebSocket orderbook.50 через SOCKS5-прокси
import asyncio
import json
import socks
import websockets
async def stream_orderbook():
# SOCKS5-прокси для WebSocket-соединения
proxy_url = "socks5://user-country-DE:pass@gate.proxyhat.com:1080"
uri = "wss://stream.bybit.com/v5/public/spot"
async with websockets.connect(
uri,
proxy=proxy_url,
ping_interval=20,
) as ws:
await ws.send(json.dumps({
"op": "subscribe",
"args": ["orderbook.50.BTCUSDT"],
}))
while True:
msg = json.loads(await ws.recv())
if msg.get("type") == "snapshot" and "data" in msg:
bids = msg["data"].get("b", [])
if bids:
print(f"Top bid: {bids[0]}")
asyncio.run(stream_orderbook())
Для WebSocket используйте SOCKS5-порт 1080 ProxyHat. Это позволяет проксировать долгоживущие TCP-соединения через residential-IP. Если соединение разрывается из-за ротации IP, реализуйте reconnect-логику с повторной подпиской.
Типичные ошибки и edge cases
- Игнорирование retCode. API может вернуть HTTP 200 с
retCode=10001(invalid symbol) и пустымresult. Всегда проверяйтеretCode == 0. - Превышение limit на orderbook. Параметр
limitпринимает только значения 25, 50, 100, 200, 500. Передача 1000 вызовет ошибку. - CloudFront 403 без retMsg. При geo-блоке CloudFront может вернуть HTML-страницу, а не JSON. Парсите
resp.status_codeпередresp.json(). - Слишком частая ротация для kline. Если менять IP на каждый запрос пагинации, cursor может оказаться невалидным для нового IP. Используйте sticky-сессии.
- Отсутствие timeout. Residential-прокси могут иметь задержку 200–800ms. Без timeout запрос зависнет. Всегда ставьте
timeout=10.
Настройка ProxyHat и внутренние ссылки
Для начала работы зарегистрируйтесь в дашборде ProxyHat и получите credentials. Residential-прокси поддерживают geo-таргетинг по стране и городу, sticky-сессии и ротацию. Для скрейпинга рыночных данных рекомендуется residential-тип — он реже блокируется CloudFront, чем datacenter-IP.
- Тарифы ProxyHat — выберите план под объём запросов.
- Use-case: web scraping — общие паттерны скрейпинга.
- Use-case: SERP tracking — если нужен параллельный сбор поисковых данных.
- Локации прокси — список доступных стран и городов.
- Документация ProxyHat — полные спецификации SDK и API.
Key Takeaways
• Bybit V5 Market API использует единый конверт с
retCode/retMsg— всегда проверяйте retCode перед обработкой result.
• IP-based rate limit на orderbook — ~50–120 req/s; превышение даёт 403 и ~10-минутный бан.
• Geo-блокировки (US/UK) реализуются через CloudFront 403; residential-прокси с-country-DEрешают задачу.
• Sticky-сессии (-session-ID) нужны для консистентной пагинации kline.
• WebSocketorderbook.50— для live-данных; используйте SOCKS5-порт 1080.
• Production-код: retries с backoff, per-endpoint rate budget, timeout=10s, логирование 403.
FAQ
Что такое скрейпинг Bybit V5 Market API через ротационные прокси?
Это сбор публичных рыночных данных (стаканы, тикеры, свечи, сделки) с эндпоинтов api.bybit.com/v5/market/* с использованием пула residential-IP, которые ротируются между запросами. Ротация позволяет обойти IP-based rate limit и geo-блокировки, сохраняя при этом легальный доступ к публичным данным.
Зачем нужны ротационные прокси для Bybit V5 Market API?
Bybit применяет IP-based rate limit (50–120 req/s на orderbook) и geo-блокировки через CloudFront. Без ротации серия запросов с одного IP быстро получает 403 и бан на ~10 минут. Ротационные residential-прокси дают каждому запросу отдельный IP с собственным rate budget, а geo-таргетинг (-country-DE) обходит региональные блокировки.
Какой тип прокси лучше для скрейпинга Bybit V5 Market API?
Residential-прокси. Datacenter-IP часто блокируются CloudFront, особенно из США и Великобритании. Residential-IP выглядят как реальные пользовательские подключения из разрешённых стран, что снижает риск 403. Mobile-прокси тоже работают, но обычно дороже и медленнее. Для WebSocket-потоков используйте SOCKS5-порт 1080.
Как избежать блокировок при скрейпинге Bybit V5 Market API?
Используйте ротационные residential-прокси с geo-таргетингом на разрешённую страну, соблюдайте per-endpoint rate budget (не более 4–10 req/s на IP для orderbook), реализуйте retries с экспоненциальным backoff, проверяйте retCode в каждом ответе, и используйте sticky-сессии для пагинации. Логируйте все 403-ответы для мониторинга качества IP-пула.
Можно ли использовать WebSocket вместо REST для стакана Bybit?
Да. Поток orderbook.50.BTCUSDT через wss://stream.bybit.com/v5/public/spot пушит дельты стакана с задержкой <50ms, что быстрее REST-снимков (~100–300ms). Для проксирования WebSocket используйте SOCKS5-порт 1080 ProxyHat. Учтите, что при ротации IP долгоживущее соединение может разорваться — реализуйте reconnect с повторной подпиской.






