Module 00: Environment Setup & First RunGet from zero to your first backtest in under 30 minutes.
This module walks you through the required toolchain and your first backtest with a minimal strategy. At this stage, the goal is to confirm that your environment works end to end.
1. Prerequisites and Dependencies
flowchart LR
subgraph os["💻 Operating System"]
direction TB
linux["Linux (Recommended)"]
mac["macOS"]
wsl["Windows WSL2"]
end
subgraph tools["🔧 Toolchain"]
direction TB
python["Python 3.11+"]
uv["uv Package Manager"]
end
subgraph nautilus["🐚 NautilusTrader"]
direction TB
pip_install["pip install"]
source["Compile from Source"]
end
os ==> tools ==> nautilus
NautilusTrader does not currently support native Windows installs because the build process depends on Unix-based tooling for Rust and Cython components.
On Windows 10 or 11, the recommended path is WSL2 (Windows Subsystem for Linux), which gives you a full Linux environment with near-native performance.
▶ 🪟 Windows (WSL2) Installation Steps
- Enable WSL
Run the following command in PowerShell as Administrator:
wsl --install
Then restart your computer. - Install Ubuntu
After the restart, the Ubuntu installation window will usually pop up. If not, search for “Ubuntu” in the Microsoft Store to install it.
Launch the application and configure your UNIX credentials. - Install VS Code and Extensions
Download and install Visual Studio Code on Windows.
Open VS Code, navigate to Extensions, and install the WSL extension. - Connect to WSL
In your Ubuntu terminal, execute:
code .
This opens VS Code automatically connected to your WSL environment. The bottom-left corner should display WSL: Ubuntu. - Start Installing NautilusTrader
You can now use the VS Code integrated terminal to run commands (e.g.,
pip install) identically to a native Linux environment.
2. Step-by-Step Installation
Step 1: Verify Python Version
# Check Python version (requires >= 3.11)
python3 --version
# Expected Output: Python 3.11.x or 3.12.x
# 💡 Why >= 3.11?
# NautilusTrader leverages several Python 3.11 features:
# - tomllib (for TOML configuration parsing)
# - Significantly faster startup times (CPython optimizations)
# - Enriched error messaging
# ❌ What if I use Python 3.9?
# pip install nautilus_trader
# → ERROR: Requires-Python >=3.11Step 2: Install NautilusTrader
# Method 1: Using pip (Simplest)
pip install -U nautilus_trader
# Method 2: Using uv (Much faster, Highly Recommended)
pip install uv
uv pip install nautilus_trader
# 💡 Why recommend uv?
# uv is an ultra-fast Python package manager written in Rust.
# ❌ pip install nautilus_trader → Can take 2-5 minutes
# ✅ uv pip install nautilus_trader → Usually done in 10-30 secondsStep 3: Installation Verification
# Verify inside the Python interpreter
import nautilus_trader
print(nautilus_trader.__version__)
# Example Output: 1.208.0
# Verify that core C-extension components load correctly
from nautilus_trader.backtest.node import BacktestNode
from nautilus_trader.model.data import QuoteTick, Bar
from nautilus_trader.trading.strategy import Strategy
print("✅ Core components loaded successfully!")If you encounter an ImportError: libpython3.11.so, you must install the Python development headers:
# Ubuntu/Debian
sudo apt install python3.11-dev
# If you see Rust-related compiler errors (when compiling from source)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh3. Your First Backtest: Hello NautilusTrader
Below is a minimal backtest example. It places no trades and is only meant to verify that your runtime environment is working correctly.
You want to verify the full pipeline first: data loading → engine initialization → strategy execution → output generation.
❌ Start with a complex strategy: if something breaks, you will not know whether the problem is your trading logic or your environment.
✅ Start with an empty strategy: if it fails, you know the setup needs attention.
"""
Your first NautilusTrader Backtest — Hello World
Save this code to a file named hello_nautilus.py, and run it using `python hello_nautilus.py`
"""
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.backtest.engine import BacktestEngineConfig
from nautilus_trader.model.currencies import USD
from nautilus_trader.model.data import QuoteTick
from nautilus_trader.model.enums import AccountType, OmsType
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.objects import Money
from nautilus_trader.trading.strategy import Strategy
from nautilus_trader.config import StrategyConfig
# ── 1. Define a Minimalist Strategy ────────────────────────
class DoNothingConfig(StrategyConfig, frozen=True):
"""Minimalist StrategyConfig: no parameters."""
pass
class DoNothingStrategy(Strategy):
"""
This strategy executes no operations.
Its sole purpose is to validate the execution environment.
"""
def __init__(self, config: DoNothingConfig):
super().__init__(config)
def on_start(self):
self.log.info("🚀 Strategy initialized. Environment validated.")
def on_stop(self):
self.log.info("🛑 Strategy terminated. Initial backtest execution successful.")
# ── 2. Configure the Backtest Engine ───────────────────────
config = BacktestEngineConfig(
logging_level="INFO", # Output logs to standard output
logging_level_file=None, # Disable file logging
)
engine = BacktestEngine(config=config)
# ── 3. Register a Venue (Exchange) ─────────────────────────
SIM = Venue("SIM") # "SIM" represents a simulated venue
engine.add_venue(
venue=SIM,
oms_type=OmsType.NETTING, # Netting OMS
account_type=AccountType.MARGIN, # Margin account type
base_currency=USD, # Account base currency
starting_balances=[Money(100_000, USD)], # Initial capital: $100,000
)
# ── 4. Register the Strategy ───────────────────────────────
strategy = DoNothingStrategy(config=DoNothingConfig())
engine.add_strategy(strategy)
# ── 5. Execute Backtest ────────────────────────────────────
engine.run()
# ── 6. Output Results ──────────────────────────────────────
print("\n" + "="*60)
print("📊 Backtest Results")
print("="*60)
print(f"Account Balances: {engine.portfolio.balances()}")
print(f"Total Orders: {len(engine.cache.orders())}")
print(f"Total Positions: {len(engine.cache.positions())}")
print("=" * 60)
print("✅ NautilusTrader environment is fully operational.")
# Dispose engine resources
engine.dispose()If the setup is working, you should see terminal output resembling this:
INFO DoNothingStrategy: 🚀 Strategy initialized. Environment validated.
INFO DoNothingStrategy: 🛑 Strategy terminated. Initial backtest execution successful.
============================================================
📊 Backtest Results
============================================================
Account Balances: {USD: Money(100000.00, USD)}
Total Orders: 0
Total Positions: 0
============================================================
✅ NautilusTrader environment is fully operational.4. Code Walkthrough
Even though the script is minimal, it demonstrates the core execution pattern of NautilusTrader:
flowchart LR
subgraph setup["⚙️ Configuration Phase"]
direction TB
config_engine["1. Configure Engine"]
add_venue["2. Register Venue"]
add_strategy["3. Register Strategy"]
config_engine --> add_venue --> add_strategy
end
subgraph run["▶️ Execution Phase"]
direction TB
init["Initialize Core Components"]
start["Invoke Strategy on_start()"]
process["Process Data Events"]
stop["Invoke Strategy on_stop()"]
init --> start --> process --> stop
end
subgraph result["📊 Analysis Phase"]
direction TB
balance["Query Account Balances"]
orders["Query Orders"]
tearsheet["Generate Tearsheet"]
end
setup ==> run ==> result
| Code Snippet | What it does | Relevant Architecture Component | Covered Next In |
|---|---|---|---|
BacktestEngine | Instantiates the backtest engine | System Core (Kernel) | Module 12 |
add_venue() | Registers a simulated venue | Adapters | Module 13 |
OmsType.NETTING | Specifies Order Management System behavior | Execution Engine | Module 08 |
Strategy | Base strategy class | Strategy Development | Module 11 |
Money(100_000, USD) | Defines capital (fixed-point arithmetic) | Domain Model | Module 04 |
engine.portfolio | Queries portfolio state | Portfolio | Module 10 |
engine.cache | Queries in-memory cache | Cache | Module 06 |
5. Python Survival Guide
If you are new to Python, below are the most frequent syntax patterns used in NautilusTrader. You do not need to master Python before starting; understanding these 7 core concepts is sufficient:
Class & Inheritance
Your custom strategy must inherit from the NautilusTrader Strategy base class to inherit system capabilities (e.g., self.cache).
class MyStrategy(Strategy):
# The strategy inherits from the Strategy base class
# This automatically grants all base capabilities__init__ Constructor
This is the class initialization method. Calling super().__init__(config) ensures the parent class is properly initialized before custom variables are defined.
def __init__(self, config):
super().__init__(config) # Let parent class process state first
self.my_var = 0 # Then define custom variables safelyThe `self` Keyword (Instance Reference)
Within class methods, instance variables are prefixed with self. to show they belong to the specific strategy instance rather than being local temporary variables.
def on_start(self):
self.log.info("...") # Accesses the instance's unique logger
self.count = 1 # Sets up the instance's unique counterType Hints
The : Bar annotation is not an assignment; it is a type hint that explicitly declares the object’s expected type, which is critical for static analysis and IDE autocomplete.
def on_bar(self, bar: Bar):
# IDEs automatically resolve 'bar' attributes: open, high, low, close
print(bar.close)frozen=True (Immutability)
Configuration objects should be immutable. Setting frozen=True locks the configuration after construction, preventing unintended runtime mutations.
class MyConfig(StrategyConfig, frozen=True):
symbol: str = "BTC-USDT"
# c = MyConfig(...)
# c.symbol = "ETH" # ❌ Error! Configuration instances are immutable.f-strings (String Formatting)
Prefix strings with f to dynamically interpolate variables using the {variable} syntax.
price = 100
self.log.info(f"The current price is {price}") # Outputs: The current price is 100Fixed-Point Arithmetic (`Decimal`)
For exact decimal arithmetic, NautilusTrader often uses Python’s Decimal module instead of standard float primitives. Always initialize Decimals from strings to avoid floating-point artifacts.
from decimal import Decimal
qty = Decimal("0.1") # ✅ Perfect precision
# qty = Decimal(0.1) # ❌ Dangerous! Floating-point inaccuraciesNautilusTrader follows a consistent architectural pattern: configuration class + strategy class + event handlers (`on_xxx`). In most cases, you place your logic inside event handlers and let the framework hide the lower-level Cython and Rust details.
6. Project Directory Map
Knowing the source tree makes debugging and tracing subsystem behavior much faster.
When reading the source repository, start with the nautilus_trader/ directory which contains the core codebase. Build and dependency files (e.g., .cargo, poetry.lock, Makefile) can be safely ignored at this stage.
nautilus_trader/
├── model/ # 💎 Domain Model (Instruments, Orders, Positions)
| |-- orders/ # Order types and order-state logic
│ ├── instruments/ # Instrument definitions (Equities, Futures, Options...)
│ ├── data.pyx # Market data structs (QuoteTick, Bar...)
│ └── position.pyx # Position accounting
│
├── trading/ # 🎯 Strategy routing and execution
│ ├── strategy.pyx # Strategy Base Class (inherited by custom strategies)
│ ├── trader.py # Main Trader Manager instance
│ └── controller.py# Trading Controllers
│
├── data/ # 📊 Data Engine
│ ├── engine.pyx # Central hub
│ └── aggregation.pyx # Bar aggregation
│
├── execution/ # ⚙️ Execution Engine
├── risk/ # 🛡️ Risk Engine (Throttlers/Rules)
├── cache/ # 💾 State Cache System
├── common/ # 🔧 Shared Modules (Actor, MessageBus, Logger)
│
├── backtest/ # 🔬 Backtest Engine
│ ├── engine.pyx # Backtest Kernel Hub
│ └── models/ # FillModel, FeeModel, LatencyModel
│
├── live/ # 🚀 Live Execution Engine
│ ├── node.py # TradingNode
│ ├── reconciliation.py # Order reconciliation
│ └── retry.py # Automated retry routines
│
├── adapters/ # 🔌 Exchange adapters (16+ integrations)
├── indicators/ # 📈 Built-in Cythonized technical indicators
├── accounting/ # 💰 Accounting & Margin calculations
├── analysis/ # 📋 Performance analysis & Tearsheets
├── persistence/ # 💿 Persistence frameworks (Parquet DataCatalog)
├── serialization/ # 📦 Protocol serialization (Arrow/MsgPack)
├── system/ # ⚡ System Core (Kernel)
└── config/ # ⚙️ Configuration data classesYou do not need to memorize this structure. Treat this schematic as an architectural map: when tracing logic or debugging, it guides you to the relevant subsystem.
7. Interactive Exercises
Run the diagnostic script below. If all checks return ✅, your environment is fully verified:
checks = {
"nautilus_trader": True,
"BacktestEngine": True,
"Strategy": True,
"QuoteTick": True,
}
try:
import nautilus_trader
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.trading.strategy import Strategy
from nautilus_trader.model.data import QuoteTick
except ImportError as e:
print(f"❌ Missing dependency: {e}")
else:
for name in checks:
print(f" ✅ {name}")
print(f"\nVersion: {nautilus_trader.__version__}")The following snippet contains 3 intentional errors. Can you identify them?
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.model.currencies import USD
engine = BacktestEngine() # Error 1: missing config
engine.add_venue(
venue="SIM", # Error 2: wrong venue type
oms_type="NETTING", # Error 3: wrong enum type
account_type=AccountType.MARGIN,
base_currency=USD,
starting_balances=[100000],
)If you want to log the full list of all available instruments when initializing DoNothingStrategy, which event handler should this logic reside? Which subsystem must be queried?
8. Module Recap
- Environment Prerequisites: Python 3.11+ is required. Linux, macOS, or WSL2 are the most reliable environments for setup.
- Installation Options: Install with
pip install nautilus_traderor useuvfor faster dependency resolution. - Backtest Lifecycle: Configuration Phase → Event-Driven Execution Phase → Post-Execution Analytics.
- Strategy Architecture: Configuration Class (
Config) + Inherited Strategy Base (Strategy) + Event-Driven Handlers (on_xxx). - Strong Typing: NautilusTrader expects proper domain objects and enums for system parameters instead of loose string values.
- Modular Subsystems: The repository is split into clear subsystems, and later modules walk through each one in detail.
Your local trading environment is now installed, smoke-tested, and ready for the next layer. The next module asks the strategic question: In an ecosystem saturated with quantitative trading frameworks, why choose NautilusTrader?