I researched every order-book attack and built the defenses into a Go engine

intrepidkarthi1 pts0 comments

orderbook — a fast, embeddable limit order book & matching engine in Go

What is this?

orderbook is a Go library you drop into your own project to run a<br>central limit order book (CLOB) and matching engine —<br>the core of an exchange, a trading simulator, a game economy, or any system where<br>buyers and sellers meet at a price. It is a focused, dependency-light core you can<br>go get today, with a small, stable API.

It’s not a hosted service or a full exchange (no accounts, custody, or settlement) —<br>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.

PRICESIZE

spread —mid —

How matching works

When a new order can trade, the engine matches it by price–time priority :<br>best price first, and among equal prices, first-come-first-served. Walk through it —<br>each step runs on the real engine.

PRICESIZE

spread —last —

▶ Start<br>Reset

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<br>Instrument converts decimals only at the boundary. No binary rounding<br>error creeping into balances, and an overflow guard rejects any order whose notional<br>would wrap.

Deterministic & replayable

The same ordered input always produces byte-identical trades and state. No wall-clock<br>or RNG in the matching path — so you can record a session and replay it exactly (verified<br>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<br>ladder. Measured: 6 ns top-of-book reads, ~2.8M match round-trips/s<br>per core, and 0 allocations on the submit/cancel/match hot path. Benchmarks run<br>in CI on every push.

Tested hard

Race, fuzz, soak, and replay-recovery suites under the race detector, plus<br>invariant checks (the book never crosses, quantity is conserved, FIFO holds). Green<br>on every push.

Embeddable & layered

The core (types · orderbook · matching) is<br>dependency-light and imports nothing above it. Drop it into your service; add only what<br>you need on top.

How it handles things

Each side is a map[price]→level plus a sorted price ladder; each level is<br>a FIFO queue (that’s time priority). One writer per book keeps it correct; you scale<br>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<br>Create an engine, submit orders, read the book:

eng := matching.NewEngine(matching.DefaultConfig("BTC-USD"))

// A resting sell (maker) — integer ticks & lots<br>ask, _ := types.NewOrder("alice", "BTC-USD", types.SideSell,<br>types.OrderTypeLimit, 30000, 5,<br>types.TIFGoodTillCancel)<br>eng.Process(ask)

// A crossing buy (taker) — trades against it<br>bid, _ := types.NewOrder("bob", "BTC-USD", types.SideBuy,<br>types.OrderTypeLimit, 30000, 3,<br>types.TIFGoodTillCancel)<br>res := eng.Process(bid)

for _, t := range res.Trades {<br>fmt.Printf("%d @ %d\n", t.Quantity, t.Price) // 3 @ 30000<br>best, qty, _ := eng.BestAsk() // 30000 x 2 left

Runnable examples:

go...

order book price types engine matching

Related Articles