Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Low-Latency Limit Order Book & Matching Engine (C++20)

An exchange-grade limit order book with price-time priority matching, built from scratch in modern C++ as a study of low-latency systems design. The project is developed in stages, each one introducing a technique used in real high-frequency trading systems and measuring its impact.

Status

Stage Focus State
1 Correct single-threaded matching engine + full test suite ✅ done
2 Cache-friendly data structures + benchmarks (before/after) ✅ done
3 Latency instrumentation (p50/p99/p99.9), throughput planned
4 Market-data feed handler (binary protocol parsing) planned
5 Lock-free SPSC queue between feed and matching threads planned
6 Custom pool allocator, zero hot-path allocations planned

What it does today

  • Limit orders with price-time priority (best price first, FIFO within a price)
  • Add / cancel / modify, with correct priority semantics on modify
  • Multi-level sweeps, partial fills, and price improvement (trades execute at the resting/maker price)
  • O(1) cancel/modify via an order-id index
  • ~12 M messages/s add+cancel throughput, flat from 10 to 10,000 price levels
  • 14 unit tests covering the matching semantics (GoogleTest)

Results (Stage 1 → Stage 2)

Same benchmarks, same machine, same flags — only the book's internals changed. Full table and analysis in BENCHMARKS.md.

Benchmark (10,000 price levels) std::map + std::list flat ladder + arena
Level lookup (quantity_at) 250 ns 6.7 ns
Add + cancel round trip 713 ns 164 ns
Sweep 64 levels 18.5 µs 8.1 µs

The point isn't the multiplier, it's the flat line: Stage 1 got slower as the book got deeper, Stage 2 doesn't — add+cancel measures 171 / 168 / 186 / 164 ns across a 1000× range of book depth.

Design notes

  • Integer fixed-point prices, never double — exact and fast to compare.
  • Flat price ladder. Price levels live in a std::vector<Level> indexed by price - base_, so finding a level is arithmetic, not a search. A Level is 16 bytes — four per cache line.
  • Order arena with an intrusive freelist. Every resting order lives in one std::vector<OrderNode> (32 bytes each); cancelled slots are recycled, so a steady-state book performs no allocation at all. Stage 1 did up to three mallocs per resting order, which the baseline showed was ~90% of its cost.
  • Links are indices, not pointers. A std::vector reallocates as it grows and every pointer into it dies; a 32-bit slot number survives. Levels hold head/tail slot numbers, and the id index maps OrderId → slot number.
  • Price band. The ladder covers a growing window of prices, capped at ~1M ticks; orders outside it are rejected, the same way a real venue's limit-up / limit-down bands reject them.
  • The engine is a library; the demo app, tests, and benchmarks link the same code.

Build & run (Windows / MSVC)

cmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release
./build/Release/order_book_test.exe                              # tests
./build/Release/demo.exe                                         # demo scenario
./build/Release/order_book_bench.exe --benchmark_min_time=0.35s  # benchmarks

On Linux/macOS, drop the -G/-A flags and use --config only if your generator is multi-config.

Layout

include/     types.hpp, order_book.hpp     — public API
src/         order_book.cpp, main.cpp      — engine + demo
tests/       order_book_test.cpp           — GoogleTest suite
benchmarks/  order_book_bench.cpp          — Google Benchmark suite
BENCHMARKS.md                              — frozen before/after numbers

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages