Skip to main content

Order Book Depth

Stream real-time order book state changes from Deepbook pools. Each event includes current bid and ask levels with prices, quantities, and order counts—essential for depth charts, spread analysis, and liquidity monitoring.

Event Type

Events are emitted with type deepbook_order_book_depth and provide a snapshot of the current order book state.

Endpoint

GET /deepbook/{poolName}/live-trades

Note: Order book depth events are delivered on the same stream as live trades. Filter by event type to handle each appropriately.

Parameters

ParameterTypeRequiredDescription
poolNamestringYesTrading pool name (e.g., "SUI_USDC")
api-keystringYesYour Surflux API key (query parameter)

Event Structure

{
"type": "deepbook_order_book_depth",
"timestamp_ms": 1758629823918,
"checkpoint_id": 193054501,
"tx_hash": "FgUfRsYpC6ynW3pRvtgCLaa4WniBZYdsSLP94jrZ3pj7",
"data": {
"pool_id": "0xe05dafb5133bcffb8d59f4e12465dc0e9faeaa05e3e342a08fe135800e3e4407",
"bids": [
{
"price": 3380100,
"total_quantity": 2957000000000,
"order_count": 2
},
{
"price": 3380000,
"total_quantity": 2366000000000,
"order_count": 1
},
{
"price": 3379900,
"total_quantity": 443800000000,
"order_count": 1
}
],
"asks": [
{
"price": 3380500,
"total_quantity": 443700000000,
"order_count": 1
},
{
"price": 3381200,
"total_quantity": 11239000000000,
"order_count": 4
},
{
"price": 3383700,
"total_quantity": 8000000000000,
"order_count": 1
}
]
}
}

Field Reference

Event Metadata

FieldTypeDescription
typestringAlways "deepbook_order_book_depth" for order book events
timestamp_msnumberEvent timestamp in milliseconds
checkpoint_idnumberSui checkpoint when order book changed
tx_hashstringTransaction hash that caused the update

Order Book Data

FieldTypeDescription
pool_idstringDeepbook pool identifier
bidsarrayArray of bid levels, sorted highest to lowest
asksarrayArray of ask levels, sorted lowest to highest

Price Level Object

Each bid and ask level contains:

FieldTypeDescription
pricenumberPrice level (in smallest units)
total_quantitynumberTotal quantity available at this price
order_countnumberNumber of individual orders at this level

Use Cases

Depth Chart Visualization

Render live order book depth charts:

let orderBook = { bids: [], asks: [] };

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
// Convert to human-readable prices and quantities
orderBook.bids = data.data.bids.map(level => ({
price: level.price / 1e6, // USDC decimals
quantity: level.total_quantity / 1e9, // SUI decimals
orders: level.order_count
}));

orderBook.asks = data.data.asks.map(level => ({
price: level.price / 1e6,
quantity: level.total_quantity / 1e9,
orders: level.order_count
}));

// Calculate cumulative quantities for depth chart
const bidsWithCumulative = calculateCumulative(orderBook.bids, 'desc');
const asksWithCumulative = calculateCumulative(orderBook.asks, 'asc');

updateDepthChart(bidsWithCumulative, asksWithCumulative);
}
};

function calculateCumulative(levels, direction) {
let cumulative = 0;
const result = [];

const sorted = direction === 'desc'
? [...levels].reverse()
: levels;

for (const level of sorted) {
cumulative += level.quantity;
result.push({ ...level, cumulative });
}

return direction === 'desc' ? result.reverse() : result;
}

Spread Calculation

Monitor bid-ask spread in real-time:

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
const bestBid = data.data.bids[0];
const bestAsk = data.data.asks[0];

if (bestBid && bestAsk) {
const spread = bestAsk.price - bestBid.price;
const spreadPercent = (spread / bestBid.price) * 100;

console.log('Spread:', {
absolute: spread / 1e6, // USDC
percent: spreadPercent.toFixed(3) + '%',
midPrice: ((bestBid.price + bestAsk.price) / 2) / 1e6
});

updateSpreadDisplay(spread, spreadPercent);
}
}
};

Liquidity Analysis

Track available liquidity at different price ranges:

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
const { bids, asks } = data.data;

// Calculate liquidity depth
const bidLiquidity = bids.reduce((sum, level) => sum + level.total_quantity, 0);
const askLiquidity = asks.reduce((sum, level) => sum + level.total_quantity, 0);

// Find liquidity imbalance
const imbalance = (bidLiquidity - askLiquidity) / (bidLiquidity + askLiquidity);

console.log('Liquidity:', {
totalBids: bidLiquidity / 1e9, // SUI
totalAsks: askLiquidity / 1e9, // SUI
imbalance: (imbalance * 100).toFixed(2) + '%',
bidLevels: bids.length,
askLevels: asks.length
});

// Positive imbalance = more buy pressure
// Negative imbalance = more sell pressure
updateLiquidityIndicator(imbalance);
}
};

Market Making Strategy

