Order Book Development
Order book is the central component of any exchange. Performance directly determines system capabilities: from execution latency to maximum throughput.
In-Memory Order Book
Order book lives in RAM. Disk access on each match is unacceptable for latency.
Classic structure: two sorted containers — bid side (buys, descending price) and ask side (sells, ascending price). At each price level — order queue (FIFO for price-time priority).
Tree choice:
- Red-black tree: O(log n) for all operations, good cache locality
- Skip list: concurrent, lockfree skip list gives better scalability
- Sorted slice + binary search: O(n) insert, O(log n) search, works for small books <1000 levels
For exchange with 10–20 trading pairs and moderate volume: one Go process handles >50,000 orders/sec.
Matching Algorithm
Price-time priority (FIFO) — standard for most exchanges. Order with best price executes first. At equal price — earlier order has priority.
Snapshot and Incremental Updates
Client doesn't receive full order book on connection — could be megabytes. Architecture:
- Client requests snapshot (top N levels, e.g. 50) via REST
- Subscribes to WebSocket channel diff updates
- Applies diff to local copy
type OrderBookSnapshot struct {
Sequence uint64 `json:"seq"`
Bids []PriceSizeKV `json:"bids"`
Asks []PriceSizeKV `json:"asks"`
Timestamp int64 `json:"ts"`
}
type OrderBookDiff struct {
Sequence uint64 `json:"seq"`
Bids []PriceSizeKV `json:"bids"` // size=0 means level removal
Asks []PriceSizeKV `json:"asks"`
}
Client discards diff with seq <= snapshot.Sequence, applies all subsequent.
Order Book Visualization
Grouping by Ticks
Real order book can have thousands of price levels. For display — grouping by "tick" (minimum display step):
function groupOrderBook(levels, tickSize, depth) {
const grouped = new Map<number, number>();
for (const [priceStr, sizeStr] of levels) {
const price = parseFloat(priceStr);
const size = parseFloat(sizeStr);
const bucket = Math.floor(price / tickSize) * tickSize;
grouped.set(bucket, (grouped.get(bucket) ?? 0) + size);
}
return Array.from(grouped.entries())
.sort((a, b) => b[0] - a[0])
.slice(0, depth)
.map(([price, size]) => ({ price, size }));
}
Ticks switched by user (0.01, 0.1, 1, 10, 100 for BTC/USDT) — this changes display granularity.
Depth Bar
Visual indicator of relative volume at level. Fills from left (asks/red) or right (bids/green) to show market pressure.
Performance
For exchange with 10–20 trading pairs and moderate volume: one Go-process handles >50,000 orders/sec.
Scaling: sharding by pairs (each pair — independent instance), horizontal API layer scaling with shared order book via Redis Sorted Sets (for read replicas).
| Metric | Value | Conditions |
|---|---|---|
| Matching latency | <100µs | In-memory, single core |
| Add order throughput | 100k+ ops/sec | Go, Red-Black tree |
| Cancel order | O(1) | Hash map lookup |
| Snapshot generation | <1ms | Top 50 levels |
| WS diff broadcast | <1ms | After each trade |
Database
Order book only in-memory. In PostgreSQL persisted:
- All orders (open, filled, cancelled)
- All trades
- Order book snapshots every N minutes (for recovery after restart)
On startup: load all status=open orders → restore in-memory book.
Development Timeline
- In-memory order book with FIFO matching: 3–4 weeks
- WebSocket diff feed + snapshots: 2–3 weeks
- Frontend visualizer with grouping, depth bars: 2–3 weeks
- Full production-ready component: 6–8 weeks







