Table of contents
- Our sample strategy
- -> Installing backtrader -
- -> Installing Yahoo Finance for Getting Data -
- -> Now let's import the Libraries-
- -> Creating class where we will define our strategy -
- -> Variable for our starting cash
- -> Create an instance of cerebro
- -> Adding our strategy
- -> Uploading the CSV file containing OHCLV data for backtesting in Google Colab.
- -> Getting data for backtesting our strategy
- -> Add the data to Cerebro
- -> Setting the broker commission to 0.2%
- -> Setting our desired cash start
- -> Run over everything
- -> Get final portfolio Value and pnl and printing them
- Output ->
Every Algorithmic trading rookie starts to wonder what Backtesting is and how it is implemented, yet many people ignore it based on their individual biases. But let me tell you frankly, it is a crucial step in building your algo trading robot.
To put it simply, your idea or strategy can be great in your head, but data never lies, and Backtesting is merely getting an indication as to whether your system will likely work or not.
To give you another example, think about the time when you have to decide which Mutual Fund or PMS service to invest in; you will always look at 3-Year, 5-Year Returns to arrive at a decision simply because data speaks for itself and "Sab Mutual Funds Sahi Nahi Hai"
Let's start Learning the Backtesting framework by creating and backtesting a simple strategy. We will be demonstrating a straightforward strategy to give a notion and introduce the library; the real-world strategy is much more complex. It needs various other factors to be considered, but the article is aimed at beginners.
Our sample strategy
Quantity = 100
Start Cash = 1,00,000
Commission = 0.2%
Position = Long
Frequency = Daily
Start Date = 1st Oct, 2021
End Date = 15th Nov, 2021
Buy Condition: When 21 RSI crosses above 30 and 50 SMA crosses above 100 SMA
Sell Condition: When 21 RSI crosses below 70
While there are various open-source Python backtesting libraries, we have chosen backtrader
for this article. Every library has its pros and cons; if you want to check out some more options, we wrote this article a while back; check it out.
-> Installing backtrader -
pip install backtrader
%[github.com/mementum/backtrader]
-> Installing Yahoo Finance for Getting Data -
pip install yfinance
yfinance
needs no introduction in the algo-trading world; everyone starts from this library and probably one of the most straightforward libraries to download global stock market data. We will be uploading our data in this example, but we want to let you know that yfinance
is also a worthy option.
-> Now let's import the Libraries-
import backtrader as bt
import yfinance as yf
from datetime import datetime
-> Creating class where we will define our strategy -
class firstStrategy(bt.Strategy):
def __init__(self):
# initializing rsi, slow and fast sma
self.rsi = bt.indicators.RSI(self.data.close, period=21)
self.fast_sma = bt.indicators.SMA(self.data.close, period=50)
self.slow_sma = bt.indicators.SMA(self.data.close, period=100)
self.crossup = bt.ind.CrossUp(self.fast_sma, self.slow_sma)
def next(self):
if not self.position:
if self.rsi > 30 and self.fast_sma > self.slow_sma: # when rsi > 30 and fast_sma cuts slow_sma
self.buy(size=100) # buying 100 quantities
else:
if self.rsi < 70: # when rsi is below 70 line
self.sell(size=100) # selling 100 quantities
-> Now let's look at each function in Class firstStrategy
separately-
def __init__(self)
def __init__(self):
# initializing rsi, slow and fast sma
self.rsi = bt.indicators.RSI(self.data.close, period=21)
self.fast_sma = bt.indicators.SMA(self.data.close, period=50)
self.slow_sma = bt.indicators.SMA(self.data.close, period=100)
self.crossup = bt.ind.CrossUp(self.fast_sma, self.slow_sma)
In this Function, we define the required elements for our strategy -
self.rsi contains our rsi indicator built on close data, and it's period = 21 days. self.fast_sma - It is the Simple Moving Average indicator with 50 days period. self.slow_sma - It is the Simple Moving Average indicator with 100 days period. self.crossup - It is when 50 days(fast SMA) cross above
100 days(slow SMA).
-> Now let's look at the other function in class firstStrategy
-
def next(self):
if not self.position:
# BUYING Condition
if self.rsi > 30 and self.fast_sma > self.slow_sma: # when rsi > 30 and fast_sma cuts slow_sma
self.buy(size=100) # buying 100 quantities of equity
else:
# SELLING Condition
if self.rsi < 70: # when rsi is below 70 line
self.sell(size=100) # selling 100 quantities of equity
In the above function, we create our strategy from the variable we created in the init
function.
If we have not taken a position we will buy 100 stocks based on the condition in our strategy and similarly if the position is already taken we will sell 100 stocks the stocks based on the condition provided.
-> Now, we have created our strategy for Backtesting. Let's look at other requirements for Backtesting the strategy.
-> Variable for our starting cash
startcash = 100000
-> Create an instance of cerebro
cerebro
is the brain of backtrader
library.
cerebro = bt.Cerebro() # It is the main class in backtrader.
To read more about Cerebro, Click here.
-> Adding our strategy
cerebro.addstrategy(firstStrategy) # adding strategy in Cerebro engine
-> Uploading the CSV file containing OHCLV data for backtesting in Google Colab.
from google.colab import files
uploaded = files.upload()
Note 1:- In the above code, we add CSV files from our local machine.
Note 2:- You can skip the above code block when running on the local machine.
We have the sample data for HDFCBANK.NS
which you can download from here if needed.
-> Getting data for backtesting our strategy
# Get HDFCBANK data from Yahoo Finance.
# ----- Use below code to fetch data from Yahoo Finance CSV -------
data = bt.feeds.YahooFinanceCSVData(
dataname="HDFCBANK.NS.csv",
fromdate=datetime(2020,11,1),
todate =datetime(2021,11,1))
Note 3:- The field dataname
should be replaced with the data file path if you are running this on the local machine.
-> Add the data to Cerebro
cerebro.adddata(data)
-> Setting the broker commission to 0.2%
cerebro.broker.setcommission(commission=0.002)
-> Setting our desired cash start
cerebro.broker.setcash(startcash)
-> Run over everything
cerebro.run()
-> Get final portfolio Value and pnl and printing them
portvalue = cerebro.broker.getvalue()
pnl = portvalue - startcash
# Printing out the final result
print('Final Portfolio Value: ${}'.format(portvalue))
print('P/L: ${}'.format(pnl))
Output ->
Note:- The currency in the output above is in USD. We can convert the currency to INR by using appropriate conversion rates.
-> There are various strategies, methods to analyze our output. We will discuss them in our upcoming blogs.
Click here to get complete code for reference.
That's it. I hope you like the content.
Constructive criticism is appreciated.
Feel free to reach out to me on Linkedin. If you have any suggestions about the blog, you can use the Feedback widget on the right hand of your screen, and if you wish to Contact Us, you can fill in the form there.
P.s- We hope to connect with you via LinkedIn or any social media platform to discuss ideas, and feel free to subscribe to the newsletter at the top of this article. You could also Buy me a Book to show some appreciation. ๐