NAUTILUS / RUST source 3eb18933
Pages

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.rs
  • crates/backtest/src/exchange.rs
  • crates/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

Backtest and live environments sharing the Nautilus model and engine core while supplying different clock, data and execution boundaries.

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_queue and fee/fill model application It manages multiple OrderMatchingEngine instances indexed by InstrumentId
  • OrderMatchingEngine: A per-instrument engine that maintains an OrderBook and uses a MatchingCore to determine fills based on incoming QuoteTick, TradeTick, or Bar data. It supports features like liquidity_consumption and queue_position tracking

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

  1. Timer Dispatch: The engine polls the TimeEventAccumulator for any scheduled callbacks that are now due
  2. Exchange Update: The data is routed to the relevant SimulatedExchange. If latency is enabled via LatencyModel, the data is queued in an inflight_queue (min-priority queue ordered by arrival timestamp)
  3. Matching: The OrderMatchingEngine processes the data. It calculates protection prices and trailing stops before attempting matching via the OrderMatchingCore

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 Rust TimeEventAccumulator
  • Logging Clock Modes: The engine manages logging time modes. On start, it sets logging_clock_set_static_mode During the loop, it uses logging_clock_set_static_time to 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 a NautilusKernel
  • Manual Data Loading: Data is added via add_data or add_data_iterator
  • Execution Loop: The run() method consumes the BacktestDataIterator until exhausted or force_stop is 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.

  1. Flushing Timers: Any remaining timers scheduled up to the end time are executed
  2. Venue Settlement: Simulated exchanges perform end-of-session tasks, such as calculating final PnL or processing "Market on Close" orders
  3. Result Generation: The BacktestEngine collects statistics to produce a BacktestResult In Rust, this uses the PortfolioAnalyzer

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: