How To Use State Space Models In Trading?

In this post I will build a state space model for trading forex. State state modeling sounds close to SpaceX and NASA than to the world of stock trading and forex trading. State state modeling was invented in early 1960s when NASA needed a recursive algorithm to solve the navigation of Apollo mission. Kalman invented the famous Kalman Filter that could filter out noise from the observation and predict the rocket trajectory. In early 1970s, finance professionals also started to use state state models in the fields of finance and economics. Today state space modeling is used in predicting both the price and volatility. State space modeling is being extensively used in financial markets. If you have no idea what a Kalman Filter is, I have developed this course Kalman Filter for Traders. In this course, I teach you everything you need to know about the state space modeling using Kalman Filter and how you can use it to predict price and volatility.

Comingback, in this post, I am going to discuss in detail, how we can use structural time series state space models in currency trading. Technical analysis has been traditionally used by trader over the past few decades in predicting price. But in the last decade more and more traders have started using statistical and quantitative analysis in predicting price. Technical analysis uses a number of indicators to predict price. Moving averages and trendlines are basic indicators that are used in technical analysis. Other popular indicators are MACD, RSI, Stochastic, CCI and of course moving averages that includes the simple moving averages and the exponential moving averages that are still being used. Moving averages are good at showing support and resistance. There are many traders who strongly believe in the predictive power of technical analysis while there are people who are skeptical about technical analysis predictive powers. Skeptics include mostly people from academia. Despite their scepticism, technical analysis works. You can take a look at my Candlestick Trading System that makes 100-200 pips with a small 10-20 pips top loss.

As I said, in this post we will be using statistical analysis in building our model. When we deal with price data basically we deal with time series data or if you want to be more precise we deal with financial time series data. Financial time series data is very difficult to model. The main problems that make modelling financial time series data is its dynamic nonlinear nature. There is a feedback loop that makes the data highly nonlinear. The output is influencing the input. Yes, this is somewhat like that. Markets are millions of people buying and selling. What they are hearing and watching, they are incorporating that into their buy/sell decisions which introduces a positive feedback loop in financial markets. What we need is a model that can include that feedback loop and give us predictions that are around 80% correct. We know we cannot be 100% correct when predicting financial markets. Achieving 80% accuracy is a tremendous achievement for us. Did you read the post on how to predict the daily candle using Elman Neural Network?

Traditional approach to modeling an financial time series especially a currency pair price time series is to fit an ARIMA model. Problem with ARIMA (Autoregressive Integrated Moving Average) Model is that it requires the time series to be stationary. Stationarity is an important condition you will find in statistical analysis. Stationary basically means that the properties of the time series do not change with time. The important properties for a time series are the mean and the variance. So stationarity requires the mean and the variance of the time series to be constant. What this means is that our time series is just oscillating around a constant level within a certain bound. This is certainly not true when we deal with price time series data. Price can go up and down and there are no bounds. What we need is a non stationary model that caters to the varying mean and varying variance. Before we proceed, I want to make it clear that algorithmic trading requires knowledge of both statistical methods as well as programming. Learning how to code can be a big plus for a trader now a days. Read the post on how to do Object Oriented Programming with MQL5.

Financial Time Series State Space Model

State space models are flexible enough and allow us to include varying mean and varying variance unlike ARIMA models. State space models provide us with different ways that we can model a time series. In financial time series as in other time series we find a trend. There can be seasonality in the stock price time series. This seasonality can be quarterly if the company business is seasonal depending on the four quarters in a year. There can be a cycle in the stock price time series. We can model all these things separately in a single model. We can model the trend separately. Below is the basic State Space model! As traders we are interested in models that can predict price with above 80% accuracy.

//Observation Equation
Y(t) = F(t)X(t) + V(t)    
//State Equation
X(t) = G(t)X(t-1) + W(t)   

