Rust edition: this page follows the live DeepWiki structure but treats the current Rust crates as implementation authority. Non-Rust surfaces are identified at their boundary and are not presented as Rust APIs.
BacktestEngine Core
Relevant Rust source files
crates/backtest/src/engine.rscrates/backtest/src/exchange.rscrates/execution/src/matching_engine/engine.rs
Purpose and Scope
The BacktestEngine is the central orchestrator for historical simulation in NautilusTrader. It manages the event loop, advances simulated time deterministically, processes market data chronologically, and coordinates multiple simulated exchanges. This page covers the core engine architecture, the three-phase execution loop, and the integration between the legacy bindings layers and the Rust-based simulation components. It addresses both the legacy bindings implementation used in the high-level API and the Rust implementation used for low-level performance-critical simulations.
Architecture Overview
The Rust BacktestEngine coordinates data flow, deterministic time progression, and venue simulation using Rust timer, engine, and matching components.
System Component Map
Sources:
Core Components
SimulatedExchange and OrderMatchingEngine
Each venue in a backtest is represented by a SimulatedExchange. This component manages the lifecycle of orders and market data for all instruments on that venue.
- SimulatedExchange: Handles venue-level logic, including latency simulation via an
inflight_queueand fee/fill model application It manages multipleOrderMatchingEngineinstances indexed byInstrumentId - OrderMatchingEngine: A per-instrument engine that maintains an
OrderBookand uses aMatchingCoreto determine fills based on incomingQuoteTick,TradeTick, orBardata. It supports features likeliquidity_consumptionandqueue_positiontracking
Sources:
The Three-Phase Execution Loop
The BacktestEngine operates in a deterministic three-phase loop for every data point or timer event.
Phase 1: Data Ingestion and Time Advancement
The engine retrieves the next chronological event from the BacktestDataIterator. It then updates the TestClock to the ts_init of that data If multiple instruments are used, the engine can be optimized by calling sort_data() once after all data is added to avoid redundant sorting
Phase 2: Timer and Exchange Processing
- Timer Dispatch: The engine polls the
TimeEventAccumulatorfor any scheduled callbacks that are now due - Exchange Update: The data is routed to the relevant
SimulatedExchange. If latency is enabled viaLatencyModel, the data is queued in aninflight_queue(min-priority queue ordered by arrival timestamp) - Matching: The
OrderMatchingEngineprocesses the data. It calculates protection prices and trailing stops before attempting matching via theOrderMatchingCore
Phase 3: Strategy Dispatch and State Update
Events generated by the exchange (e.g., OrderFilled) are published to the MessageBus. Strategies receive these events via their lifecycle hooks (e.g., on_order_filled), allowing them to submit new orders via trading commands for the next iteration.
Event Loop Logic
The loop is a deterministic sequence rather than a separate architecture: advance TestClock, dispatch due TimeEvents, process the next ordered datum, settle simulated venues, publish generated events, and allow strategy handlers to issue the next typed command.
Sources:
Deterministic Time Model
NautilusTrader uses a nanosecond-precision TestClock for backtesting
- Deterministic Replay: Because the engine merges multiple data streams into a single monotonic sequence, the simulation is perfectly reproducible
- Timer Handling: Components use
clock.set_timer_ns()to schedule future logic. These are stored in the RustTimeEventAccumulator - Logging Clock Modes: The engine manages logging time modes. On start, it sets
logging_clock_set_static_modeDuring the loop, it useslogging_clock_set_static_timeto align log output with simulated time
Sources:
Rust BacktestEngine and Low-Level API
The Rust BacktestEngine provides a native implementation for high-performance scenarios.
- Initialization: Created via
BacktestEngine::new(config)which initializes aNautilusKernel - Manual Data Loading: Data is added via
add_dataoradd_data_iterator - Execution Loop: The
run()method consumes theBacktestDataIteratoruntil exhausted orforce_stopis triggered - Streaming Mode: Supports manual chunking of data batches, which is the pattern used internally by
BacktestNode
Sources:
Venue Settlement and Finalization
When a backtest reaches its end, the engine performs a settlement phase.
- Flushing Timers: Any remaining timers scheduled up to the end time are executed
- Venue Settlement: Simulated exchanges perform end-of-session tasks, such as calculating final PnL or processing "Market on Close" orders
- Result Generation: The
BacktestEnginecollects statistics to produce aBacktestResultIn Rust, this uses thePortfolioAnalyzer
Sources:
Summary of Key Entities
| Class | Source | Responsibility |
|---|---|---|
BacktestEngine |
crates/backtest/src/engine.rs |
Rust event loop and deterministic time orchestration. |
BacktestEngine (Rs) |
crates/backtest/src/engine.rs |
Native Rust event loop for performance-critical backtests. |
SimulatedExchange |
crates/backtest/src/exchange.rs |
Simulates venue latency, fees, and account state. |
OrderMatchingEngine |
crates/execution/src/matching_engine/engine.rs |
Per-instrument order book and high-fidelity fill logic. |
InflightCommand |
crates/backtest/src/exchange.rs |
Priority queue item for simulating network latency |
Sources: