Como Raspar a Bybit V5 Market API com Proxies Rotativos

Guia prático para desenvolvedores sobre como raspar os endpoints públicos /v5/market da Bybit com proxies residenciais rotativos via ProxyHat, incluindo rate limits, geo-restrições e WebSocket.

How to Scrape the Bybit V5 Market API with Rotating Proxies
Neste artigo

Raspar a Bybit V5 Market API é tentador para bots de trading e pipelines de dados de cripto: os endpoints públicos de orderbook, tickers e klines não exigem autenticação e respondem em poucas dezenas de milissegundos. O problema aparece quando você passa de algumas requisições de teste para centenas de símbolos em loop — a Bybit impõe limites rigorosos por IP, bloqueia regiões inteiras via CloudFront e pode banir seu endereço por ~10 minutos. Neste guia você vai aprender como raspar a Bybit V5 Market API com proxies rotativos usando o gateway gate.proxyhat.com, com exemplos em Python e Node.js, sessões sticky para paginação de klines e fallback para WebSocket.

Aviso legal: Este guia cobre apenas endpoints públicos de dados de mercado da Bybit (/v5/market/*). Sempre consulte os Termos de Serviço da Bybit e respeite robots.txt antes de coletar dados em escala. Não incentivamos scraping de endpoints autenticados, de conta ou de trading.

Por que raspar a Bybit V5 Market API com proxies rotativos é necessário

A V5 é a API unificada da Bybit, documentada em docs.bybit.com/v5/market. Ela substitui as antigas v2/v3 e unifica spot, linear e option sob o parâmetro category. O domínio público é api.bybit.com, servido atrás da AWS CloudFront, o que significa que bloqueios geo aparecem como 403 Forbidden antes mesmo de chegar à aplicação.

Existem dois motivos principais para usar proxies ao raspar a Bybit:

  • Rate limits por IP: Cada endpoint tem um teto de requisições por segundo por IP de origem. Estourar repetidamente gera 403 e uma janela de ban de ~10 minutos.
  • Geo-restrições: A Bybit bloqueia usuários em regiões restritas (EUA, Reino Unido, Canadá, Singapura, entre outras). Sem um IP de país permitido, a CloudFront devolve 403 sem corpo JSON.

Com proxies residenciais rotativos do ProxyHat, cada requisição (ou cada sessão) sai de um IP diferente localizado em um país permitido, contornando ambos os problemas de forma elegante.

Mapa dos endpoints públicos /v5/market

EndpointUsoParams obrigatórios
GET /v5/market/orderbookSnapshot de livro de ofertascategory, symbol
GET /v5/market/tickersCotação atual de um ou todos os símboloscategory
GET /v5/market/klineVelas OHLCV históricascategory, symbol, interval
GET /v5/market/recent-tradeTrades recentescategory, symbol

Todos retornam o envelope padrão:

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

retCode: 0 indica sucesso. Qualquer valor diferente (ex.: 10001 para parâmetro inválido, 403 para bloqueio) exige tratamento explícito. Veja a lista oficial de códigos de erro.

Rate limits da Bybit: como o /v5/market/orderbook derruba seu IP

A Bybit aplica limites por endpoint e por IP de origem. Para dados públicos de mercado, os limites típicos são:

  • Orderbook: ~50 requisições/seg por IP (categoria spot/linear).
  • Tickers: ~10 req/s por IP.
  • Kline: ~10 req/s por IP.
  • Recent-trade: ~20 req/s por IP.

Esses números mudam — confirme sempre na documentação oficial. O ponto crítico é o orderbook: em bots de market-making que fazem polling agressivo de profundidade, é trivial estourar 50 req/s em um único IP. Quando isso acontece repetidamente, a Bybit retorna 403 e o IP entra numa janela de cooldown de aproximadamente 10 minutos.

Estratégias de mitigação:

  1. Rate budgeting por endpoint: Use um token bucket ou semáforo para limitar a concorrência real.
  2. Backoff exponencial: Em 403 ou 429, espere 1s, 2s, 4s, 8s e reinicie.
  3. Rotação de IP: Cada requisição sai de um IP diferente, efetivamente multiplicando seu teto de throughput.

Geo-restrições da Bybit e como proxies residenciais restauram acesso

A Bybit restringe acesso de residentes em jurisdições como EUA, Reino Unido, Canadá, Singapura, Cuba, Irã, Coreia do Norte e outras. A filtragem acontece na borda da CloudFront: o IP de origem é comparado a uma lista de blocos de ASN/país e, se restrito, a CloudFront devolve 403 sem chegar ao backend da Bybit.

Para bots de dados que rodam em clouds US/EU, isso é fatal: mesmo endpoints públicos de mercado ficam inacessíveis. A solução é rotear o tráfego por um proxy residencial localizado em um país permitido, como Alemanha, Japão ou Brasil.

Com o ProxyHat você controla o país diretamente no username:

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

Para SOCKS5:

socks5://user-country-DE:pass@gate.proxyhat.com:1080

Você também pode segmentar por cidade: user-country-DE-city-berlin. Consulte a lista completa em /pt/locations.

Exemplo 1: curl com proxy bruto (linha de comando)

Antes de qualquer SDK, valide manualmente que o proxy funciona contra a Bybit:

# Orderbook spot BTCUSDT via proxy residencial em DE
curl -x http://user-country-DE:SUA_SENHA@gate.proxyhat.com:8080 \
  "https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=50"

# Tickers linear
url -x http://user-country-DE:SUA_SENHA@gate.proxyhat.com:8080 \
  "https://api.bybit.com/v5/market/tickers?category=linear"

# Kline 1m, últimos 200 candles
url -x http://user-country-DE:SUA_SENHA@gate.proxyhat.com:8080 \
  "https://api.bybit.com/v5/market/kline?category=linear&symbol=ETHUSDT&interval=1&limit=200"

Se você receber JSON com retCode: 0, o proxy está funcionando. Se receber HTML da CloudFront com 403, troque o país (algumas saídas residenciais podem estar em ASNs bloqueados — rotacione).

Exemplo 2: Python com requests + proxy bruto

import os
import time
import logging
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")

BYBIT_BASE = "https://api.bybit.com"
PROXY_USER = os.environ["PROXYHAT_USER"]
PROXY_PASS = os.environ["PROXYHAT_PASS"]
PROXY_URL = f"http://{PROXY_USER}-country-DE:{PROXY_PASS}@gate.proxyhat.com:8080"

session = requests.Session()
retry = Retry(
    total=5,
    backoff_factor=1.5,  # 1.5s, 3s, 6s, 12s, 24s
    status_forcelist=(429, 403, 500, 502, 503),
    allowed_methods=["GET"],
)
session.mount("https://", HTTPAdapter(max_retries=retry))
session.proxies.update({"http": PROXY_URL, "https": PROXY_URL})

def fetch_orderbook(symbol: str, category: str = "linear", limit: int = 50):
    url = f"{BYBIT_BASE}/v5/market/orderbook"
    params = {"category": category, "symbol": symbol, "limit": limit}
    r = session.get(url, params=params, timeout=10)
    r.raise_for_status()
    body = r.json()
    if body.get("retCode") != 0:
        raise RuntimeError(f"Bybit retCode={body.get('retCode')} msg={body.get('retMsg')}")
    return body["result"]

if __name__ == "__main__":
    symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "XRPUSDT"]
    for sym in symbols:
        try:
            ob = fetch_orderbook(sym)
            bid = float(ob["b"][0][0])
            ask = float(ob["a"][0][0])
            logging.info("%s bid=%s ask=%s spread=%.4f", sym, bid, ask, ask - bid)
        except Exception as e:
            logging.error("%s falhou: %s", sym, e)
        time.sleep(0.2)  # rate budget: 5 req/s

Note o rate budget de 0.2s entre chamadas — mesmo com proxy, respeitar o teto por IP evita desperdício de sessões. O Retry do urllib3 trata 403/429 automaticamente com backoff exponencial.

Exemplo 3: Python com ProxyHat SDK (rotação automática)

O ProxyHat SDK abstrai a rotação de IP, retries e seleção de país. Você não precisa construir URLs de proxy manualmente:

import asyncio
import logging
from proxyhat import ProxyHatClient  # pacote: pip install proxyhat

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")

client = ProxyHatClient(
    username="SUA_SENHA_USER",
    password="SUA_SENHA",
    country="DE",
    rotate=True,          # IP novo a cada requisição
    max_retries=5,
    backoff_factor=1.5,
    timeout=10,
)

BYBIT = "https://api.bybit.com/v5/market"

async def fetch_tickers(category: str = "linear"):
    async with client.get(f"{BYBIT}/tickers", params={"category": category}) as r:
        data = await r.json()
        if data["retCode"] != 0:
            raise RuntimeError(f"retCode={data['retCode']} msg={data['retMsg']}")
        return data["result"]["list"]

async def fetch_orderbook(symbol: str, category: str = "linear", limit: int = 50):
    async with client.get(
        f"{BYBIT}/orderbook",
        params={"category": category, "symbol": symbol, "limit": limit},
    ) as r:
        data = await r.json()
        return data["result"]

async def main():
    tickers = await fetch_tickers("linear")
    logging.info("Recebidos %d tickers linear", len(tickers))
    symbols = [t["symbol"] for t in tickers[:10]]
    tasks = [fetch_orderbook(s) for s in symbols]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    for sym, res in zip(symbols, results):
        if isinstance(res, Exception):
            logging.error("%s: %s", sym, res)
        else:
            logging.info("%s top bid=%s", sym, res["b"][0][0])

asyncio.run(main())

Aqui usamos asyncio.gather para paralelizar 10 chamadas de orderbook. Como cada uma sai de um IP diferente via rotate=True, o teto de 50 req/s por IP não é um problema.

Exemplo 4: Node.js com axios e rotação de IP

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { ProxyHat } = require('proxyhat');

const PROXYHAT_USER = process.env.PROXYHAT_USER;
const PROXYHAT_PASS = process.env.PROXYHAT_PASS;

// Cliente ProxyHat com rotação por requisição
const ph = new ProxyHat({
  username: PROXYHAT_USER,
  password: PROXYHAT_PASS,
  country: 'DE',
  rotate: true,
  maxRetries: 5,
  backoffFactor: 1.5,
});

const BYBIT = 'https://api.bybit.com/v5/market';

async function fetchOrderbook(symbol, category = 'linear', limit = 50) {
  const proxyUrl = await ph.nextProxyUrl(); // http://user-country-DE:pass@gate.proxyhat.com:8080
  const agent = new HttpsProxyAgent(proxyUrl);
  const { data } = await axios.get(`${BYBIT}/orderbook`, {
    params: { category, symbol, limit },
    httpsAgent: agent,
    timeout: 10000,
  });
  if (data.retCode !== 0) {
    throw new Error(`retCode=${data.retCode} msg=${data.retMsg}`);
  }
  return data.result;
}

async function main() {
  const symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT'];
  const results = await Promise.allSettled(
    symbols.map((s) => fetchOrderbook(s).catch(async (err) => {
      // backoff manual em caso de 403
      if (err.response && err.response.status === 403) {
        await new Promise((r) => setTimeout(r, 2000));
        return fetchOrderbook(s);
      }
      throw err;
    }))
  );
  results.forEach((r, i) => {
    if (r.status === 'fulfilled') {
      console.log(symbols[i], 'bid=', r.value.b[0][0], 'ask=', r.value.a[0][0]);
    } else {
      console.error(symbols[i], 'falhou:', r.reason.message);
    }
  });
}

main();

O Promise.allSettled garante que uma falha em um símbolo não derruba o batch inteiro. O backoff manual em 403 complementa o retry interno do SDK.

Exemplo 5: Sessões sticky para paginação de klines

O endpoint /v5/market/kline retorna no máximo 1000 candles por chamada. Para construir séries históricas longas, você pagina via start e end (timestamps em ms). O problema: se cada chamada sair de um IP diferente, você pode acabar com lacunas se um IP for banido no meio da sequência.

A solução é uma sessão sticky — o ProxyHat mantém o mesmo IP de saída durante toda a sessão:

import os
import time
import requests

PROXY_USER = os.environ["PROXYHAT_USER"]
PROXY_PASS = os.environ["PROXYHAT_PASS"]

# Sessão sticky: mesmo IP durante toda a coleta de klines
PROXY_URL = f"http://{PROXY_USER}-session-kline-btc-001:{PROXY_PASS}@gate.proxyhat.com:8080"

session = requests.Session()
session.proxies.update({"http": PROXY_URL, "https": PROXY_URL})

def fetch_klines(symbol, category, interval, start_ms, end_ms):
    url = "https://api.bybit.com/v5/market/kline"
    params = {
        "category": category,
        "symbol": symbol,
        "interval": interval,
        "start": start_ms,
        "end": end_ms,
        "limit": 1000,
    }
    r = session.get(url, params=params, timeout=10)
    r.raise_for_status()
    body = r.json()
    if body["retCode"] != 0:
        raise RuntimeError(f"retCode={body['retCode']} msg={body['retMsg']}")
    return body["result"]["list"]

def collect_history(symbol, category, interval, days=30):
    end_ms = int(time.time() * 1000)
    start_ms = end_ms - days * 24 * 3600 * 1000
    all_candles = []
    cursor = start_ms
    while cursor < end_ms:
        batch = fetch_klines(symbol, category, interval, cursor, end_ms)
        if not batch:
            break
        all_candles.extend(batch)
        # próximo batch: último timestamp + 1ms
        cursor = int(batch[-1][0]) + 1
        time.sleep(0.15)  # rate budget: ~6 req/s, abaixo do teto de 10
    return all_candles

if __name__ == "__main__":
    candles = collect_history("BTCUSDT", "linear", "60", days=7)
    print(f"Coletados {len(candles)} candles de 1h em 7 dias")

O flag -session-kline-btc-001 no username garante que o ProxyHat atribua um IP residencial fixo para essa string de sessão. Se você rodar múltiplos símbolos em paralelo, use IDs de sessão distintos por símbolo (-session-kline-eth-001, etc.) para distribuir a carga entre IPs.

Exemplo 6: WebSocket público vs REST snapshot

Para orderbook em tempo real, REST polling é ineficiente. A Bybit oferece um stream WebSocket público em wss://stream.bybit.com/v5/public/linear com o canal orderbook.50.BTCUSDT, que entrega snapshots incrementais a ~10ms. Para bots de market-making, essa é a fonte canônica.

import json
import asyncio
import websockets

async def listen_orderbook():
    url = "wss://stream.bybit.com/v5/public/linear"
    async with websockets.connect(url, ping_interval=20) as ws:
        # Snapshot inicial
        await ws.send(json.dumps({
            "op": "subscribe",
            "args": ["orderbook.50.BTCUSDT"]
        }))
        async for msg in ws:
            data = json.loads(msg)
            if data.get("topic", "").startswith("orderbook.50"):
                ob = data["data"]
                top_bid = ob["b"][0][0] if ob["b"] else None
                top_ask = ob["a"][0][0] if ob["a"] else None
                print(f"type={data['type']} bid={top_bid} ask={top_ask}")

asyncio.run(listen_orderbook())

Comparação rápida:

AspectoREST /v5/market/orderbookWebSocket orderbook.50
Latência~50-200ms (com proxy)~10-50ms
Taxa de atualizaçãoSob demanda (polling)Push em tempo real
Custo de IPAlto (rate limit por IP)Baixo (1 conexão persistente)
Ideal paraSnapshot histórico, backfillMarket-making, execução ao vivo

Nota: o WebSocket público da Bybit também pode sofrer geo-restrição. Se necessário, conecte via socks5://user-country-DE:pass@gate.proxyhat.com:1080.

Erros comuns e edge cases

  • 403 sem corpo JSON: É CloudFront bloqueando por geo. Troque o país do proxy.
  • retCode 10001: Parâmetro inválido — verifique category (spot vs linear vs option).
  • retCode 403 ou 429: Rate limit excedido. Faça backoff e reduza a concorrência.
  • IP banido por 10 minutos: Se você insiste após 403, o ban se prolonga. Implemente circuit breaker.
  • Lacunas em klines: Use sessões sticky e valide retCode em cada batch.
  • Símbolos deslistados: Sempre consulte /v5/market/instruments-info antes de raspar tickers de símbolos que podem ter sido removidos.
  1. Crie sua conta em /pt/pricing e escolha um plano residencial adequado ao seu volume.
  2. Configure as variáveis de ambiente PROXYHAT_USER e PROXYHAT_PASS.
  3. Escolha países permitidos pela Bybit (DE, JP, BR, etc.) consultando /pt/locations.
  4. Para casos de uso de scraping em geral, veja /pt/use-cases/web-scraping.
  5. Para tracking de SERP e monitoramento de concorrentes, veja /pt/use-cases/serp-tracking.
  6. Documentação técnica do ProxyHat: docs.proxyhat.com.

Key Takeaways

  • Rate limit por IP é o gargalo número 1. O orderbook tem ~50 req/s por IP; bursts derrubam o IP por ~10 min.
  • Geo-restrição vem da CloudFront. 403 sem JSON = bloqueio de país. Use proxy residencial em país permitido.
  • Sessões sticky para paginação. Use -session-xxx no username para manter o mesmo IP em sequências longas de klines.
  • WebSocket para tempo real, REST para snapshots. Não faça polling de orderbook se você precisa de <50ms de latência.
  • Sempre valide retCode. A Bybit não usa HTTP status para erros de aplicação — retCode != 0 exige tratamento.

FAQ

O que é raspar a Bybit V5 Market API com proxies rotativos?

É a prática de coletar dados públicos de mercado da Bybit (orderbook, tickers, klines, trades recentes) roteando cada requisição HTTP por um proxy residencial diferente, evitando rate limits por IP e contornando geo-restrições da CloudFront. O ProxyHat fornece o gateway gate.proxyhat.com:8080 (HTTP) ou :1080 (SOCKS5) com rotação automática e geo-targeting por país.

Por que isso importa para usuários de proxy?

Porque a Bybit impõe limites estritos por IP (~50 req/s no orderbook) e bloqueia regiões inteiras via CloudFront. Sem rotação de IP, um bot de trading que monitora 50 símbolos em polling pode ser banido em minutos. Proxies residenciais rotativos multiplicam o teto efetivo de throughput e restauram o acesso de clouds em países restritos, permitindo coleta de dados em escala.

Qual tipo de proxy funciona melhor para raspar a Bybit V5 Market API?

Proxies residenciais são a melhor escolha porque seus IPs vêm de ASNs de ISPs reais, dificilmente bloqueados pela CloudFront. Datacenter proxies tendem a ser flaggeados como datacenter e bloqueados mais rápido. Para paginação de klines, use sessões sticky (-session-xxx) para manter consistência de IP durante a sequência. Para polling de orderbook em paralelo, use rotação pura.

Como evitar bloqueios ao raspar a Bybit V5 Market API?

Implemente rate budgeting (token bucket por endpoint), backoff exponencial em 403/429, circuit breaker após N falhas consecutivas, e rotação de IP via ProxyHat. Mantenha concorrência abaixo do teto por IP (ex.: 5 req/s para orderbook com 1 IP, ou 50 req/s com 10 IPs rotativos). Sempre valide retCode no envelope de resposta e consulte a documentação oficial para limites atualizados.

WebSocket público da Bybit também precisa de proxy?

Pode precisar. O endpoint WebSocket wss://stream.bybit.com/v5/public/linear também passa pela CloudFront e pode sofrer geo-restrição. Se sua infraestrutura está em país bloqueado, conecte via SOCKS5 (socks5://user-country-DE:pass@gate.proxyhat.com:1080). WebSocket tem vantagem sobre REST: uma única conexão persistente substitui centenas de polls, reduzindo drasticamente o consumo de IPs.

Perguntas frequentes

O que é raspar a Bybit V5 Market API com proxies rotativos?

É a prática de coletar dados públicos de mercado da Bybit (orderbook, tickers, klines, trades recentes) roteando cada requisição HTTP por um proxy residencial diferente, evitando rate limits por IP e contornando geo-restrições da CloudFront. O ProxyHat fornece o gateway gate.proxyhat.com:8080 (HTTP) ou :1080 (SOCKS5) com rotação automática e geo-targeting por país.

Por que isso importa para usuários de proxy?

Porque a Bybit impõe limites estritos por IP (~50 req/s no orderbook) e bloqueia regiões inteiras via CloudFront. Sem rotação de IP, um bot de trading que monitora 50 símbolos em polling pode ser banido em minutos. Proxies residenciais rotativos multiplicam o teto efetivo de throughput e restauram o acesso de clouds em países restritos.

Qual tipo de proxy funciona melhor para raspar a Bybit V5 Market API?

Proxies residenciais são a melhor escolha porque seus IPs vêm de ASNs de ISPs reais, dificilmente bloqueados pela CloudFront. Datacenter proxies tendem a ser flaggeados como datacenter e bloqueados mais rápido. Para paginação de klines, use sessões sticky (-session-xxx) para manter consistência de IP durante a sequência.

Como evitar bloqueios ao raspar a Bybit V5 Market API?

Implemente rate budgeting (token bucket por endpoint), backoff exponencial em 403/429, circuit breaker após N falhas consecutivas, e rotação de IP via ProxyHat. Mantenha concorrência abaixo do teto por IP. Sempre valide retCode no envelope de resposta e consulte a documentação oficial para limites atualizados.

WebSocket público da Bybit também precisa de proxy?

Pode precisar. O endpoint WebSocket wss://stream.bybit.com/v5/public/linear também passa pela CloudFront e pode sofrer geo-restrição. Se sua infraestrutura está em país bloqueado, conecte via SOCKS5 (socks5://user-country-DE:pass@gate.proxyhat.com:1080). WebSocket tem vantagem sobre REST: uma única conexão persistente substitui centenas de polls.

Pronto para começar?

Proxies residenciais, ISP e móveis em mais de 148 países. Crie uma conta grátis.

Criar conta grátis
← Voltar ao Blog