First is the observation equation that relates the observation with the state variable. First equation gives us the observation model. State variable is not observable and is also known as the latent variable. Second equation is known as the state equation. This equation actually models the data generating process. We can only observe Y(t) while X(t) is not observable and hidden. V(t) is the observation covariance matrix while W(t) is state covariance matrix. As I have said above, we can break a time series into different components like the trend, seasonal, cyclical and the white noise which is purely random and cannot be explained. What we need to do is learn how to build simple models that we can use in algorithmic trading. Trend is very important for us traders. It is by catching the trends early and latching onto the trend for a major part, professional traders make millions. Many books have been written by traders on how to do trend trading. Trend develops when price starts moving in one direction in a sustained manner. It doesn’t mean that price moves in a straight line. It just means that price over a certain period moves in a direction which can be up or down. Did you read the post on how to use Random Forest Algorithm in trading?

Local Linear Trend State Space Price Model

Trend is very important. We need a model that can tell us when the price is going to trend. There are many methods to model that trend. Most of the time we use a polynomial to model the trend. Polynomial can be second order or order. Higher the polynomial order, more paramters we will nned to estiamte. When developing algorithmic trading models, we should try to use less paramters. The most basic model for the trend is the random walk that includes a changing local level. We want the slope also to vary along with the local level. Below I have provided the local linear trend model that models a trend that changes level and slope at each point in time.

#Local Linear Trend DLM model
Y(t) = ū(t)+ σ(t)       // observation equation
ū(t) = ū(t-1) + ß(t-1) + ξ(t) // local level equation
ß(t)= ß(t-1)+ ζ(t)   // local slope equation

#implement the above Local Linear Trend Model in R
library(dlm)
# Import the csv file
data1 <- read.csv("D:/Shared/MarketData/GBPUSD60.csv", 
                  header=FALSE)
colnames(data1) <- c("Date", "Time", "Open", "High", "Low", 
                     "Close", "Volume") 

#number of rows 
x1 <- nrow(data1)
quotes1 <- as.ts(data1$Close)
y <- quotes1[(x1-125):(x1-25)]
# set parameter restrictions (only variances here)
parm_rest <- function(parm){
return( c(exp(parm[1]),exp(parm[2]), exp(parm[3])) )
}

ssllt <- function(parm){
parm <- parm_rest(parm)
dlm <- dlm(FF = matrix(c(1, 0), nr = 1),
V = parm[1],
GG = matrix(c(1, 0, 1, 1), nr = 2),
W = diag(c(0, parm[2])),
m0 = rep(0, 2),
C0 = parm[3]* diag(2))
# get distribution variance of initial state
return(dlm)
}

#estimate the local linear trend model parameters using MLE
fit <- dlmMLE(y, parm=rep(0,3), ssllt)
fit$convergence
fit$par 

dlmPrice <- ssllt(fit$par)
dlmPrice <- build(fit$par) 
 
#filter the price and forecast
nAhead <-25
filterDLM <- dlmFilter(c(y, rep(NA, nAhead)), mod =dlmPrice)
#filterDLM <- dlmFilter(y, mod = ssModel1)
#forecastDLM <- dlmForecast(filterDLM, nAhead = 25)
#tail(forecastDLM$f, nAhead)
tail(filterDLM$f, nAhead)

tail(data1,25)
plot(y)
lines(as.ts(filterDLM$f), col='red')

In the above code, first I have defined three equations which define the local linear trend model. What we want is a model that changes level as well as slope. As I said in the beginning, price time series is non stationary which changes level and slope at each step. We need a model that can cater to a changing local level and changing local slope. First equation is the observation equation that says that each observation is the sum of a local level and an error term which is pure white noise. This error terms ensures that that the local level changes randomly. In the second equation we model that local level as an autoregressive model that depends on the last local level and the last slope. The last equation says that the local slope is also autoregressive and depends on the previous local slope and the error. If you run the above R code, you can compare the predicted price with the actual price and check how much close the predicted price is with the actual price. In the post a simple Kalman Filter for swing trading, I tried to develop a kalman filter for swing trading but it didn’t succeed.  There were some fundamental flaws in that post. While writing that post I had not mastered state space modeling and how to use Kalman Filter. In this post, I try to do what I couldn’t do in that post.

