admin

Stock Forecast - Autoregressive Model

Trading Strategy


This article discuss the implementation of Auto-Regressive (AR) Model as a forecasting trading strategy, then backtest the preformance in ALGOGENE Research Lab.


Library to use:

The discussion below adopts a widely used Statistics Python package 'statsmodels'.


Modeling Instruction:

In addition to estimating the parameters of a model, the library can also do forecasting, both in-sample and out-of-sample using 'statsmodels'. The in-sample is a forecast of the next data point using the data up to that point, and the out-of-sample forecasts any number of data points in the future. These forecasts can be made using either the predict() method if you want the forecasts in the form of a series of data, or using the plot_predict() method if you want a plot of the forecasted data. You supply the starting point for forecasting and the ending point, which can be any number of data points after the data set ends.

  • Import the class 'ARMA' in the module 'statsmodels.tsa.arima_model'
  • Create an instance of the ARMA class called 'mod' using the backtest data series data_1 and the order (p,q) of the model (in this case, for an AR(1) order=(1,0)
  • Fit the model mod using the method '.fit()' and save it in a results object called res
  • Start the forecast 5 data points before the end of the 30 point series at 25, and end the forecast 5 data points after the end of the series at point 35

Trading Logic:

Suppose we apply an AR(1) for daily Hang Seng Index CFD closing price, over the year of 2018.

  • Based on a sliding window approach to collect the last 30 closing price
  • Fit an AR(1) model, and forecast the next 5 closing price
  • Submit a buy order if the 5th forecast price is above current level; else submit a sell order
  • Set the holding period to 5 days for each position opening
  • Repeat the process until the backtest period end

Full Source Code:

from AlgoAPI import AlgoAPIUtil, AlgoAPI_Backtest
from datetime import datetime, timedelta

# Import the ARMA module from statsmodels
from statsmodels.tsa.arima_model import ARMA

class AlgoEvent:
    def __init__(self):
        self.lasttradetime = datetime(2000,1,1)
        self.numOfData = 30
        self.numOfForecast = 5
        self.data_1 = []

    def on_bulkdatafeed(self, isSync, bd, ab):
        pass

    def on_orderfeed(self, of):
        pass

    def on_dailyPLfeed(self, pl):
        pass

    def on_openPositionfeed(self, op, oo, uo):
        pass

    def on_marketdatafeed(self, md, ab):
        # check if it is a new day
        if md.timestamp > self.lasttradetime + timedelta(hours=24):
            # append last closing price 
            self.data_1.append(md.lastPrice)
            # check if data_1 contain sufficient data point
            if len(self.data_1)>self.numOfData:
                # keep only the latest observation
                self.data_1 = self.data_1[-self.numOfData:]
                # base on AR(1) to make prediction 
                val = self.nextMove()
                # print out result to console
                self.evt.consoleLog(md.timestamp, val)
                # send a buy order
                if val>0:
                    self.sendOrder(1, 'open')
                # send a sell order
                elif val<0:
                    self.sendOrder(-1, 'open')
            # update timer
            self.lasttradetime = md.timestamp

    def nextMove(self):
        # fit AR(1) model
        mod = ARMA(self.data_1, order=(1,0))
        res = mod.fit()
        # forecast the next 
        arrPred = res.predict(start=self.numOfData, end=self.numOfData+self.numOfForecast)
        # calculate the distance between the 5th forecasted Price and current price
        currentPrice = self.data_1[-1]
        forecastPrice = arrPred[-1]
        return forecastPrice-currentPrice

    def sendOrder(self, buysell, openclose):
        orderObj = AlgoAPIUtil.OrderObject()
        orderObj.instrument = self.myinstrument
        orderObj.holdtime = 5*24*60*60  #unit in second, set maximun holding time to 5 days
        orderObj.volume = 0.01
        orderObj.openclose = openclose
        orderObj.buysell = buysell
        orderObj.ordertype = 0   #0=market_order, 1=limit_order
        self.evt.sendOrder(orderObj)

    def start(self, mEvt):
        self.myinstrument = mEvt['subscribeList'][0]
        self.evt = AlgoAPI_Backtest.AlgoEvtHandler(self, mEvt)
        self.evt.start()

Result: