Orderbook Channel
Real-time orderbook updates with bids and asks
Overview
The book channel provides real-time orderbook updates for a specific trading product. You'll receive a snapshot of the current orderbook upon subscription, followed by incremental updates as the orderbook changes.
Channel: book
Authentication: Not required (Public)
Products: BTC-VND, ETH-VND, SOL-VND, XRP-VND
Subscribe
Request:
{
"op": "sub",
"channel": "book",
"product": "BTC-VND"
}Friendly format:
sub book BTC-VNDParameters:
op(string, required) - Must be"sub"channel(string, required) - Must be"book"product(string, required) - Trading pair (e.g.,"BTC-VND")
Responses
Subscription Confirmation
Upon successful subscription:
{
"channel": "book",
"product": "BTC-VND",
"type": "subscribed"
}Snapshot Message
Immediately after subscription, you'll receive a complete snapshot of the current orderbook:
{
"channel": "book",
"product": "BTC-VND",
"type": "snapshot",
"data": {
"bids": [
["3123300000", "0.079"],
["3123250000", "0.150"],
["3123200000", "0.200"]
],
"asks": [
["3123340000", "0.008"],
["3123400000", "0.050"],
["3123500000", "0.100"]
]
}
}Update Messages
After the snapshot, you'll receive incremental updates when the orderbook changes:
{
"channel": "book",
"product": "BTC-VND",
"type": "update",
"data": {
"bids": [
["3123300000", "0.060"]
],
"asks": []
}
}Data Structure
Each price level is represented as a tuple [price, size]:
type PriceLevel = [string, string];
interface OrderbookData {
bids: PriceLevel[]; // Buy orders, sorted by price (highest first)
asks: PriceLevel[]; // Sell orders, sorted by price (lowest first)
}Price Level Fields:
price(string) - Price in quote currency (VND)size(string) - Total quantity available at this price level
Understanding Updates
Price Level Updates
When you receive an update:
- New price level - If the price doesn't exist in your local orderbook, add it
- Size update - If the price exists, update the size
- Price removal - If size is
"0"or the price is not included, remove that price level
Example: Processing Updates
class OrderbookManager {
constructor() {
this.bids = new Map(); // price -> size
this.asks = new Map();
}
handleMessage(message) {
if (message.type === 'snapshot') {
// Reset orderbook with snapshot
this.bids.clear();
this.asks.clear();
message.data.bids.forEach(([price, size]) => {
this.bids.set(price, size);
});
message.data.asks.forEach(([price, size]) => {
this.asks.set(price, size);
});
} else if (message.type === 'update') {
// Apply incremental updates
message.data.bids.forEach(([price, size]) => {
if (parseFloat(size) === 0) {
this.bids.delete(price);
} else {
this.bids.set(price, size);
}
});
message.data.asks.forEach(([price, size]) => {
if (parseFloat(size) === 0) {
this.asks.delete(price);
} else {
this.asks.set(price, size);
}
});
}
}
getBestBid() {
const prices = Array.from(this.bids.keys()).map(Number);
const bestPrice = Math.max(...prices);
return { price: bestPrice, size: this.bids.get(bestPrice.toString()) };
}
getBestAsk() {
const prices = Array.from(this.asks.keys()).map(Number);
const bestPrice = Math.min(...prices);
return { price: bestPrice, size: this.asks.get(bestPrice.toString()) };
}
}Unsubscribe
To stop receiving orderbook updates:
Request:
{
"op": "unsub",
"channel": "book",
"product": "BTC-VND"
}Friendly format:
unsub book BTC-VNDResponse:
{
"type": "unsubscribed",
"channel": "book",
"product": "BTC-VND"
}Complete Example
const WebSocket = require('ws');
const ws = new WebSocket('wss://ws.dev.mbhq.net/ws');
const orderbook = new OrderbookManager();
ws.on('open', () => {
console.log('Connected to WebSocket');
// Subscribe to BTC-VND orderbook
ws.send(JSON.stringify({
op: 'sub',
channel: 'book',
product: 'BTC-VND'
}));
});
ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.channel === 'book') {
if (message.type === 'subscribed') {
console.log('Subscribed to orderbook');
} else if (message.type === 'snapshot' || message.type === 'update') {
orderbook.handleMessage(message);
const bestBid = orderbook.getBestBid();
const bestAsk = orderbook.getBestAsk();
const spread = bestAsk.price - bestBid.price;
console.log(`Best Bid: ${bestBid.price} (${bestBid.size})`);
console.log(`Best Ask: ${bestAsk.price} (${bestAsk.size})`);
console.log(`Spread: ${spread}`);
}
}
});Use Cases
- Market Making - Monitor bid-ask spread and adjust orders
- Price Display - Show real-time orderbook depth in your application
- Trading Signals - Detect large orders or liquidity changes
- Market Analysis - Analyze order flow and market depth
Best Practices
- Maintain Local State - Keep a local copy of the orderbook and apply updates incrementally
- Handle Reconnections - Re-subscribe after disconnection to get a fresh snapshot
- Validate Data - Check for price/size consistency and handle edge cases
- Optimize Performance - Use efficient data structures (Map, SortedMap) for price levels
- Monitor Latency - Track message timestamps to detect delays
Related Channels
- Ticker Channel - Best bid/ask prices only (lighter weight)
- Trades Channel - Actual trade executions