Local Linear Trend Model

Above you can see the actual price as dots and the local linear trend state space model smoothed price as red. The last red portion is the predicted price for 25 hours. I have used GBPUSD 1 hour price data. I want to develop a model that can predict price 25 hours in the future. The red lines that you see in the beginning are due to the filter starting. After that you can see the filter starts following the price pretty close. If you have followed the above code, you will see I have first build a local linear trend model then I use Maximum  Likelihood Estimation for estimating the parameters of the model. After that I use the Kalman Filter to filter price and predict price for the next 25 hours.

> tail(filterDLM$f, nAhead)
 [1] 1.415067 1.412767 1.410466 1.408166 1.405866 1.403565 1.401265 1.398965 1.396664 
1.394364 1.392063 1.389763 1.387463 1.385162
[15] 1.382862 1.380562 1.378261 1.375961 1.373660 1.371360 1.369060 1.366759 
1.364459 1.362159 1.359858
> tail(data1,25)
           Date  Time    Open    High     Low   Close Volume
2953 2018.02.02 14:00 1.41561 1.41697 1.41347 1.41378   4079
2954 2018.02.02 15:00 1.41373 1.41389 1.41017 1.41222   4007
2955 2018.02.02 16:00 1.41219 1.41355 1.41127 1.41243   3243
2956 2018.02.02 17:00 1.41241 1.41672 1.41238 1.41547   3091
2957 2018.02.02 18:00 1.41549 1.41735 1.41477 1.41502   2653
2958 2018.02.02 19:00 1.41501 1.41510 1.41232 1.41265   2955
2959 2018.02.02 20:00 1.41263 1.41282 1.41111 1.41209   2759
2960 2018.02.02 21:00 1.41206 1.41221 1.41129 1.41153   1486
2961 2018.02.04 22:00 1.41074 1.41074 1.40925 1.40932    921
2962 2018.02.04 23:00 1.40934 1.41125 1.40816 1.41094   1869
2963 2018.02.05 00:00 1.41090 1.41221 1.41043 1.41219   2040
2964 2018.02.05 01:00 1.41214 1.41214 1.41022 1.41118   2005
2965 2018.02.05 02:00 1.41123 1.41206 1.40964 1.41183   1914
2966 2018.02.05 03:00 1.41184 1.41257 1.41109 1.41123   1413
2967 2018.02.05 04:00 1.41125 1.41204 1.41098 1.41162   1260
2968 2018.02.05 05:00 1.41161 1.41280 1.41130 1.41222   1225
2969 2018.02.05 06:00 1.41219 1.41221 1.41042 1.41055   1823
2970 2018.02.05 07:00 1.41056 1.41159 1.40873 1.40888   2895
2971 2018.02.05 08:00 1.40890 1.41366 1.40890 1.41304   3108
2972 2018.02.05 09:00 1.41312 1.41493 1.41112 1.41152   2758
2973 2018.02.05 10:00 1.41153 1.41314 1.41071 1.41078   1849
2974 2018.02.05 11:00 1.41079 1.41080 1.40391 1.40481   2777
2975 2018.02.05 12:00 1.40482 1.40574 1.40249 1.40346   2535
2976 2018.02.05 13:00 1.40349 1.40537 1.40349 1.40407   2665
2977 2018.02.05 14:00 1.40409 1.40409 1.39986 1.40005   2751

Above is the predicted price and the actual price. You can see the state space model is predicting price to be 1.3600 after 25 hours while the actual price is 1.4005. Now this is just a preliminary model. We need to add more components to our structural time series model and see if we get better predictions.

Local Linear Trend Plus Autoregression

