systems project // active development
Order Book [ Phase 05 // Cancellation & Order Lifecycle ]
I am building a correctness-first electronic limit order book in modern C++ because apparently my idea of a relaxing side project is asking, "what if a queue had opinions about fairness, latency, and the memory hierarchy?"
This is explicitly a current work in progress. It is not done, not polished, and not pretending to be a production exchange. The goal is to understand the infrastructure underneath modern markets: matching orders, preserving price-time priority, and designing data structures that do not make the CPU file a formal complaint.
As it grows, I am planning to add benchmarking, profiling, unit tests, market data feeds, replay tools, and progressively more performance-focused experiments. Less "hot stock tip," more "let me build the tiny engine room where the market plumbing lives."
[DONE] define orders and price levels
[DONE] store bids and asks in price priority
[DONE] preserve FIFO within each price level
[DONE] index active orders by ID
[DONE] match by price-time priority across price levels
[DONE] execute at the resting (maker) price
[DONE] rest any remainder at its own limit
[ACTIVE] cancellation and the complete order lifecycle
[QUEUED] replay, benchmark, and profile (before bragging about speed)
awaiting next commit
| Bid Size | Bid | Ask | Ask Size |
|---|---|---|---|
| 420 | 101.24 | 101.25 | 180 |
| 310 | 101.23 | 101.26 | 260 |
| 780 | 101.22 | 101.27 | 640 |
| 150 | 101.21 | 101.28 | 390 |
| 900 | 101.20 | 101.29 | 710 |
The engine now does the one thing an engine is contractually obligated to do: when a buyer and a seller agree on a price, it makes them trade. Here is one order walking into the book, start to finish.
BEFORE
| Who | Side | Price | Qty |
|---|---|---|---|
| STOP Dee | SELL | 101.28 | 200 |
| #3 Cam | SELL | 101.26 | 100 |
| #2 Ben | SELL | 101.25 | 30 |
| #1 Ana | SELL | 101.25 | 50 |
| Eli | BUY | 101.20 | 100 |
Sellers on top, buyers below, best prices meet in the middle. Ana got in line before Ben.
AFTER
| Who | Side | Price | Qty |
|---|---|---|---|
| Dee | SELL | 101.28 | 200 |
| NEW You | BUY | 101.27 | 20 |
| Eli | BUY | 101.20 | 100 |
180 bought, 20 still waiting. Ana, Ben, and Cam are done for the day.
INCOMING
FILLED 180 / 200BUY 200 // PAY UP TO $101.27
- #1BUY 50 @ $101.25 from Ana
Cheapest seller, and she got in line first. Fills completely.
- #2BUY 30 @ $101.25 from Ben
Same price as Ana, but he showed up after her. At equal prices, whoever arrived first trades first.
- #3BUY 100 @ $101.26 from Cam
$101.25 is cleaned out, so the engine moves one level up. Still under the $101.27 limit.
- STOPDee wants $101.28
One cent over the limit. 20 shares are still wanted, but nobody left is willing to sell at that price.
- RESTBID 20 @ $101.27 joins the book
The leftover waits at its original limit, not at $101.26 (the last price it traded at).
WHY YOU PAID $101.25 AND NOT $101.27
Trades happen at the price of the order that was already waiting. Ana posted "I'll sell at $101.25" and gets exactly that. Your $101.27 was a ceiling, not a target, so the difference stays with you. Nobody walks up to a $20 price tag at a garage sale and insists on paying $25.
In market terms, the order that was already waiting is the MAKERAn order that was already sitting on the book. It made a price available for someone else to take. Ana, Ben, and Cam were the makers here. (it made the price available) and the order that shows up and trades against it is the TAKERThe order that shows up and trades right away against what is already waiting. Your buy order was the taker. Real exchanges often charge takers higher fees than makers, as a small tax on impatience.. The trade always happens at the maker's price. Across the three fills here, that works out to $2.60 saved. Please do not spend it all in one place.
Browse the C++ implementation, tests, benchmarks, and build setup.
[ OPEN GITHUB REPOSITORY ]