Jak scrapować API rynku Bybit V5 z rotującymi proxy

Przewodnik dla programistów: pobieraj dane orderbook, tickers i kline z Bybit V5 Market API z rotującymi proxy ProxyHat. Gotowe przykłady w Python i Node.js, obsługa limitów, geo-blokad i sesji sticky.

How to Scrape the Bybit V5 Market API with Rotating Proxies
W tym artykule

Zastrzeżenie prawne: Publiczne endpointy /v5/market/ są dostępne bez uwierzytelnienia, ale musisz przestrzegać warunków korzystania z API Bybit oraz lokalnych przepisów. Ten przewodnik dotyczy wyłącznie publicznych danych rynkowych i nie zachęca do naruszania ToS.

Jeśli tworzysz bota handlowego lub potok danych rynkowych, prawdopodobnie spotkałeś się z błędem 403 z api.bybit.com/v5/market/orderbook po kilku minutach intensywnego scrapowania. Bybit V5 Market API jest szybkie i dobrze udokumentowane, ale ma limity IP, geo-blokady i CDN CloudFront, które mogą zablokować Twoje żądania. W tym przewodniku pokazujemy, jak scrapować API rynku Bybit V5 z rotującymi proxy — z gotowymi przykładami w Node.js i Python, obsługą limitów, geo-blokad i sesji sticky.

Dlaczego scrapowanie API rynku Bybit V5 z rotującymi proxy wymaga proxy

Bybit V5 Market API udostępnia publiczne dane rynkowe pod api.bybit.com/v5/market/. Wszystkie odpowiedzi mają spójną kopertę:

{
  "retCode": 0,
  "retMsg": "OK",
  "result": { ... },
  "time": 1700000000000
}

Gdy retCode wynosi 0, żądanie się powiodło. Każda inna wartość — np. 10001 (parametr wymagany) lub 10010 (przekroczony limit) — oznacza błąd, a retMsg zawiera opis. Musisz sprawdzać retCode przy każdym żądaniu, inaczej Twoja aplikacja cicho przetwarza puste dane.

Główne endpointy, które scrapujemy:

  • /v5/market/orderbook — książka zleceń; parametr category przyjmuje spot lub linear, a limit (głębokość) od 1 do 200.
  • /v5/market/tickers — bieżące tickery dla kategorii; zwraca listę z lastPrice, high24h, volume24h.
  • /v5/market/kline — świece OHLCV; parametr interval od 1 do D, limit do 1000, paginacja przez cursor.
  • /v5/market/recent-trade — ostatnie transakcje; category + symbol + opcjonalny limit.

Parametr category jest kluczowy: spot to rynek spot, linear to perp/futures USDT, a inverse to kontrakty odwrotne. Mieszanie kategorii to częsty błąd.

Limity IP w Bybit V5 i dlaczego orderbook jest wrażliwy

Bybit stosuje limity per-endpoint i per-IP. Według dokumentacji limitów Bybit V5, endpoint /v5/market/orderbook ma osobny budżet, a /v5/market/tickers inny. Kiedy przekroczysz limit, otrzymujesz HTTP 403 z retCode wskazującym rate limit, a Twoje IP może trafić na listę banów na około 10 minut.

Orderbook jest szczególnie wrażliwy, ponieważ typowo odpytujesz go z wysoką częstotliwością (np. co 100–200 ms na symbol). Przy 10 symbolach to 50–100 żądań/s z jednego IP — wystarczy, by szybko wyczerpać budżet. Rotujące proxy rozpraszają te żądania na wiele adresów IP, więc każdy IP utrzymuje się poniżej progu.

Typowe objawy wyczerpania limitu:

  • HTTP 403 z retMsg zawierającym "rate limit" lub "too many requests".
  • Nagły spadek sukcesu z 99% do 0% na wszystkich żądaniach.
  • Ban trwający ~10 minut, po którym ruch wraca bez interwencji.

Geo-blokady Bybit i CloudFront

Bybit ogranicza dostęp z niektórych regionów (m.in. USA, UK, części UE) ze względów regulacyjnych. Żądania z zablokowanych IP otrzymują HTTP 403 lub są odrzucane przez CDN CloudFront przed dotarciem do API. Jeśli Twój serwer datacenter znajduje się w zablokowanym regionie, nie dostaniesz się do /v5/market/ bez proxy z dozwolonego kraju.

Rozwiązaniem są proxy residential z geo-targetingiem. ProxyHat pozwala wskazać kraj w nazwie użytkownika, np. user-country-DE kieruje ruch przez niemiecki adres IP ISP. To wystarczy, aby Bybit widział żądanie z dozwolonego regionu.