Adjust order placement based on real-time book state:

const marketMaker = {
targetSpreadBps: 10, // 0.1% spread
minLiquidity: 1000 // Minimum 1000 SUI liquidity
};

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
const { bids, asks } = data.data;

if (!bids.length || !asks.length) return;

const bestBid = bids[0].price;
const bestAsk = asks[0].price;
const midPrice = (bestBid + bestAsk) / 2;

// Calculate liquidity
const topBidLiquidity = bids[0].total_quantity / 1e9;
const topAskLiquidity = asks[0].total_quantity / 1e9;

// Check if market making opportunity exists
const currentSpreadBps = ((bestAsk - bestBid) / midPrice) * 10000;

if (currentSpreadBps > marketMaker.targetSpreadBps) {
// Wide spread - place orders inside
const newBidPrice = midPrice * (1 - marketMaker.targetSpreadBps / 20000);
const newAskPrice = midPrice * (1 + marketMaker.targetSpreadBps / 20000);

console.log('Market making opportunity:', {
currentSpread: currentSpreadBps.toFixed(2) + ' bps',
suggestedBid: newBidPrice / 1e6,
suggestedAsk: newAskPrice / 1e6
});

// Execute market making strategy
placeMarketMakerOrders(newBidPrice, newAskPrice);
}
}
};

Order Book Display

Build a traditional order book UI:

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
const { bids, asks } = data.data;

// Take top 10 levels for display
const displayBids = bids.slice(0, 10).map(level => ({
price: (level.price / 1e6).toFixed(4),
quantity: (level.total_quantity / 1e9).toFixed(2),
total: (level.total_quantity / 1e9).toFixed(2),
orders: level.order_count
}));

const displayAsks = asks.slice(0, 10).map(level => ({
price: (level.price / 1e6).toFixed(4),
quantity: (level.total_quantity / 1e9).toFixed(2),
total: (level.total_quantity / 1e9).toFixed(2),
orders: level.order_count
}));

// Render order book table
renderOrderBook({
asks: displayAsks.reverse(), // Display asks from best to worst
spread: calculateSpread(bids[0], asks[0]),
bids: displayBids
});
}
};

Understanding Order Book Structure

Bids (Buy Orders)

Bids are sorted from highest to lowest price:

  • bids[0] is the best bid (highest buy price)
  • Traders willing to buy at these prices
  • Provides support in price analysis

Asks (Sell Orders)

Asks are sorted from lowest to highest price:

  • asks[0] is the best ask (lowest sell price)
  • Traders willing to sell at these prices
  • Provides resistance in price analysis

The Spread

The difference between best bid and best ask:

const spread = asks[0].price - bids[0].price;
const spreadPercent = (spread / bids[0].price) * 100;

Tight spreads indicate high liquidity and active trading. Wide spreads suggest lower liquidity.

Event Frequency

Order book depth events are emitted when:

  • New orders are placed
  • Existing orders are filled
  • Orders are cancelled or modified

Expect multiple events per second during active trading periods. Consider throttling UI updates to maintain performance:

let lastUpdate = 0;
const updateThrottle = 200; // Max 5 updates per second

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
const now = Date.now();

if (now - lastUpdate >= updateThrottle) {
updateOrderBookUI(data.data);
lastUpdate = now;
}
}
};

Price and Quantity Conversion

All values are in smallest units. Convert using pool metadata from Get Pools.

Example for SUI_USDC

  • Base asset (SUI): 9 decimals
  • Quote asset (USDC): 6 decimals
// Convert price level
const rawPrice = 3380100;
const humanPrice = rawPrice / Math.pow(10, 6); // = 3.3801 USDC per SUI

// Convert quantity
const rawQuantity = 2957000000000;
const humanQuantity = rawQuantity / Math.pow(10, 9); // = 2957 SUI

Connection Example

const poolName = 'SUI_USDC';
const apiKey = 'YOUR_API_KEY';

const url = `https://flux.surflux.dev/deepbook/${poolName}/live-trades?api-key=${apiKey}`;

const eventSource = new EventSource(url);

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'deepbook_order_book_depth') {
console.log('Order book update:', {
pool: data.data.pool_id.slice(0, 10) + '...',
bestBid: data.data.bids[0]?.price,
bestAsk: data.data.asks[0]?.price,
bidLevels: data.data.bids.length,
askLevels: data.data.asks.length,
time: new Date(data.timestamp_ms).toISOString()
});
}
};

Best Practices

  • Throttle UI Updates — Don't update on every event; batch updates every 100-200ms for smooth rendering
  • Limit Displayed Levels — Show top 10-20 levels in UI; full book can have 100+ levels
  • Cache Pool Decimals — Fetch once and reuse for all price/quantity conversions
  • Calculate Cumulative Depth — For depth charts, accumulate quantities from best price outward
  • Monitor Spread — Alert on abnormally wide spreads indicating low liquidity
  • Combine with Trades — Use both order book and live trades for complete market view

Next Steps