OPEN SOURCE · GO · MIT

A limit order book & matching engine,
built for production — in Go.

The piece of software at the heart of every exchange: it holds every buy and sell order and matches them, fairly and fast. This one is embeddable, uses integer-exact pricing (int64 ticks, never floats), is fully deterministic, ships every order type real venues use, and defends against real market-manipulation attacks. The engine below is the real thing — compiled to WebAssembly, running in your browser.

Get started See the features View source
6 nsbest bid/ask read
~2.8M/smatch round-trip
0alloc on the hot path
int64exact pricing, no floats

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.

  1. 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”).
  2. 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.
  3. Size at each price is depth. Lots of size = a deep, liquid market that’s hard to move. Little size = thin, and prices swing.
  4. 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.

PRICESIZE
spread —mid —

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.

PRICESIZE
spread —last —

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:

⭐ Star it on GitHub
loading the engine…