إذا كنت تطوّر بوت تداول أو تجمع بيانات سوق التشفير، فمن المرجح أنك واجهت مشكلة حظر IP عند محاولة استخراج بيانات من Bybit V5 Market API. منصة Bybit تفرض قيودًا صارمة على المعدل وتقييدات جغرافية تجعل جمع البيانات على نطاق واسع أمرًا صعبًا دون بنية بروكسي مناسبة. في هذا الدليل، نشرح كيفية استخراج بيانات Bybit V5 Market API باستخدام بروكسيات دوارة عبر نقاط نهاية محددة، مع أمثلة كود قابلة للتشغيل في Node.js وPython باستخدام ProxyHat.
تنبيه قانوني: هذه المقالة تغطي نقاط نهاية البيانات العامة فقط (orderbook, tickers, kline, recent-trading). تأكد دائمًا من مراجعة شروط خدمة Bybit و سياسة الخصوصية قبل جمع أي بيانات. لا تستخدم نقاط نهاية المصادقة أو بيانات المستخدم دون إذن صريح.
نظرة عامة على Bybit V5 Market API ونقاط النهاية
تستضيف Bybit واجهة V5 الموحدة على api.bybit.com. نقاط نهاية البيانات العامة تحت مسار /v5/market/ لا تتطلب مصادقة وتُرجع بيانات السوق في الوقت الفعلي أو شبه الفعلي. إليك النقاط الأربع الرئيسية التي نهتم بها:
| نقطة النهاية | الطريقة | الغرض | المعاملات الأساسية |
|---|---|---|---|
/v5/market/orderbook |
GET | لقطة دفتر الطلبات | category, symbol, limit |
/v5/market/tickers |
GET | أسعار/حجم جميع الرموز أو رمز واحد | category, symbol (اختياري) |
/v5/market/kline |
GET | بيانات الشموع اليابانية (OHLCV) | category, symbol, interval, start, end |
/v5/market/recent-trade |
GET | أحدث الصفقات المنفذة | category, symbol, limit |
المعامل category هو محوري في V5 — يقبل القيم spot (الفوري), linear (العقود الخطية), inverse (العقود العكسية), و option (الخيارات). لكل فئة مساحة أسماء رموز خاصة بها، لذا BTCUSDT في spot يختلف عن BTCUSDT في linear.
مغلف الاستجابة: retCode و retMsg
تُرجع جميع نقاط نهاية V5 JSON بمغلف موحد:
{
"retCode": 0,
"retMsg": "OK",
"result": {
"category": "spot",
"symbol": "BTCUSDT",
"list": [...]
},
"time": 1700000000000
}
عندما يكون retCode = 0، الطلب ناجح. أي قيمة غير صفرية تشير إلى خطأ — راجع توثيق أخطاء Bybit V5 لقائمة الرموز. القيم الشائعة تشمل 10001 (معامل غير صالح) و 10010 (تجاوز حد المعدل). يجب على الكود الخاص بك التحقق من retCode قبل معالجة result.
حدود المعدل وحظر IP في Bybit
تطبق Bybit حدود معدل لكل IP على كل نقطة نهاية. وفقًا لـ توثيق حدود المعدل في Bybit V5، فإن نقطة نهاية دفتر الطلبات /v5/market/orderbook لديها حد أقصى حوالي 200 طلب في الثانية لكل IP، لكن هذا الرقم يختلف حسب الفئة. نقاط نهاية kline و tickers لها حدود منخفضة بشكل عام.
عندما تتجاوز الحد، يستجيب الخادم بـ HTTP 403 Forbidden مع retMsg يشير إلى تجاوز حد المعدل. الأسوأ من ذلك، Bybit تفرض نافذة حظر تبلغ تقريبًا 10 دقائق على IPs التي تستمر في تجاوز الحدود. خلال هذه النافذة، يتم رفض جميع الطلبات من ذلك IP — وليس فقط نقطة النهاية التي تم تجاوزها.
هذا يعني أن اندفاعًا قصيرًا على api.bybit.com/v5/market/orderbook لجمع دفاتر طلبات 50 رمزًا يمكن أن يوقف مجموعة البيانات بأكملها لمدة 10 دقائق. الحل هو توزيع الطلبات عبر عناوين IP متعددة باستخدام بروكسيات دوارة.
القيود الجغرافية وحظر CloudFront
Bybit تقيد الوصول من مناطق معينة، بما في ذلك الولايات المتحدة والمملكة المتحدة ودول أخرى. الطلبات من IPs في هذه المناطق تتلقى HTTP 403 مع رسالة حظر CloudFront أو صفحة خطأ جغرافية. هذا يمثل مشكلة للمطورين الذين يعملون من هذه المناطق ويحتاجون إلى الوصول إلى بيانات السوق العامة.
البروكسيات السكنية تحل هذه المشكلة عن طريق توجيه حركة المرور عبر IPs سكنية حقيقية في دول مسموحة. مع ProxyHat، يمكنك تحديد الدولة في اسم المستخدم باستخدام تنسيق user-country-XX لضمان أن الطلبات تخرج من IP في دولة مسموحة مثل اليابان أو سنغافورة.
إعداد ProxyHat: البروكسي الخام مقابل SDK
ProxyHat يوفر بوابة HTTP على gate.proxyhat.com:8080 و SOCKS5 على gate.proxyhat.com:1080. يمكنك استخدام البروكسي الخام مباشرة في أي عميل HTTP، أو استخدام ProxyHat SDK للإدارة المتقدمة للجلسات. إليك مقارنة سريعة:
| النهج | المزايا | العيوب |
|---|---|---|
| البروكسي الخام (URL) | بسيط، يعمل مع أي مكتبة HTTP | إدارة الجلسات يدوية |
| ProxyHat SDK | تدوير تلقائي، جلسات لاصقة، إعادة المحاولة | يتطلب تثبيت حزمة |
مثال 1: طلب دفتر الطلبات باستخدام curl مع بروكسي خام
# بروكسي HTTP خام مع تحديد الدولة (اليابان)
curl -x http://user-country-JP:YOUR_PASSWORD@gate.proxyhat.com:8080 \
"https://api.bybit.com/v5/market/orderbook?category=spot&symbol=BTCUSDT&limit=50"
# بروكسي SOCKS5 مع جلسة لاصقة
curl -x socks5://user-country-JP-session-abc123:YOUR_PASSWORD@gate.proxyhat.com:1080 \
"https://api.bybit.com/v5/market/orderbook?category=linear&symbol=ETHUSDT&limit=100"
مثال 2: Node.js (axios) — تدوير IP عبر قائمة رموز باستخدام البروكسي الخام
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
const PROXY_USER = 'user';
const PROXY_PASS = 'YOUR_PASSWORD';
const PROXY_HOST = 'gate.proxyhat.com';
const PROXY_PORT = 8080;
const symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT'];
const categories = ['spot', 'linear'];
async function fetchOrderbook(symbol, category, sessionTag) {
const proxyUrl = `http://${PROXY_USER}-country-JP-session-${sessionTag}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}`;
const agent = new HttpsProxyAgent(proxyUrl);
try {
const resp = await axios.get('https://api.bybit.com/v5/market/orderbook', {
params: { category, symbol, limit: 50 },
httpsAgent: agent,
timeout: 10000,
});
if (resp.data.retCode !== 0) {
throw new Error(`Bybit retCode ${resp.data.retCode}: ${resp.data.retMsg}`);
}
return { symbol, category, bids: resp.data.result.bids, asks: resp.data.result.asks };
} catch (err) {
console.error(`[FAIL] ${category}/${symbol}: ${err.message}`);
return null;
}
}
async function main() {
const tasks = symbols.map((sym, i) =>
fetchOrderbook(sym, 'spot', `sess-${i}-${Date.now()}`)
);
const results = await Promise.allSettled(tasks);
const ok = results.filter(r => r.status === 'fulfilled' && r.value !== null);
console.log(`نجاح: ${ok.length}/${symbols.length}`);
}
main();
مثال 3: Node.js (axios) — نفس العملية باستخدام ProxyHat SDK
const axios = require('axios');
const { ProxyHatClient } = require('@proxyhat/sdk');
const client = new ProxyHatClient({
username: 'user',
password: 'YOUR_PASSWORD',
country: 'JP',
rotation: 'per-request',
maxRetries: 3,
backoffMs: 2000,
});
const symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT'];
async function fetchOrderbookSDK(symbol, category) {
const proxyAgent = await client.getAgent(); // IP جديد لكل طلب
try {
const resp = await axios.get('https://api.bybit.com/v5/market/orderbook', {
params: { category, symbol, limit: 50 },
httpsAgent: proxyAgent,
timeout: 10000,
});
if (resp.data.retCode !== 0) {
throw new Error(`retCode ${resp.data.retCode}: ${resp.data.retMsg}`);
}
return resp.data.result;
} catch (err) {
// SDK يتعامل مع إعادة المحاولة تلقائيًا مع IP جديد
console.error(`[FAIL] ${category}/${symbol}: ${err.message}`);
return null;
}
}
async function main() {
const results = await Promise.allSettled(
symbols.map(s => fetchOrderbookSDK(s, 'spot'))
);
console.log(`اكتمل: ${results.filter(r => r.status === 'fulfilled').length}/${symbols.length}`);
}
main();
مثال 4: Python — جمع بيانات kline مع جلسات لاصقة وترقيم الصفحات
import requests
import time
from urllib.parse import urlencode
PROXY_USER = 'user'
PROXY_PASS = 'YOUR_PASSWORD'
PROXY_HOST = 'gate.proxyhat.com'
PROXY_PORT = 8080
BASE_URL = 'https://api.bybit.com/v5/market/kline'
def get_proxy(session_id, country='JP'):
"""بناء URL بروكسي مع جلسة لاصقة للترقيم."""
username = f'{PROXY_USER}-country-{country}-session-{session_id}'
proxy_url = f'http://{username}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}'
return {'http': proxy_url, 'https': proxy_url}
def fetch_kline_page(symbol, category, interval, start, end, session_id):
"""جلب صفحة واحدة من بيانات kline مع بروكسي لاصق."""
params = {
'category': category,
'symbol': symbol,
'interval': interval, # 1, 5, 15, 30, 60, 240, D, W, M
'start': start,
'end': end,
'limit': 200, # الحد الأقصى للصفحة
}
proxies = get_proxy(session_id)
for attempt in range(3):
try:
resp = requests.get(BASE_URL, params=params, proxies=proxies, timeout=10)
if resp.status_code == 403:
print(f'403 محظور، إعادة المحاولة {attempt + 1}/3')
time.sleep(2 ** attempt)
continue
data = resp.json()
if data['retCode'] != 0:
raise Exception(f"retCode {data['retCode']}: {data['retMsg']}")
return data['result']['list']
except requests.RequestException as e:
print(f'خطأ شبكة: {e}')
time.sleep(2 ** attempt)
return None
def fetch_all_klines(symbol, category, interval, start_ms, end_ms):
"""جمع كل بيانات kline عبر ترقيم الصفحات بنفس الجلسة اللاصقة."""
session_id = f'kline-{symbol}-{int(time.time())}'
all_candles = []
cursor = start_ms
while cursor < end_ms:
page_end = min(cursor + 200 * 60 * 1000 * int(interval), end_ms)
candles = fetch_kline_page(symbol, category, interval, cursor, page_end, session_id)
if not candles:
break
all_candles.extend(candles)
# التقدم إلى آخر شمعة في الصفحة
last_ts = int(candles[-1][0])
cursor = last_ts + 1
time.sleep(0.5) # احترام حد المعدل
return all_candles
# مثال: جمع بيانات BTCUSDT spot لمدة ساعة
candles = fetch_all_klines('BTCUSDT', 'spot', '1', 1700000000000, 1700003600000)
print(f'تم جمع {len(candles)} شمعة')
مثال 5: Python — ProxyHat SDK مع ميزانية معدل لكل نقطة نهاية
import time
import logging
from proxyhat import ProxyHatClient
import requests
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
class BybitMarketScraper:
def __init__(self, country='JP'):
self.client = ProxyHatClient(
username='user',
password='YOUR_PASSWORD',
country=country,
rotation='per-request',
max_retries=3,
backoff_ms=2000,
)
# ميزانية المعدل لكل نقطة نهاية (طلب/ثانية)
self.rate_budget = {
'orderbook': 50, # حد آمن تحت 200/ثانية
'tickers': 10,
'kline': 5,
'recent-trade': 20,
}
self.last_request = {ep: 0 for ep in self.rate_budget}
def _respect_rate(self, endpoint):
min_interval = 1.0 / self.rate_budget[endpoint]
elapsed = time.time() - self.last_request[endpoint]
if elapsed < min_interval:
time.sleep(min_interval - elapsed)
self.last_request[endpoint] = time.time()
def fetch(self, endpoint, params):
self._respect_rate(endpoint)
proxy = self.client.get_proxy_dict() # {'http': ..., 'https': ...}
url = f'https://api.bybit.com/v5/market/{endpoint}'
for attempt in range(3):
try:
resp = requests.get(url, params=params, proxies=proxy, timeout=10)
if resp.status_code == 403:
logging.warning(f'403 من Bybit، تدوير IP وإعادة المحاولة')
proxy = self.client.get_proxy_dict(force_new_ip=True)
time.sleep(2 ** attempt)
continue
data = resp.json()
if data['retCode'] != 0:
logging.error(f'retCode {data["retCode"]}: {data["retMsg"]}')
if data['retCode'] == 10010: # تجاوز حد المعدل
time.sleep(60) # انتظار طويل
return None
return data['result']
except Exception as e:
logging.error(f'استثناء: {e}')
time.sleep(2 ** attempt)
return None
# الاستخدام
scraper = BybitMarketScraper(country='JP')
result = scraper.fetch('orderbook', {'category': 'spot', 'symbol': 'BTCUSDT', 'limit': 50})
if result:
print(f'أفضل سعر شراء: {result["bids"][0] if result["bids"] else "N/A"}')
مثال 6: Python — recent-trade مع بروكسي SOCKS5 خام
import requests
# استخدام SOCKS5 على المنفذ 1080
proxy_url = 'socks5://user-country-SG-session-trades-001:YOUR_PASSWORD@gate.proxyhat.com:1080'
proxies = {'http': proxy_url, 'https': proxy_url}
resp = requests.get(
'https://api.bybit.com/v5/market/recent-trade',
params={'category': 'linear', 'symbol': 'BTCUSDT', 'limit': 50},
proxies=proxies,
timeout=10,
)
data = resp.json()
if data['retCode'] == 0:
trades = data['result']['list']
print(f'تم استرجاع {len(trades)} صفقة')
for t in trades[:5]:
print(f' السعر: {t["price"]} | الحجم: {t["size"]} | الوقت: {t["time"]}')
else:
print(f'خطأ: {data["retMsg"]}')
REST مقابل WebSocket: لقطات مقابل بث مباشر
للبيانات اللحظية، توفر Bybit قناة WebSocket عامة orderbook.50.{symbol} و orderbook.100.{symbol} التي تدفع تحديثات دفتر الطلبات في الوقت الفعلي. هذا أكثر كفاءة من استطلاع REST /v5/market/orderbook بشكل متكرر.
| المعيار | REST /v5/market/orderbook | WebSocket orderbook.50 |
|---|---|---|
| زمن الوصول | ~50-100ms لكل طلب | ~10-30ms للتحديثات |
| استهلاك النطاق | عالي (طلب كامل لكل تحديث) | منخفض (تحديثات تدريجية) |
| حد المعدل | ~200 طلب/ثانية لكل IP | لا يوجد حد معدل REST |
| الحاجة لبروكسي | نعم للتدوير | نعم للاتصال الأولي فقط |
للحصول على تفاصيل WebSocket، راجع توثيق WebSocket العام في Bybit V5. القناة العامة متاحة على wss://stream.bybit.com/v5/public/spot للفوري و wss://stream.bybit.com/v5/public/linear للعقود الخطية.
أخطاء شديدة وحالات حافة
1. تجاهل retCode والاعتماد على HTTP 200 فقط
Bybit قد تُرجع HTTP 200 مع retCode غير صفر. إذا تحقق الكود فقط من resp.ok، فسيعالج بيانات خطأ كأنها بيانات صحيحة.
2. عدم احترام نافذة الحظر البالغة 10 دقائق
عند تلقي 403، بعض المطورين يعيدون المحاولة فورًا بنفس IP — وهذا يطيل فترة الحظر. الصحيح هو التدوير إلى IP جديد والانتظار على الأقل 60 ثانية قبل إعادة المحاولة.
3. استخدام دفتر طلبات بعمق 200 لكل رمز
عمق limit=200 يستهلك مزيدًا من النطاق ويضغط على حد المعدل. معظم استراتيجيات التداول تحتاج فقط limit=50 أو حتى limit=10.
4. خلط الفئات
BTCUSDT في spot ليس نفس BTCUSDT في linear. تأكد دائمًا من تمرير category الصحيحة.
إعداد ProxyHat والروابط الداخلية
للبدء مع ProxyHat، سجل الدخول إلى dashboard.proxyhat.com للحصول على بيانات اعتمادك. تحقق من صفحة الأسعار لخطط البروكسي السكنية والمتنقلة. للمزيد حول حالات استخدام استخراج البيانات، راجع صفحة استخراج الويب و تتبع نتائج البحث. لدعم الدول المدعومة، راجع صفحة المواقع. للتوثيق الفني الكامل، راجع docs.proxyhat.com.
النقاط الرئيسية
- تحقق من retCode دائمًا: HTTP 200 لا يعني النجاح في Bybit V5 — تحقق من
retCode === 0. - احترم حدود المعدل:
/v5/market/orderbookيسمح بحوالي 200 طلب/ثانية لكل IP، لكن الحظر يستمر ~10 دقائق عند التجاوز. - استخدم البروكسيات السكنية: تجاوز القيود الجغرافية باستخدام
-country-JPأو-country-SGفي اسم المستخدم. - الجلسات اللاصقة للترقيم: استخدم
-session-abc123لضمان نفس IP عبر صفحات kline متعددة. - ميزانية المعدل لكل نقطة نهاية: لا تتعامل مع جميع النقاط بنفس السرعة — kline أبطأ من orderbook.
- فكر في WebSocket: للبيانات اللحظية،
orderbook.50أكثر كفاءة من استطلاع REST.
للحصول على أفضل النتائج، ابدأ بمعدل منخفض (10 طلب/ثانية لكل IP) وارفعه تدريجيًا مع مراقبة نسبة 403. استخدم ProxyHat SDK للتدوير التلقائي وإعادة المحاولة بدلاً من بناء منطق مخصص.






