Customizing the trading strategy

In this post, we introduce other settings to customize the trading strategy as follows:

  1. Creating a tuple to easily alter static parameters in our trading strategy.
  2. Change the position size of each trade.

The code additions here are in the following cells:

  1. Strategy Class
  2. Backtest settings

Import modules

In [6]:
import datetime
import os.path
import sys
import backtrader as bt
import matplotlib.pyplot as plt

Data

In [7]:
homepath = os.getenv('HOME')
datapath = os.path.join(homepath, 'github/backtrader/datas/orcl-1995-2014.txt')

data = bt.feeds.YahooFinanceCSVData(
    dataname=datapath,
    fromdate=datetime.datetime(2000,1,1),
    todate = datetime.datetime(2000,12,31),
    reverse=False)

Strategy Class

We add a tuple of tuples called params at the top of the class so we can easily update these strategy variables. The exitbars is set to 10 instead of 5.

We also update the sell signal from (self.bar_executed+5) to (self.bar_executed+self.params.exitbars).

In [8]:
class Strat1_2BD_5BH(bt.Strategy):
    
    params = (
        ('exitbars',10), # Tuple of tuples containing any variable settings required by the strategy.
    )
    
    def __init__(self):
        self.dataclose= self.datas[0].close    # Keep a reference to the "close" line in the data[0] dataseries
        self.order = None # Property to keep track of pending orders.  There are no orders when the strategy is initialized.
        self.buyprice = None
        self.buycomm = None
    
    
    def log(self, txt, dt=None):
        # Logging function for the strategy.  'txt' is the statement and 'dt' can be used to specify a specific datetime
        dt = dt or self.datas[0].datetime.date(0)
        print('{0},{1}'.format(dt.isoformat(),txt))
    
    def notify_order(self, order):
        # 1. If order is submitted/accepted, do nothing 
        if order.status in [order.Submitted, order.Accepted]:
            return
        # 2. If order is buy/sell executed, report price executed
        if order.status in [order.Completed]: 
            if order.isbuy():
                self.log('BUY EXECUTED, Price: {0:8.2f}, Cost: {1:8.2f}, Comm: {2:8.2f}'.format(
                    order.executed.price,
                    order.executed.value,
                    order.executed.comm))
                
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:
                self.log('SELL EXECUTED, {0:8.2f}, Cost: {1:8.2f}, Comm{2:8.2f}'.format(
                    order.executed.price, 
                    order.executed.value,
                    order.executed.comm))
            
            self.bar_executed = len(self) #when was trade executed
        # 3. If order is canceled/margin/rejected, report order canceled
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
            
        self.order = None
    
    def notify_trade(self,trade):
        if not trade.isclosed:
            return
        
        self.log('OPERATION PROFIT, GROSS {0:8.2f}, NET {1:8.2f}'.format(
            trade.pnl, trade.pnlcomm))
    
    def next(self):
        # Log the closing prices of the series from the reference
        self.log('Close, {0:8.2f}'.format(self.dataclose[0]))

        if self.order: # check if order is pending, if so, then break out
            return
                
        # since there is no order pending, are we in the market?    
        if not self.position: # not in the market
            if self.dataclose[0] < self.dataclose[-1]:
                if self.dataclose[-1] < self.dataclose[-2]:
                    self.log('BUY CREATE {0:8.2f}'.format(self.dataclose[0]))
                    self.order = self.buy()           
        else: # in the market
            if len(self) >= (self.bar_executed+self.params.exitbars):
                self.log('SELL CREATE, {0:8.2f}'.format(self.dataclose[0]))
                self.order = self.sell()

Backtest settings

Parameters that are defined in the trading strategy can also be modified in the cerebro.addstrategy() function and this will override the parameters set within the Strategy class. We see that we have set exitbars=10.

For the size of each trade, we have set a cerebro.addsizer that sets the number of units (e.g., futures contracts, share lots) to be purchased. In the below code, we have set the stake=10 such that 10 units of the asset is purchased each time there is a successful Buy signal.

In [9]:
cerebro = bt.Cerebro()  
cerebro.adddata(data) 
cerebro.addstrategy(Strat1_2BD_5BH, exitbars=10) 
cerebro.addsizer(bt.sizers.FixedSize,stake=10)
cerebro.broker.setcash(100000.0) 
cerebro.broker.setcommission(commission=0.001) 

Run backtest

We can see from below that the Buy signal is still the same as buy orders are created after the closing price is down twice in a row, except that Sell signal is triggered only after 10 trading days (i.e, Buy is on 2000-01-06, and Sell is on 2000-01-21). The trading strategy continues to be profitable with a Final value of $100155.

In [10]:
print('Starting Portfolio Value: {0:8.2f}'.format(cerebro.broker.getvalue()))
cerebro.run()
print('Final Portfolio Value: {0:8.2f}'.format(cerebro.broker.getvalue()))
Starting Portfolio Value: 100000.00
2000-01-03,Close,    26.27
2000-01-04,Close,    23.95
2000-01-05,Close,    22.68
2000-01-05,BUY CREATE    22.68
2000-01-06,BUY EXECUTED, Price:    22.27, Cost:   222.70, Comm:     0.22
2000-01-06,Close,    21.35
2000-01-07,Close,    22.99
2000-01-10,Close,    25.74
2000-01-11,Close,    24.99
2000-01-12,Close,    23.49
2000-01-13,Close,    23.36
2000-01-14,Close,    23.75
2000-01-18,Close,    24.74
2000-01-19,Close,    25.41
2000-01-20,Close,    26.35
2000-01-21,Close,    26.55
2000-01-21,SELL CREATE,    26.55
2000-01-24,SELL EXECUTED,    26.80, Cost:   222.70, Comm    0.27
2000-01-24,OPERATION PROFIT, GROSS    45.30, NET    44.81
2000-01-24,Close,    24.10
2000-01-25,Close,    25.10
2000-01-26,Close,    24.49
2000-01-27,Close,    23.04
2000-01-27,BUY CREATE    23.04
2000-01-28,BUY EXECUTED, Price:    22.90, Cost:   229.00, Comm:     0.23
2000-01-28,Close,    21.07
2000-01-31,Close,    22.22
2000-02-01,Close,    24.02
2000-02-02,Close,    24.16
2000-02-03,Close,    25.21
2000-02-04,Close,    25.71
2000-02-07,Close,    26.66
2000-02-08,Close,    26.49
2000-02-09,Close,    26.66
2000-02-10,Close,    27.71
2000-02-11,Close,    26.55
2000-02-11,SELL CREATE,    26.55
2000-02-14,SELL EXECUTED,    27.07, Cost:   229.00, Comm    0.27
2000-02-14,OPERATION PROFIT, GROSS    41.70, NET    41.20
2000-02-14,Close,    27.66
2000-02-15,Close,    27.30
2000-02-16,Close,    27.24
2000-02-16,BUY CREATE    27.24
2000-02-17,BUY EXECUTED, Price:    27.46, Cost:   274.60, Comm:     0.27
2000-02-17,Close,    27.41
2000-02-18,Close,    26.05
2000-02-22,Close,    26.38
2000-02-23,Close,    28.05
2000-02-24,Close,    27.55
2000-02-25,Close,    31.41
2000-02-28,Close,    30.52
2000-02-29,Close,    33.02
2000-03-01,Close,    31.80
2000-03-02,Close,    30.47
2000-03-03,Close,    33.36
2000-03-03,SELL CREATE,    33.36
2000-03-06,SELL EXECUTED,    33.27, Cost:   274.60, Comm    0.33
2000-03-06,OPERATION PROFIT, GROSS    58.10, NET    57.49
2000-03-06,Close,    33.69
2000-03-07,Close,    33.33
2000-03-08,Close,    36.97
2000-03-09,Close,    37.36
2000-03-10,Close,    36.30
2000-03-13,Close,    35.02
2000-03-13,BUY CREATE    35.02
2000-03-14,BUY EXECUTED, Price:    36.41, Cost:   364.10, Comm:     0.36
2000-03-14,Close,    34.25
2000-03-15,Close,    34.97
2000-03-16,Close,    36.44
2000-03-17,Close,    35.50
2000-03-20,Close,    34.75
2000-03-21,Close,    35.89
2000-03-22,Close,    37.39
2000-03-23,Close,    38.64
2000-03-24,Close,    38.69
2000-03-27,Close,    39.33
2000-03-28,Close,    38.50
2000-03-28,SELL CREATE,    38.50
2000-03-29,SELL EXECUTED,    38.28, Cost:   364.10, Comm    0.38
2000-03-29,OPERATION PROFIT, GROSS    18.70, NET    17.95
2000-03-29,Close,    36.69
2000-03-29,BUY CREATE    36.69
2000-03-30,BUY EXECUTED, Price:    34.91, Cost:   349.10, Comm:     0.35
2000-03-30,Close,    34.88
2000-03-31,Close,    34.72
2000-04-03,Close,    34.19
2000-04-04,Close,    33.77
2000-04-05,Close,    34.80
2000-04-06,Close,    36.55
2000-04-07,Close,    38.75
2000-04-10,Close,    36.69
2000-04-11,Close,    34.41
2000-04-12,Close,    32.52
2000-04-13,Close,    31.99
2000-04-13,SELL CREATE,    31.99
2000-04-14,SELL EXECUTED,    31.10, Cost:   349.10, Comm    0.31
2000-04-14,OPERATION PROFIT, GROSS   -38.10, NET   -38.76
2000-04-14,Close,    27.80
2000-04-14,BUY CREATE    27.80
2000-04-17,BUY EXECUTED, Price:    26.91, Cost:   269.10, Comm:     0.27
2000-04-17,Close,    33.27
2000-04-18,Close,    35.11
2000-04-19,Close,    33.16
2000-04-20,Close,    31.49
2000-04-24,Close,    32.22
2000-04-25,Close,    33.61
2000-04-26,Close,    32.11
2000-04-27,Close,    34.38
2000-04-28,Close,    35.55
2000-05-01,Close,    35.44
2000-05-02,Close,    34.61
2000-05-02,SELL CREATE,    34.61
2000-05-03,SELL EXECUTED,    34.19, Cost:   269.10, Comm    0.34
2000-05-03,OPERATION PROFIT, GROSS    72.80, NET    72.19
2000-05-03,Close,    33.72
2000-05-03,BUY CREATE    33.72
2000-05-04,BUY EXECUTED, Price:    33.49, Cost:   334.90, Comm:     0.33
2000-05-04,Close,    33.02
2000-05-05,Close,    34.16
2000-05-08,Close,    32.16
2000-05-09,Close,    32.02
2000-05-10,Close,    30.08
2000-05-11,Close,    32.19
2000-05-12,Close,    32.99
2000-05-15,Close,    34.25
2000-05-16,Close,    35.22
2000-05-17,Close,    34.77
2000-05-18,Close,    32.49
2000-05-18,SELL CREATE,    32.49
2000-05-19,SELL EXECUTED,    32.02, Cost:   334.90, Comm    0.32
2000-05-19,OPERATION PROFIT, GROSS   -14.70, NET   -15.36
2000-05-19,Close,    31.16
2000-05-19,BUY CREATE    31.16
2000-05-22,BUY EXECUTED, Price:    31.16, Cost:   311.60, Comm:     0.31
2000-05-22,Close,    30.16
2000-05-23,Close,    27.85
2000-05-24,Close,    28.57
2000-05-25,Close,    29.55
2000-05-26,Close,    29.80
2000-05-30,Close,    32.99
2000-05-31,Close,    31.97
2000-06-01,Close,    34.63
2000-06-02,Close,    35.66
2000-06-05,Close,    36.00
2000-06-06,Close,    34.27
2000-06-06,SELL CREATE,    34.27
2000-06-07,SELL EXECUTED,    34.13, Cost:   311.60, Comm    0.34
2000-06-07,OPERATION PROFIT, GROSS    29.70, NET    29.05
2000-06-07,Close,    35.58
2000-06-08,Close,    36.64
2000-06-09,Close,    36.77
2000-06-12,Close,    35.83
2000-06-13,Close,    36.33
2000-06-14,Close,    35.13
2000-06-15,Close,    36.69
2000-06-16,Close,    36.41
2000-06-19,Close,    38.25
2000-06-20,Close,    38.27
2000-06-21,Close,    38.33
2000-06-22,Close,    36.25
2000-06-23,Close,    35.36
2000-06-23,BUY CREATE    35.36
2000-06-26,BUY EXECUTED, Price:    35.69, Cost:   356.90, Comm:     0.36
2000-06-26,Close,    36.77
2000-06-27,Close,    36.58
2000-06-28,Close,    36.89
2000-06-29,Close,    35.97
2000-06-30,Close,    37.39
2000-07-03,Close,    35.66
2000-07-05,Close,    32.16
2000-07-06,Close,    33.63
2000-07-07,Close,    33.75
2000-07-10,Close,    32.97
2000-07-11,Close,    32.16
2000-07-11,SELL CREATE,    32.16
2000-07-12,SELL EXECUTED,    32.66, Cost:   356.90, Comm    0.33
2000-07-12,OPERATION PROFIT, GROSS   -30.30, NET   -30.98
2000-07-12,Close,    33.22
2000-07-13,Close,    33.69
2000-07-14,Close,    33.86
2000-07-17,Close,    33.86
2000-07-18,Close,    32.99
2000-07-19,Close,    32.80
2000-07-19,BUY CREATE    32.80
2000-07-20,BUY EXECUTED, Price:    33.27, Cost:   332.70, Comm:     0.33
2000-07-20,Close,    34.75
2000-07-21,Close,    33.55
2000-07-24,Close,    33.36
2000-07-25,Close,    33.80
2000-07-26,Close,    34.13
2000-07-27,Close,    33.38
2000-07-28,Close,    32.19
2000-07-31,Close,    33.44
2000-08-01,Close,    32.52
2000-08-02,Close,    32.52
2000-08-03,Close,    34.44
2000-08-03,SELL CREATE,    34.44
2000-08-04,SELL EXECUTED,    34.83, Cost:   332.70, Comm    0.35
2000-08-04,OPERATION PROFIT, GROSS    15.60, NET    14.92
2000-08-04,Close,    36.27
2000-08-07,Close,    36.41
2000-08-08,Close,    36.91
2000-08-09,Close,    36.19
2000-08-10,Close,    35.61
2000-08-10,BUY CREATE    35.61
2000-08-11,BUY EXECUTED, Price:    35.55, Cost:   355.50, Comm:     0.36
2000-08-11,Close,    36.08
2000-08-14,Close,    36.64
2000-08-15,Close,    36.14
2000-08-16,Close,    36.11
2000-08-17,Close,    37.33
2000-08-18,Close,    36.16
2000-08-21,Close,    37.00
2000-08-22,Close,    37.16
2000-08-23,Close,    36.86
2000-08-24,Close,    37.66
2000-08-25,Close,    37.64
2000-08-25,SELL CREATE,    37.64
2000-08-28,SELL EXECUTED,    37.80, Cost:   355.50, Comm    0.38
2000-08-28,OPERATION PROFIT, GROSS    22.50, NET    21.77
2000-08-28,Close,    38.58
2000-08-29,Close,    39.03
2000-08-30,Close,    39.25
2000-08-31,Close,    40.44
2000-09-01,Close,    41.19
2000-09-05,Close,    40.50
2000-09-06,Close,    39.69
2000-09-06,BUY CREATE    39.69
2000-09-07,BUY EXECUTED, Price:    40.08, Cost:   400.80, Comm:     0.40
2000-09-07,Close,    40.56
2000-09-08,Close,    38.50
2000-09-11,Close,    37.11
2000-09-12,Close,    35.30
2000-09-13,Close,    36.39
2000-09-14,Close,    37.78
2000-09-15,Close,    34.83
2000-09-18,Close,    34.01
2000-09-19,Close,    35.27
2000-09-20,Close,    35.55
2000-09-21,Close,    35.11
2000-09-21,SELL CREATE,    35.11
2000-09-22,SELL EXECUTED,    33.77, Cost:   400.80, Comm    0.34
2000-09-22,OPERATION PROFIT, GROSS   -63.10, NET   -63.84
2000-09-22,Close,    35.91
2000-09-25,Close,    35.02
2000-09-26,Close,    35.33
2000-09-27,Close,    35.52
2000-09-28,Close,    36.24
2000-09-29,Close,    35.02
2000-10-02,Close,    35.02
2000-10-03,Close,    30.91
2000-10-04,Close,    30.30
2000-10-04,BUY CREATE    30.30
2000-10-05,BUY EXECUTED, Price:    30.38, Cost:   303.80, Comm:     0.30
2000-10-05,Close,    30.38
2000-10-06,Close,    30.08
2000-10-09,Close,    29.69
2000-10-10,Close,    28.74
2000-10-11,Close,    27.69
2000-10-12,Close,    28.02
2000-10-13,Close,    31.69
2000-10-16,Close,    30.74
2000-10-17,Close,    29.96
2000-10-18,Close,    29.85
2000-10-19,Close,    32.36
2000-10-19,SELL CREATE,    32.36
2000-10-20,SELL EXECUTED,    32.13, Cost:   303.80, Comm    0.32
2000-10-20,OPERATION PROFIT, GROSS    17.50, NET    16.87
2000-10-20,Close,    31.35
2000-10-23,Close,    30.30
2000-10-23,BUY CREATE    30.30
2000-10-24,BUY EXECUTED, Price:    31.13, Cost:   311.30, Comm:     0.31
2000-10-24,Close,    31.85
2000-10-25,Close,    30.58
2000-10-26,Close,    30.30
2000-10-27,Close,    30.41
2000-10-30,Close,    28.13
2000-10-31,Close,    29.35
2000-11-01,Close,    27.91
2000-11-02,Close,    26.30
2000-11-03,Close,    26.96
2000-11-06,Close,    24.85
2000-11-07,Close,    23.63
2000-11-07,SELL CREATE,    23.63
2000-11-08,SELL EXECUTED,    24.35, Cost:   311.30, Comm    0.24
2000-11-08,OPERATION PROFIT, GROSS   -67.80, NET   -68.35
2000-11-08,Close,    22.07
2000-11-08,BUY CREATE    22.07
2000-11-09,BUY EXECUTED, Price:    21.96, Cost:   219.60, Comm:     0.22
2000-11-09,Close,    24.18
2000-11-10,Close,    22.63
2000-11-13,Close,    22.01
2000-11-14,Close,    25.24
2000-11-15,Close,    25.68
2000-11-16,Close,    24.35
2000-11-17,Close,    25.63
2000-11-20,Close,    22.01
2000-11-21,Close,    21.24
2000-11-22,Close,    19.85
2000-11-24,Close,    21.46
2000-11-24,SELL CREATE,    21.46
2000-11-27,SELL EXECUTED,    22.63, Cost:   219.60, Comm    0.23
2000-11-27,OPERATION PROFIT, GROSS     6.70, NET     6.25
2000-11-27,Close,    20.57
2000-11-28,Close,    20.15
2000-11-28,BUY CREATE    20.15
2000-11-29,BUY EXECUTED, Price:    20.63, Cost:   206.30, Comm:     0.21
2000-11-29,Close,    20.35
2000-11-30,Close,    23.57
2000-12-01,Close,    23.52
2000-12-04,Close,    25.07
2000-12-05,Close,    28.02
2000-12-06,Close,    26.85
2000-12-07,Close,    25.18
2000-12-08,Close,    26.74
2000-12-11,Close,    28.41
2000-12-12,Close,    27.35
2000-12-13,Close,    25.24
2000-12-13,SELL CREATE,    25.24
2000-12-14,SELL EXECUTED,    26.02, Cost:   206.30, Comm    0.26
2000-12-14,OPERATION PROFIT, GROSS    53.90, NET    53.43
2000-12-14,Close,    24.46
2000-12-14,BUY CREATE    24.46
2000-12-15,BUY EXECUTED, Price:    26.18, Cost:   261.80, Comm:     0.26
2000-12-15,Close,    25.41
2000-12-18,Close,    28.46
2000-12-19,Close,    27.24
2000-12-20,Close,    25.35
2000-12-21,Close,    26.24
2000-12-22,Close,    28.35
2000-12-26,Close,    27.52
2000-12-27,Close,    27.30
2000-12-28,Close,    27.63
2000-12-29,Close,    25.85
Final Portfolio Value: 100155.09

Plot backtest results

In [27]:
%matplotlib inline
cerebro.plot()
Out[27]:
[[<Figure size 432x288 with 4 Axes>]]

Conclusion

In this post, we learnt how to customize the trading strategy as follows:

  1. We learnt how to set static parameters using a tuple of tuples at the top of the strategy class. These parameters can also be modified in the cerebro.addstrategy().
  2. We also set the number of units/contracts for the trading strategy to enter.

In the next post, we will look at adding indicators.

The below code needs to be run to execute cerebro.plot() successfullly

In [26]:
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randint(0,100,size=(100,4)),columns = list('ABCD'))
df.head()
df.plot()
Out[26]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f2312b3a940>
In [ ]:
 

Introduction to automated trading with backtrader

This is an introduction to the backtrader automated trading system. We decompose the backtrader package into its core components, and explain the very basics of creating your own trading system.

  1. Data Feeds. The data for the trading strategy needs to be loaded into the backtester needs to be loaded in.
  2. Trading strategy. The trading strategy is the most complex and involved part of the programming process since this is where decisions are made to buy/sell the asset.
  3. Backtester settings. Cerebro is the name of the backtester. Cerebro requires several settings such as (i) Trading capital (ii) Broker Comissions (iii) Datafeed (iv) Trading strategy (v) Size of each trading position.
  4. Running backtest. Run the Cerebro backtester and print out all trades executed.
  5. Evaluating performance. Graphically evaluate the performance of the backtested trading strategy.

Note: The reference to [0] in an array containing price data refers to the current datapoint and [-1] ([-2])is the first previous datapoint (second previous data point).

Import modules

In [1]:
import datetime
import os.path
import sys
import backtrader as bt
import matplotlib.pyplot as plt

Data

The datafeed code below reads a local file that is formatted as a Yahoo!Finance CSV file. The data feed can be updated to suit Google Finance data feeds or any other files of the asset returns that you have.

In [2]:
homepath = os.getenv('HOME')
datapath = os.path.join(homepath, 'github/backtrader/datas/orcl-1995-2014.txt')

data = bt.feeds.YahooFinanceCSVData(
    dataname=datapath,
    fromdate=datetime.datetime(2000,1,1),
    todate = datetime.datetime(2000,12,31),
    reverse=False)

Strategy Class

The trading strategy class code contains important parameters and functions for executing the strategy. Important aspects of the Strategy class are as follows:

  1. params - This allows you to easily change the values of any variables/parameters in your trading strategy, rather than going into the guts of the code itself.
  2. log - This is a logging function for your strategy. It will print out the datetime and the txt variable provided for the function.
  3. init - This is the code for initializing the class instance of the trading strategy.
  4. notify_order - This keeps track of the status of any orders. Orders have states such as being submitted, accepted, buy/sell execution & price, cancelled/rejected.
  5. notify_trade - This keeps track of the status of any trades. Any trade that is closed will have the gross & net profit reported.
  6. next - This is where the trading strategy is actually programmed. The next command refers to when we step into the next trading bar/window, it performs the checks to see a. Is an order pending?
      If an order is pending, then we break out of the function.
    
    b. No order is pending, so are do we have any open positions (i.e., are we in the market?)
      i. We have **no open positions**, thus, we check if *buy* conditions are triggered.  
      ii. We have **open positions**, thus, we check if the *sell* conditions are triggered.

The trading strategy below is as follows:

  1. Buy signal - Purchase the asset when the its closing price is 2 bars down in a row.
  2. Sell signal - Liquidate the position after the asset is held for 5 bars. In this case, each bar is a day, but it can be a minute/hour/week/any time period.
In [3]:
class Strat1_2BD_5BH(bt.Strategy):
    
    def __init__(self):
        self.dataclose= self.datas[0].close    # Keep a reference to the "close" line in the data[0] dataseries
        self.order = None # Property to keep track of pending orders.  There are no orders when the strategy is initialized.
        self.buyprice = None
        self.buycomm = None
    
    
    def log(self, txt, dt=None):
        # Logging function for the strategy.  'txt' is the statement and 'dt' can be used to specify a specific datetime
        dt = dt or self.datas[0].datetime.date(0)
        print('{0},{1}'.format(dt.isoformat(),txt))
    
    def notify_order(self, order):
        # 1. If order is submitted/accepted, do nothing 
        if order.status in [order.Submitted, order.Accepted]:
            return
        # 2. If order is buy/sell executed, report price executed
        if order.status in [order.Completed]: 
            if order.isbuy():
                self.log('BUY EXECUTED, Price: {0:8.2f}, Cost: {1:8.2f}, Comm: {2:8.2f}'.format(
                    order.executed.price,
                    order.executed.value,
                    order.executed.comm))
                
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:
                self.log('SELL EXECUTED, {0:8.2f}, Cost: {1:8.2f}, Comm{2:8.2f}'.format(
                    order.executed.price, 
                    order.executed.value,
                    order.executed.comm))
            
            self.bar_executed = len(self) #when was trade executed
        # 3. If order is canceled/margin/rejected, report order canceled
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
            
        self.order = None
    
    def notify_trade(self,trade):
        if not trade.isclosed:
            return
        
        self.log('OPERATION PROFIT, GROSS {0:8.2f}, NET {1:8.2f}'.format(
            trade.pnl, trade.pnlcomm))
    
    def next(self):
        # Log the closing prices of the series from the reference
        self.log('Close, {0:8.2f}'.format(self.dataclose[0]))

        if self.order: # check if order is pending, if so, then break out
            return
                
        # since there is no order pending, are we in the market?    
        if not self.position: # not in the market
            if self.dataclose[0] < self.dataclose[-1]:
                if self.dataclose[-1] < self.dataclose[-2]:
                    self.log('BUY CREATE {0:8.2f}'.format(self.dataclose[0]))
                    self.order = self.buy()           
        else: # in the market
            if len(self) >= (self.bar_executed+5):
                self.log('SELL CREATE, {0:8.2f}'.format(self.dataclose[0]))
                self.order = self.sell()

Backtest settings

The backtester is known as Cerebro and requires several settings as follows:

  1. Add trading strategy - It is necessary to addstrategies into the backtester so it can start testing the performance of the system.
  2. Data - Data needs to be added to the backtester so it can implement the trading strategy on it.
  3. Broker settings - Broker settings such as the amount of trading capital and the trading comissions are required to provide an indication of the gross and net wealth accumulated when executing the trading strategy.
  4. Position sizing - Sets the size of the trades taken as part of the strategy.
In [4]:
cerebro = bt.Cerebro()  # We initialize the `cerebro` backtester.
cerebro.adddata(data) # We add the dataset in the Data cell.
cerebro.addstrategy(Strat1_2BD_5BH) # We add the strategy described in the `Strategy class` cell
cerebro.broker.setcash(100000.0) # We set an initial trading capital of $100,000
cerebro.broker.setcommission(commission=0.001) # We set broker comissions of 0.1%

Run backtest

We can see from below that the Buy signal is that Buy orders are created after the closing price is down twice in a row, and that the Sell signal is triggered only after 5 trading days (i.e, Buy is on 2000-01-06, and Sell is on 2000-01-13)

In [8]:
print('Starting Portfolio Value: {0:8.2f}'.format(cerebro.broker.getvalue()))
cerebro.run()
print('Final Portfolio Value: {0:8.2f}'.format(cerebro.broker.getvalue()))
Starting Portfolio Value: 100016.06
2000-01-03,Close,    26.27
2000-01-04,Close,    23.95
2000-01-05,Close,    22.68
2000-01-05,BUY CREATE    22.68
2000-01-06,BUY EXECUTED, Price:    22.27, Cost:    22.27, Comm:     0.02
2000-01-06,Close,    21.35
2000-01-07,Close,    22.99
2000-01-10,Close,    25.74
2000-01-11,Close,    24.99
2000-01-12,Close,    23.49
2000-01-13,Close,    23.36
2000-01-13,SELL CREATE,    23.36
2000-01-14,SELL EXECUTED,    24.24, Cost:    22.27, Comm    0.02
2000-01-14,OPERATION PROFIT, GROSS     1.97, NET     1.92
2000-01-14,Close,    23.75
2000-01-18,Close,    24.74
2000-01-19,Close,    25.41
2000-01-20,Close,    26.35
2000-01-21,Close,    26.55
2000-01-24,Close,    24.10
2000-01-25,Close,    25.10
2000-01-26,Close,    24.49
2000-01-27,Close,    23.04
2000-01-27,BUY CREATE    23.04
2000-01-28,BUY EXECUTED, Price:    22.90, Cost:    22.90, Comm:     0.02
2000-01-28,Close,    21.07
2000-01-31,Close,    22.22
2000-02-01,Close,    24.02
2000-02-02,Close,    24.16
2000-02-03,Close,    25.21
2000-02-04,Close,    25.71
2000-02-04,SELL CREATE,    25.71
2000-02-07,SELL EXECUTED,    26.38, Cost:    22.90, Comm    0.03
2000-02-07,OPERATION PROFIT, GROSS     3.48, NET     3.43
2000-02-07,Close,    26.66
2000-02-08,Close,    26.49
2000-02-09,Close,    26.66
2000-02-10,Close,    27.71
2000-02-11,Close,    26.55
2000-02-14,Close,    27.66
2000-02-15,Close,    27.30
2000-02-16,Close,    27.24
2000-02-16,BUY CREATE    27.24
2000-02-17,BUY EXECUTED, Price:    27.46, Cost:    27.46, Comm:     0.03
2000-02-17,Close,    27.41
2000-02-18,Close,    26.05
2000-02-22,Close,    26.38
2000-02-23,Close,    28.05
2000-02-24,Close,    27.55
2000-02-25,Close,    31.41
2000-02-25,SELL CREATE,    31.41
2000-02-28,SELL EXECUTED,    31.69, Cost:    27.46, Comm    0.03
2000-02-28,OPERATION PROFIT, GROSS     4.23, NET     4.17
2000-02-28,Close,    30.52
2000-02-29,Close,    33.02
2000-03-01,Close,    31.80
2000-03-02,Close,    30.47
2000-03-02,BUY CREATE    30.47
2000-03-03,BUY EXECUTED, Price:    31.63, Cost:    31.63, Comm:     0.03
2000-03-03,Close,    33.36
2000-03-06,Close,    33.69
2000-03-07,Close,    33.33
2000-03-08,Close,    36.97
2000-03-09,Close,    37.36
2000-03-10,Close,    36.30
2000-03-10,SELL CREATE,    36.30
2000-03-13,SELL EXECUTED,    34.91, Cost:    31.63, Comm    0.03
2000-03-13,OPERATION PROFIT, GROSS     3.28, NET     3.21
2000-03-13,Close,    35.02
2000-03-13,BUY CREATE    35.02
2000-03-14,BUY EXECUTED, Price:    36.41, Cost:    36.41, Comm:     0.04
2000-03-14,Close,    34.25
2000-03-15,Close,    34.97
2000-03-16,Close,    36.44
2000-03-17,Close,    35.50
2000-03-20,Close,    34.75
2000-03-21,Close,    35.89
2000-03-21,SELL CREATE,    35.89
2000-03-22,SELL EXECUTED,    36.02, Cost:    36.41, Comm    0.04
2000-03-22,OPERATION PROFIT, GROSS    -0.39, NET    -0.46
2000-03-22,Close,    37.39
2000-03-23,Close,    38.64
2000-03-24,Close,    38.69
2000-03-27,Close,    39.33
2000-03-28,Close,    38.50
2000-03-29,Close,    36.69
2000-03-29,BUY CREATE    36.69
2000-03-30,BUY EXECUTED, Price:    34.91, Cost:    34.91, Comm:     0.03
2000-03-30,Close,    34.88
2000-03-31,Close,    34.72
2000-04-03,Close,    34.19
2000-04-04,Close,    33.77
2000-04-05,Close,    34.80
2000-04-06,Close,    36.55
2000-04-06,SELL CREATE,    36.55
2000-04-07,SELL EXECUTED,    37.22, Cost:    34.91, Comm    0.04
2000-04-07,OPERATION PROFIT, GROSS     2.31, NET     2.24
2000-04-07,Close,    38.75
2000-04-10,Close,    36.69
2000-04-11,Close,    34.41
2000-04-11,BUY CREATE    34.41
2000-04-12,BUY EXECUTED, Price:    34.66, Cost:    34.66, Comm:     0.03
2000-04-12,Close,    32.52
2000-04-13,Close,    31.99
2000-04-14,Close,    27.80
2000-04-17,Close,    33.27
2000-04-18,Close,    35.11
2000-04-19,Close,    33.16
2000-04-19,SELL CREATE,    33.16
2000-04-20,SELL EXECUTED,    32.83, Cost:    34.66, Comm    0.03
2000-04-20,OPERATION PROFIT, GROSS    -1.83, NET    -1.90
2000-04-20,Close,    31.49
2000-04-20,BUY CREATE    31.49
2000-04-24,BUY EXECUTED, Price:    29.96, Cost:    29.96, Comm:     0.03
2000-04-24,Close,    32.22
2000-04-25,Close,    33.61
2000-04-26,Close,    32.11
2000-04-27,Close,    34.38
2000-04-28,Close,    35.55
2000-05-01,Close,    35.44
2000-05-01,SELL CREATE,    35.44
2000-05-02,SELL EXECUTED,    35.11, Cost:    29.96, Comm    0.04
2000-05-02,OPERATION PROFIT, GROSS     5.15, NET     5.08
2000-05-02,Close,    34.61
2000-05-02,BUY CREATE    34.61
2000-05-03,BUY EXECUTED, Price:    34.19, Cost:    34.19, Comm:     0.03
2000-05-03,Close,    33.72
2000-05-04,Close,    33.02
2000-05-05,Close,    34.16
2000-05-08,Close,    32.16
2000-05-09,Close,    32.02
2000-05-10,Close,    30.08
2000-05-10,SELL CREATE,    30.08
2000-05-11,SELL EXECUTED,    30.66, Cost:    34.19, Comm    0.03
2000-05-11,OPERATION PROFIT, GROSS    -3.53, NET    -3.59
2000-05-11,Close,    32.19
2000-05-12,Close,    32.99
2000-05-15,Close,    34.25
2000-05-16,Close,    35.22
2000-05-17,Close,    34.77
2000-05-18,Close,    32.49
2000-05-18,BUY CREATE    32.49
2000-05-19,BUY EXECUTED, Price:    32.02, Cost:    32.02, Comm:     0.03
2000-05-19,Close,    31.16
2000-05-22,Close,    30.16
2000-05-23,Close,    27.85
2000-05-24,Close,    28.57
2000-05-25,Close,    29.55
2000-05-26,Close,    29.80
2000-05-26,SELL CREATE,    29.80
2000-05-30,SELL EXECUTED,    30.63, Cost:    32.02, Comm    0.03
2000-05-30,OPERATION PROFIT, GROSS    -1.39, NET    -1.45
2000-05-30,Close,    32.99
2000-05-31,Close,    31.97
2000-06-01,Close,    34.63
2000-06-02,Close,    35.66
2000-06-05,Close,    36.00
2000-06-06,Close,    34.27
2000-06-07,Close,    35.58
2000-06-08,Close,    36.64
2000-06-09,Close,    36.77
2000-06-12,Close,    35.83
2000-06-13,Close,    36.33
2000-06-14,Close,    35.13
2000-06-15,Close,    36.69
2000-06-16,Close,    36.41
2000-06-19,Close,    38.25
2000-06-20,Close,    38.27
2000-06-21,Close,    38.33
2000-06-22,Close,    36.25
2000-06-23,Close,    35.36
2000-06-23,BUY CREATE    35.36
2000-06-26,BUY EXECUTED, Price:    35.69, Cost:    35.69, Comm:     0.04
2000-06-26,Close,    36.77
2000-06-27,Close,    36.58
2000-06-28,Close,    36.89
2000-06-29,Close,    35.97
2000-06-30,Close,    37.39
2000-07-03,Close,    35.66
2000-07-03,SELL CREATE,    35.66
2000-07-05,SELL EXECUTED,    34.16, Cost:    35.69, Comm    0.03
2000-07-05,OPERATION PROFIT, GROSS    -1.53, NET    -1.60
2000-07-05,Close,    32.16
2000-07-05,BUY CREATE    32.16
2000-07-06,BUY EXECUTED, Price:    31.91, Cost:    31.91, Comm:     0.03
2000-07-06,Close,    33.63
2000-07-07,Close,    33.75
2000-07-10,Close,    32.97
2000-07-11,Close,    32.16
2000-07-12,Close,    33.22
2000-07-13,Close,    33.69
2000-07-13,SELL CREATE,    33.69
2000-07-14,SELL EXECUTED,    33.88, Cost:    31.91, Comm    0.03
2000-07-14,OPERATION PROFIT, GROSS     1.97, NET     1.90
2000-07-14,Close,    33.86
2000-07-17,Close,    33.86
2000-07-18,Close,    32.99
2000-07-19,Close,    32.80
2000-07-19,BUY CREATE    32.80
2000-07-20,BUY EXECUTED, Price:    33.27, Cost:    33.27, Comm:     0.03
2000-07-20,Close,    34.75
2000-07-21,Close,    33.55
2000-07-24,Close,    33.36
2000-07-25,Close,    33.80
2000-07-26,Close,    34.13
2000-07-27,Close,    33.38
2000-07-27,SELL CREATE,    33.38
2000-07-28,SELL EXECUTED,    33.41, Cost:    33.27, Comm    0.03
2000-07-28,OPERATION PROFIT, GROSS     0.14, NET     0.07
2000-07-28,Close,    32.19
2000-07-28,BUY CREATE    32.19
2000-07-31,BUY EXECUTED, Price:    31.91, Cost:    31.91, Comm:     0.03
2000-07-31,Close,    33.44
2000-08-01,Close,    32.52
2000-08-02,Close,    32.52
2000-08-03,Close,    34.44
2000-08-04,Close,    36.27
2000-08-07,Close,    36.41
2000-08-07,SELL CREATE,    36.41
2000-08-08,SELL EXECUTED,    36.02, Cost:    31.91, Comm    0.04
2000-08-08,OPERATION PROFIT, GROSS     4.11, NET     4.04
2000-08-08,Close,    36.91
2000-08-09,Close,    36.19
2000-08-10,Close,    35.61
2000-08-10,BUY CREATE    35.61
2000-08-11,BUY EXECUTED, Price:    35.55, Cost:    35.55, Comm:     0.04
2000-08-11,Close,    36.08
2000-08-14,Close,    36.64
2000-08-15,Close,    36.14
2000-08-16,Close,    36.11
2000-08-17,Close,    37.33
2000-08-18,Close,    36.16
2000-08-18,SELL CREATE,    36.16
2000-08-21,SELL EXECUTED,    36.52, Cost:    35.55, Comm    0.04
2000-08-21,OPERATION PROFIT, GROSS     0.97, NET     0.90
2000-08-21,Close,    37.00
2000-08-22,Close,    37.16
2000-08-23,Close,    36.86
2000-08-24,Close,    37.66
2000-08-25,Close,    37.64
2000-08-28,Close,    38.58
2000-08-29,Close,    39.03
2000-08-30,Close,    39.25
2000-08-31,Close,    40.44
2000-09-01,Close,    41.19
2000-09-05,Close,    40.50
2000-09-06,Close,    39.69
2000-09-06,BUY CREATE    39.69
2000-09-07,BUY EXECUTED, Price:    40.08, Cost:    40.08, Comm:     0.04
2000-09-07,Close,    40.56
2000-09-08,Close,    38.50
2000-09-11,Close,    37.11
2000-09-12,Close,    35.30
2000-09-13,Close,    36.39
2000-09-14,Close,    37.78
2000-09-14,SELL CREATE,    37.78
2000-09-15,SELL EXECUTED,    36.08, Cost:    40.08, Comm    0.04
2000-09-15,OPERATION PROFIT, GROSS    -4.00, NET    -4.08
2000-09-15,Close,    34.83
2000-09-18,Close,    34.01
2000-09-18,BUY CREATE    34.01
2000-09-19,BUY EXECUTED, Price:    34.44, Cost:    34.44, Comm:     0.03
2000-09-19,Close,    35.27
2000-09-20,Close,    35.55
2000-09-21,Close,    35.11
2000-09-22,Close,    35.91
2000-09-25,Close,    35.02
2000-09-26,Close,    35.33
2000-09-26,SELL CREATE,    35.33
2000-09-27,SELL EXECUTED,    35.66, Cost:    34.44, Comm    0.04
2000-09-27,OPERATION PROFIT, GROSS     1.22, NET     1.15
2000-09-27,Close,    35.52
2000-09-28,Close,    36.24
2000-09-29,Close,    35.02
2000-10-02,Close,    35.02
2000-10-03,Close,    30.91
2000-10-04,Close,    30.30
2000-10-04,BUY CREATE    30.30
2000-10-05,BUY EXECUTED, Price:    30.38, Cost:    30.38, Comm:     0.03
2000-10-05,Close,    30.38
2000-10-06,Close,    30.08
2000-10-09,Close,    29.69
2000-10-10,Close,    28.74
2000-10-11,Close,    27.69
2000-10-12,Close,    28.02
2000-10-12,SELL CREATE,    28.02
2000-10-13,SELL EXECUTED,    27.57, Cost:    30.38, Comm    0.03
2000-10-13,OPERATION PROFIT, GROSS    -2.81, NET    -2.87
2000-10-13,Close,    31.69
2000-10-16,Close,    30.74
2000-10-17,Close,    29.96
2000-10-17,BUY CREATE    29.96
2000-10-18,BUY EXECUTED, Price:    28.07, Cost:    28.07, Comm:     0.03
2000-10-18,Close,    29.85
2000-10-19,Close,    32.36
2000-10-20,Close,    31.35
2000-10-23,Close,    30.30
2000-10-24,Close,    31.85
2000-10-25,Close,    30.58
2000-10-25,SELL CREATE,    30.58
2000-10-26,SELL EXECUTED,    30.91, Cost:    28.07, Comm    0.03
2000-10-26,OPERATION PROFIT, GROSS     2.84, NET     2.78
2000-10-26,Close,    30.30
2000-10-26,BUY CREATE    30.30
2000-10-27,BUY EXECUTED, Price:    30.69, Cost:    30.69, Comm:     0.03
2000-10-27,Close,    30.41
2000-10-30,Close,    28.13
2000-10-31,Close,    29.35
2000-11-01,Close,    27.91
2000-11-02,Close,    26.30
2000-11-03,Close,    26.96
2000-11-03,SELL CREATE,    26.96
2000-11-06,SELL EXECUTED,    27.30, Cost:    30.69, Comm    0.03
2000-11-06,OPERATION PROFIT, GROSS    -3.39, NET    -3.45
2000-11-06,Close,    24.85
2000-11-07,Close,    23.63
2000-11-07,BUY CREATE    23.63
2000-11-08,BUY EXECUTED, Price:    24.35, Cost:    24.35, Comm:     0.02
2000-11-08,Close,    22.07
2000-11-09,Close,    24.18
2000-11-10,Close,    22.63
2000-11-13,Close,    22.01
2000-11-14,Close,    25.24
2000-11-15,Close,    25.68
2000-11-15,SELL CREATE,    25.68
2000-11-16,SELL EXECUTED,    25.57, Cost:    24.35, Comm    0.03
2000-11-16,OPERATION PROFIT, GROSS     1.22, NET     1.17
2000-11-16,Close,    24.35
2000-11-17,Close,    25.63
2000-11-20,Close,    22.01
2000-11-21,Close,    21.24
2000-11-21,BUY CREATE    21.24
2000-11-22,BUY EXECUTED, Price:    21.01, Cost:    21.01, Comm:     0.02
2000-11-22,Close,    19.85
2000-11-24,Close,    21.46
2000-11-27,Close,    20.57
2000-11-28,Close,    20.15
2000-11-29,Close,    20.35
2000-11-30,Close,    23.57
2000-11-30,SELL CREATE,    23.57
2000-12-01,SELL EXECUTED,    23.46, Cost:    21.01, Comm    0.02
2000-12-01,OPERATION PROFIT, GROSS     2.45, NET     2.41
2000-12-01,Close,    23.52
2000-12-04,Close,    25.07
2000-12-05,Close,    28.02
2000-12-06,Close,    26.85
2000-12-07,Close,    25.18
2000-12-07,BUY CREATE    25.18
2000-12-08,BUY EXECUTED, Price:    26.74, Cost:    26.74, Comm:     0.03
2000-12-08,Close,    26.74
2000-12-11,Close,    28.41
2000-12-12,Close,    27.35
2000-12-13,Close,    25.24
2000-12-14,Close,    24.46
2000-12-15,Close,    25.41
2000-12-15,SELL CREATE,    25.41
2000-12-18,SELL EXECUTED,    26.68, Cost:    26.74, Comm    0.03
2000-12-18,OPERATION PROFIT, GROSS    -0.06, NET    -0.11
2000-12-18,Close,    28.46
2000-12-19,Close,    27.24
2000-12-20,Close,    25.35
2000-12-20,BUY CREATE    25.35
2000-12-21,BUY EXECUTED, Price:    24.74, Cost:    24.74, Comm:     0.02
2000-12-21,Close,    26.24
2000-12-22,Close,    28.35
2000-12-26,Close,    27.52
2000-12-27,Close,    27.30
2000-12-28,Close,    27.63
2000-12-29,Close,    25.85
2000-12-29,SELL CREATE,    25.85
Final Portfolio Value: 100016.06

Plot backtest results

We see x3 separate graphs in the figure plotted by cerebro.

  1. Wealth accumulation. We can see the accumulation/loss of wealth over the data period that the trading strategy is implemented.
  2. Trade Gain/Loss. The blue (red) dots indicate profitable (losing) trades and how much was gained (lost).
  3. Price chart. The green and red arrows show the entry and exit points, respectively of the trading strategy. The black line is the price of the asset over time. The bars indicate the trading volume of the asset during each bar.
In [7]:
%matplotlib inline
cerebro.plot()
Out[7]:
[[<Figure size 432x288 with 4 Axes>]]

Conclusion

In this post, we learnt the basics of using the backtester package with cerebro. We performed the following:

  1. Added a datafeed from a local CSV file that has price information stored in Yahoo!Finance format.
  2. Created a trading strategy that has a Buy signal when the closing price is down 2 days in a row, with a Sell signal when the position is held for more than 5 days.
  3. Set a broker commission for each trade tobe 0.1%.
  4. Run the backtester and printed out details on all executed trading positions (i.e., buy/sell price, gross and net profits).
  5. Printed out the initial and final portfolio value.

In the next post, we will look at the following:

  1. Creating a tuple to easily alter static parameters in our trading strategy. For example, for the sell signal, the code currently requires us to change the number of days that the position is held in the next function in the Strategy class.
  2. Change the position size of each trade. Currently, the default of 1 unit is used as the position size of each trade. We can change this to a fixed unit/variable dollar/percentage amount.

