orderbook

August 17, 2026 · View on GitHub

A fast, embeddable limit-order-book and matching engine in Go — and a research harness plus an animated, hosted explainer for market microstructure, market making, and strategy backtesting.

Status: implemented and evolving — current release and history in the CHANGELOG · Author: Karthikeyan NG · Last updated: 2026-08-03

Companion documents:


1. Vision

This repository has a deliberate three-part mandate:

  1. A library others can use. A clean, efficient, well-tested, embeddable central limit order book (CLOB) and matching engine — something you can go get and drop into an exchange, a simulator, a teaching tool, or a trading application.

  2. A research harness. A place to build, backtest, and honestly evaluate market-microstructure ideas — order-flow imbalance, market making (Avellaneda–Stoikov), price impact (Kyle's lambda), delta/CVD, adverse selection — with reproducible experiments rather than screenshots and anecdotes.

  3. A hosted, animated explainer. A web demo that runs the real engine in the browser (via WebAssembly) and teaches — with animation — how an order book works, how matching works, and how market making works. Useful to anyone trying to understand these systems.

These goals pull in slightly different directions: a reusable core wants to be lean and dependency-light; a research harness and a rich UI want heavier tooling. The design reconciles them with one rule, enforced everywhere:

Strict downward layering. The core library never imports the research, simulation, strategy, or presentation layers. Dependencies flow one way only.

That single constraint lets one repository be a credible engineering artifact, a research platform, and an educational product without any of the three compromising the others.


2. Goals & non-goals

Goals

  • Correct, deterministic matching with price–time priority (and optional pro-rata) — money is never a float.
  • Embeddable: a small, stable public API with minimal dependencies.
  • Fast enough to be interesting: hundreds of thousands of ops/sec/core (§7), with benchmarks tracked in-repo.
  • A full, real-world order-type and market-integrity surface (§5) — the set popular exchanges actually ship, not just market/limit.
  • A research layer that turns microstructure claims into falsifiable experiments.
  • An animated demo that compiles the core to WASM and runs it live in-browser.

Non-goals (for now)

  • Not a nanosecond-latency colocated HFT engine. This is Go, not C++ with kernel bypass; we compete on clarity, correctness, and throughput.
  • Not a full exchange (no auth, custody, KYC, settlement) — though the core is designed to be embeddable inside one.
  • Not financial advice or a "profitable strategy" generator. The research tooling exists to understand and stress-test ideas — including proving some don't survive costs.

3. Architecture

Layered; dependencies flow downward only. The presentation column is a sibling that consumes the core through the WASM boundary.

┌───────────────────────────────┐        ┌──────────────────────────────┐
│  apps / cmd                    │        │  web/ (React + TS)           │
│  demos, tools, experiment      │        │  animated educational demo   │
│  runners                       │        │  ── consumes ──▶ obwasm      │
├───────────────────────────────┤        └──────────────┬───────────────┘
│  backtest   PnL, inventory,    │                       │ (WASM boundary)
│             Sharpe, adverse    │                       │
│             selection, reports │        ┌──────────────▼───────────────┐
├───────────────────────────────┤        │  cmd/obwasm                  │
│  strategy   market making      │        │  Go→WASM bindings over core  │
│             (Avellaneda–Stoikov)        └──────────────┬───────────────┘
├───────────────────────────────┤                       │
│  sim        exchange simulator,│                       │
│             synthetic agents   │                       │
├───────────────────────────────┤                       │
│  signals    OFI, imbalance,    │                       │
│             delta/CVD, lambda  │                       │
├───────────────────────────────┤                       │
│  marketdata feeds, L2/L3       │                       │
│             replay, capture    │                       │
╞═══════════════════════════════╪═══════════════════════╡
│  CORE LIBRARY (standalone, importable, dependency-light)               │
│    surveillance  spoofing/layering, cascade, rate/velocity limits      │
│    matching      price-time (+ pro-rata), TIF, STP, auctions           │
│    orderbook     CLOB structure, L2/L3, depth, snapshots               │
│    types         Order, Trade, Side, errors, Instrument (int64 ticks)  │
└───────────────────────────────────────────────────────────────────────┘

Everything above the double line is research/tooling/presentation and may depend on the core. Nothing below it may depend on anything above it.


4. Package layout

orderbook/
├── go.mod                      module github.com/intrepidkarthi/orderbook
├── README.md
├── CHANGELOG.md                release history
├── LICENSE                     MIT
├── docs/
│   ├── SPEC.md                 this document
│   ├── THREAT-MODEL.md         attacks & defenses (with real enforcement cases)
│   ├── INTEGRATION.md          embedding & operating the engine
│   ├── CONFIG.md               every configuration knob
│   ├── EXCHANGE-ARCHITECTURE.md how real venues implement matching
│   ├── BENCHMARKS.md           performance results & method
│   ├── LEARN.md                order books from first principles
│   ├── research-roadmap.md     microstructure research agenda
│   └── DEMO-SPEC.md            animated demo + hosting spec
├── legacy/
│   └── orderbook_v0.go         original float64 prototype (frozen, build-ignored)
├── pkg/
│   ├── types/                  Order, Trade, Side, OrderType, TIF, iceberg, errors
│   ├── orderbook/              CLOB: price levels, ladder, depth, L2/L3, snapshot
│   ├── matching/               engine (price-time, pro-rata), Runner, events,
│   │                          snapshots, pre-trade risk & anti-manipulation controls
│   ├── wal/                    durable write-ahead log + snapshot persistence + recovery
│   ├── auction/               uniform-price uncross + call-auction session (open/close)
│   ├── surveillance/           spoofing, OTR, marking-the-close, ramping, pinging, cross-book
│   ├── gateway/               enforcing edge controls: rate gate + taker speed bump
│   ├── marketdata/             feed interfaces, L2/L3 replay, live capture
│   ├── signals/                OFI, imbalance, delta, CVD, Kyle's lambda
│   ├── strategy/               market-making strategies (AS, …)
│   ├── study/                 microstructure studies over captured data
│   ├── sim/                    exchange simulator + synthetic agents
│   └── backtest/               harness + performance metrics
├── cmd/                        obdemo, obwasm, surveil, l2capture, obmm,
│                               ofistudy, lambdastudy, flowstudy
├── examples/                   basic, eventfeed, gateway, marketmaker, signals
└── web/                        React + TypeScript animated demo (see DEMO-SPEC.md)

5. The order model (real-world surface)

The set of order types, matching modes, and market-integrity controls that production venues (Binance, Coinbase, Kraken, CME, Nasdaq, LMAX, dYdX, Hyperliquid) actually ship. Not all land day one — see the milestones (§10) — but the core is designed so each slots in without redesign.

5.1 Order types

TypeNotes
MarketTakes liquidity immediately; may sweep multiple levels.
LimitRests at a price or better.
Stop / Stop-LimitTriggers a market/limit order when the market touches a stop price (stop-loss, take-profit).
Iceberg / ReserveShows only a display quantity; the hidden remainder auto-refills as the tip fills.
Hidden / DarkFully non-displayed resting liquidity.
Post-OnlyMaker-only; rejected (or repriced) if it would cross and take.
PeggedPrice tracks a reference (mid / bid / ask; primary & market peg).
OCOOne-cancels-other (e.g., take-profit + stop-loss bracket).
OTO / BracketOne-triggers-other; entry that arms exits on fill.
Trailing stopStop that follows the market by an offset.
Auction ordersMarket/Limit-on-open, Market/Limit-on-close.
Reduce-only / Min-qtyDerivatives & execution constraints.

5.2 Matching & execution

  • Price–time priority (FIFO) as the default; pro-rata and price-time/ pro-rata hybrid allocation as a per-symbol mode (common in futures).
  • Time-in-force: GTC, GTD, DAY, IOC, FOK.
  • Trades print at the maker's (resting) price.
  • Self-trade prevention: cancel-newest / cancel-oldest / cancel-both / decrement.
  • Fees: maker–taker with tiers and rebates (modeled for backtests).
  • Auctions: opening / closing / volatility auctions with single-price uncrossing.
  • Guards: tick size, lot size, min notional, price bands / LULD circuit breakers.

5.3 Market integrity & surveillance

A first-class concern: every control is grounded in a real enforcement case or incident, catalogued in THREAT-MODEL.md (attack → detection signal → defense → core-or-layer). It splits four ways:

  • In-core pre-trade controls (matching.Config, cold path, Privileged-exempt, replay-safe): fat-finger & dust size/notional caps, per-account order cap, minimum resting time (anti-spoofing), ClientOrderID idempotency, mark-price step + depth bounds (anti oracle-pump), per-call ForceTrade cap (chunked liquidation), timed band-breach pause, self-output Guardrail (the Knight tripwire), STP, feature-flagged order types, degraded states (halt / cancel-only), and randomized iceberg peaks. Full knob list in CONFIG.md.
  • Surveillance (pkg/surveillance, alert-only): spoofing/layering, order-to-trade ratio, marking-the-close, ramping, pinging, and a CrossBookMonitor for cross-product abuse — fed off the engine's sequenced event stream.
  • Gateway (pkg/gateway, enforcing at the edge): a token-bucket rate gate that rejects (cancels never gated) and an asymmetric taker speed bump.
  • Auction (pkg/auction): uniform-price open/close/recovery call auction with a replay-safe randomized close (defeats marking-the-close).

Stop-cascade protection (halt when triggers chain past a threshold) is built into the matcher; kill-switch / mass-cancel and cancel-on-disconnect are gateway concerns.

5.4 Market data

  • L1 (top of book), L2 (aggregated per price), L3 / MBO (full order-by-order).
  • Snapshots + incremental diffs, monotonic sequence numbers, gap detection.
  • Trade tape (time & sales), depth heatmap, OHLCV aggregation.

6. Core design decisions

Each records the choice, the rationale, and the alternative we deferred.

6.1 Price & quantity — int64 ticks & lots (decimal at the edge)

  • Choice: the engine works in integer ticks and lots (int64). A per- symbol types.Instrument{TickSize, LotSize} converts human decimals to/from ticks at the API boundary; the hot path never touches decimal or floats.
  • Why: integers are both exact (no binary FP error — the bug the legacy/ float64 prototype had) and fast (no allocation, no big.Int). Decimals are correct but allocate; keeping them only at the edge gave a zero-alloc, integer-exact match path.
  • History: the engine shipped decimal-first (v0.1.0) for correctness, then moved to int64 ticks in v0.2.0 once the benchmarks showed decimal allocation dominating the hot path. shopspring/decimal remains only for the Instrument boundary and display formatting.

6.2 Book structure — map + sorted ladder

  • Choice: map[price]→*PriceLevel (O(1) lookup) + a price-sorted slice with binary-search insertion (O(log n) new-level insert, O(1) best access). Each level is a FIFO queue → price–time priority.
  • Why: best bid/ask is read constantly; it must be O(1). New price levels are comparatively rare.
  • Deferred, and not attempted: heap / balanced BST / skip-list / radix-bucketed ladders. Stated this way deliberately — an earlier wording called them "benchmark alternatives", which entitles a reader to assume a comparison exists. None was ever built, and no alternative is kept behind an interface for A/B measurement. See PERFORMANCE-ROADMAP.md M11, experiments 2 and 3.

6.3 Concurrency — single writer per book (lock-free hot path)

  • One matching goroutine owns each book with no lock on the hot path (the LMAX single-writer principle). Concurrent producers submit through an MPSC command queue (matching.Runner); the writer applies commands in FIFO order, preserving determinism. Readers use the book's own RW-lock for snapshots.
  • The bare Engine is the single-writer core (drive it from one goroutine); Runner is the concurrency front. Landed in v0.3.0 (removed the engine mutex). Scale-out is across symbols (one book/goroutine each), not by parallelizing one book.
  • Deferred: sharding across symbols on a thread pool; swapping the channel queue for a lock-free ring buffer (the command/dispatch split leaves room).

6.4 Determinism — a hard requirement

Given the same ordered input stream, the engine produces byte-identical trades and state. No wall-clock or RNG in the matching path; anything that must be deterministic (timestamps, IDs) is injected. Determinism is what makes replay, golden-file tests, and honest backtests possible.

6.5 Identifiers

  • UUIDv7 (time-ordered) at the boundary; monotonic sequence numbers internally for deterministic ordering and replay.

7. Performance targets

Aspirational baselines from the author's prior matching engine on an Apple M4; treated as regression targets once benchmarks exist — not marketing.

MetricTarget (per core)
Order insert (resting)≥ 500k / sec
Order match≥ 200k / sec
Best bid/ask read< 1 µs
Hot-path allocationsbounded, measured

Benchmarks live in-repo (go test -bench), tracked over time, run under the race detector in CI.


8. Testing & quality

  • Unit tests per package.
  • Invariant/property tests: book never crosses (best bid < best ask); total quantity conserved across a match; no negative sizes; FIFO preserved per level.
  • Fuzzing on random order streams (no panics; invariants hold).
  • Golden-file replay: a recorded stream reproduces identical trades/state — the determinism guarantee.
  • Race detector and benchmarks in CI (GitHub Actions).

9. Research agenda (summary)

Detailed in research-roadmap.md. Each item ships as implementation → runnable experiment → honest write-up (does it survive out-of-sample data and trading costs?):

  1. Order-flow imbalance (Cont, Kukanov & Stoikov, 2014) — reproduce the strong contemporaneous R²; then test whether it predicts the next interval. That distinction is the whole ballgame.
  2. Kyle's lambda (1985) — estimate price impact per unit of flow inside the simulator, where ground truth is known.
  3. Avellaneda–Stoikov (2008) — reservation price + optimal spread market making; backtest and measure inventory, adverse selection, PnL, Sharpe.
  4. Delta / CVD / absorption — implement the retail order-flow primitives and stress-test the "trapped trader" narratives statistically.

10. Milestones (each = one or more small commits) — historical

This is not the project's plan. PERFORMANCE-ROADMAP.md is. The table below is the original pre-WAL research plan, kept because it records the order the library was actually built in and because several sections above refer to it. Every milestone in it is delivered. Its M0M11 numbering is unrelated to the roadmap's M0M15, which is a production-readiness plan for a system that did not exist when this was written — so "M3" means two entirely different things in the two documents. Two milestone lists in docs/ with different content and colliding identifiers is precisely how a status pass goes wrong; this note is the guard rail.

#Milestone
M0Spec (this doc) + research roadmap + demo spec.
M1Core: types + orderbook + lean matching (market/limit, GTC/IOC/FOK, STP) + tests + cmd/obdemo + CI (build/vet/test-race).
M2signals: book imbalance + OFI, with tests.
M3sim + marketdata replay: synthetic order flow to trade against.
M4strategy Avellaneda–Stoikov + backtest harness + metrics.
M5Live L2 capture (crypto WS) + OFI contemporaneous-vs-predictive study.
M6Advanced order types: Stop/Stop-Limit, Iceberg/Hidden, Post-Only, Pegged, OCO/Bracket, Trailing.
M7surveillance: STP modes, spoofing/layering, stop-cascade, rate/ratio limits.
M8Auctions + circuit breakers (LULD); pro-rata matching mode.
M9cmd/obwasm WASM bindings + web/ scaffolding + demo scenes 1–4 (mechanics).
M10Demo scenes 5–8 (signals, market making, surveillance) + GitHub Pages deploy. (CI landed early in M1.)
M11Perf pass (int-tick fast path, allocation audit); L3/MBO feed; benchmark dashboard.

11. Provenance & license

The core design is informed by the author's prior production matching engine (alef/matching-engine): decimal pricing, price–time priority, the map+ladder book structure, and the matching algorithm. This repository is a clean, research- and education-oriented re-implementation — not a copy of that exchange stack.

License: MIT.