Anvil
A C++20 price-time-priority matching engine with a live, interactive demo. The engine matches new/cancel/amend flow using fixed-point integer prices, packed order ids, and a pool/index data model over flat_map book sides — deterministic and single-threaded by design, the way a real venue matches a single instrument. A Crow server links it as a library and streams live order-book state over REST + WebSocket to a React trading-terminal UI, driven by a throttled, on-demand feeder; correctness is pinned by a differential oracle, a runtime invariant verifier, and adversarial load tests. Deployed on AWS Lightsail behind nginx.
// Overview
Anvil is a price-time-priority matching engine: it reads a stream of new, cancel, and amend messages and matches them into trades under strict price-then-time priority, holding the resting book in memory and emitting deterministic, replayable output. Matching is single-threaded by design — price-time priority is a total order over arrivals and deterministic output is a venue requirement, so the book is driven serially, the way a real venue matches one instrument, with horizontal sharding by ticker as the scaling axis rather than threads on a single book. Two things share the repository: the matching core, built properly within its scope, and a live demo layer that wraps it unmodified. The framing matters — this is the matching core done well, not a production venue; the venue-scale gaps are a designed-for boundary, named at the close, not an oversight.
Correctness and speed both fall out of the data model. Prices are fixed-point integer ticks parsed straight from decimal text, so a double never touches order data and tick equality is exact — map keys never drift. Order ids of up to ten characters from a 63-symbol alphabet pack losslessly into a single uint64, removing string hashing, allocation, and comparison from the path entirely. Orders and price levels live in pre-sized pools addressed by 32-bit indices rather than pointers, so the pools can reallocate on growth without dangling anything and the engine stays trivially relocatable; each book side is a sorted contiguous flat_map whose best price is begin(), paying an O(L) memmove only when a brand-new price level appears, L being the few tens of live levels.
The trading semantics are equally deliberate, each chosen with its alternative consciously rejected. Trades execute at the resting order's price, not the aggressor's — the passive side set the price, so a sweep through several levels prints at successively worse resting prices rather than one blended fill. Amend quantity is the new total (remaining = total − filled), matching cancel/replace on real venues; an amend at or below the already-filled quantity auto-cancels rather than erroring, because the only correct resting quantity is then zero. Cancels are by id alone, the echoed side and price and quantity ignored, because a cancel that fails on a stale echo leaves live risk resting on a book the client believes is dead.
Correctness is evidenced three independent ways. A differential oracle — a deliberately naive reference engine implementing the same settled semantics — is byte-diffed against the C++ engine over seeded workloads, so any divergence is a bug in one of two independent implementations. A runtime invariant verifier audits the whole state after every message: the book is never crossed, FIFO integrity holds at every level, and the id index and the book stay in exact bijection. Adversarial and scale workloads — level-churn, deep-book sweeps, cancel-storms, many-tickers — confirm the cost model and that memory tracks live order count, not total messages. The limit is named too: differential testing verifies the implementation against a second one, not the interpretation — but the verifier and the reference together make "the engine does what was specified" very well evidenced.
The live demo wraps that engine without changing it. The matching core emits to a single output seam — one sink reference — and the only engine-side change is what that reference points at: a CLI sink reproducing the original byte-identical text output, or a tee fanning the same events out to a WebSocket publisher. The server runs the engine on one dedicated thread fed by a single queue, preserving the serial determinism, publishes coalesced top-of-book snapshots and per-fill trades over REST and WebSocket, and drives the book with a throttled, on-demand feeder that idles when no one is watching; the browser renders a trading terminal — depth ladder, trade tape, price chart, order entry — streaming live.
The discipline that paid off most was cold-running on the actual target. Every real defect in the engine phase was caught not by CI but by extracting the build and running it on the target platform — a UTF-8 BOM silently invalidating the first line, CRLF endings, MSVC's multi-config build needing an explicit --config Release, a shell set -e masking a non-zero return. The demo's own deployment repeated the lesson: a doubled-scheme CORS origin (https://https://…, a leftover from an abandoned path-hosting plan) left the server rejecting the browser's WebSocket origin, which surfaced as a 502 on the /ws handshake while every REST route worked throughout — one corrected origin string fixed it.
What separates Anvil from a venue is a whole category of work, and almost none of it is built — by design. Durability and crash recovery, high availability and replication, real FIX or binary order-entry gateways and a sequenced market-data feed, pre-trade risk and self-trade prevention, order-type and auction breadth, and scale-out sharding are all absent. The architecture is positioned for most of them at seams that already exist: the sink fan-out is exactly where a durable journal or a reliable execution feed attaches; the single inbound queue is the sequencing point, and command journaling there plus deterministic replay is the recovery path; the deterministic serial core is what makes replication tractable; and the per-ticker books are the shard boundary. The gaps that do not attach at a seam are the matching-semantics ones — self-trade prevention, order types, auctions — which are honest engine work. Placing the seams without yet building behind them is the deliberate scope: the matching core, done properly, with the road out mapped.