Konfiguracja ProxyHat: HTTP 8080 i SOCKS5 1080

ProxyHat używa jednej bramy dla wszystkich typów proxy. Parametry geo i sesji przekazujesz w nazwie użytkownika.

TypURL proxyUżycie
HTTPhttp://user-country-DE:pass@gate.proxyhat.com:8080Domyślny, rotacja per-żądanie
SOCKS5socks5://user-country-DE:pass@gate.proxyhat.com:1080Niskolatencyjny, dobre dla WebSocket
Sticky HTTPhttp://user-session-abc123-country-DE:pass@gate.proxyhat.com:8080Paginacja kline, spójny IP

Sprawdź dostępne lokalizacje na stronie /pl/locations i cennik na /pl/pricing. Więcej o zastosowaniach scrapowania znajdziesz w przypadku użycia web scraping i SERP tracking.

Przykład 1: curl z surowym proxy

Najprostszy test — orderbook spot BTCUSDT przez niemiecki IP:

curl -x http://user-country-DE:pass@gate.proxyhat.com:8080 \
  "https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=200"

Odpowiedź zawiera result.b (bids) i result.a (asks) jako listę par [cena, wielkość]. Jeśli retCode ≠ 0, sprawdź retMsg.

Przykład 2: Node.js (axios) z ProxyHat SDK — rotacja IP po liście symboli

const axios = require('axios');
const pLimit = require('p-limit');

const PROXYHAT = {
  host: 'gate.proxyhat.com',
  port: 8080,
  auth: { username: 'user-country-DE', password: 'pass' }
};

const limit = pLimit(5); // max 5 współbieżnych

async function scrapeOrderbooks(symbols) {
  const results = [];
  await Promise.all(symbols.map(sym =>
    limit(async () => {
      for (let attempt = 0; attempt < 3; attempt++) {
        try {
          const { data } = await axios.get(
            'https://api.bybit.com/v5/market/orderbook',
            {
              params: { category: 'spot', symbol: sym, limit: 50 },
              proxy: PROXYHAT,
              timeout: 8000
            }
          );
          if (data.retCode !== 0) throw new Error(data.retMsg);
          results.push({ symbol: sym, bids: data.result.b.slice(0, 5) });
          return;
        } catch (err) {
          if (attempt === 2) {
            results.push({ symbol: sym, error: err.message });
            return;
          }
          await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
        }
      }
    })
  ));
  return results;
}

scrapeOrderbooks(['BTCUSDT', 'ETHUSDT', 'SOLUSDT']).then(console.log);

Każde żądanie przechodzi przez bramę ProxyHat. Parametr country-DE w nazwie użytkownika utrzymuje stałą lokalizację, ale IP rotuje między żądaniami (chyba że dodasz session-...). Limit współbieżności 5 zapobiega burstom.

Przykład 3: Python (requests) z surowym proxy i retry

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

PROXY = "http://user-country-DE:pass@gate.proxyhat.com:8080"

session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
retry = Retry(
    total=3,
    backoff_factor=1.5,
    status_forcelist=[429, 500, 502, 503],
    allowed_methods=["GET"]
)
session.mount("https://", HTTPAdapter(max_retries=retry))

def fetch_tickers(category="linear"):
    resp = session.get(
        "https://api.bybit.com/v5/market/tickers",
        params={"category": category},
        timeout=10
    )
    resp.raise_for_status()
    payload = resp.json()
    if payload["retCode"] != 0:
        raise RuntimeError(f"Bybit error {payload['retCode']}: {payload['retMsg']}")
    return payload["result"]["tickerList"]

tickers = fetch_tickers("linear")
print(f"Pobrano {len(tickers)} tickerów")
print(tickers[0]["symbol"], tickers[0]["lastPrice"])

Retry z backoff_factor=1.5 odczekuje 1.5s, 3s, 4.5s przed kolejnymi próbami. To wystarczy, aby przeczekać chwilowe 429 bez banu.

Przykład 4: Python (aiohttp) — sticky session dla paginacji kline

Paginacja kline wymaga spójnego IP, aby uniknąć resetu kursora. Sticky session utrzymuje ten sam adres IP przez cały ciąg żądań.

import asyncio
import aiohttp

