Nowadays, data manipulation and programming are essential in finance for analyzing large datasets of historical data, modeling different financial scenarios, and, of course, backtesting trading strategies. But what do they use to do all this? The answer is Python.
Python is the most popular programming language in finance, but most people think it is complicated and hard to learn. However, it is pretty intuitive and easy to get started with. As we will show you, you can backtest a simple trading strategy by writing only a few lines of code.
In this article, we are going to demonstrate how to backtest a trading strategy in Python: from choosing the libraries and downloading the data to generating the trading signals and plotting the returns.
Also, if you are looking for a profitable investment strategy, you might want to check out that clickable link. We have hundreds of strategies with specific trading rules and backtests, also Python trading strategies.
What libraries are we going to use?
A Python library is a collection of related modules. It contains bundles of code that can be used repeatedly in different programs. It makes Python Programming simpler and more convenient for the programmer as we don’t need to write the same code again and again for different programs.
This is one of the most important aspects to define because many libraries are dedicated exclusively to backtest trading strategies such as Zipline and Backtesting. However, in this case, we prefer to use pandas because it is more intuitive and easy to learn. Pandas is a very popular library used for data manipulation and analysis of large data sets.
Apart from pandas, we are going to use yfinance to download stock data from the Yahoo Finance website and matplotlib to create some charts and illustrate the results and performance of the strategy.
In the first few lines of our program, we need to import these libraries and define them:
Downloading stocks historical data
As we mentioned earlier, we are going to download our data from Yahoo Finance. Using the yfinance library, this is pretty simple: we define a variable, which we named data, and download the dataframe of the historical prices of SPY in it using a yfinance function called yf.dowload().
Here is the output if we print data:
We have all the daily open, high, low, close, adjusted close, and volume values for SPY since 1993!
Creating the strategy and calculating the indicators
The trading rules of the strategy we are going to backtest are the following:
- We buy and hold SPY if it’s above its 200-day simple moving average and 200-day exponential moving average
- We sell if either one of the conditions is not met.
How do we calculate the simple moving average and exponential moving average in python?
Luckily, pandas provide a function that can do it for us. It is called pandas.Series.rolling(window_size). To this function, we add .mean() at the end, and we have our simple moving average.
There is another pandas function to calculate the exponential moving average that makes two simple changes: we change rolling for ewm and instead of window inside the parentheses we put span.
We store these moving averages in two new columns we call sma and ema.
Also, we delete the first 200 rows of the data frame because, in that time frame, we don’t have the values of the simple nor exponential moving average.
Now if we print data, here is the output:
Generation the trading signals
Now we have to calculate the trading signals. In order to do that we are going to do a loop through the data frame using the for function.
This means that we are going to scan every row in the data frame one by one, checking for 2 conditions: close price must be above the simple moving average and above the exponential moving average.
We are going to create a new column called regime and put 1 if the two conditions are met and 0 if only one or neither of the conditions is met.
It is important to note that we put 1 in the following row because remember that the signal is triggered at the close of the day, meaning that we didn’t gain or lose any money the day the signal was generated.
Calculating the returns
To calculate the returns of the strategy, first, we have to calculate the daily returns of SPY. This is done with a function called pct_change(). To this function, we sum one at the end to compound the returns later.
But given that the strategy isn’t invested all of the time we have to compound the returns only when the regime columns values are equal to 1. This means that we have to do another loop through the data frame.
We create a new column called returns filled with one values and replace those values for the change in SPY when the regime column equals 1. When the regime equals 0, the value on the returns column does not change.
Plotting the returns of the strategy
Now we are going to use the library matplotlib. However, this is not a tutorial on how to use matplotlib and the post would get too long, so here is what each line of code does:
- Creates a blank chart of 10 inches in width and 8 inches in length
- Plot the cumulative returns for the SPY and add a label called S&P
- Same but with the cumulative returns of the strategy and the label called Strategy
- Makes the y-scale logarithmic
- Creates a title in the top of the chart
- Shows the labels in the chart
- Displays the chart
And here is the output:
How much does the strategy perform? The accumulated returns are 804.82%, while buy and hold returns 1505.31%. Thus, the strategy underperforms.
How I created a trading strategy using Python – conclusion
To sum up, we demonstrated that it doesn’t take a finance or computer science degree to backtest a trading strategy. It can be easily done through Python.