A modular Python backtesting system for evaluating trading strategies on historical market data. This project demonstrates object-oriented design, immutable dataclasses, mutable order management, exception handling, and performance analysis.
- CSV Data Ingestion: Load market data from CSV files with automatic parsing
- Immutable Data Points: Frozen dataclasses for market data to ensure data integrity
- Mutable Order Management: Flexible order system with status tracking
- Abstract Strategy Interface: Extensible design for implementing custom trading strategies
- Multiple Built-in Strategies: Moving average crossover and momentum strategies
- Robust Execution Engine: Order execution with error handling and failure simulation
- Comprehensive Reporting: Performance metrics, visualizations, and Markdown reports
- Exception Handling: Custom exceptions for invalid orders and execution failures
Algorithmic-Trading-Backtester/
├── data_generator.py # Generates synthetic market data
├── data_loader.py # CSV parsing and MarketDataPoint creation
├── models.py # Order class and custom exceptions
├── strategies.py # Abstract Strategy base class and implementations
├── engine.py # Backtest execution engine
├── reporting.py # Performance metrics and report generation
├── main.py # Main entry point
├── test.py # Unit tests
├── performance.ipynb # Jupyter notebook for analysis
├── market_data.csv # Sample market data file
└── README.md # This file
- Python 3.8 or higher
- pip (Python package manager)
-
Clone or download this repository
-
Install required packages:
pip install -r requirements.txt
Or manually install:
pip install pandas numpy matplotlib jupyter
-
Generate market data (if not already present):
python data_generator.py
This will create
market_data.csvwith 500 ticks of market data.
Run the complete backtest:
python main.pyThis will:
- Load market data from
market_data.csv - Initialize trading strategies
- Execute the backtest
- Generate a performance report in
performance.md
Test immutable/mutable behavior and exception handling:
python test.pyOpen and run performance.ipynb in Jupyter Notebook or JupyterLab:
jupyter notebook performance.ipynbThis provides interactive analysis with:
- Performance metrics tables
- Equity curve visualizations
- Return distribution charts
- Drawdown analysis
- Narrative interpretation
- Purpose: Load and parse CSV market data
- Key Components:
MarketDataPoint: Frozen dataclass for immutable market data pointsload_market_data(): Reads CSV into pandas DataFrameconvert_to_market_data_points(): Converts DataFrame to list of MarketDataPoint instances
- Purpose: Define data models and exceptions
- Key Components:
Order: Mutable class for managing trading ordersOrderError: Exception for invalid orders (zero/negative quantity, etc.)ExecutionError: Exception for execution failures
- Purpose: Define trading strategy interfaces and implementations
- Key Components:
Strategy: Abstract base class withgenerate_signals()methodMovingAverageCrossover: Golden/death cross strategyMomentumStrategy: Price momentum-based strategy
- Purpose: Execute backtests and manage portfolio state
- Key Components:
BacktestEngine: Main execution engine- Manages cash and positions
- Executes orders
- Tracks equity history
- Handles execution failures
- Purpose: Calculate metrics and generate reports
- Key Components:
calculate_total_return(): Total return percentagecalculate_periodic_returns(): Period-over-period returnscalculate_sharpe_ratio(): Risk-adjusted return metriccalculate_max_drawdown(): Maximum peak-to-trough declinegenerate_performance_report(): Creates Markdown report
- Purpose: Orchestrate the backtesting workflow
- Functionality:
- Loads market data
- Initializes strategies
- Runs backtest engine
- Generates performance report
- Immutable:
MarketDataPointis a frozen dataclass. Once created, its attributes cannot be modified, ensuring data integrity. - Mutable:
Orderclass allows status updates and attribute modifications, providing flexibility for order management.
- Abstract Base Class:
Strategydefines the interface that all strategies must implement - Inheritance: Concrete strategies (
MovingAverageCrossover,MomentumStrategy) inherit fromStrategy - Encapsulation: Private attributes (e.g.,
_prices,_window) hide implementation details
- Lists: Store market data points, equity history, and signals
- Dictionaries: Track positions keyed by symbol with quantity and average price
- Custom Exceptions:
OrderErrorandExecutionErrorfor specific error types - Error Recovery: Engine catches exceptions and continues processing to prevent backtest interruption
The backtester calculates:
- Total Return: Overall percentage gain/loss
- Periodic Returns: Time series of period-over-period returns
- Sharpe Ratio: Risk-adjusted return metric
- Maximum Drawdown: Largest peak-to-trough decline
- Order Statistics: Execution success rates and counts
After running python main.py, you'll see:
- Console logs of the backtest progress
performance.mdwith formatted tables and metrics- Summary statistics printed to console
The performance.ipynb notebook provides interactive visualizations including:
- Equity curve over time
- Return distribution histograms
- Drawdown charts
- Position analysis
- Create a new class inheriting from
Strategy - Implement the
generate_signals()method - Return a list of tuples:
(action, symbol, quantity, price) - Add the strategy to the strategies list in
main.py
Example:
class MyStrategy(Strategy):
def generate_signals(self, tick: MarketDataPoint) -> List[Tuple[str, str, int, float]]:
# Your strategy logic here
return signalsModify parameters when initializing strategies in main.py:
ma_strategy = MovingAverageCrossover(
symbol="AAPL",
short_window=10, # Adjust short MA window
long_window=30, # Adjust long MA window
quantity=20 # Adjust position size
)Run unit tests to verify:
- Immutable dataclass behavior (cannot modify MarketDataPoint)
- Mutable Order behavior (can update status and attributes)
- Exception raising and handling
- Strategy signal generation
- Simulated execution (does not account for slippage, market impact)
- Simple execution failure simulation (random)
- No transaction costs in basic implementation
- Limited to CSV input format
Potential improvements:
- Add transaction costs (commissions, slippage)
- Support multiple timeframes
- Add more sophisticated strategies
- Implement portfolio optimization
- Add real-time data feed support
- Export results to databases
This project is for educational purposes.
Moinak Nath
- Uses pandas for data manipulation
- matplotlib for visualizations
- Python's dataclasses for immutable data structures
- Abstract base classes for strategy design patterns