This repository consists of an event-driven backtester, based on a series of articles written by Michael Halls-Moore from the QuantStart website.
The code has been rewritten by hand, modified and improved for most parts. The author gave the direction on how to implement a backtester, but some additional work was necessary to make the code function properly.
Some additions have also been added in terms of data handling and strategies implemented:
YahooDataHandler
that allows to get data directly from Yahoo Finance website and update the latest "bar" in a live manner.HistoricMySQLDataHandler
designed to read a MySQL database for each requested symbol from disk, and provides an interface to obtain the "latest" bar in a manner identical to a live trading interface.MovingAverageCrossOverStrat
to carry out a basic Moving Average Crossover strategy with a short/long simple weighted moving average.ETFDailyForecastStrategy
to carry out a forecast prediction of the price of an ETF on next day, and enter/exit trades based on that prediction.OLSMRStratedy
to generate signals on a trading pair (should follow a mean reversion pattern to be tested), using rolling OLS method to find the best hedging ratio between 2 assets timeseries. Position signals are then generated based on exceeding z_scores, whether we are currently having positions in the market, or needing to exit.
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
You need Python 3.x to run the following code. You can have multiple Python versions (2.x and 3.x) installed on the same system without problems. Python needs to be first installed then SciPy and pymysql as there are dependencies on packages.
In Ubuntu, Mint and Debian you can install Python 3 like this:
sudo apt-get install python3 python3-pip
Alongside Python, the SciPy packages are also required. In Ubuntu and Debian, the SciPy ecosystem can be installed by:
sudo apt-get install python-numpy python-scipy python-matplotlib ipython ipython-notebook python-pandas python-sympy python-nose
The latest release of Scikit-Learn machine learning package, which can be installed with pip:
pip install -U scikit-learn
The pymysql package for connecting to MySQL databases using Python, which can be installed with pip:
pip install pymysql
For getting the data of price timeseries from Yahoo Finance, we use the yfinance package that can be installed using the pip package manager:
pip install yfinance
For other Linux flavors, OS X and Windows, packages are available at:
http://www.python.org/getit/ for Python
https://www.scipy.org/install.html for the SciPy ecosystem
https://scikit-learn.org/stable/install.html for Scikit-Learn
https://pypi.org/project/yfinance/ for the yfinance module
- 'BacktesterLoop.py' in which the Backtest class hierarchy encapsulates the other classes, to carry out a nested while-loop event-driven system in order to handle the events placed on the Event Queue object.
- 'DataHandler.py' which defines a class that gives all subclasses an interface for providing market data to the remaining components within the system. Data can be obtained directly from the web, a database or be read from CSV files for instance.
- 'Events.py' with four types of events (market, signal, order and fill), which allow communication between the above components via an event queue, are implemented.
- 'Execution.py' to simulate the order handling mechanism and ultimately tie into a brokerage or other means of market connectivity.
- 'Main.py' which is the main Python program, englobing all the different subroutines, and where the different parameters to initialize the backtesting simulations are specified.
- 'Performance.py' in which performance assessment criteria are implemented such as the Sharpe ratio and drawdowns.
- 'PlotPerformance.py' to plot figures based on the equity curve obtained after backtesting.
- 'Portfolio.py' that keeps track of the positions within a portfolio, and generates orders of a fixed quantity of stock based on signals.
- 'RiskManagement.py' which would be the class for implementing risk management measures, as its name suggests such as VaR calculation, Kelly criterion for position sizing, etc.
- 'Strategy.py' to generate a signal event from a particular strategy to communicate to the portfolio.
- In the 'Strategies' directory, different trading strategies are implemented to be used for backtesting:
- 'Buy_And_Hold_Strat.py' in which a simple buy and hold strategy is coded.
- 'MAC_Strat.py' to generate signals from simple moving averages.
- 'CreateLaggedSeries.py' to create lagged timeseries, to be used in the ETF forecast strategy (helper function).
- 'ETF_Forecast.py' to generate signals on the current from previous days prices of an ETF.
- 'OLS_MR_Strategy.py' to generate signals on a trading pair following a mean reversion pattern.
The different ".py" files need to be placed in the same folder for the main script to be run. The code is then ready to be used, and just requires running the following command:
python Main.py
The code is well commented and easy to understand. The different parameters calculated and used for the simulations are:
if __name__ == "__main__":
data_dir = Path.cwd() / 'DataDir' # For reading from CSV files
symbol_list = ['^OEX']
initial_capital = 100000.0
start_date = datetime(2016, 1, 1, 0, 0, 0)
end_date = datetime(2021, 1, 1, 0, 0, 0)
interval = '1d'
heartbeat = 0.0 # necessary for live feed
backtest = Backtest(data_dir, # data directory of CSV files
symbol_list, # list of symbols
initial_capital, # initial capital available for trading
heartbeat, # heartbeat to count time in real live trading simulation
start_date, # starting time of the trading
end_date, # ending time of the trading
interval, # interval of the data
YahooDataHandler, # data management method
SimpleSimulatedExecutionHandler, # Type of execution in relationship to broker
Portfolio, # portfolio management method
ETFDailyForecastStrategy) # strategy chosen
backtest.simulate_trading()
Running the backtester will generate a CSV file "equity.csv", with PnL curve, returns, drawdowns, etc. By running the following Python script, a plot can be generated to assess the strategy:
python PlotPerformance.py
The picture below shows an example with the parameters highlighted above.
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
We use SemVer for versioning. For the versions available, see the tags on this repository.
- David Cicoria - Initial work - DavidCico
See also the list of contributors who participated in this project.