L'API Market V5 de Bybit expose des données publiques essentielles — carnets d'ordres, tickers, bougies OHLCV et transactions récentes — via api.bybit.com/v5/market/. Mais les développeurs de bots de trading et de pipelines de données se heurtent rapidement aux limites de taux par IP et aux blocages géographiques. Dans ce guide, nous expliquons comment scraper l'API Market Bybit V5 avec des proxys rotatifs, avec du code runnable en Node.js et Python, une gestion rigoureuse des rate limits et des sessions sticky pour la pagination.
Avertissement : les endpoints
/v5/market/diffusent des données de marché publiques. Vérifiez toujours les conditions d'utilisation de Bybit avant toute collecte automatisée. Ce guide couvre uniquement les données publiques, non authentifiées, et ne traite pas des endpoints de trading privés.
Comment scraper l'API Market Bybit V5 avec des proxys rotatifs : vue d'ensemble
L'API V5 unifiée de Bybit regroupe les anciennes API spot, dérivés et options sous un même domaine. Les endpoints de marché publics se trouvent sous /v5/market/ et ne nécessitent aucune authentification. Chaque réponse suit une enveloppe standard :
{
"retCode": 0,
"retMsg": "OK",
"result": { ... },
"time": 1700000000000
}
Un retCode différent de 0 indique une erreur — par exemple 10001 pour un paramètre invalide ou un code spécifique pour un throttling. Voici les quatre endpoints principaux pour le bybit api scraping :
| Endpoint | Paramètres requis | Limite indicative | Cas d'usage |
|---|---|---|---|
/v5/market/orderbook | category, symbol, limit | 120 req/min | Snapshot de profondeur |
/v5/market/tickers | category | 100 req/min | Prix et stats en temps réel |
/v5/market/kline | category, symbol, interval, limit | 60 req/min | Bougies OHLCV historiques |
/v5/market/recent-trade | category, symbol | 80 req/min | Transactions récentes |
Le paramètre category est central : il accepte spot, linear (contrats perpétuels/futures USDT), inverse ou option. Pour scrape bybit order book en spot, utilisez category=spot. Pour les perpétuels USDT, utilisez category=linear. Le paramètre limit de l'orderbook accepte les valeurs 1, 25, 50, 100 et 200, contrôlant la profondeur retournée. Consultez la documentation officielle de l'API V5 pour le détail complet des paramètres.
Rate limits et bannissements IP chez Bybit
Bybit applique des limites de taux par adresse IP sur chaque endpoint. Dépasser la limite déclenche d'abord des 429 Too Many Requests, puis un 403 Forbidden si le comportement persiste. Le bannissement IP dure environ 10 minutes selon les retours de la communauté, mais peut s'étendre en cas d'abus répétés. L'endpoint api.bybit.com/v5/market/orderbook est particulièrement sensible car les développeurs ont tendance à le poller en rafale pour suivre la profondeur.
Les limites varient par endpoint et par catégorie. D'après la documentation de rate limit de Bybit, les endpoints de marché public partagent un budget global par IP. Une stratégie de burst sur /v5/market/orderbook peut épuiser ce budget et bloquer tous les autres endpoints de marché pour la même IP.
Les symptômes typiques :
retCodedifférent de 0 avecretMsgindiquant un dépassement de taux- HTTP 403 avec un body CloudFront (blocage géo ou IP)
- Timeouts intermittents indiquant un throttling côté serveur
La solution : distribuer vos requêtes sur plusieurs IPs via un proxy rotatif et respecter un budget par endpoint. Un délai de 200ms entre requêtes sur la même IP suffit généralement à rester sous la limite pour /v5/market/orderbook.
Geo-restrictions : pourquoi Bybit bloque certaines IPs
Bybit restreint l'accès depuis plusieurs juridictions, notamment les États-Unis, le Royaume-Uni, Singapour et le Canada. Les requêtes depuis ces régions reçoivent un 403 via CloudFront, le CDN d'AWS, avant même d'atteindre l'API. Cela affecte aussi l'API publique de marché — pas seulement le trading.
Les proxys résidentiels résolvent ce problème en faisant transiter vos requêtes via une IP d'un pays autorisé (Allemagne, Japon, etc.). Avec ProxyHat, le géo-ciblage se fait directement dans le nom d'utilisateur :
# Proxy HTTP avec géo-ciblage Allemagne
curl -x http://user-country-DE:pass@gate.proxyhat.com:8080 \
"https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=50"
Le format user-country-DE indique à ProxyHat d'utiliser une IP résidentielle allemande. Consultez la liste complète des pays disponibles sur notre page des localisations. Pour le bybit v5 market api proxy, l'Allemagne, les Pays-Bas ou le Japon sont d'excellents choix car ils ne sont pas sur la liste restreinte et offrent une faible latence vers les serveurs de Bybit.
Implémentation Node.js : rotation d'IP avec axios
Commençons par un exemple brut avec un proxy statique, puis passons à un manager de rotation ProxyHat qui change d'IP à chaque requête.
Proxy statique — récupération des tickers
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
// Proxy brut ProxyHat — IP résidentielle allemande
const agent = new HttpsProxyAgent(
'http://user-country-DE:pass@gate.proxyhat.com:8080'
);
async function fetchTickers(category = 'spot') {
const url = 'https://api.bybit.com/v5/market/tickers?category=' + category;
try {
const { data } = await axios.get(url, {
httpsAgent: agent,
timeout: 10000
});
if (data.retCode !== 0) {
throw new Error('Bybit ' + data.retCode + ': ' + data.retMsg);
}
console.log('Tickers reçus:', data.result.list.length);
return data.result;
} catch (err) {
console.error('Échec:', err.message);
throw err;
}
}
fetchTickers('spot');
ProxyHat rotation manager — orderbook multi-symboles
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
class ProxyHatManager {
constructor(user, pass, host = 'gate.proxyhat.com', port = 8080) {
this.user = user;
this.pass = pass;
this.host = host;
this.port = port;
this.counter = 0;
}
// Rotation : nouvelle session = nouvelle IP
nextAgent(country = 'DE') {
const sid = 'sess' + Date.now() + '_' + this.counter++;
const url = 'http://' + this.user + '-country-' + country
+ '-session-' + sid + ':' + this.pass
+ '@' + this.host + ':' + this.port;
return new HttpsProxyAgent(url);
}
}
const manager = new ProxyHatManager('user', 'pass');
const symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT'];
async function fetchOrderbook(symbol, category = 'spot') {
const agent = manager.nextAgent('DE');
const url = 'https://api.bybit.com/v5/market/orderbook'
+ '?category=' + category + '&symbol=' + symbol + '&limit=50';
const { data } = await axios.get(url, {
httpsAgent: agent,
timeout: 10000
});
if (data.retCode !== 0) {
throw new Error('Bybit ' + data.retCode + ': ' + data.retMsg);
}
return data.result;
}
async function scrapeAll() {
for (const sym of symbols) {
try {
const ob = await fetchOrderbook(sym);
const bestBid = ob.b[0][0];
const bestAsk = ob.a[0][0];
console.log(sym + ': bid=' + bestBid + ' ask=' + bestAsk);
await new Promise(r => setTimeout(r, 200));
} catch (err) {
console.error(sym + ' échec:', err.message);
await new Promise(r => setTimeout(r, 1000));
}
}
}
scrapeAll();
Ce pattern garantit que chaque symbole est fetché depuis une IP différente. Le délai de 200ms entre requêtes est conservé pour respecter le budget de rate limit par IP. Pour des volumes plus élevés, consultez notre tarification et augmentez la concurrence.
Implémentation Python : sessions sticky et pagination kline
Pour /v5/market/kline, la pagination via cursor nécessite une session sticky — la même IP doit être utilisée pour toute la séquence de pages, sinon Bybit peut rejeter le curseur. ProxyHat supporte les sessions sticky via le flag -session- dans le nom d'utilisateur.
Proxy brut — récupération kline simple
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
PROXY = "http://user-country-DE:pass@gate.proxyhat.com:8080"
BASE = "https://api.bybit.com/v5/market"
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
retry = Retry(total=3, backoff_factor=0.5,
status_forcelist=[429, 503])
adapter = HTTPAdapter(max_retries=retry)
session.mount("https://", adapter)
def fetch_kline(symbol, interval="60", limit="200"):
params = {"category": "spot", "symbol": symbol,
"interval": interval, "limit": limit}
resp = session.get(f"{BASE}/kline", params=params, timeout=10)
resp.raise_for_status()
body = resp.json()
if body["retCode"] != 0:
raise Exception(f"retCode {body['retCode']}: {body['retMsg']}")
return body["result"]["list"]
candles = fetch_kline("BTCUSDT")
print(f"Récupéré {len(candles)} bougies")
Session sticky — pagination kline avec backoff exponentiel
import requests
import time
import random
BASE = "https://api.bybit.com/v5/market"
class ProxyHatClient:
def __init__(self, user, pass_, country="DE"):
self.user = user
self.pass_ = pass_
self.country = country
def proxy_url(self, session_id=None):
u = f"{self.user}-country-{self.country}"
if session_id:
u += f"-session-{session_id}"
return f"http://{u}:{self.pass_}@gate.proxyhat.com:8080"
def fetch(self, path, params, session_id=None,
max_retries=3):
proxy = self.proxy_url(session_id)
for attempt in range(max_retries):
try:
resp = requests.get(
f"{BASE}/{path}",
params=params,
proxies={"http": proxy, "https": proxy},
timeout=10
)
if resp.status_code == 403:
raise Exception("403 — IP bloquée")
resp.raise_for_status()
body = resp.json()
if body["retCode"] != 0:
raise Exception(
f"retCode {body['retCode']}: {body['retMsg']}"
)
return body["result"]
except Exception as e:
wait = (2 ** attempt) + random.uniform(0, 1)
print(f"Tentative {attempt+1}: {e}, "
f"attente {wait:.1f}s")
time.sleep(wait)
raise Exception(f"Échec après {max_retries} essais")
client = ProxyHatClient("user", "pass", country="DE")
sid = "kline_btc_001"
all_candles = []
cursor = None
for page in range(5):
params = {"category": "spot", "symbol": "BTCUSDT",
"interval": "60", "limit": "200"}
if cursor:
params["cursor"] = cursor
result = client.fetch("kline", params,
session_id=sid)
candles = result["list"]
all_candles.extend(candles)
cursor = result.get("nextPageCursor")
if not cursor:
break
time.sleep(0.25)
print(f"Total: {len(all_candles)} bougies")
La session kline_btc_001 maintient la même IP résidentielle pendant toute la pagination. Si vous scrapez plusieurs symboles en parallèle, utilisez un session_id différent par symbole pour répartir la charge sur plusieurs IPs tout en gardant la cohérence du curseur par symbole.
REST snapshots vs WebSocket orderbook.50
L'API REST /v5/market/orderbook retourne un snapshot à un instant T. Pour suivre la profondeur en temps réel, Bybit propose un flux WebSocket public sur wss://stream.bybit.com/v5/public/spot avec le topic orderbook.50.{symbol}, qui pousse des mises à jour différentielles à haute fréquence.
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 d = msg.data;
console.log('Update:', d.b?.length, 'bids,',
d.a?.length, 'asks, type:', d.type);
}
});
ws.on('error', (err) => console.error('WS:', err.message));
Le WebSocket ne nécessite généralement pas de proxy pour les données publiques (le flux est accessible globalement), mais si vous êtes dans une région restreinte, un proxy SOCKS5 peut être nécessaire. Dans ce cas, utilisez le port 1080 :
# SOCKS5 ProxyHat pour WebSocket
socks5://user-country-DE:pass@gate.proxyhat.com:1080
Pour la plupart des cas d'usage de bybit api scraping, alternez entre REST (snapshots périodiques avec rotation d'IP) et WebSocket (streaming temps réel) selon vos besoins de latence. Le REST est plus simple à mettre en œuvre et à déboguer ; le WebSocket est indispensable pour le trading haute fréquence où une latence inférieure à 100ms est critique.
Erreurs courantes et bonnes pratiques
- Ignorer
retCode: un HTTP 200 ne signifie pas succès. Vérifiez toujoursretCode === 0avant de traiterresult. - Bourrer
/v5/market/orderbook: cet endpoint est le plus sensible aux rate limits. Espacez vos requêtes d'au moins 200ms par IP. - Changer d'IP en pleine pagination : Bybit lie le
cursorà l'IP. Utilisez une session sticky pour/v5/market/kline. - Oublier le backoff exponentiel : sur un 429 ou 403, attendez 1s, 2s, 4s avant de réessayer sur une nouvelle IP.
- Utiliser un datacenter proxy : Bybit peut détecter et filtrer les plages d'IPs de datacenters. Les proxys résidentiels offrent un taux de succès supérieur. En savoir plus sur le scraping web.
Points clés à retenir
- L'API V5 Market de Bybit est publique mais limitée par IP — la rotation de proxys est essentielle pour dépasser 120 req/min par endpoint.
- Les sessions sticky (
-session-xxx) sont obligatoires pour paginer/v5/market/klinesans rupture de curseur.- Le géo-ciblage (
-country-DE) viagate.proxyhat.com:8080contourne les blocages CloudFront des régions restreintes.- Toujours valider
retCodedans l'enveloppe de réponse, pas seulement le statut HTTP.- Alterner REST (snapshots) et WebSocket (
orderbook.50) selon le besoin de latence.
Pour aller plus loin, consultez la documentation ProxyHat et explorez nos cas d'usage de tracking SERP qui appliquent les mêmes patterns de rotation. Pour des stratégies avancées de scraping de données de marché, notre page tarifs détaille les plans adaptés au volume de votre pipeline.






