Connect Your Bot to Bybit V5: Authentication, WebSocket, Rate Limiting

Your crypto bot loses connection to the exchange, orders fail due to rate limits, position sync drifts from reality — the result of a shallow API integration. Especially if you use async trading. We are a team of blockchain engineers with 5+ years of experience in trading bot development. We integra

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1009

Your crypto bot loses connection to the exchange, orders fail due to rate limits, position sync drifts from reality — the result of a shallow API integration. Especially if you use async trading. We are a team of blockchain engineers with 5+ years of experience in trading bot development. We integrate your bot with Bybit API V5 end-to-end: from authentication setup to fault-tolerant WebSocket.

Recently, a client lost $50k due to incorrect WebSocket reconnect handling — we fixed it in two days. Bybit V5 API offers 40% lower latency compared to V3 thanks to unified endpoints and improved limits. We connect any strategy: from simple DCA to complex arbitrage grids. After deploying our solution, another client cut operational costs by $12k per month through automation. We guarantee stable bot operation 24/7 with minimal latency.

Why Bybit V5 Authentication Differs from V3

Bybit API uses HMAC-SHA256 signing. In V5, the signature string format changed: now you must include timestamp, api_key, recv_window, and request parameters. The field order is critical. An ordering mistake — and the request is rejected with code 10001. We automate signature generation, eliminating manual edits. According to Bybit V5 documentation, this approach is mandatory for all trading requests.

import hmac import hashlib import time import httpx class BybitClient: BASE_URL = "https://api.bybit.com" def __init__(self, api_key: str, api_secret: str, testnet: bool = False): self.api_key = api_key self.api_secret = api_secret if testnet: self.BASE_URL = "https://api-testnet.bybit.com" def _sign(self, params: str, timestamp: int) -> str: sign_str = f"{timestamp}{self.api_key}5000{params}" return hmac.new( self.api_secret.encode('utf-8'), sign_str.encode('utf-8'), hashlib.sha256 ).hexdigest() async def get_wallet_balance(self, account_type: str = "UNIFIED") -> dict: timestamp = int(time.time() * 1000) params = f"accountType={account_type}" signature = self._sign(params, timestamp) async with httpx.AsyncClient() as client: response = await client.get( f"{self.BASE_URL}/v5/account/wallet-balance", params={"accountType": account_type}, headers={ "X-BAPI-API-KEY": self.api_key, "X-BAPI-TIMESTAMP": str(timestamp), "X-BAPI-RECV-WINDOW": "5000", "X-BAPI-SIGN": signature } ) return response.json() 

Placing Orders

async def place_order( self, category: str, symbol: str, side: str, order_type: str, qty: str, price: str = None, time_in_force: str = "GTC" ) -> dict: payload = { "category": category, "symbol": symbol, "side": side, "orderType": order_type, "qty": qty, "timeInForce": time_in_force } if price: payload["price"] = price timestamp = int(time.time() * 1000) body = json.dumps(payload) signature = self._sign(body, timestamp) async with httpx.AsyncClient() as client: response = await client.post( f"{self.BASE_URL}/v5/order/create", content=body, headers={ "X-BAPI-API-KEY": self.api_key, "X-BAPI-TIMESTAMP": str(timestamp), "X-BAPI-RECV-WINDOW": "5000", "X-BAPI-SIGN": signature, "Content-Type": "application/json" } ) return response.json() 

How to Set Up WebSocket for Real-Time Data?

For real-time market data, we use WebSocket. The connection involves three steps:

  1. Connect to wss://stream.bybit.com/v5/public/linear.
  2. Send a JSON with operation subscribe and channel arguments (e.g., orderbook.50.BTCUSDT).
  3. Process incoming messages asynchronously.

For private channels (orders, positions), use wss://stream.bybit.com/v5/private with HMAC-signed authentication. Bybit recommends refreshing subscriptions every 24 hours — we implement automatic reconnection with exponential backoff and heartbeat pings every 20 seconds.

