Strategy Backtesting
Relevant source files
The following files were used as context for generating this wiki page:
Strategy backtesting in the hyperdrive library is the process of testing trading strategies against historical market data to evaluate their performance. It leverages the vectorbt library for high-performance vectorized backtesting and focuses on generating trade signals, simulating portfolios, and calculating performance metrics.
The system is designed to compare custom strategies against standard benchmarks, such as a "Buy and Hold" strategy, providing a comprehensive set of financial metrics including returns, drawdowns, and risk-adjusted ratios.
Sources: README.md:12-16, hyperdrive/History.py:1-42
Core Components
The backtesting architecture relies on several interconnected modules to fetch data, process signals, and execute simulations.
The Historian Class
The Historian class is the primary engine for backtesting. It provides methods to create portfolios from historical price data and signal arrays. It can generate optimal signals based on local extrema and evaluate random strategies to find high-performing parameters.
Sources: hyperdrive/History.py:27-100, test/test_History.py:38-66
Data Flow and Portfolio Simulation
The backtesting flow involves fetching OHLC (Open, High, Low, Close) data via MarketData and passing it through the Historian to produce a vectorbt.Portfolio object.
The diagram shows how historical data and signals are combined to produce a portfolio object for analysis.
Sources: README.md:103-120, hyperdrive/History.py:39-44
Performance Metrics
hyperdrive evaluates strategies using a standardized set of metrics derived from the portfolio simulation. These metrics are used to compare the strategy's effectiveness against a benchmark.
| Metric | Description |
|---|---|
| Total Return [%] | The percentage increase in portfolio value over the duration. |
| Benchmark Return [%] | The return achieved by a simple buy-and-hold strategy. |
| Max Drawdown [%] | The largest peak-to-trough decline in portfolio value. |
| Win Rate [%] | The percentage of trades that resulted in a profit. |
| Sharpe Ratio | A measure of risk-adjusted return. |
| Sortino Ratio | A variation of Sharpe that only considers downside risk. |
| Profit Factor | The ratio of gross profit to gross loss. |
Sources: README.md:122-135, scripts/update_api.py:34-45
Signal Generation and Processing
Trading signals are represented as boolean arrays where True typically indicates a "Buy" or "Long" position and False indicates a "Sell" or "Short" position.
Optimal Signals
The get_optimal_signals function uses the scipy.signal.argrelextrema method to identify the best possible entry and exit points (local minimums and maximums) in historical data. This serves as a "perfect" reference for training models.
Sources: hyperdrive/History.py:64-77
Signal Interpolation
The library handles gaps in signal data through filling methods:
- Forward Fill (ffill): Carries the last known signal forward.
- Nearest Fill: Interpolates to the closest known signal value.
- Unfill: A utility to remove redundant consecutive signals, leaving only the change points (entry/exit).
Sources: hyperdrive/History.py:46-62, test/test_History.py:46-53
Machine Learning Integration
The backtesting module includes utilities for preparing data for predictive modeling.
The diagram illustrates the pipeline for training and evaluating multiple classification models for signal prediction.
Sources: hyperdrive/History.py:102-155
Classification Pipeline
The run_classifiers method automatically trains and evaluates a variety of models, including:
- K-Nearest Neighbors
- Support Vector Machines (Linear and RBF)
- Random Forest and Decision Trees
- Multi-layer Perceptrons (Neural Nets)
- AdaBoost and Naive Bayes
Models are ranked based on their accuracy score on the test set, provided the ratio of training performance to testing performance remains within a threshold (1.15) to prevent overfitting.
Sources: hyperdrive/History.py:173-205
Practical Example: Comparison Script
The update_api.py script demonstrates how the system generates a comparison between "HODL" (Hold) and "hyperdrive" strategies. It calculates the portfolio value over time and packages the statistics into a JSON preview.
# From scripts/update_api.py:53-56
holding_pf = hist.create_portfolio(close, holding_signals, init_cash)
hyper_pf = hist.create_portfolio(
close, ~signals if invert else signals, init_cash, 0.001)
Sources: scripts/update_api.py:53-56, scripts/update_api.py:80-95
Summary
Strategy Backtesting in hyperdrive is a multi-stage process that integrates data acquisition via MarketData, signal optimization in Historian, and rigorous performance evaluation using vectorbt. By combining statistical analysis with machine learning classifiers, the system allows for the development and validation of trading strategies against historical benchmarks.