async def fetch_klines(symbol, category="linear", interval="60", max_pages=10):
    session_id = "kline-btc-001"
    proxy = (
        f"http://user-session-{session_id}-country-DE:pass"
        "@gate.proxyhat.com:8080"
    )
    all_candles = []
    connector = aiohttp.TCPConnector(limit=20)
    async with aiohttp.ClientSession(connector=connector) as http:
        cursor = ""
        for page in range(max_pages):
            params = {
                "category": category,
                "symbol": symbol,
                "interval": interval,
                "limit": "1000"
            }
            if cursor:
                params["cursor"] = cursor
            async with http.get(
                "https://api.bybit.com/v5/market/kline",
                params=params,
                proxy=proxy,
                timeout=aiohttp.ClientTimeout(total=15)
            ) as r:
                data = await r.json()
            if data["retCode"] != 0:
                raise RuntimeError(f"{data['retCode']}: {data['retMsg']}")
            all_candles.extend(data["result"]["list"])
            cursor = data["result"].get("nextPageCursor", "")
            if not cursor:
                break
            await asyncio.sleep(0.25)  # szanuj limit per-endpoint
    return all_candles

candles = asyncio.run(fetch_klines("BTCUSDT"))
print(f"Pobrano {len(candles)} świec")

Flaga session-kline-btc-001 przywiązuje wszystkie żądania w funkcji do jednego IP. Bez niej każde żądanie dostałoby nowy IP, a kursor paginacji mógłby się nie zachować prawidłowo po stronie Bybit.

Przykład 5: Node.js — budget per-endpoint z backoffem

Gdy scrapujesz wiele endpointów jednocześnie, każdy potrzebuje własnego budżetu. Poniższy przykład używa token bucket per-endpoint.

const axios = require('axios');

class RateBudget {
  constructor(maxPerSec) {
    this.maxPerSec = maxPerSec;
    this.tokens = maxPerSec;
    this.lastRefill = Date.now();
  }
  async take() {
    const now = Date.now();
    const elapsed = (now - this.lastRefill) / 1000;
    this.tokens = Math.min(this.maxPerSec, this.tokens + elapsed * this.maxPerSec);
    this.lastRefill = now;
    if (this.tokens < 1) {
      await new Promise(r => setTimeout(r, (1 - this.tokens) / this.maxPerSec * 1000));
      this.tokens = 0;
    } else {
      this.tokens -= 1;
    }
  }
}

const budgets = {
  orderbook: new RateBudget(8),   // ~8 req/s na IP
  tickers: new RateBudget(5),
  kline: new RateBudget(3)
};

async function callBybit(endpoint, params, budgetKey) {
  const budget = budgets[budgetKey];
  for (let attempt = 0; attempt < 4; attempt++) {
    await budget.take();
    try {
      const { data } = await axios.get(`https://api.bybit.com${endpoint}`, {
        params,
        proxy: {
          host: 'gate.proxyhat.com',
          port: 8080,
          auth: { username: 'user-country-DE', password: 'pass' }
        },
        timeout: 8000
      });
      if (data.retCode !== 0) throw new Error(data.retMsg);
      return data.result;
    } catch (err) {
      if (attempt === 3) throw err;
      await new Promise(r => setTimeout(r, 500 * Math.pow(2, attempt)));
    }
  }
}

// użycie
const ob = await callBybit('/v5/market/orderbook',
  { category: 'spot', symbol: 'BTCUSDT', limit: 50 }, 'orderbook');
console.log('top bid:', ob.b[0]);

Budżet 8 req/s dla orderbook zostawia margines pod limit Bybit. Backoff wykładniczy (0.5s, 1s, 2s) chroni przed kaskadowymi 403.

Przykład 6: WebSocket orderbook.50 vs REST snapshot

REST /v5/market/orderbook zwraca snapshot — idealny do punktowego odczytu. Do live depth lepiej użyć publicznego WebSocket wss://stream.bybit.com/v5/public/spot i strumienia orderbook.50.{symbol}.

const WebSocket = require('ws');

const ws = new WebSocket('wss://stream.bybit.com/v5/public/spot');

ws.on('open', () => {
  ws.send(JSON.stringify({
    op: 'subscribe',
    args: ['orderbook.50.BTCUSDT']
  }));
});

ws.on('message', (raw) => {
  const msg = JSON.parse(raw);
  if (msg.topic && msg.topic.startsWith('orderbook.50')) {
    const { b, a, u } = msg.data;
    console.log(`update seq=${u} bids=${b.length} asks=${a.length}`);
  }
});

ws.on('error', (err) => console.error('WS error:', err.message));

// reconnect z backoffem w produkcji
setInterval(() => {
  if (ws.readyState === WebSocket.CLOSED) {
    ws.close();
    // ponowne połączenie...
  }
}, 5000);

WebSocket nie wymaga proxy dla samych limitów IP (połączenie jest długotrwałe), ale jeśli jesteś w zablokowanym regionie, kieruj WebSocket przez SOCKS5 ProxyHat na porcie 1080. Większość bibliotek WS wspiera agenta SOCKS5 przez socks-proxy-agent.

