Selected Track: Software & Technology

Problem Statement

What problem am I solving? Every stock trade in the world passes through a piece of software called a matching engine: it decides who trades with whom, at what price, in what order. It is simple to describe and brutally unforgiving to build, and when it breaks, it breaks expensively.

Who experiences this? Everyone with a pension, an index fund, or a brokerage account, whether they know it or not.

Why does it matter?

  • Knight Capital, 2012: a deployment reached 7 of 8 servers. The company lost $460 million in 45 minutes and ceased to exist independently.
  • Nasdaq, Facebook's IPO, 2012: the opening auction entered an infinite loop because a validation step could never converge under load. 38,000 orders were excluded. $10M penalty.
  • NYSE, fined $9M in March 2026: primary and backup systems ran at the same time, and 2,800+ opening auctions silently never happened. There was no policy requiring anyone to check that they had.

What are the existing limitations? Real matching engines are closed source. The public examples are toys: they use floating-point prices (which cannot represent money exactly), they are never tested against real market data, and they publish speed numbers with no methodology.

My Solution

pricetime is a matching engine built to be proven correct rather than claimed correct.

1. It is checked against a second implementation, constantly. I wrote the engine twice: once slow and obviously correct, once fast and not obviously anything. A fuzz test drives 623,000 random operations through both and demands they produce byte-identical output after every single operation. This caught real bugs during development within seconds.

2. It runs on real market data. It decodes the Investors Exchange's actual historical feed (42 million network packets, 50,163,616 real orders across 8,159 stocks from 23 December 2024) down to the individual order ID.

3. It grades itself against the exchange's own records. The feed says which orders were executed. My engine reconstructs what must have happened and checks whether it reaches the same conclusion. For Apple: 1,499 out of 1,499 executions matched exactly. 100.0%.

4. I made it 40x faster by finding a hardware-level cause. Real data ran 30x slower than my synthetic tests. It was not the algorithm. The price table had grown to 27.7 MB, and this CPU's fast cache holds 20 MB. Restructuring so the hot data stays in cache took Apple from 1,986 nanoseconds to 50 and S&P 500 ETF flow from 4,634 to 62, with correctness unchanged.

5. It runs across CPU cores, and I proved that is safe. Books are split across threads with no locks, for a 9.01x speedup on 12 threads. The test that matters is not speed, it is that running sharded produces byte-identical results to running on one thread.

6. It handles multiple exchanges. Real markets are fragmented across 17 US stock exchanges. pricetime computes the best price across all of them and flags "trade-throughs", where someone got a worse price than was available elsewhere.

7. It survives being killed, and proves it. Two of the three disasters at the top of this page were not matching bugs, they were recovery failures. Nasdaq's failover engine had state frozen 19 minutes stale and excluded 38,000 orders. NYSE could not answer whether 2,800 opening auctions had happened because no authoritative record existed to ask.

pricetime journals every input before applying it, and because the engine is deterministic, those inputs are the state. To test it I killed the process at every single byte offset in the journal, all 16,807 of them, and demanded that what recovered replays to byte-identical state. 16,406 of those cuts landed mid-record. All recovered correctly. It also reports exactly how many inputs the crash cost, rather than claiming everything is fine. An operator needs to know how far the world rewound.

8. It consolidates three live exchanges into one best price. Bitstamp, Coinbase and Kraken all quote BTC/USD at the same moment, so the engine rebuilds Bitstamp's book order by order and consolidates it against the other two into a real cross-venue best bid and offer. (Crypto rather than stocks for a specific reason: the free US stock-exchange archives do not overlap in time, so no two of them can be compared at the same instant.)

Building it surfaced two bugs, both caught by checking my output against the exchanges' own published prices rather than trusting it. A live order feed without an opening snapshot gives you only the orders created after you connected, which showed a $2.21 spread where the real one was $0.01. And a quote that is twenty seconds stale does not look stale, it looks like free money.

9. Price-time priority is a choice, and it is not the only one. Which order fills first, once several sit at the same price, is a separate decision from price priority. CME runs ten different answers and publishes which one applies per instrument. pricetime implements four behind one unified kernel: FIFO, pro-rata, CME's configurable split between them, and time-weighted.

It matters because the rule changes behaviour, not just outcomes. Under pro-rata a large order that arrived a moment ago outranks a small one that has rested all day, so traders submit size they never intend to fill: documented pro-rata markets show cancellation rates above 96 percent and depth around 100 times mean trade size.

10. It watches the market for abuse, and found something real. A surveillance layer reads the engine's own output and screens for the patterns regulators care about. Run against real Apple order flow it found that 106,476 orders, 49.1% of every order that joined the queue that day, were cancelled within one thousandth of a second of arriving, against a cancel-to-trade ratio of 124:1.

That is not an accusation. High cancellation is normal market-making behaviour, and the report says so in its own output. It is an example of the engine measuring something true about how modern markets actually work.

An optional stage turns those findings into plain prose for a compliance reviewer using Claude. The boundary is deliberate and I would defend it in an interview: a matching engine must be deterministic and auditable, and a language model is neither. So it runs as a separate process, never touches a price or a fill or a matching decision, is handed only numbers the engine already computed, and is explicitly forbidden from inventing figures or asserting intent. With no API key it is skipped and nothing is lost, because the deterministic report is the actual deliverable.

