CCXT: How WebSocket Orderbook Methods Really Work

MarketMaker.cc Team
クオンツ・リサーチ&戦略
Read More

Data Communication in Algo Trading Systems: A Technology Overview

Matrices, Tensors, and Tropical Algebra: Linear Algebra for Arbitrage Detection


MarketMaker.cc Team
クオンツ・リサーチ&戦略



Hello! Today we'll dive into one of the most important topics for trading system developers — how WebSocket methods for getting orderbooks work in CCXT. If you've ever faced questions like "why is the method in the documentation but doesn't work in practice?" or "which method to choose for monitoring 100+ trading pairs?", this article is for you.
When working with CCXT for market data collection, many face critical questions:
In this article — a detailed breakdown of popular methods, their features, and the real situation with 75+ exchanges.
Modern exchange APIs offer several ways to get orderbook data via WebSocket. Let's examine each of them:
watchOrderBook - Classic ApproachThis is the main method for subscribing to orderbook updates for a single trading pair.
Key characteristics:
Usage example:
const exchange = new ccxt.pro.binance();
const orderbook = await exchange.watchOrderBook('BTC/USDT');
console.log(orderbook);
watchOrderBookForSymbols - Bulk SubscriptionThis method allows subscribing to multiple trading pairs simultaneously, if the exchange supports it.
Key characteristics:
Example response:
{
"BTC/USDT": {
"bids": [[50000.1, 1.5], [50000.0, 2.1]],
"asks": [[50001.0, 1.2], [50001.1, 0.8]],
"timestamp": 1717398000000,
"datetime": "2025-06-03T12:00:00Z"
},
"ETH/USDT": {
"bids": [[3000.5, 10.2], [3000.4, 5.7]],
"asks": [[3001.0, 8.3], [3001.1, 12.1]],
"timestamp": 1717398000000,
"datetime": "2025-06-03T12:00:00Z"
}
}
Important warning: In reality, not supported on all exchanges. Sometimes the method exists in the API but isn't implemented.
watchBidsAsks - Optimized MonitoringThe most economical way to track best prices across multiple trading pairs.
Key characteristics:
Example response:
{
"BTC/USDT": {
"bids": [[50000.1, 1.5]],
"asks": [[50001.0, 1.2]],
"timestamp": 1717398000000,
"datetime": "2025-06-03T12:00:00Z"
},
"ETH/USDT": {
"bids": [[3000.5, 10.2]],
"asks": [[3001.0, 8.3]],
"timestamp": 1717398000000,
"datetime": "2025-06-03T12:00:00Z"
}
}
Feature: Usually implemented via ticker endpoint — saves resources for both client and exchange.
fetchOrderBookWs - One-time RequestsAlternative to REST API for getting orderbook snapshots.
Key characteristics:
Understanding differences between methods is critical for choosing the right approach:
watchBidsAsks vs watchOrderBookForSymbols:
watchBidsAsks — 100–1000 times less traffic, ideal for bulk monitoringwatchOrderBookForSymbols — powerful but very heavy on traffic and not supported by all exchangesTraffic calculation example:
Visual comparison of data intensity between full orderbook and top-of-book (Bids/Asks) methods
Let's look at a real example of how documentation might not match practice.
watchOrderBookForSymbols on Gate.ioAttempting to subscribe to 10 popular trading pairs:
const symbols = [
'1CAT/USDT:USDT',
'1INCH/USDT:USDT',
'A8/USDT:USDT',
'AAVE/USDT:USDT',
'ACE/USDT:USDT',
'ACH/USDT:USDT',
'ACT/USDT:USDT',
'ACX/USDT:USDT',
'ADA/USDT:USDT',
'ADX/USDT:USDT'
];
const exchange = new ccxt.pro.gateio();
try {
const orderbooks = await exchange.watchOrderBookForSymbols(symbols);
console.log('Success!', orderbooks);
} catch (error) {
console.error('Error:', error.message);
}
Actual result:
NotSupported: gateio watchOrderBookForSymbols() is not supported yet
Important lesson: Even if a method is declared in API documentation, this doesn't guarantee it works for a specific exchange. Always test in practice!
To get a real picture of method support, a script was written to check all CCXT exchanges:
const ccxt = require('ccxt');
async function checkAllExchangeMethods() {
const results = [];
// Get list of all supported exchanges
const exchangeIds = ccxt.pro.exchanges;
for (const exchangeId of exchangeIds) {
try {
const exchange = new ccxt.pro[exchangeId]();
// Check for method presence
const hasWatchOrderBook = typeof exchange.watchOrderBook === 'function';
const hasWatchBidsAsks = typeof exchange.watchBidsAsks === 'function';
const hasWatchOrderBookForSymbols = typeof exchange.watchOrderBookForSymbols === 'function';
// Check spot and futures support
const hasSpot = exchange.has['spot'];
const hasFutures = exchange.has['future'] || exchange.has['swap'];
results.push({
exchange: exchangeId,
spot: hasSpot,
futures: hasFutures,
watchOrderBook: hasWatchOrderBook,
watchBidsAsks: hasWatchBidsAsks,
watchOrderBookForSymbols: hasWatchOrderBookForSymbols
});
} catch (error) {
console.error(`Error checking ${exchangeId}:`, error.message);
}
}
return results;
}
// Run the check
checkAllExchangeMethods().then(results => {
console.table(results);
});
Exchange | Spot (OB/BA/OBS) | Futures (OB/BA/OBS)
----------------------------------------------------------
binance | ✓/✓/✓ | ✓/✓/✓
bybit | ✓/✓/✓ | ✓/✓/✓
okx | ✓/✓/✓ | ✓/✓/✓
gateio | ✓/✓/✓ | ✓/✓/✓
mexc | ✓/✓/✓ | ✓/✓/✓
kucoin | ✓/✓/✓ | ✓/✓/✓
huobi | ✓/✓/✓ | ✓/✓/✓
bitget | ✓/✓/✓ | ✓/✓/✓
Important note:
The script only checks for method presence in the JavaScript object, not actual support on the exchange side. So "✓" doesn't always mean functionality — as we saw with the Gate.io example.
1. Monitoring large number of pairs (100+):
watchBidsAsks2. Building full orderbook for one pair:
watchOrderBook3. Monitoring several pairs with full depth:
watchOrderBookForSymbolswatchOrderBook4. One-time data retrieval:
fetchOrderBookWs or regular REST APIConnection management:
// Bad: creating multiple connections
const symbols = ['BTC/USDT', 'ETH/USDT', 'ADA/USDT'];
const orderbooks = await Promise.all(
symbols.map(symbol => exchange.watchOrderBook(symbol))
);
// Good: one connection for all pairs (if supported)
try {
const orderbooks = await exchange.watchOrderBookForSymbols(symbols);
} catch (error) {
// Fallback to individual subscriptions
const orderbooks = await Promise.all(
symbols.map(symbol => exchange.watchOrderBook(symbol))
);
}
Depth management:
// Limit depth to save traffic
const orderbook = await exchange.watchOrderBook('BTC/USDT', 20); // only 20 levels
WebSocket connections can drop, so proper error handling is important:
async function robustWatchOrderBook(exchange, symbol, maxRetries = 3) {
let retries = 0;
while (retries < maxRetries) {
try {
const orderbook = await exchange.watchOrderBook(symbol);
retries = 0; // reset counter on success
return orderbook;
} catch (error) {
retries++;
console.error(`Subscription error (attempt ${retries}):`, error.message);
if (retries >= maxRetries) {
throw new Error(`Failed to subscribe after ${maxRetries} attempts`);
}
// Exponential backoff
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, retries)));
}
}
}
It's important to track the quality of received data:
function validateOrderBook(orderbook) {
// Check basic structure
if (!orderbook.bids || !orderbook.asks) {
throw new Error('Invalid orderbook structure');
}
// Check data freshness
const now = Date.now();
const dataAge = now - orderbook.timestamp;
if (dataAge > 10000) { // older than 10 seconds
console.warn('Stale orderbook data:', dataAge, 'ms');
}
// Check price logic
const bestBid = orderbook.bids[0] ? orderbook.bids[0][0] : 0;
const bestAsk = orderbook.asks[0] ? orderbook.asks[0][0] : 0;
if (bestBid >= bestAsk && bestBid > 0 && bestAsk > 0) {
console.warn('Crossed spread:', { bestBid, bestAsk });
}
}
Based on practical experience with CCXT, here are the main recommendations:
Always test methods on real data before implementing in production. Method presence in API doesn't guarantee functionality.
watchBidsAskswatchOrderBookfetchOrderBookWsFor monitoring large numbers of pairs, watchBidsAsks can be 1000x more efficient than watchOrderBookForSymbols.
Implement robust retry logic and data quality monitoring.
API behavior can differ dramatically under load vs test requests.
The industry is moving toward more standardized approaches:
WebSocket APIs for orderbooks are powerful tools but require deep understanding of each exchange's specifics. CCXT significantly simplifies the work by unifying interfaces, but reality is still more complex than documentation.
The key to success is testing, monitoring, and choosing the right methods for specific tasks. Remember: what works on one exchange might not work on another, even if the APIs look identical.
A successful trading system is not just correct algorithms, but also reliable data infrastructure. And CCXT WebSocket methods are an important part of this infrastructure.
What's your experience with exchange WebSocket APIs? Have you encountered unexpected issues? Share in the comments!
@software{soloviov2025ccxtprowebsocketorderbook, author = {Soloviov, Eugen}, title = {CCXT: How WebSocket Orderbook Methods Really Work}, year = {2025}, url = {https://marketmaker.cc/en/blog/post/ccxt-pro-websocket-orderbook-methods}, version = {0.1.0}, description = {Detailed breakdown of CCXT WebSocket methods for orderbooks: watchOrderBook, watchBidsAsks, watchOrderBookForSymbols. Real tests on 75+ exchanges.} }