What is this?
orderbook is a Go library you drop into your own project to run a
central limit order book (CLOB) and matching engine —
the core of an exchange, a trading simulator, a game economy, or any system where
buyers and sellers meet at a price. It is a focused, dependency-light core you can
go get today, with a small, stable API.
It’s not a hosted service or a full exchange (no accounts, custody, or settlement) — it’s the engine. Everything you see on this page is powered by that exact engine.
First, what is an order book?
If you’ve never seen one, here it is from the ground up.
- People post offers. A bid is a buy order (“I’ll buy 5 at 100”). An ask is a sell order (“I’ll sell 3 at 101”).
- They’re sorted by price. Best bid (highest a buyer will pay) and best ask (lowest a seller will accept) sit in the middle. The gap between them is the spread.
- Size at each price is depth. Lots of size = a deep, liquid market that’s hard to move. Little size = thin, and prices swing.
- That whole ladder is the order book — a live list of everyone’s intentions, updating constantly. →
The ladder on the right is a real book from this engine. Best bid/ask are highlighted; the spread is the gap in the middle.
How matching works
When a new order can trade, the engine matches it by price–time priority: best price first, and among equal prices, first-come-first-served. Walk through it — each step runs on the real engine.
Press Start to build a book, rest an order, and send a market order that matches.
- Maker — a limit order that rests and provides liquidity.
- Taker — a market/crossing order that removes it, paying the spread.
- Trades print at the maker’s price. Big orders “walk the book” and pay more (slippage).
Everything it does
The order-type and market-integrity surface real venues ship — all in the core.
Order types
- Market & Limit
- Stop & Stop-limit
- Iceberg (hidden reserve, auto-refill)
- Post-only (maker-guaranteed)
- Pegged (to bid / ask / mid + offset)
- OCO / bracket (one-cancels-other)
- Trailing stop
Matching & priority
- Price–time priority (FIFO)
- Pro-rata allocation mode
- Trades at the maker price
- Self-trade prevention (5 modes)
- Time-in-force: GTC · IOC · FOK
- Call-auction uncross (open/close)
Market integrity
- Pre-trade risk caps (fat-finger, dust, per-account)
- Anti-spoofing: min resting time, order-to-trade ratio
- Mark-price step + depth bounds; self-output guardrail
- Surveillance: marking-close, ramping, pinging, cross-book
- Halt / cancel-only states; enforcing gateway
- Grounded in a threat model ↗
Market data
- L1 top-of-book
- L2 aggregated depth
- L3 / MBO (order-by-order)
- Snapshots + sequence numbers
- Trade tape (time & sales)
Why it’s production-grade
Money is never a float
Prices and quantities are int64 ticks and lots — a per-symbol
Instrument converts decimals only at the boundary. No binary rounding
error creeping into balances, and an overflow guard rejects any order whose notional
would wrap.
Deterministic & replayable
The same ordered input always produces byte-identical trades and state. No wall-clock or RNG in the matching path — so you can record a session and replay it exactly (verified by a record→replay→identical-digest test).
Fast, with real numbers
O(1) best bid/ask, O(1) cancel, O(log n) inserts via a map + binary-search price ladder. Measured: 6 ns top-of-book reads, ~2.8M match round-trips/s per core, and 0 allocations on the submit/cancel/match hot path. Benchmarks run in CI on every push.
Tested hard
Race, fuzz, soak, and replay-recovery suites under the race detector, plus invariant checks (the book never crosses, quantity is conserved, FIFO holds). Green on every push.
Embeddable & layered
The core (types · orderbook · matching) is
dependency-light and imports nothing above it. Drop it into your service; add only what
you need on top.
How it handles things
Each side is a map[price]→level plus a sorted price ladder; each level is
a FIFO queue (that’s time priority). One writer per book keeps it correct; you scale
out across symbols. IDs and timestamps are injected where determinism requires it.
Use it in your project
Install:
go get github.com/intrepidkarthi/orderbook/pkg/matching
Create an engine, submit orders, read the book:
eng := matching.NewEngine(matching.DefaultConfig("BTC-USD"))
// A resting sell (maker) — integer ticks & lots
ask, _ := types.NewOrder("alice", "BTC-USD", types.SideSell,
types.OrderTypeLimit, 30000, 5,
types.TIFGoodTillCancel)
eng.Process(ask)
// A crossing buy (taker) — trades against it
bid, _ := types.NewOrder("bob", "BTC-USD", types.SideBuy,
types.OrderTypeLimit, 30000, 3,
types.TIFGoodTillCancel)
res := eng.Process(bid)
for _, t := range res.Trades {
fmt.Printf("%d @ %d\n", t.Quantity, t.Price) // 3 @ 30000
}
best, qty, _ := eng.BestAsk() // 30000 x 2 left
Runnable examples:
go run ./examples/basic # place & match
go run ./examples/signals # book imbalance + OFI
go run ./cmd/obdemo # end-to-end demo
Docs:
- Documentation — design, internals, features, benchmarks
- API reference — pkg.go.dev
- Order books from scratch
- Source & issues