Prototype / Demonstration

Working software. Public, MIT-licensed, zero dependencies: https://github.com/Minifigures/pricetime

The demo is the claim, running live: https://pricetime-mu.vercel.app

Two independent implementations of the same engine run in your browser on the same input. Every event is compared. The divergence count stays at zero. Hovering a price level quotes what sweeping to it would actually fill at: size taken, average fill, distance from mid, notional. Over a production long run of 1,000,000 messages, 1,835,376 events were compared and 0 diverged.

git clone https://github.com/Minifigures/pricetime && cd pricetime
make test        # 101 tests including the differential fuzz
make bench       # latency, four flow regimes
make replay      # live animated order book in your terminal
make recover     # journal a run, crash it, recover, prove it

No package manager, no frameworks. g++ and make. Anyone can verify every number on the README in under a minute.

Presentation. An 8-slide deck covering the concept, solution, implementation and expected impact is in the repository at docs/pricetime-presentation.pdf. The same slides are in the image gallery above.

Results

before after
Apple, real order flow 1,986 ns/order 50 ns/order
S&P 500 ETF, real flow 4,634 ns/order 62 ns/order
throughput 0.59 M/sec 12.8 M/sec
real orders replayed from one trading day 50,163,616
executions matched against the venue's own records (Apple) 1,499 of 1,499
events compared across two engines, production long run 1,835,376, 0 divergent
crash points verified 16,807, all recovering to byte-identical state
live exchanges consolidated 3 (Bitstamp order-by-order, Coinbase, Kraken)
sharding speedup on 12 threads 9.01x
allocation policies 4 (FIFO, pro-rata, CME split, time-weighted)
  • 101 automated tests, 623,000 fuzzed operations
  • 100.0% agreement with the exchange's own execution records (Apple)
  • Clean under AddressSanitizer, UndefinedBehaviorSanitizer, ThreadSanitizer

The AI question, answered honestly

Quantitative firms do use AI, and I could have bolted a language model onto the price path to look current. I did not, because it would have been wrong: the component that decides who trades with whom has to produce identical output for identical input, every time, and be explainable to a regulator line by line.

So the AI does the job it is actually good at (reading structured findings and writing them up for a human) behind a hard boundary from the part that must never guess. Knowing where not to put the model is the engineering judgment.

What I am proudest of

ThreadSanitizer found a bug that my own test could not. I wrote a test that hammered a concurrent data structure with 400,000 simultaneous reads and it reported zero errors. ThreadSanitizer said it was broken anyway, and it was right: the code was technically undefined behaviour that merely happened to work on Intel chips. Passing your own test is not the same as being correct.

A bug my own differential method was structurally incapable of catching. Fill-or-kill means fill everything or nothing. Self-trade prevention means your own resting size is not fillable by you. The precheck summed level totals with no owner filter, so it counted size that self-trade prevention was about to refuse, admitted an order that could never fill, and then cancelled the resting order on the way through. The order filled nothing and destroyed the sender's own position, the exact opposite of what both mechanisms exist to do.

Both engines had it identically, so the fuzz passed: it compares them against each other and they agreed on the wrong answer. Testing one implementation against another only finds disagreements, never a shared misreading of the rules. I wrote the failing test first, confirmed it reproduced, then fixed both.

I also published a hypothesis I got wrong. I predicted which workload would be slowest; it turned out to be the fastest by 4x. That is in the README, not deleted, because a refuted prediction is worth as much as a confirmed one.

What I learned

That "fast" is not a property of an algorithm. The same code, unchanged, ran 40x slower purely because the data outgrew a CPU cache. And that honest measurement is harder than optimization: I had to catch myself running two benchmarks simultaneously and reporting the contaminated numbers.

And that the hardest part of measuring anything is catching yourself measuring the wrong thing. Three separate times a result looked like a discovery and was actually an artifact of my own setup: a benchmark contaminated by running two at once, a book missing half its depth because I never fetched a snapshot, and a stale quote masquerading as an arbitrage. Each was caught by checking against an independent source rather than by staring at the output.

Attribution

Market data provided for free by IEX. By accessing or using IEX Historical Data you agree to the IEX Historical Data Terms of Use.

Pre-existing components disclosed (per rules)

None. All code in this repository was written during the challenge period. Third-party inputs are limited to the C++ standard library, GNU Make, and publicly available IEX historical market data used under its published terms.

7. It survives being killed, and proves it. I killed the process at every single byte offset in the journal, all 16,807 of them, and demanded that what recovered replays to byte-identical state. 16,406 of those cuts landed mid-record. All recovered correctly.

Built With

  • addresssanitizer
  • anthropic-claude-api
  • c++
  • c++20
  • emscripten
  • github-actions
  • gnu-make
  • iex-deep+
  • nextjs
  • pcap
  • pcapng
  • react
  • threadsanitizer
  • typescript
  • undefinedbehaviorsanitizer
  • webassembly
Share this project:

Updates

Submission history