nanobook
n*10⁻⁹ — A deterministic, nanosecond-precision limit order book and matching engine for testing trading algorithms.
What Is This?
A simulated stock exchange that processes orders exactly like a real exchange — with proper price-time priority, partial fills, and cancellations.
Who Should Use This?
| If you're a... | Use this for... |
|---|---|
| Quant developer | Backtesting trading strategies with realistic market microstructure |
| Algo trader | Testing order execution logic (slippage, queue position, fill rates) |
| Student | Learning how exchanges actually work under the hood |
| Rust developer | Reference implementation of a financial data structure |
Why This Library?
- Deterministic — Same inputs always produce same outputs (essential for reproducible backtests)
- Fast — 8M+ orders/sec single-threaded, sub-microsecond latency
- Complete — GTC/IOC/FOK, partial fills, modify, cancel, L1/L2/L3 snapshots
- Multi-symbol —
MultiExchangefor independent per-symbol order books - Portfolio engine — Position tracking, cost modeling, rebalancing, financial metrics (Sharpe, Sortino, max drawdown)
- Simple — Single-threaded, in-process, minimal dependencies
See It In Action
Building order book...
SELL 100 @ $50.25 (Alice) ASK $50.50 150 shares
SELL 150 @ $50.50 (Bob) ASK $50.25 100 shares
BUY 100 @ $50.00 (Carol) ---- spread: $0.25 ----
BUY 200 @ $49.75 (Dan) BID $50.00 100 shares
BID $49.75 200 shares
Incoming: BUY 120 @ $50.25 (Eve) - CROSSES SPREAD!
Trades: 100 shares @ $50.25 (Alice filled completely)
Filled: 100, Resting: 20 (Eve's remainder rests on book)
Incoming: MARKET BUY 200 (Frank) - SWEEPS THE BOOK!
Trades: 150 shares @ $50.50 (Bob filled completely)
Unfilled: 50 (no more liquidity!)
The interactive demo explains price-time priority, partial fills, IOC/FOK, and order cancellation.
Features
- Order types: Limit, Market, Cancel, Modify
- Time-in-force: GTC, IOC, FOK
- Price-time priority: FIFO matching at each price level
- Nanosecond timestamps: Monotonic counter (not system clock)
- Deterministic: Same inputs → same outputs (essential for backtesting)
- Fast: 8M+ orders/second single-threaded (see Performance)
- Book snapshots: L1 (BBO), L2 (depth), L3 (full book), imbalance, weighted mid
- Event replay: Complete audit trail for deterministic replay
- Portfolio: Position tracking, VWAP entry, cost model, Sharpe/Sortino/drawdown metrics
- Multi-symbol: Independent order books per symbol via
MultiExchange - Parallel sweeps: Rayon-based parameter grid search (optional feature)
Quick Example
use ;
Installation
Add to Cargo.toml:
[]
= "0.3"
Or build from source:
API Overview
Core Types
/// Price in smallest units (e.g., cents). Price(10050) = $100.50
;
/// Order side
/// Time-in-force: how long an order stays active
/// Order status
Exchange Operations
let mut exchange = new;
// Submit limit order (returns order ID + any immediate trades)
let result = exchange.submit_limit;
println!;
// Submit market order (always IOC semantics)
let result = exchange.submit_market;
// Cancel an order
let cancel_result = exchange.cancel;
// Modify an order (cancel + replace, loses time priority)
let modify_result = exchange.modify;
// Get order status
if let Some = exchange.get_order
// Book snapshots
let = exchange.best_bid_ask; // L1
let depth = exchange.depth; // L2: top 10 levels
let full = exchange.full_book; // L3: everything
Result Types
How It Works
Order Book Structure
BIDS (sorted high→low) ASKS (sorted low→high)
$100.00: [O1]→[O2]→[O3] $100.50: [O7]→[O8]
$99.50: [O4]→[O5] $101.00: [O9]
$99.00: [O6] $102.00: [O10]→[O11]
↑ Best Bid ↑ Best Ask
- BTreeMap<Price, Level> for sorted price levels
- VecDeque for FIFO queue at each level
- HashMap<OrderId, OrderRef> for O(1) lookup/cancel
- Cached best_price for O(1) BBO access
Matching Algorithm
- Incoming order checks opposite side of book
- If prices cross (buy ≥ best ask, or sell ≤ best bid), match
- Fill at resting order's price (price improvement for aggressor)
- Continue until no more crosses or order fully filled
- Remaining quantity: rests (GTC), cancels (IOC/Market), or entire order cancels (FOK)
Time-in-Force Behavior
| TIF | Partial Fill OK? | Rests on Book? |
|---|---|---|
| GTC | Yes | Yes (remainder) |
| IOC | Yes | No (remainder cancelled) |
| FOK | No | No (all-or-nothing) |
Determinism
- No randomness anywhere
- Timestamps from monotonic counter, not system clock
- Same order sequence always produces same trades
- Event log enables exact replay
Performance
Benchmarks
Measured on AMD Ryzen / Intel Core (single-threaded):
| Operation | Time | Throughput | Complexity |
|---|---|---|---|
| Submit (no match) | 120 ns | 8.3M ops/sec | O(log P) |
| Submit (with match) | ~200 ns | 5M ops/sec | O(log P + M) |
| BBO query | 1 ns | 1B ops/sec | O(1) |
| Cancel | 660 ns† | 1.5M ops/sec | O(N) |
| L2 snapshot (10 levels) | ~500 ns | 2M ops/sec | O(D) |
Where P = price levels, M = orders matched, N = orders at price level, D = depth.
†Cancel is O(N) in orders at that price level. See "Future Optimizations" below.
Optimizations Applied
- FxHash — Non-cryptographic hash for OrderId lookups (+25% vs std HashMap)
- Cached BBO — Best bid/ask cached for O(1) access
- Optional event logging — Disable for max throughput:
# With event logging (default) - enables replay
# Without event logging - maximum performance
Where Time Goes (Submit, No Match)
submit_limit() ~120 ns breakdown:
├── FxHashMap insert ~30 ns order storage
├── BTreeMap insert ~30 ns price level (O(log P))
├── VecDeque push ~5 ns FIFO queue
├── Event recording ~10 ns (optional, for replay)
└── Overhead ~45 ns struct creation, etc.
Future Optimizations
| Optimization | Potential Gain | Complexity | Tradeoff |
|---|---|---|---|
| O(1) cancel | 10x for deep levels | High | Intrusive linked list or tombstones |
| Array-indexed levels | -30 ns | Medium | Requires bounded price range |
| Slab allocator | -10 ns | Medium | More complex memory management |
O(1) Cancel: Currently cancel scans the VecDeque to find the order. For true O(1):
- Tombstone approach: mark cancelled, skip during matching
- Intrusive doubly-linked list with HashMap<OrderId, NodePtr>
These add complexity. Current O(N) cancel is fine unless you have thousands of orders at a single price level (rare in practice).
Use Cases
Strategy Backtesting
for event in historical_events
Market Impact Analysis
let = exchange.best_bid_ask;
let result = exchange.submit_market;
let = exchange.best_bid_ask;
let slippage = bid_after.unwrap.0 - bid_before.unwrap.0;
Queue Position Testing
// Who's first in line at $100?
let competitor = exchange.submit_limit;
let mine = exchange.submit_limit;
// Sell comes in — who gets filled?
exchange.submit_limit;
// Competitor was first, gets filled first
let comp_order = exchange.get_order.unwrap;
let my_order = exchange.get_order.unwrap;
assert_eq!;
assert_eq!;
IOC for Aggressive Execution
// Take liquidity without resting an order
let result = exchange.submit_limit;
// Fills what's available at ≤$100.50, remainder cancelled
println!;
Comparison with Other Rust LOBs
| Library | Throughput | Threading | Order Types | Deterministic | Use Case |
|---|---|---|---|---|---|
| nanobook (this) | 8M ops/sec | Single | Limit, Market, GTC/IOC/FOK | Yes | Backtesting, education |
| limitbook | 3-5M ops/sec | Single | Limit, Market | No | General purpose |
| lobster | ~300K ops/sec | Single | Limit, Market | No | Simple matching |
| OrderBook-rs | 200K ops/sec | Multi | Many (iceberg, peg, etc.) | No | Production HFT |
When to use what:
- This library: You need deterministic replay for backtesting, or you're learning how exchanges work
- limitbook: General-purpose LOB without replay requirements
- OrderBook-rs: Production systems needing thread-safety and complex order types
Feature Flags
| Feature | Default | Description |
|---|---|---|
event-log |
Yes | Event recording for deterministic replay |
serde |
No | Serialize/deserialize all public types |
persistence |
No | File-based event sourcing (JSON Lines) |
portfolio |
No | Portfolio engine, position tracking, metrics |
parallel |
No | Rayon-based parallel parameter sweeps |
Limitations
This is an educational/testing tool, not a production exchange:
- No networking: In-process only
- No compliance: Self-trade prevention, circuit breakers
- No complex orders: Iceberg, pegged, trailing stops
See SPECS.md for the complete specification.
License
MIT
Contributing
Issues and PRs welcome. See SPECS.md for the technical specification.
Recording a Demo GIF
To create an animated GIF of the demo (for docs, presentations, etc.):
# Using vhs (recommended): https://github.com/charmbracelet/vhs
# Using asciinema + agg: