This article aims to provide a step-by-step guide to conducting a backtest for a strategy based on technical indicators using Python. We will focus on implementing a Bollinger Band based strategy to generate signals and positions.
There are various alternatives to this code, but we will be adopting a vectorized backtesting approach using the pandas framework.
Read more such Articles :- How to Build an Indian Stock Market Prediction App Using Prophet
Bollinger Band Reversal Strategy
The Bollinger Band strategy we’ll employ involves the following steps:
- Generating Bollinger Bands with a 20-day window, allowing for variations within plus or minus 2 standard deviations, based on the adjusted closing price.
- Buying when the price rises above the lower band from above and maintaining the position until the price surpasses the upper band from below on the subsequent occasion.
- Selling when the price crosses below the upper band from below and retaining the position until the price crosses above the lower band from the top in the next instance.
How to Backtest Bollinger Band Reversal Strategy
Here are the steps to create your own back-testing code:
Step 1: Import Necessary Libraries
To get started, import the essential libraries:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
import pyfolio as pf
import warnings
warnings.filterwarnings('ignore') # Ignore printing all warnings
# Print all outputs
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
Step 2: Download OHLCV Data
To gather historical data for analysis, we utilize the Yahoo Finance Python API (yfinance). Alternatively, you can use various open and free resources for historical data.
# Downloading historical data for backtesting and analysis
start_date ='2015-01-01'
end_date = '2020-12-31'
ticker = '^NSEI'
df = yf.download(tickers=ticker, start=start_date, end=end_date)
Also Read:- How to use Pairs Trading Strategy for Swing Trading
Step 3: Calculate Daily Returns
Calculate daily returns to assess the strategy’s performance compared to a buy-and-hold strategy:
# Calculating buy and hold strategy returns
df['buy_and_hold_returns'] = np.log(df['Adj Close'] / df['Adj Close'].shift(1))
df.head(3)
Step 4: Create Strategy-Based Data Columns
Develop indicators specific to the strategy, such as moving averages and Bollinger Bands:
# Creating Bollinger Band indicators
df['MA_20days'] = df['Adj Close'].rolling(window=20).mean()
df['std'] = df['Adj Close'].rolling(window=20).std()
df['upper_band'] = df['MA_20days'] + (2 * df['std'])
df['lower_band'] = df['MA_20days'] - (2 * df['std'])
df.drop(['Open', 'High', 'Low', 'Close'], axis=1, inplace=True, errors='ignore')
df.tail(5)
Step 5: Create Strategy Indicators
Generate long and short signals and positions according to the Bollinger Band strategy:
# Long condition
df['signal'] = 0
df['signal'] = np.where((df['Adj Close'] < df['lower_band']) &
(df['Adj Close'].shift(1) >= df['lower_band']), 1, 0)
# Short condition
df['signal'] = np.where((df['Adj Close'] > df['upper_band']) &
(df['Adj Close'].shift(1) <= df['upper_band']), -1, df['signal'])
# Creating long and short positions
df['position'] = df['signal'].replace(to_replace=0, method='ffill')
df['position'] = df['position'].shift(1)
# Calculating strategy returns
df['strategy_returns'] = df['buy_and_hold_returns'] * (df['position'])
df.tail(5)
df['signal'].value_counts()
Step 6: Analyze Results
In this stage, utilize Pyfolio, a Python library designed for portfolio performance and risk assessment:
pf.create_simple_tear_sheet(df['strategy_returns'].diff())
Results
The results obtained through Pyfolio offer a clear and comprehensive overview of the findings.
In the analysis of historical data, it becomes evident that the ‘Bollinger Band strategy does not outperform the straightforward buy-and-hold approach. To illustrate, the cumulative daily returns for the buy and hold strategy reached 1.44 times the initial investment, while the Bollinger band strategy only yielded returns amounting to 0.37 times the initial investment.
However, it is crucial to exercise caution when considering the transition from back-testing to live implementation, even if the former suggests promising returns. Several factors, including transaction costs and stock price momentum, can introduce unforeseen risks.
To enhance a strategy’s performance, explore optimization opportunities by assessing returns associated with various strategy parameters. Additionally, combining different technical indicators can generate more reliable signals, mitigating risks and improving overall performance.
For live strategies, implement safeguards such as stop-loss mechanisms and kill switches to maintain control in case the strategy deviates from its intended course. These precautions are vital for safeguarding investments and minimizing potential losses.
For more such strategies follow me at Github\QuantifiedTrader
Conclusion
Back-testing is a critical step in evaluating the viability of a trading strategy, and Python, along with Pyfolio, offers robust tools for this purpose. Understanding and analyzing the results obtained from back-testing is essential for making informed investment decisions.