Döndürülen Proxy'lerle Bybit V5 Market API Nasıl Scrape Edilir: Geliştirici Rehberi
Bybit V5 Market API'sini scrape etmek, crypto trading bot'ları ve piyasa verisi mühendisleri için günlük bir ihtiyaçtır — ancak Bybit'in IP bazlı rate limitleri ve coğrafi kısıtlamaları, sürekli veri çekmeyi zorlaştırır. Döndürülen proxy'lerle Bybit V5 Market API'sini scrape etmek, tek bir IP'nin banlanmadan yüksek hacimli orderbook, ticker ve kline verisi çekmenin en pratik yoludur. Bu rehberde api.bybit.com/v5/market/ uç noktalarını, rate limit mimarisini, geo-block'ları ve ProxyHat ile nasıl güvenli bir scraping pipeline kuracağınızı adım adım göstereceğiz.
Yasal Uyarı: Bybit'in API Kullanım Şartları, public market verisinin kişisel kullanım için serbest olabileceğini ancak ticari yeniden dağıtımın kısıtlandığını belirtir. Bu rehber yalnızca eğitim amaçlıdır; Bybit'in resmi V5 API dokümantasyonunu ve Kullanım Şartlarını inceleyin. Her zaman robots.txt ve platform ToS'una uyun.
Bybit V5 Market API Uç Noktaları ve Yanıt Zarfı
Bybit'in V5 API'si, tüm public market verisini /v5/market/ altında birleştirir. Her uç nokta category parametresi alır: spot (spot), linear (USDT perpetual), inverse (inverse contracts) ve option (opsiyonlar). Tüm yanıtlar standart bir zarf içinde gelir:
{
"retCode": 0,
"retMsg": "OK",
"result": { ... },
"time": 1700000000000
}
retCode 0 ise istek başarılıdır; 0 dışındaki değerler hatayı gösterir ve retMsg açıklama içerir. Rate limit aşıldığında retCode 10001 dönebilir veya doğrudan HTTP 403 alabilirsiniz.
GET /v5/market/orderbook
Order book snapshot'ı döndürür. category (spot|linear|inverse|option), symbol ve limit (1–200) parametreleri alır. Yanıt, bids ve asks array'leri içerir; her eleman [price, size] formatındadır. Bybit V5 dokümantasyonuna göre, limit=200 için maksimum 200 seviye döner.
GET /v5/market/tickers
Belirli bir kategorideki tüm veya tek bir sembolün ticker verisini döndürür. category zorunludur; symbol opsiyoneldir (verilmezse tüm semboller döner). Spot için lastPrice, volume24h, turnover24h alanlarını içerir.
GET /v5/market/kline
Mum (candlestick) verisi döndürür. category, symbol, interval (1, 5, 15, 30, 60, 240, D, W, M) ve limit (max 200) alır. cursor parametresi ile sayfalama yapılır; yanıttaki nextPageCursor sonraki sayfaya geçiş için kullanılır. Her mum [startTime, open, high, low, close, volume, turnover] formatındadır.
GET /v5/market/recent-trade
Son işlemleri döndürür. category, symbol ve limit (max 1000) alır. Her işlem [execId, price, size, time, side] formatındadır.
IP Bazlı Rate Limitler ve ~10 Dakikalık Ban Penceresi
Bybit, rate limitleri IP bazlı uygular. Bybit V5 rate limit dokümantasyonuna göre, public market uç noktaları genellikle saniyede 5–20 istek izni verir; ancak /v5/market/orderbook gibi yoğun uç noktalarda bu sınır daha düşük olabilir. Limit aşıldığında:
- HTTP 403 veya
retCode: 10001döner. - IP yaklaşık 10 dakika boyunca banlanır.
- Ban penceresi boyunca tüm market uç noktaları bu IP için engellenir.
Bu, tek bir sunucudan orderbook scrape eden bot'lar için kritik bir sorundur. 5 saniyede 50 istek gönderirseniz, IP'niz 10 dakika boyunca banlanır ve veri akışınız kesilir. Döndürülen proxy'ler, her isteği farklı bir IP'den yaparak bu sorunu çözer.
Coğrafi Kısıtlamalar ve CloudFront Blokları
Bybit, ABD, İngiltere ve bazı diğer bölgelerde coğrafi kısıtlamalar uygular. Kısıtlı bir bölgeden API'ye erişmeye çalıştığınızda, CloudFront tabanlı bir 403 Forbidden yanıtı alırsınız — bu, API'nin retCode zarfına hiç ulaşmadan önce gerçekleşir. HTTP proxy'ler, isteği farklı bir coğrafyadan yönlendirerek bu engeli aşmanıza yardımcı olur.
ProxyHat'ın residential proxy'leri ile -country-US gibi username flag'leri kullanarak izin verilen bir bölgeden bağlanabilirsiniz. Residential IP'ler, datacenter IP'lerinden daha az tespit edilir çünkü gerçek ISP IP'lerine benzer. ProxyHat 100+ lokasyonda residential IP sunar.
Ham Proxy vs ProxyHat ile Kod Örnekleri
Aşağıda her örnek iki varyasyon gösterir: ham proxy (generic proxy URL) ve ProxyHat entegrasyonu (gate.proxyhat.com ile geo-targeting ve session flag'leri).
1. curl ile Orderbook Sorgulama
Ham proxy ile:
# Ham proxy ile Bybit orderbook
curl -x http://proxyuser:proxypass@192.168.1.100:3128 \
"https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=50"
ProxyHat ile (US geo-targeting):
# ProxyHat residential proxy ile US lokasyonundan
curl -x http://user-country-US:pass@gate.proxyhat.com:8080 \
"https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=50"
2. Node.js (axios) ile Ticker Scrape — IP Rotasyonu
Ham proxy ile (sabit IP, rate limit riski):
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
const proxyUrl = 'http://proxyuser:proxypass@192.168.1.100:3128';
const agent = new HttpsProxyAgent(proxyUrl);
async function fetchTickersRaw(symbols) {
const results = [];
for (const symbol of symbols) {
try {
const res = await axios.get(
'https://api.bybit.com/v5/market/tickers',
{
params: { category: 'spot', symbol },
httpsAgent: agent,
timeout: 5000
}
);
if (res.data.retCode === 0) {
results.push(...res.data.result.list);
} else {
console.error(`API hatası: ${res.data.retCode} - ${res.data.retMsg}`);
}
} catch (err) {
console.error(`İstek hatası for ${symbol}:`, err.message);
}
}
return results;
}
fetchTickersRaw(['BTCUSDT', 'ETHUSDT', 'SOLUSDT']).then(console.log);
ProxyHat ile (her sembol için yeni IP):
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
// ProxyHat proxy URL builder (SDK pattern)
function proxyHatUrl(country, session) {
let username = 'user';
if (country) username += `-country-${country}`;
if (session) username += `-session-${session}`;
return `http://${username}:pass@gate.proxyhat.com:8080`;
}
async function fetchTickersProxyHat(symbols) {
const results = [];
for (const symbol of symbols) {
// Her sembol için yeni residential IP (rotating)
const agent = new HttpsProxyAgent(proxyHatUrl('US'));
try {
const res = await axios.get(
'https://api.bybit.com/v5/market/tickers',
{
params: { category: 'spot', symbol },
httpsAgent: agent,
timeout: 5000
}
);
if (res.data.retCode === 0) {
results.push(...res.data.result.list);
} else {
console.error(`API hatası: ${res.data.retCode} - ${res.data.retMsg}`);
}
} catch (err) {
console.error(`İstek hatası for ${symbol}:`, err.message);
}
}
return results;
}
fetchTickersProxyHat(['BTCUSDT', 'ETHUSDT', 'SOLUSDT']).then(console.log);
3. Python ile Kline Verisi Çekme
Ham proxy ile:
import requests
proxies = {
'http': 'http://proxyuser:proxypass@192.168.1.100:3128',
'https': 'http://proxyuser:proxypass@192.168.1.100:3128'
}
def fetch_kline_raw(symbol, interval='60', limit=200):
url = 'https://api.bybit.com/v5/market/kline'
params = {
'category': 'linear',
'symbol': symbol,
'interval': interval,
'limit': limit
}
try:
resp = requests.get(url, params=params, proxies=proxies, timeout=10)
data = resp.json()
if data.get('retCode') == 0:
return data['result']['list']
else:
print(f"API hatası: {data.get('retCode')} - {data.get('retMsg')}")
return []
except Exception as e:
print(f"İstek hatası: {e}")
return []
candles = fetch_kline_raw('BTCUSDT', '60', 200)
print(f"{len(candles)} mum verisi alındı")
ProxyHat sticky session ile (kline pagination için aynı IP):
import requests
import time
def proxyhat_url(country='US', session=None):
username = f'user-country-{country}'
if session:
username += f'-session-{session}'
return f'http://{username}:pass@gate.proxyhat.com:8080'
def fetch_kline_paginated(symbol, interval='60', total=1000):
"""Sticky session ile kline pagination — aynı IP'de kalır."""
session_id = f'kline-{symbol}-{int(time.time())}'
proxy_url = proxyhat_url(country='US', session=session_id)
proxies = {'http': proxy_url, 'https': proxy_url}
all_candles = []
cursor = None
while len(all_candles) < total:
url = 'https://api.bybit.com/v5/market/kline'
params = {
'category': 'linear',
'symbol': symbol,
'interval': interval,
'limit': 200
}
if cursor:
params['cursor'] = cursor
try:
resp = requests.get(url, params=params, proxies=proxies, timeout=10)
data = resp.json()
if data.get('retCode') == 0:
candles = data['result']['list']
all_candles.extend(candles)
cursor = data['result'].get('nextPageCursor')
if not cursor or not candles:
break
time.sleep(0.2) # Rate budgeting: ~5 req/s
else:
print(f"API hatası: {data.get('retCode')} - {data.get('retMsg')}")
break
except Exception as e:
print(f"İstek hatası: {e}")
break
return all_candles[:total]
candles = fetch_kline_paginated('BTCUSDT', '60', 1000)
print(f"Toplam {len(candles)} mum verisi alındı")
Rate Budgeting, Retry ve Backoff Stratejileri
Production'da yalnızca IP rotasyonu yeterli değildir; her uç nokta için ayrı bir rate budget belirlemeniz gerekir. Aşağıdaki Node.js örneği, per-endpoint rate limiting, exponential backoff ve circuit breaker pattern'ini birleştirir:
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
class BybitScraper {
constructor() {
this.requestTimestamps = [];
this.maxRequestsPerSecond = 5;
this.maxRetries = 3;
this.circuitOpen = false;
this.failureCount = 0;
this.failureThreshold = 5;
}
getProxyAgent(country = 'US', session = null) {
let username = `user-country-${country}`;
if (session) username += `-session-${session}`;
return new HttpsProxyAgent(
`http://${username}:pass@gate.proxyhat.com:8080`
);
}
async rateLimit() {
const now = Date.now();
this.requestTimestamps = this.requestTimestamps.filter(
ts => now - ts < 1000
);
if (this.requestTimestamps.length >= this.maxRequestsPerSecond) {
const wait = 1000 - (now - this.requestTimestamps[0]);
await new Promise(r => setTimeout(r, wait));
}
this.requestTimestamps.push(Date.now());
}
async request(endpoint, params, retries = 0) {
if (this.circuitOpen) {
throw new Error('Circuit breaker açık — 30s sonra tekrar deneyin');
}
await this.rateLimit();
const agent = this.getProxyAgent('US');
try {
const res = await axios.get(
`https://api.bybit.com/v5/market/${endpoint}`,
{ params, httpsAgent: agent, timeout: 10000 }
);
if (res.data.retCode === 0) {
this.failureCount = 0;
return res.data.result;
}
// Rate limit hatası — backoff ile tekrar dene
if (res.data.retCode === 10001 && retries < this.maxRetries) {
const backoff = Math.pow(2, retries) * 1000;
console.log(`Rate limit hit, ${backoff}ms bekleniyor...`);
await new Promise(r => setTimeout(r, backoff));
return this.request(endpoint, params, retries + 1);
}
throw new Error(`API: ${res.data.retCode} - ${res.data.retMsg}`);
} catch (err) {
this.failureCount++;
if (this.failureCount >= this.failureThreshold) {
this.circuitOpen = true;
setTimeout(() => {
this.circuitOpen = false;
this.failureCount = 0;
}, 30000);
}
if (retries < this.maxRetries) {
const backoff = Math.pow(2, retries) * 1000;
console.log(`Hata: ${err.message}, ${backoff}ms sonra tekrar...`);
await new Promise(r => setTimeout(r, backoff));
return this.request(endpoint, params, retries + 1);
}
throw err;
}
}
async scrapeOrderbook(symbols) {
const results = {};
for (const symbol of symbols) {
try {
const data = await this.request('orderbook', {
category: 'spot',
symbol,
limit: 50
});
results[symbol] = data;
console.log(`${symbol}: ${data.bids.length} bid, ${data.asks.length} ask`);
} catch (err) {
console.error(`${symbol} başarısız: ${err.message}`);
}
}
return results;
}
}
const scraper = new BybitScraper();
scraper.scrapeOrderbook(['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT'])
.then(() => console.log('Tamamlandı'));
Sticky Session'lar ile Kline Pagination
Bybit kline endpoint'i cursor tabanlı sayfalama kullanır. Eğer her istekte IP döndürürseniz, cursor tutarsız olabilir veya Bybit şüpheli davranış olarak işaretleyebilir. ProxyHat'ın -session-abc123 flag'i ile belirli bir süre boyunca aynı IP'de kalabilirsiniz. Bu, pagination boyunca tutarlı bir bağlantı sağlar ve rate limit bütçenizi tek bir IP üzerinde yönetmenize olanak tanır.
Yukarıdaki Python örneğinde session_id parametresi ile sticky session kullanılmıştır. Pagination tamamlandığında yeni bir session_id ile farklı bir IP'ye geçebilirsiniz.
REST Snapshot vs WebSocket Orderbook
REST ile orderbook çekmek her istekte ~200ms gecikme üretir ve rate limit tüketir. Sürekli depth takibi için WebSocket çok daha verimlidir:
| Özellik | REST /v5/market/orderbook | WebSocket orderbook.50 |
|---|---|---|
| Latens | ~200ms per istek | ~50ms push (artımlı) |
| Rate limit | ~5 req/s (IP bazlı) | 1 bağlantı, sınırsız push |
| Veri tazeliği | Snapshot (anlık) | Artımlı güncelleme |
| Kullanım | Tek seferlik sorgu | Sürekli monitoring |
| Karmaşıklık | Düşük | Orta (reconnect/replay) |
WebSocket ile ProxyHat SOCKS5 proxy üzerinden orderbook.50 stream'ine abone olabilirsiniz:
const WebSocket = require('ws');
const { SocksProxyAgent } = require('socks-proxy-agent');
// ProxyHat SOCKS5 proxy ile US residential IP
const agent = new SocksProxyAgent(
'socks5://user-country-US:pass@gate.proxyhat.com:1080'
);
const ws = new WebSocket(
'wss://stream.bybit.com/v5/public/spot',
{ agent }
);
ws.on('open', () => {
ws.send(JSON.stringify({
op: 'subscribe',
args: ['orderbook.50.BTCUSDT']
}));
console.log('orderbook.50.BTCUSDT aboneliği aktif');
});
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.topic && msg.topic.startsWith('orderbook')) {
const { bids, asks } = msg.data;
console.log(`Depth: ${bids.length} bid, ${asks.length} ask`);
}
});
ws.on('error', (err) => console.error('WS hata:', err.message));
ws.on('close', () => console.log('WS kapandı — reconnect gerekli'));
WebSocket kullanırken dikkat edin: bağlantı kopması durumunda snapshot almanız gerekir (REST ile /v5/market/orderbook çağırıp mevcut durumu senkronize edin). Bybit WebSocket protokolü, reconnect sonrası snapshot ve sonrasındaki delta mesajlarını gönderir.
Önemli Çıkarımlar
- IP rotasyonu şart: Bybit'in IP bazlı rate limitleri ve ~10 dakikalık ban penceresi, tek IP'den yüksek hacimli scrape'i imkansız kılar. Her istekte yeni IP kullanın.
- Residential proxy tercih edin: Datacenter IP'leri CloudFront tarafından tespit edilip 403 dönebilir. ProxyHat residential IP'leri ile
-country-USflag'i kullanın. - Sticky session pagination için: Kline cursor pagination'da
-session-abc123ile aynı IP'de kalın; pagination bitince yeni session'a geçin. - Rate budgeting uygulayın: Döndürülen proxy kullansanız bile saniyede maksimum 5 istek ile kendinizi sınırlayın.
- WebSocket tercih edin: Sürekli orderbook takibi için REST yerine WebSocket
orderbook.50stream'ini kullanın; 10x daha düşük latens ve rate limit tasarrufu sağlar. - retCode kontrolü yapın: Her yanıtta
retCode === 0kontrolü yapın; 10001 rate limit, diğer kodlar farklı hatalar anlamına gelir.
ProxyHat ile residential proxy'lere erişmek için fiyatlandırma sayfasını inceleyin. Web scraping use case sayfamızda daha fazla örnek bulabilirsiniz. Detaylı proxy yapılandırması için ProxyHat dokümantasyonuna bakın.