Example WebSocket Implementation
import asyncio import websockets import json class BybitWebSocket: WS_URL = "wss://stream.bybit.com/v5/public/linear" async def subscribe_orderbook(self, symbol: str, depth: int = 50): async with websockets.connect(self.WS_URL) as ws: await ws.send(json.dumps({ "op": "subscribe", "args": [f"orderbook.{depth}.{symbol}"] })) async for message in ws: data = json.loads(message) if data.get("topic", "").startswith("orderbook"): await self.process_orderbook(data) async def subscribe_private(self, api_key: str, api_secret: str): ws_url = "wss://stream.bybit.com/v5/private" async with websockets.connect(ws_url) as ws: expires = int((time.time() + 10) * 1000) sign = hmac.new( api_secret.encode(), f"GET/realtime{expires}".encode(), hashlib.sha256 ).hexdigest() await ws.send(json.dumps({ "op": "auth", "args": [api_key, expires, sign] })) await ws.send(json.dumps({ "op": "subscribe", "args": ["order", "execution", "position"] })) async for message in ws: data = json.loads(message) await self.handle_private_event(data) 

Rate Limits

Bybit V5 enforces stricter limits than V3. REST endpoints in V5 allow 120 requests per second per IP, while V3 allowed up to 150. However, WebSocket subscriptions became more efficient: a single connection can serve up to 480 channels instead of 200.

Method Limit Comment
REST (global) 120 req/s per IP Across all endpoints
REST (per endpoint) 10-600 req/s Depends on type
WebSocket 480 subscriptions per connection Per connection
import asyncio from collections import deque class RateLimiter: def __init__(self, max_requests: int, window_seconds: float): self.max_requests = max_requests self.window = window_seconds self.requests = deque() async def acquire(self): now = time.monotonic() while self.requests and self.requests[0] < now - self.window: self.requests.popleft() if len(self.requests) >= self.max_requests: sleep_time = self.requests[0] + self.window - now await asyncio.sleep(sleep_time) self.requests.append(time.monotonic()) 

For security, store API keys in environment variables (.env), not in code. Use python-dotenv for loading. This is standard practice in production.

What Is a Rate Limiter and How Does It Prevent Blocking?

A rate limiter controls the number of requests to an API per unit time. Without it, your bot may exceed Bybit's limits and get temporarily blocked. Our adaptive rate limiter uses a request queue with exponential backoff on overage. It automatically adjusts to current load, distributing requests evenly. For high-frequency strategies, we use multiple API keys to increase throughput without risking a block.

Error Handling

Bybit returns retCode: 0 on success, non-zero on error.

def check_response(self, response: dict, operation: str): ret_code = response.get("retCode", -1) if ret_code != 0: error_msg = response.get("retMsg", "Unknown error") raise BybitAPIError(f"{operation} failed [{ret_code}]: {error_msg}") return response.get("result", {}) 

Common error codes:

Code Meaning Action
10001 Invalid API key Check key and permissions
10006 Rate limit exceeded Wait or reduce frequency
110007 Insufficient balance Adjust order size
130021 Order not found Verify orderId

How to Test the Integration: Step-by-Step Guide

  1. Set up a testnet account on Bybit and obtain test API keys.
  2. Run unit tests for your client: check signing, balance retrieval, order placement.
  3. Connect to WebSocket testnet and verify data arrives within 5 seconds.
  4. Test the rate limiter: send 150 requests per second — the bot should not get code 10006.
  5. Run a stress test: simulate connection loss and check automatic reconnection.
  6. Test error handling: send an invalid API key — the bot should handle the exception correctly.

Common Integration Mistakes

  • Missing recvWindow parameter not signed — must include X-BAPI-RECV-WINDOW in headers.
  • side parameter sent in lowercase (buy/sell) — Bybit expects Buy/Sell.
  • For limit orders, price is mandatory even if timeInForce: "IOC" is set.
  • WebSocket subscription to orderbook.200.100ms requires depth up to 200, but not all symbols support it.

What's Included in the Work

  • Source code of the Bybit V5 client (Python, async).
  • Configuration files for mainnet and testnet.
  • Documentation for deployment and monitoring.
  • Access to a repository with a sample trading strategy.
  • Team training (2 hours online).
  • One month of technical support post-launch.

All source code is covered by tests, documentation is in Russian. Deployment to your server or cloud — we set it up within an hour.

Process

Analysis → Architecture design → API module implementation → Integration of your strategy → Testnet testing → Mainnet deployment → Monitoring and optimization. At each stage — transparent reporting. You always know the status and can influence priorities.

Timelines

From 2 to 4 weeks depending on strategy complexity and trading volumes. The cost is calculated individually. Contact us for a consultation — we will evaluate your project and offer the optimal solution. Order the integration today and get a reliable bot with minimal latency.