Najczęstsze błędy i przypadki brzegowe

  • Ignorowanie retCode. HTTP 200 z retCode=10010 to nadal błąd limitu. Zawsze sprawdzaj kopertę.
  • Mieszanie kategorii. category=spot dla symbolu linear zwróci błąd lub puste dane.
  • Zbyt wysoka współbieżność. 50 współbieżnych żądań orderbook z jednego IP = gwarantowany ban. Utrzymuj ≤10.
  • Brak sticky session przy paginacji. Kursor kline może się zachowywać niestabilnie przy zmianie IP między stronami.
  • Geo-blokada datacenter. Proxy datacenter w zablokowanym kraju nie pomogą — użyj residential z country-DE lub innym dozwolonym.
  • Brak timeoutów. Zawieszone żądania blokują pulę połączeń. Ustaw timeout 8–15s.

Najlepsze praktyki produkcyjne

  • Rejestruj retCode. Loguj każdy niezerowy retCode z timestampem i symbolem — to ujawnia wzorce limitów.
  • Circuit breaker. Jeśli >20% żądań zwraca 403 w oknie 60s, wstrzymaj scrap na 5 minut zamiast nakręcać ban.
  • Rotacja per-żądanie vs sticky. Rotacja dla tickers/orderbook; sticky dla kline paginacji i długich ciągów.
  • Monitoruj sukces. Celuj w >95% success rate. Spadek poniżej 80% oznacza zbliżający się ban lub geo-blokadę.
  • Szanuj ToS. Publiczne dane rynkowe są dozwolone, ale respektuj robots.txt i dokumentację API. Nie próbuj omijać limitów autoryzowanych endpointów prywatnych.

Pełną dokumentację ProxyHat znajdziesz na docs.proxyhat.com.

Najważniejsze wnioski

  • Sprawdzaj retCode przy każdym żądaniu — HTTP 200 nie oznacza sukcesu.
  • Orderbook ma najsurowsze limity IP; utrzymuj ≤8 req/s na IP.
  • Geo-blokady (US/UK) wymagają proxy residential z country-XX w nazwie użytkownika.
  • Sticky session (session-abc123) jest kluczowa dla paginacji kline.
  • WebSocket orderbook.50 jest lepszy do live depth; REST do snapshotów.
  • Backoff wykładniczy + circuit breaker zapobiegają kaskadowym banom.

Scrapowanie API rynku Bybit V5 z rotującymi proxy to kwestia szacowania limitów, geo-targetingu i spójności sesji. ProxyHat daje Ci jedną bramę (gate.proxyhat.com:8080) z elastyczną konfiguracją w nazwie użytkownika — wystarczy, by utrzymać stabilny potok danych rynkowych. Zacznij od cennika i wybierz pakiet residential pasujący do Twojego throughput.

Często zadawane pytania

Czym jest scrapowanie API rynku Bybit V5 z rotującymi proxy?

To technika pobierania publicznych danych rynkowych z endpointów api.bybit.com/v5/market/ przy użyciu proxy, które automatycznie zmienia adres IP między żądaniami. Pozwala to omijać limity IP, geo-blokady i blokady CloudFront, utrzymując jednocześnie stabilny dostęp do orderbook, tickers i kline.

Dlaczego rotujące proxy mają znaczenie dla scrapowania Bybit API?

Bybit nakłada limity IP na endpointy /v5/market/orderbook i inne, a nadmiarowe żądania mogą skutkować błędem 403 i banem na około 10 minut. Rotujące proxy rozpraszają ruch na wiele adresów IP, co zmniejsza ryzyko wyczerpania limitu i utrzymuje wyższy throughput dla botów handlowych.

Który typ proxy najlepiej sprawdza się przy scrapowaniu Bybit V5 API?

Proxy residential są najlepsze, ponieważ pochodzą z prawdziwych adresów ISP i rzadziej są wykrywane przez CDN Bybit (CloudFront). Proxy datacenter mogą być szybsze, ale są łatwiej blokowane. Proxy mobile są alternatywą, ale zazwyczaj droższe i wolniejsze.

Jak unikać blokad przy scrapowaniu Bybit V5 Market API?

Używaj rotujących proxy residential z geo-targetingiem na dozwolone kraje, zachowuj limity per-endpoint, wdrażaj wycofywanie (backoff) przy błędach 429/403 i utrzymuj niską współbieżność. Sticky sessions pomagają przy paginacji kline, zachowując ten sam IP w ramach jednego ciągu żądań.

Sprawdź konfigurację proxy w kilka sekund

Darmowy tester proxy — potwierdź, że Twoje IP są szybkie, anonimowe i nieblokowane.

Sprawdź proxy za darmo
← Powrót do Bloga