Skip to content

mnath12/Algorithmic-Trading-Backtester

Repository files navigation

Algorithmic Trading Backtester

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.

Features

  • 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

Project Structure

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

Setup Instructions

Prerequisites

  • Python 3.8 or higher
  • pip (Python package manager)

Installation

  1. Clone or download this repository

  2. Install required packages:

    pip install -r requirements.txt

    Or manually install:

    pip install pandas numpy matplotlib jupyter
  3. Generate market data (if not already present):

    python data_generator.py

    This will create market_data.csv with 500 ticks of market data.

Usage

Running the Backtester

Run the complete backtest:

python main.py

This will:

  1. Load market data from market_data.csv
  2. Initialize trading strategies
  3. Execute the backtest
  4. Generate a performance report in performance.md

Running Unit Tests

Test immutable/mutable behavior and exception handling:

python test.py

Running the Performance Notebook

Open and run performance.ipynb in Jupyter Notebook or JupyterLab:

jupyter notebook performance.ipynb

This provides interactive analysis with:

  • Performance metrics tables
  • Equity curve visualizations
  • Return distribution charts
  • Drawdown analysis
  • Narrative interpretation

Module Descriptions

data_loader.py

  • Purpose: Load and parse CSV market data
  • Key Components:
    • MarketDataPoint: Frozen dataclass for immutable market data points
    • load_market_data(): Reads CSV into pandas DataFrame
    • convert_to_market_data_points(): Converts DataFrame to list of MarketDataPoint instances

models.py

  • Purpose: Define data models and exceptions
  • Key Components:
    • Order: Mutable class for managing trading orders
    • OrderError: Exception for invalid orders (zero/negative quantity, etc.)
    • ExecutionError: Exception for execution failures

strategies.py

  • Purpose: Define trading strategy interfaces and implementations
  • Key Components:
    • Strategy: Abstract base class with generate_signals() method
    • MovingAverageCrossover: Golden/death cross strategy
    • MomentumStrategy: Price momentum-based strategy

engine.py

  • 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

reporting.py

  • Purpose: Calculate metrics and generate reports
  • Key Components:
    • calculate_total_return(): Total return percentage
    • calculate_periodic_returns(): Period-over-period returns
    • calculate_sharpe_ratio(): Risk-adjusted return metric
    • calculate_max_drawdown(): Maximum peak-to-trough decline
    • generate_performance_report(): Creates Markdown report

main.py

  • Purpose: Orchestrate the backtesting workflow
  • Functionality:
    • Loads market data
    • Initializes strategies
    • Runs backtest engine
    • Generates performance report

Key Concepts Demonstrated

Immutable vs Mutable Types

  • Immutable: MarketDataPoint is a frozen dataclass. Once created, its attributes cannot be modified, ensuring data integrity.
  • Mutable: Order class allows status updates and attribute modifications, providing flexibility for order management.

Object-Oriented Design

  • Abstract Base Class: Strategy defines the interface that all strategies must implement
  • Inheritance: Concrete strategies (MovingAverageCrossover, MomentumStrategy) inherit from Strategy
  • Encapsulation: Private attributes (e.g., _prices, _window) hide implementation details

Container Management

  • Lists: Store market data points, equity history, and signals
  • Dictionaries: Track positions keyed by symbol with quantity and average price

Exception Handling

  • Custom Exceptions: OrderError and ExecutionError for specific error types
  • Error Recovery: Engine catches exceptions and continues processing to prevent backtest interruption

Performance Metrics

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

Example Output

After running python main.py, you'll see:

  • Console logs of the backtest progress
  • performance.md with 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

Customization

Adding New Strategies

  1. Create a new class inheriting from Strategy
  2. Implement the generate_signals() method
  3. Return a list of tuples: (action, symbol, quantity, price)
  4. 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 signals

Adjusting Strategy Parameters

Modify 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
)

Testing

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

Limitations

  • 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

Future Enhancements

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

License

This project is for educational purposes.

Author

Moinak Nath

Acknowledgments

  • Uses pandas for data manipulation
  • matplotlib for visualizations
  • Python's dataclasses for immutable data structures
  • Abstract base classes for strategy design patterns

About

Design and implement a modular Python backtester

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published