Ticker Channel
Best bid/ask price updates
Overview
The ticker channel provides real-time updates of the best bid and ask prices for a specific trading product. This is a lightweight alternative to the orderbook channel when you only need top-of-book data.
Channel: ticker
Authentication: Not required (Public)
Products: BTC-VND, ETH-VND, SOL-VND, XRP-VND
Subscribe
Request:
{
"op": "sub",
"channel": "ticker",
"product": "BTC-VND"
}Friendly format:
sub ticker BTC-VNDParameters:
op(string, required) - Must be"sub"channel(string, required) - Must be"ticker"product(string, required) - Trading pair (e.g.,"BTC-VND")
Responses
Subscription Confirmation
Upon successful subscription:
{
"channel": "ticker",
"product": "BTC-VND",
"type": "subscribed"
}Snapshot Message
Immediately after subscription, you'll receive the current best bid and ask:
{
"channel": "ticker",
"product": "BTC-VND",
"type": "snapshot",
"data": {
"bid": {
"price": "3123760000",
"size": "0.033"
},
"ask": {
"price": "3124680000",
"size": "0.034"
}
},
"timestamp": "1755243387119627000"
}Update Messages
After the snapshot, you'll receive updates whenever the best bid or ask changes:
{
"channel": "ticker",
"product": "BTC-VND",
"type": "update",
"data": {
"bid": {
"price": "3123470000",
"size": "0.101"
},
"ask": {
"price": "3124680000",
"size": "0.034"
}
},
"timestamp": "1755243388119627000"
}Data Structure
interface TickerData {
bid: {
price: string; // Best bid price
size: string; // Size at best bid
};
ask: {
price: string; // Best ask price
size: string; // Size at best ask
};
}
interface TickerMessage {
channel: "ticker";
product: string;
type: "snapshot" | "update";
data: TickerData;
timestamp: string; // Nanoseconds since epoch
}Field Descriptions:
- bid.price - Highest buy order price (in quote currency, VND)
- bid.size - Total quantity available at the best bid
- ask.price - Lowest sell order price (in quote currency, VND)
- ask.size - Total quantity available at the best ask
- timestamp - Time of the update (nanoseconds since Unix epoch)
Example: Processing Ticker Updates
const WebSocket = require('ws');
const ws = new WebSocket('wss://ws.dev.mbhq.net/ws');
ws.on('open', () => {
console.log('Connected to WebSocket');
// Subscribe to BTC-VND ticker
ws.send(JSON.stringify({
op: 'sub',
channel: 'ticker',
product: 'BTC-VND'
}));
});
ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.channel === 'ticker') {
if (message.type === 'subscribed') {
console.log('Subscribed to ticker');
} else if (message.type === 'snapshot' || message.type === 'update') {
const { bid, ask } = message.data;
const bidPrice = parseFloat(bid.price);
const askPrice = parseFloat(ask.price);
const spread = askPrice - bidPrice;
const spreadPercent = (spread / bidPrice) * 100;
const midPrice = (bidPrice + askPrice) / 2;
console.log('=== BTC-VND Ticker ===');
console.log(`Bid: ${bid.price} VND (${bid.size} BTC)`);
console.log(`Ask: ${ask.price} VND (${ask.size} BTC)`);
console.log(`Spread: ${spread.toFixed(0)} VND (${spreadPercent.toFixed(3)}%)`);
console.log(`Mid Price: ${midPrice.toFixed(0)} VND`);
// Convert timestamp
const time = new Date(parseInt(message.timestamp) / 1000000);
console.log(`Time: ${time.toISOString()}`);
}
}
});Example: Price Alert System
class PriceAlert {
constructor(product, targetPrice, condition) {
this.product = product;
this.targetPrice = targetPrice;
this.condition = condition; // 'above' or 'below'
this.triggered = false;
}
check(tickerData) {
const midPrice = (parseFloat(tickerData.bid.price) +
parseFloat(tickerData.ask.price)) / 2;
if (this.triggered) return false;
if (this.condition === 'above' && midPrice >= this.targetPrice) {
this.triggered = true;
return true;
}
if (this.condition === 'below' && midPrice <= this.targetPrice) {
this.triggered = true;
return true;
}
return false;
}
}
// Usage
const alerts = [
new PriceAlert('BTC-VND', 3200000000, 'above'),
new PriceAlert('BTC-VND', 3000000000, 'below')
];
ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.channel === 'ticker' && message.type === 'update') {
alerts.forEach((alert, index) => {
if (alert.check(message.data)) {
console.log(`🚨 ALERT ${index + 1} TRIGGERED!`);
console.log(`${alert.product} price ${alert.condition} ${alert.targetPrice}`);
// Send notification, email, etc.
}
});
}
});Example: Multi-Product Ticker Dashboard
class TickerDashboard {
constructor() {
this.tickers = new Map();
}
update(product, data) {
const bidPrice = parseFloat(data.bid.price);
const askPrice = parseFloat(data.ask.price);
this.tickers.set(product, {
bid: bidPrice,
ask: askPrice,
spread: askPrice - bidPrice,
spreadPercent: ((askPrice - bidPrice) / bidPrice) * 100,
midPrice: (bidPrice + askPrice) / 2,
bidSize: parseFloat(data.bid.size),
askSize: parseFloat(data.ask.size)
});
}
display() {
console.clear();
console.log('='.repeat(80));
console.log('MOONBASE TICKER DASHBOARD');
console.log('='.repeat(80));
console.log('Product | Bid | Ask | Spread | Mid Price');
console.log('-'.repeat(80));
this.tickers.forEach((ticker, product) => {
console.log(
`${product.padEnd(10)} | ` +
`${ticker.bid.toFixed(0).padStart(13)} | ` +
`${ticker.ask.toFixed(0).padStart(13)} | ` +
`${ticker.spreadPercent.toFixed(3)}% | ` +
`${ticker.midPrice.toFixed(0)}`
);
});
}
}
// Connect to multiple products
const dashboard = new TickerDashboard();
const products = ['BTC-VND', 'ETH-VND', 'SOL-VND', 'XRP-VND'];
ws.on('open', () => {
products.forEach(product => {
ws.send(JSON.stringify({
op: 'sub',
channel: 'ticker',
product: product
}));
});
});
ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.channel === 'ticker' &&
(message.type === 'snapshot' || message.type === 'update')) {
dashboard.update(message.product, message.data);
dashboard.display();
}
});Unsubscribe
To stop receiving ticker updates:
Request:
{
"op": "unsub",
"channel": "ticker",
"product": "BTC-VND"
}Friendly format:
unsub ticker BTC-VNDResponse:
{
"type": "unsubscribed",
"channel": "ticker",
"product": "BTC-VND"
}Ticker vs. Orderbook
| Feature | Ticker Channel | Orderbook Channel |
|---|---|---|
| Data | Best bid/ask only | Full order depth |
| Message frequency | Lower | Higher |
| Bandwidth | Minimal | Higher |
| Use case | Price display | Order execution, market making |
| Latency | Very low | Low |
When to use Ticker:
- Displaying current price in UI
- Price alerts and notifications
- Multi-product dashboards
- Lower bandwidth requirements
When to use Orderbook:
- Market making strategies
- Analyzing market depth
- Visualizing orderbook
- Precise order placement
Use Cases
- Price Display - Show current market price in your application
- Spread Monitoring - Track bid-ask spread for trading opportunities
- Multi-Product Dashboard - Monitor multiple markets efficiently
- Price Alerts - Trigger alerts based on price thresholds
- Quick Quote - Get instant price quotes without full orderbook
Best Practices
- Lightweight - Use ticker instead of orderbook when you only need best prices
- Calculate Mid Price - Use (bid + ask) / 2 for a fair market price
- Monitor Spread - Large spreads may indicate low liquidity
- Combine with Trades - Use ticker for price, trades for actual executions
- Efficient Updates - Ticker updates only when top of book changes
Related Channels
- Orderbook Channel - Full market depth
- Trades Channel - Actual trade executions
- Portfolio Channel - Account balances for valuation