Как скрейпить Bybit V5 Market API через ротационные прокси: руководство разработчика

Практическое руководство по скрейпингу публичных эндпоинтов Bybit V5 Market API (orderbook, tickers, kline, recent-trade) с ротационными residential-прокси через gate.proxyhat.com. Примеры на Python и Node.js, обработка rate limit, 403-банов и geo-блокировок.

How to Scrape the Bybit V5 Market API with Rotating Proxies
В этой статье

Внимание: данное руководство охватывает только публичные рыночные данные 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/orderbookGETcategory, symbol, limit (25/50/100/200/500)Снимок стакана заявок
/v5/market/tickersGETcategory, опционально symbolСписок тикеров с lastPrice, volume24h и т.д.
/v5/market/klineGETcategory, symbol, interval, limit, cursorИсторические свечи (OHLCV)
/v5/market/recent-tradeGETcategory, 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/orderbookWebSocket orderbook.50
Тип данныхПолный снимокДельта + периодические снапшоты
Задержка~100–300ms на запрос<50ms (push)
Rate limitIP-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.

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.
• WebSocket orderbook.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 с повторной подпиской.

Часто задаваемые вопросы

Что такое скрейпинг 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-таргетинг обходит региональные блокировки.

Какой тип прокси лучше для скрейпинга Bybit V5 Market API?

Residential-прокси. Datacenter-IP часто блокируются CloudFront, особенно из США и Великобритании. Residential-IP выглядят как реальные пользовательские подключения из разрешённых стран, что снижает риск 403. Для WebSocket-потоков используйте SOCKS5-порт 1080.

Как избежать блокировок при скрейпинге Bybit V5 Market API?

Используйте ротационные residential-прокси с geo-таргетингом на разрешённую страну, соблюдайте per-endpoint rate budget (4–10 req/s на IP для orderbook), реализуйте retries с экспоненциальным backoff, проверяйте retCode в каждом ответе, и используйте sticky-сессии для пагинации.

Можно ли использовать WebSocket вместо REST для стакана Bybit?

Да. Поток orderbook.50.BTCUSDT через wss://stream.bybit.com/v5/public/spot пушит дельты стакана с задержкой менее 50ms, что быстрее REST-снимков. Для проксирования WebSocket используйте SOCKS5-порт 1080 ProxyHat. При ротации IP долгоживущее соединение может разорваться — реализуйте reconnect с повторной подпиской.

Готовы начать?

Резидентные, ISP и мобильные прокси в 148+ странах. Создайте бесплатный аккаунт.

Создать бесплатный аккаунт
← Вернуться в Блог