A limit order book with price-time priority matching — the core algorithm behind any exchange, implemented from scratch and tested against the edge cases that actually break naive implementations.
This isn't a wrapper around an existing library — it's a from-scratch implementation of the matching logic that sits at the heart of trading, exchange, and prediction-market platforms: maintaining a sorted book of resting orders, matching incoming orders against it at the correct price, and preserving price-time priority (better prices always win; among equal prices, whoever arrived first gets filled first).
- Limit and market order types
- Price-time priority matching (price first, then arrival order)
- Partial fills — on both the incoming order and resting orders
- Matching always executes at the resting (maker) order's price, never the aggressor's
- Multi-level book walking — a large aggressive order consumes multiple price levels in one call
- Order cancellation by id, in O(1) lookup + O(k) removal at that price level
- Best bid/ask and spread queries
- Aggregated order book snapshot (price, total quantity, order count per level)
npm run demo
Resting two sell orders...
Book: { bids: [], asks: [ { price: 100, quantity: 5, orderCount: 1 }, { price: 101, quantity: 5, orderCount: 1 } ] }
Submitting an aggressive buy order for 8 @ 101...
Trades: [
{ takerOrderId: 'b1', makerOrderId: 's1', price: 100, quantity: 5, ... },
{ takerOrderId: 'b1', makerOrderId: 's2', price: 101, quantity: 3, ... }
]
Remaining unfilled: 0
Book after match: { bids: [], asks: [ { price: 101, quantity: 2, orderCount: 1 } ] }
The order paid 100 for the first 5 units (the better available price) and 101 for the remaining 3 — never its own limit price of 101 for the whole thing.
src/
├── types.ts # Order, trade, and snapshot types
├── order-book.ts # One side of the book (bids or asks), price-time sorted
├── matching-engine.ts # Orchestrates matching, cancellation, and book state
└── demo.ts # Runnable example
test/
└── matching-engine.test.ts # 24 tests covering matching, priority, and edge cases
npm install
npm test
npm run demo
24 tests across six areas:
| Area | What's covered |
|---|---|
| Resting orders | Orders added to the book when nothing matches |
| Matching | Correct maker-price execution, partial fills, multi-level walks |
| Price-time priority | Same-price FIFO ordering, price always beats time |
| Market orders | Fill against best price, no resting on insufficient liquidity |
| Cancellation | Removal by id, price-level cleanup, double-cancel safety |
| Validation & queries | Input validation, spread calculation, sorted snapshots |
Note
This is a portfolio piece demonstrating matching logic, not a production exchange core.
Explicitly out of scope:
- Price level storage is O(n) per insert (linear scan over a sorted array). A production engine at real order-flow volume would index price levels with a balanced tree or skip list for O(log n) inserts.
- No self-trade prevention — an account could match against its own resting order.
- No persistence — the book lives in memory only; a real engine would need a durable event log for crash recovery.
- Single-threaded, single-instrument — no sharding across trading pairs or concurrent order streams.
- TypeScript
- Vitest
- ESLint
MIT — see LICENSE for details.
Nicolás Pedernera
Systems Engineer — Universidad de Buenos Aires, 2024
Focused on backend engineering, fintech, cryptocurrency, blockchain infrastructure, and AI systems.
- GitHub: Nicolas-Pedernera
- LinkedIn: nicolas-pedernera-zendx
- Upwork: perfil de freelancer