The below code needs to be run to execute cerebro.plot() successfullly

In [6]:
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randint(0,100,size=(100,4)),columns = list('ABCD'))
df.head()
df.plot()
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fca2c7a30b8>
In [ ]:
 

Model validation for logistic regression models

This is an overview of the diagnostic and performance tests that need to be performed to ensure the validity of a logistic regression model. The logistic regression measures the relationship between a binary dependent variable, and one or more continuous/categorical independent variables by estimating probabilities. It is able to do so via the logit link function.

\begin{equation*} ln \left (\frac{P}{1-P} \right) = \beta_{0} + \beta_{1} x_{1} + \beta_{2} x_{2} + \ldots + \beta_{n} x_{n} \end{equation*}

The logit link function ensures that $P$ is bounded by 0 and 1. The logit function is preferred compared to the probit model due to the ease of interpretability of the results being the adjusted odds ratio.

6 minute read…

Model validation for classification trees

This is an overview of the diagnostic and performance tests that need to be performed to ensure the validity of a linear regression model that has one or more continuous/categorical independent variables. These are for linear regression models that are optimized using (Ordinary Least Squares (OLS) or Maximum Likelihood Estimation (MLE). The equation for the linear regression model is as follows:

\begin{equation*} Y_{i} = \alpha + \beta_{1} x_{1} + \beta_{2} x_{2} + \beta_{3} x_{3} + \ldots + \epsilon_{i} \text{, where } \epsilon \backsim N(0,\sigma) \end{equation*}

6 minute read…

Model validation for linear regression models

This is an overview of the diagnostic and performance tests that need to be performed to ensure the validity of a linear regression/ordinary least squares model that has one or more continuous/categorical independent variables. These are for linear regression models that are optimized using Ordinary Least Squares (OLS) or Maximum Likelihood Estimation (MLE). The equation for the linear regression model is as follows:

\begin{equation*} Y_{i} = \alpha + \beta_{1} x_{1} + \beta_{2} x_{2} + \beta_{3} x_{3} + \ldots + \epsilon_{i} \text{, where } \epsilon \backsim N(0,\sigma) \end{equation*}

10 minute read…