How the Backtesting Service Simulates Trading Over Time in AI Hedge Fund
The backtesting service in virattt/ai-hedge-fund simulates trading by iterating through historical timestamps, applying agent-driven decisions to a virtual portfolio, and tracking net asset value (NAV) through a time-step loop orchestrated by the Engine component.
The virattt/ai-hedge-fund repository provides a modular backtesting framework that reproduces market conditions using pure Python and in-memory data structures. Understanding how this backtesting service simulates trading over time is essential for researchers validating AI-driven strategies before deploying capital.
Core Components of the Simulation Architecture
The simulation separates concerns across five primary modules, each handling a distinct phase of the trading lifecycle.
Engine (src/backtesting/engine.py)
The Engine drives the simulation loop. It loads historical market data, steps forward one time-slice at a time, and invokes the trader for each interval. This component maintains the chronological integrity of the simulation, ensuring that agents only access data available at the current simulated timestamp.
Trader (src/backtesting/trader.py)
The Trader encapsulates decision-making logic. At every time step, it receives the current market snapshot and queries configured agents—such as valuation, technicals, or sentiment analyzers—for buy/sell signals. The trader aggregates these signals into discrete orders and forwards them to the portfolio for execution.
Portfolio (src/backtesting/portfolio.py)
The Portfolio maintains virtual cash and positions. It processes orders from the trader, adjusting holdings while applying slippage and commission models. This module tracks the evolution of holdings over time and enforces position limits and cash constraints.
Valuation (src/backtesting/valuation.py)
The Valuation module calculates the portfolio’s net asset value (NAV) at each simulation step. Using the latest price data and custom valuation metrics, it determines the total portfolio value required for performance tracking and agent decision-making.
Step-by-Step Simulation Flow
The backtesting service executes a deterministic pipeline that transforms historical data into performance metrics through discrete phases.
1. Initialization
The controller builds a BacktestConfig object (defined in src/backtesting/types.py) specifying the date range, target assets, initial cash balance, and active agent list. This configuration object serves as the immutable blueprint for the entire simulation.
2. Data Loading
The engine retrieves historical price series (OHLCV) and auxiliary datasets (fundamentals, sentiment scores) for the specified symbols and date range. All data loads into memory as pandas DataFrames to enable fast vectorized operations during the simulation.
3. Time-Step Loop
For each timestamp in the historical range:
- The engine passes the current market slice to the trader
- The trader queries enabled agents, which return suggested orders based on their respective algorithms
- The portfolio processes executed orders, updating cash and position quantities while applying transaction cost models
- The valuation module recomputes NAV using the latest market prices
- The engine logs the portfolio state, orders, and intermediate metrics for post-analysis
4. Recording
During execution, the engine persists each step’s portfolio state, executed trades, and agent signals to in-memory buffers or disk storage, creating a complete audit trail of the simulation.
5. Post-Processing
Upon reaching the final timestamp, the metrics module (in src/backtesting/metrics.py) aggregates the time-series data into performance statistics including Sharpe ratio, maximum drawdown, and total return. The output module (in src/backtesting/output.py) then serializes these results to CSV or JSON formats for downstream analysis.
Running a Backtest: Code Examples
You can execute simulations programmatically or via the command-line interface.
Python API
The BacktestController provides a high-level interface for embedding backtests in research workflows:
from src.backtesting.controller import BacktestController
from src.backtesting.types import BacktestConfig
# Define configuration: test Apple (AAPL) from 2020-01-01 to 2021-01-01
config = BacktestConfig(
symbols=["AAPL"],
start_date="2020-01-01",
end_date="2021-01-01",
initial_cash=100_000,
agents=["valuation", "technicals"], # enable valuation & technical agents
)
# Execute the backtest
result = BacktestController.run(config)
# Print performance summary
print(result.metrics.summary())
Command-Line Interface
For batch processing or shell scripts, use the CLI wrapper defined in src/backtesting/cli.py:
python -m src.backtesting.cli \
--symbols AAPL \
--start 2020-01-01 \
--end 2021-01-01 \
--cash 100000 \
--agents valuation technicals
Both entry points invoke engine.run_backtest(config), which implements the time-step simulation described above.
Key Files and Their Responsibilities
| File | Purpose |
|---|---|
src/backtesting/engine.py |
Core simulation loop that steps through time and invokes the trader. |
src/backtesting/trader.py |
Coordinates agents, creates orders, and forwards them to the portfolio. |
src/backtesting/portfolio.py |
Manages cash, positions, applies execution logic, and tracks NAV. |
src/backtesting/valuation.py |
Computes portfolio valuation and supports custom metrics. |
src/backtesting/metrics.py |
Calculates performance statistics after the simulation. |
src/backtesting/output.py |
Persists backtest results to CSV/JSON for analysis. |
src/backtesting/controller.py |
High-level API for programmatic use. |
src/backtesting/cli.py |
Command-line interface wrapper. |
src/backtesting/types.py |
Dataclasses defining configuration and result structures. |
Summary
- The Engine in
src/backtesting/engine.pydrives the simulation by iterating through historical timestamps in chronological order. - The Trader queries AI agents for signals, while the Portfolio executes orders and tracks virtual cash and positions.
- Valuation recalculates NAV at each step, enabling accurate performance tracking throughout the simulation.
- The framework supports both programmatic and CLI execution through
controller.pyandcli.py. - Post-simulation analysis relies on
metrics.pyfor statistics andoutput.pyfor data serialization.
Frequently Asked Questions
How does the backtesting engine handle transaction costs?
The Portfolio module in src/backtesting/portfolio.py applies slippage and commission models when processing orders from the trader. These costs are deducted from the virtual cash balance during each time step, ensuring that simulated returns reflect realistic execution friction.
Can I run backtests on multiple assets simultaneously?
Yes. The BacktestConfig object accepts a list of symbols, allowing the engine to simulate a multi-asset portfolio. The trader evaluates signals for each asset independently at every timestamp, while the portfolio tracks positions and NAV across the entire universe of configured symbols.
What performance metrics does the backtesting service calculate?
After the simulation completes, src/backtesting/metrics.py aggregates the time-series data into statistics including the Sharpe ratio, maximum drawdown, total return, and volatility. These metrics are attached to the result object and can be serialized to CSV or JSON via src/backtesting/output.py.
How do I add custom agents to the backtesting simulation?
Custom agents can be registered in the trader configuration by passing their identifiers to the agents parameter in BacktestConfig. The Trader in src/backtesting/trader.py dynamically instantiates and queries these agents at each time step, aggregating their signals into executable orders. Ensure your agent implements the expected interface for signal generation to integrate seamlessly with the simulation loop.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →