Bollinger Backtest using Python and REST API Part 2

Welcome to the second part of the backtesting tutorial on a Bollinger band strategy using REST API and Python. We will be using the Jupyter notebook to do a simple backtest of a strategy that will trigger trades based on the lower band of the Bollinger band indicator.

As mentioned in part 1 of this Bollinger Band strategy backtest we can backtest one of two ways: The first option that was covered was the short hand version showing the cumulative profit or losses plotted out over the backtest. The second option is to run a backtest that will print out all the rates that you either bought or sold the price. (For example, we sold at 1.2242 when percent B was over 80%).  We would then take those rates and calculate the profit or loss by taking the difference in pips between the buy and sell rates. This method would be useful when we want to see the actual rates of the signals and the corresponding profit or loss of each trade. Today, we will be covering the

Just as we did in the last article, we will begin by importing the necessary packages, each of which can quickly be installed using the “pip install” command from your command prompt if you don’t already have them.  We will be using fxcmpy to pull historical prices, pandas and numpy for analyzing our time series data, pyti for quick access to technical indicators, matplotlib for visualizing our results, and lastly datetime to organize the date and time in an easy to read format.


#Create imports for modules
import fxcmpy
import pandas as pd
import numpy as np
import datetime as dt

#import funcs
from pyti.bollinger_bands import upper_bollinger_band as ubb
from pyti.bollinger_bands import middle_bollinger_band as mbb
from pyti.bollinger_bands import lower_bollinger_band as lbb
from pyti.bollinger_bands import percent_bandwidth as percent_b

#import plots and styling
import matplotlib.pyplot as plt
%matplotlib inline
from matplotlib import style
style.use('ggplot')

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

Now we will connect to FXCM’s REST API which will allow us to stream historical prices, live prices, and place live trades. We will use a config file to store the account access token for a secure connection to the API. To learn how to create a token, watch this tutorial.

#Establish connection using python-wrapper and config file
socket = fxcmpy.fxcmpy(config_file = 'fxcm.cfg')
print (socket.get_instruments_for_candles())

Now we know we are connected to the demo account using REST API. When we print it out, it will look something like this:

Once we are connected to the REST API, we will retrieve the historical data needed for the backtest:

 data = socket.get_candles(instrument = 'EUR/GBP', period = 'D1', start = dt.datetime(2016,1,1), end = dt.datetime(2018, 6, 10))

The next step is to define the variables we will need for the strategy. We will define the four parts of the Bollinger indicator (Upper band, Mid Band, Lower Band, and Percent B) using the Ask Close rate for the last 20 periods.

data['upper_band'] = ubb(data['askclose'], period = 20)
data['mid_band'] = mbb(data['askclose'], period = 20 )
data['lower_band'] = lbb(data['askclose'], period = 20 )
data['percent_b'] = percent_b(data['askclose'], period =20)
data

All we need to do is enter data below and we can visualize the information in a dataframe so that it is in an easy to read format:

Now we can take this dataframe and plot this on a graph to visualize our results using this code:

fig = plt.figure(figsize=(12,8))

ax1 = fig.add_subplot(111,  xlabel = 'Date',ylabel='Close')

data['askclose'].plot(ax=ax1, color='r', lw=1)
data['upper_band'].plot(ax=ax1, color = 'b', lw= 1)
data['mid_band'].plot(ax=ax1, color = 'g', lw= 1)
data['lower_band'].plot(ax=ax1, color = 'y', lw= 1)

And our output looks like this:

band_fig = plt.figure(figsize=(12,8))
ax2 = band_fig.add_subplot(111, ylabel='%B')
data['percent_b'].plot(ax=ax2, color = 'b', lw= 1)

If this line is above 1 than price is above the upper band. See the reference below on where price is located in comparison to Percent B.

    • %B Equal to 1 = Price is at the Upper Band
    • %B Above .50 = Price is Above the Middle Line
    • %B Below .50 = Price is Below the Middle Line
    • %B Equal to 0 = Price is at the Lower Band
    • %B Below 0 = Price is Below the Lower Band
    • %B Above .80 = Price is Nearing the Upper Band
    • %B Below .20 = Price is Nearing the Lower Band

The important variable that we will want to consider in this strategy is the %B line as we will be entering a long position based on this. Commonly, traders will enter a long trade when Percent B is less than 20% or take a short trade when Percent B is above 80%. For our strategy, the logic is to enter long when Percent B is greater than .2 or 20%. Note that according to our strategy, when %B is above .80 then price is nearing the upper band and when %B below .20 then price is nearing the lower band.

As mentioned before, we will enter a long when Percent B is greater than .2 or 20%. The code is simple and looks like this:


#Define the strategy
buy_prices = []
sell_prices = []

order = False
for i, row in data.iterrows():
    #buy
    if row['percent_b'] <= .2 and order == False:
        print("Create buy order since percent_b under 20%")
        print("Price bought: " +str(float(row['askclose'])))
        buy_prices.append(float(row['askclose']))
        order = True
    # close buy order
    if row['percent_b'] >= .75 and order == True:
        print("Create sell order since percent_b over 80%")
        print("Price sold: " +str(float(row['bidclose'])))
        sell_prices.append(float(row['bidclose']))
        order = False

Now that we have the signal printed, showing us at the rate at which we bought or sold, we can take it step further to add the total profit or loss in monetary value.  We start by first printing out the buy and sell prices and then we calculate the difference between them in pips.

buy_prices

sell_prices

pip_cost = 1
lot_size = 10
profits = 0
for i in range(len(buy_prices)-1):
    profit = (sell_prices[i] - buy_prices[i]) * 100 * pip_cost * lot_size
    
    profits += profit
    print("The return for trade " + str(i + 1) + " is: " + str(round(profit,2)))
    
print("The return for the period is: " + str(round(profits,2)))


We can see the profits and losses of the Bollinger band strategy we created in dollars. We triggered trades using the Bollinger band indicator on the EUR/GBP. You can use this same method to easily backtest other strategies using various indicators. Be sure to check out the functions of the fxcmpy Python wrapper to make backtesting with Python even easier.

Want the full code? Check it our on our GitHub page!


Risk Warning: The FXCM Group does not guarantee accuracy and will not accept liability for any loss or damage which arise directly or indirectly from use of or reliance on information contained within the webinars. The FXCM Group may provide general commentary which is not intended as investment advice and must not be construed as such. FX/CFD trading carries a risk of losses in excess of your deposited funds and may not be suitable for all investors. Please ensure that you fully understand the risks involved.