
building a trading firm's machinery: matching engine, risk controls, live execution
The execution arm of a miniature trading firm, built as a reality check on the backtests: a deterministic C++ limit order book at 10M ops/sec, a risk-control gateway no strategy can bypass, and a live paper-trading pipeline that measures how far live results drift from what the backtest promised.
the problem
Every strategy on the research side of quantlab was validated on a backtest, and a backtest is a fantasy. It fills your orders at clean prices, never makes you wait in a queue, never moves the market against you, and never has a bad afternoon. I wanted to know how much of my results leaned on that fantasy, and the only honest way to find out is to leave the backtest behind and push real orders into a real market. So this project is the reality check on that research: the machinery that carries a signal all the way to a filled trade, and a live pipeline built to measure the gap between what a backtest promised and what actually happens.
Building it also meant learning what a trading firm mostly is. Firms rarely blow up because a strategy was mediocre; they blow up in the plumbing between the strategy and the market. Knight Capital lost $440 million in 45 minutes in 2012, not from a bad signal, but from a botched deployment with no effective controls between its code and the exchange. A trading firm is a systems problem wearing a math costume: exchange mechanics, risk controls, and accountability infrastructure, with the strategy sitting on top. A framework or a broker API would have hidden all of that, which is exactly what I wanted to see, so I built a miniature of it the way real desks structure it, where no strategy is ever trusted to talk to a broker directly and every decision leaves a record.
the matching engine
Every exchange is, at its core, one data structure: the limit order book. Understanding market microstructure from the inside meant building one.
It sounds simple and is full of edge cases. A buy order for 100 shares at $50 first matches against any resting sells at $50 or below, taking the oldest order at the best price first, filling partially if that order is smaller and walking down to the next price level until it is done or the book runs out. Whatever cannot fill joins the queue of resting buys at $50, behind everyone already waiting at that price. A cancel has to locate and remove one specific resting order without disturbing the queue around it. Every one of those paths is a chance to get the ordering subtly wrong, which is what the nine tests pin down one at a time: price priority, time priority for ties, partial fills, sweeping multiple price levels, cancels, and the book staying self-consistent after a long random stream of operations.
Mine is dependency-free C++20 with nine correctness tests, and the test I care most about is the determinism check. It replays a long fixed stream of orders through two independent engine instances and hashes the full sequence of resulting trades and final book state; the two hashes must be byte-identical. Exchanges and their regulators care about this property more than raw speed, because a matching engine that can produce two different histories from one input is a lawsuit, not a product. It also makes every other kind of bug reproducible: a determinism hash that changes is a tripwire for accidental nondeterminism creeping in, an iteration over an unordered map, an uninitialised field, a stray dependence on memory addresses.
Speed came from the same discipline. Resting orders live in price-sorted structures with intrusive queues at each level, so matching and cancelling touch only the orders they must, with no allocation in the hot path. The result is 10.4 million operations per second, about 97 nanoseconds each, on a laptop. That will not out-run a colocated production engine built by a team, but it is fast enough to prove the point: the bottleneck in a matching engine is getting the data structures and their invariants exactly right, and speed follows from that rather than from cleverness bolted on afterward. Fast code is easy to claim; provably deterministic fast code is the version worth showing a trading firm. The v2 roadmap, scoped in the repo, adds pooled allocation, latency histograms, order modification, and replay of real exchange-format message logs.
risk before orders
Real trading desks never let a strategy talk to a broker directly, so neither does quantlab. Every order proposes itself to a risk service first, a small HTTP service with the API real control layers expose: propose an order and receive an approval or a rejection with explainable reasons, plus pause, flatten, and status endpoints for a human operator. The rules it enforces: gross exposure caps, per-stock concentration caps, an allowed-symbol list, and a daily-loss kill switch. One asymmetry is deliberate and important: orders that reduce risk are always allowed, even under a tripped kill switch. You can always get out; you can never dig deeper.
Every decision, approved or rejected, lands in an append-only audit log with its timestamp, the order, and the reasons. Nothing is ever edited or deleted; accountability infrastructure that can be rewritten isn’t accountability infrastructure. And strategies run as isolated books with their own limits and their own kill switches, so one strategy blowing its daily loss cannot halt another, while their orders still net against each other before reaching the broker. If the momentum book wants to buy 30 shares of a name the same day the low-vol book is selling 30 of it, the broker sees nothing at all, and neither book pays a cost for a trade that never needed to happen.
A small honest note on how this section got written: the asymmetry above, that risk-reducing orders survive a tripped kill switch, was true of the interactive demo and this description before it was true of the engine. The original code rejected every order once the switch tripped. The article was the specification, and I changed the code to match it. Documentation that is ahead of the implementation is a bug in the implementation.
The playground below runs the real rule logic. Try to get an order past it.
live, on paper
The capstone wires it all together against a real brokerage’s paper trading account. It runs four strategies at once as virtual books: momentum and low-volatility from the research side, the moving-average trend baseline, and In & Out as a deliberately-labeled cautionary exhibit. Each book keeps its own ledger and its own risk engine; the broker only ever sees the netted total.
One correctness detail matters more than it looks. Momentum and low-vol were backtested rebalancing monthly, so the live books rebalance monthly too, on the first cycle of each new month, while the two timing strategies respond every day. If the live process rebalanced on a different schedule than the backtest, it would drift from the backtest for a reason that has nothing to do with real-world execution, which would quietly poison the one measurement the whole capstone exists to make. The live process must match the tested process exactly. The exact momentum code from the research side computes daily target positions, each book diffs targets against its holdings to produce orders, orders net across books, and everything flows through the risk service to the broker. One structural safety choice: the broker adapter is hard-pinned to the paper-trading endpoint at the code level, so routing an order to a live-money account is not a configuration mistake anyone can make; the capability simply does not exist in the module. Every run also appends a snapshot to a drift journal, building toward the exhibit that matters most: live results versus what the backtest promised, tracked from the first day. The audit log’s very first production entry is the risk service correctly rejecting one of my own orders: the SPY trend-following strategy (the moving-average baseline running on the S&P 500 ETF) tried to put its whole $25k budget into one symbol, under a concentration cap I had carelessly copied from the multi-stock strategy’s config. The control layer caught its author on day one.
It now runs daily, and the exhibit it is building is the one every backtest secretly owes you. A backtest is a promise about a world that never quite exists: fills at clean prices, no queue, no partial days, no gap between deciding and doing. Paper trading keeps the strategy fixed and swaps the simulated market for a real one, so the gap that opens up between the live equity curve and what the backtest expected over the same window is a direct measurement of everything the simulation was quietly assuming away. That gap is only meaningful with time, which is the honest catch: the number that matters here cannot be manufactured, only accrued, one trading day at a time.
what i’d claim
- Determinism is a feature you test for. Fast code is easy to claim; a matching engine that provably produces byte-identical state from identical input is the version worth showing a trading firm.
- Structure is safety. Strategy, then risk service, then broker, with an append-only audit trail and explainable rejections. No bypass path exists, by construction.
- Controls earn their keep on day one. The risk gateway’s first production act was correctly rejecting its own author’s misconfigured order. That is the system working, not failing.
The signals flowing through this machinery come from the research side, covered in quant strategy research. The AI research arm, fine-tuning small open models into an analyst whose memos are verifiably correct, is covered in distilling a financial analyst.