Overview
Connect to receive real-time orderbook data for a specific market, including initial snapshots and incremental updates.
Connection
wss://api.bison.markets/ws/kalshi/orderbook/{marketTicker}
The Kalshi market ticker (e.g., KXBTC-100K-DEC31)
Example Connection
const marketTicker = "KXBTC-100K-DEC31";
const ws = new WebSocket(
`wss://api.bison.markets/ws/kalshi/orderbook/${marketTicker}`
);
// Track orderbook state
let orderbook = {
yes: new Map(), // price_uusdc -> quantity
no: new Map() // price_uusdc -> quantity
};
ws.onopen = () => {
console.log(`Connected to ${marketTicker} orderbook`);
// Send heartbeat every 30 seconds
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: "ping" }));
}
}, 30000);
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === "orderbook_snapshot") {
handleSnapshot(data);
} else if (data.type === "orderbook_delta") {
handleDelta(data);
}
};
function handleSnapshot(snapshot) {
// Reset orderbook with full snapshot
orderbook.yes.clear();
orderbook.no.clear();
if (snapshot.yes) {
snapshot.yes.forEach(level => {
orderbook.yes.set(level.price_uusdc, level.quantity);
});
}
if (snapshot.no) {
snapshot.no.forEach(level => {
orderbook.no.set(level.price_uusdc, level.quantity);
});
}
console.log("Orderbook initialized:", orderbook);
}
function handleDelta(delta) {
// Apply incremental update
const book = delta.side === "yes" ? orderbook.yes : orderbook.no;
const currentQty = book.get(delta.price_uusdc) || 0;
const newQty = currentQty + delta.delta;
if (newQty <= 0) {
book.delete(delta.price_uusdc);
} else {
book.set(delta.price_uusdc, newQty);
}
console.log(`Orderbook updated: ${delta.side} @ ${delta.price_uusdc}: ${newQty}`);
}
Message Types
The Orderbook WebSocket sends two types of messages:
Snapshot Message
Sent immediately upon connection, providing the complete current orderbook state.
{
"type": "orderbook_snapshot",
"market_ticker": "KXBTC-100K-DEC31",
"yes": [
{ "price_uusdc": 750000, "quantity": 100 },
{ "price_uusdc": 740000, "quantity": 250 },
{ "price_uusdc": 730000, "quantity": 500 }
],
"no": [
{ "price_uusdc": 260000, "quantity": 150 },
{ "price_uusdc": 270000, "quantity": 300 },
{ "price_uusdc": 280000, "quantity": 400 }
]
}
Always "orderbook_snapshot"
Market ticker for this orderbook
Array of YES side price levels, ordered by price
Total quantity available at this price
Array of NO side price levels, ordered by priceStructure is the same as yes array.
Delta Message
Sent for each orderbook change, providing an incremental update.
{
"type": "orderbook_delta",
"market_ticker": "KXBTC-100K-DEC31",
"side": "yes",
"price_uusdc": 750000,
"delta": 50
}
Market ticker for this update
Price level being updated
Change in quantity (positive for additions, negative for removals)
Maintaining Accurate State
To maintain an accurate orderbook:
- Initialize with the snapshot on connection
- Apply each delta by adding it to the current quantity at that price level
- Remove price levels when their quantity reaches zero or below
Example: Orderbook Display
class OrderbookManager {
constructor(marketTicker) {
this.marketTicker = marketTicker;
this.orderbook = {
yes: new Map(),
no: new Map()
};
this.ws = null;
}
connect() {
this.ws = new WebSocket(
`wss://api.bison.markets/ws/kalshi/orderbook/${this.marketTicker}`
);
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === "orderbook_snapshot") {
this.applySnapshot(data);
} else if (data.type === "orderbook_delta") {
this.applyDelta(data);
}
};
// Heartbeat
setInterval(() => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: "ping" }));
}
}, 30000);
}
applySnapshot(snapshot) {
this.orderbook.yes.clear();
this.orderbook.no.clear();
if (snapshot.yes) {
snapshot.yes.forEach(level => {
this.orderbook.yes.set(level.price_uusdc, level.quantity);
});
}
if (snapshot.no) {
snapshot.no.forEach(level => {
this.orderbook.no.set(level.price_uusdc, level.quantity);
});
}
this.render();
}
applyDelta(delta) {
const book = delta.side === "yes" ? this.orderbook.yes : this.orderbook.no;
const currentQty = book.get(delta.price_uusdc) || 0;
const newQty = currentQty + delta.delta;
if (newQty <= 0) {
book.delete(delta.price_uusdc);
} else {
book.set(delta.price_uusdc, newQty);
}
this.render();
}
render() {
console.log(`\n=== ${this.marketTicker} Orderbook ===`);
// YES side (sorted descending by price)
console.log("\nYES:");
const yesPrices = Array.from(this.orderbook.yes.keys()).sort((a, b) => b - a);
yesPrices.forEach(price => {
const qty = this.orderbook.yes.get(price);
const priceUSDC = (price / 1_000_000).toFixed(2);
console.log(` ${priceUSDC}: ${qty} contracts`);
});
// NO side (sorted descending by price)
console.log("\nNO:");
const noPrices = Array.from(this.orderbook.no.keys()).sort((a, b) => b - a);
noPrices.forEach(price => {
const qty = this.orderbook.no.get(price);
const priceUSDC = (price / 1_000_000).toFixed(2);
console.log(` ${priceUSDC}: ${qty} contracts`);
});
}
getBestBidAsk() {
const yesPrices = Array.from(this.orderbook.yes.keys());
const noPrices = Array.from(this.orderbook.no.keys());
return {
yesBid: yesPrices.length > 0 ? Math.max(...yesPrices) : null,
yesAsk: yesPrices.length > 0 ? Math.min(...yesPrices) : null,
noBid: noPrices.length > 0 ? Math.max(...noPrices) : null,
noAsk: noPrices.length > 0 ? Math.min(...noPrices) : null,
};
}
disconnect() {
if (this.ws) {
this.ws.close();
}
}
}
// Usage
const manager = new OrderbookManager("KXBTC-100K-DEC31");
manager.connect();
// Later, get best bid/ask
const { yesBid, yesAsk, noBid, noAsk } = manager.getBestBidAsk();
console.log(`Best YES: ${yesBid} / ${yesAsk}`);
console.log(`Best NO: ${noBid} / ${noAsk}`);
Use Cases
Order Book Depth
Display full market depth with all price levels
Trading Interfaces
Build professional trading UIs with real-time order flow
Market Making
Monitor liquidity for algorithmic trading strategies
Price Discovery
Analyze order book imbalances and market sentiment
Best Practices
Initialize with Snapshot
Always start by processing the initial snapshot message to establish baseline state.
Apply Deltas Incrementally
Add delta values to existing quantities rather than replacing them.
Clean Up Zero Quantities
Remove price levels from your orderbook when their quantity reaches zero or below.
Sort Price Levels
Sort bids descending and asks ascending for proper display.
Handle Reconnection
On reconnection, the snapshot will reset your state automatically.