As I pointed out above, local linear trend model is predicting price that is quite off the mark. Most of the time, you must have observed that price depends on past values as well. This is known as auto regression in statistical terms. When we are doing technical analysis, we are looking at the past price to predict the future price. We need to use the past price in our model. So let’s add a autoregressive (AR) component. I add a AR(3) model. Let’s see if we get better predictions now. This time I have used EURUSD hourly data.

#Local Linear Trend DLM model
library(dlm)
# Import the csv file
data1 <- read.csv("D:/Shared/MarketData/EURUSD60.csv", 
                  header=FALSE)
colnames(data1) <- c("Date", "Time", "Open", "High", "Low", 
                     "Close", "Volume") 

#number of rows 
x1 <- nrow(data1)
quotes1 <- as.ts(data1$Close)
y <- quotes1[(x1-225):(x1-25)]
# set parameter restrictions (only variances here)
parm_rest <- function(parm){
   return( c(exp(parm[1]),exp(parm[2]), exp(parm[3]),
             parm[4], parm[5], parm[6], exp(parm[7])) ) 
}

ssllt <- function(parm){
  parm <- parm_rest(parm)
  dlm1 <- dlm(FF = matrix(c(1, 0), nr = 1), 
                   V = parm[1], 
                   GG = matrix(c(1, 0, 1, 1), nr = 2), 
                   W = diag(c(0, parm[2])), 
                   m0 = rep(0, 2), 
                   C0 = parm[3]* diag(2))
    # add an AR(3) component to the local linear trend
  dlm2 <- dlmModARMA(ar=c(parm[4],parm[5], parm[6]), 
             ma=NULL, sigma2=parm[7])
  dlm <- dlm1 + dlm2
  return(dlm)
}



fit <- dlmMLE(y, parm=rep(0.1,7), ssllt) 
fit$convergence
fit$par 


dlmPrice <- ssllt(fit$par) 

#filter the price and forecast
nAhead <-25
filterDLM <- dlmFilter(c(y, rep(NA, nAhead)), mod =dlmPrice)
#filterDLM <- dlmFilter(y, mod = ssModel1)
#forecastDLM <- dlmForecast(filterDLM, nAhead = 25)
#tail(forecastDLM$f, nAhead)
tail(filterDLM$f, nAhead)
tail(data1,25)
#plot the actual price and the predicted price
plot(y)
lines(as.ts(filterDLM$f), col='red')

Now when we run the model we get the following predictions! Below I have posted the plot of actual EURUSD hourly price and the predicted price is red. I predict EURUSD price for the next 25 hours.

Local Linear Trend Model plus AR

Below is the predicted price in tabular form!

> tail(filterDLM$f, nAhead)
 [1] 1.244033 1.243016 1.242020 1.241022 1.240024 1.239027 1.238029
 [8] 1.237032 1.236034 1.235036 1.234039 1.233041 1.232044 1.231046
[15] 1.230049 1.229051 1.228054 1.227057 1.226059 1.225062 1.224065
[22] 1.223067 1.222070 1.221073 1.220075

Now you can see the predictions have improved. So things have improved somewhat. We can think about adding a cyclical component and check if we get improvement in the model. So you can see structural time series state space models allow us to break the price into different components like the trend, autoregression, cyclical and seasonal. I don’t think seasonal component is important for high frequency price data. However we may need adding cyclical component. We can also add structural breaks plust exogenous variables.

Limitations of Kalman Filter in Predicting Price

This post was meant for educational purposes. Using a Kalman Filter in predicting price has limitations. Kalman Filter uses the basic assumption that the errors are normally distributed. This assumption is broken most of the time. Normal distribution means price has no fat tail. We know from practical experience that price distribution has heavy tails. Having heavy tails means price can increase and decrease by big amount. We have seen this happen during periods of high market volatility. We need to build a model that uses a distribution with heavy tails. In the future post, I will show you how  we can do that. Read my blog on regular basis, I provide you will good models and strategies for swing trading.