nanobook
Production-grade Rust execution infrastructure for automated trading. Zero-allocation hot paths. No panics on external input. MIRI-verified memory safety. Python computes the strategy. nanobook handles everything else.
Architecture
┌─────────────────────────────────────────────────┐
│ Your Python Strategy (private) │
│ Factors · Signals · Sizing · Scheduling │
├─────────────────────────────────────────────────┤
│ nanobook (Rust, open-source) │
│ ┌──────────┬──────────┬──────────┬──────────┐ │
│ │ Broker │ Risk │Portfolio │ LOB │ │
│ │ IBKR │ Engine │Simulator │ Engine │ │
│ │ Binance │ PreTrade │ Backtest │ 8M ops/s │ │
│ └──────────┴──────────┴──────────┴──────────┘ │
│ Rebalancer CLI: weights → diff → execute │
└─────────────────────────────────────────────────┘
Python computes what to trade — factor rankings, signals, target weights. nanobook executes how — order routing, risk checks, portfolio simulation, and a deterministic matching engine. Clean separation: strategy logic stays in Python, execution runs in Rust.
Workspace
| Crate | Description |
|---|---|
nanobook |
LOB matching engine, portfolio simulator, backtest bridge |
nanobook-broker |
Broker trait with IBKR and Binance adapters |
nanobook-risk |
Pre-trade risk engine (position limits, leverage, short exposure) |
nanobook-python |
PyO3 bindings for all layers |
nanobook-rebalancer |
CLI: target weights → IBKR execution with audit trail |
Install
Python:
Rust:
[]
= "0.9"
From source:
# Python bindings
&&
The Bridge: Python Strategy → Rust Execution
The canonical integration pattern — Python computes a weight schedule, Rust simulates the portfolio and returns metrics:
=
# per-period symbol weights
# stop trigger metadata
Your optimizer produces weights. py_backtest_weights() handles rebalancing,
cost modeling, position tracking, and return computation at compiled speed
with the GIL released.
Clean aliases are also available for new callers:
backtest_weights, capabilities, garch_forecast, optimize_*.
qtrade v0.4 Capability Gating
Use py_capabilities() and keep fallback logic in calc.bridge:
# noqa: F401
return True
return False
return
return False
=
return True
# Symbol fallback for older builds
=
=
return
Layer Examples
LOB Engine (Rust)
use ;
let mut exchange = new;
exchange.submit_limit;
let result = exchange.submit_limit;
assert_eq!;
assert_eq!;
Portfolio + Metrics (Python)
=
=
Broker + Risk (Python)
# Pre-trade risk check
=
=
# Execute through IBKR
=
=
Rebalancer CLI
# Build
# Dry run — show plan without executing
# Execute with confirmation prompt
# Compare actual vs target positions
Performance
Single-threaded benchmarks (AMD Ryzen / Intel Core):
| Operation | Latency | Throughput |
|---|---|---|
| Submit (no match) | 120 ns | 8.3M ops/sec |
| Submit (with match) | ~200 ns | 5M ops/sec |
| BBO query | ~1 ns | 1B ops/sec |
| Cancel (tombstone) | 170 ns | 5.9M ops/sec |
| L2 snapshot (10 levels) | ~500 ns | 2M ops/sec |
Single-threaded throughput is roughly equivalent to Numba (both compile to LLVM IR). Where Rust wins: zero cold-start, true parallelism via Rayon with no GIL contention, and deterministic memory without GC pauses.
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, strategy trait |
parallel |
No | Rayon-based parallel parameter sweeps |
itch |
No | NASDAQ ITCH 5.0 binary protocol parser |
Design Constraints
Engineering decisions that keep the system simple and fast:
- Single-threaded — deterministic by design; same inputs always produce same outputs
- In-process — no networking overhead; wrap externally if needed
- No compliance layer — no self-trade prevention or circuit breakers (out of scope)
- No complex order types — no iceberg or pegged orders
Documentation
License
MIT