Stationarity and Cointegration in R (adf, egcm, pp, kpss)

When we refer to a time series as stationary, we mean to say that its mean, variance and autocorrelation are all consistent over time. Cointegration, on the other hand, is when we have two time series that are non-stationary, but a linear combination of them results in a stationary time series. So, why is the concept of stationarity important? Well, a large purpose of time series modelling is to be able to predict future values from current data.

This task becomes much more difficult when mean, variance and autocorrelation parameters do not follow a consistent pattern over time, resulting in an unreliable time series model.

Additionally, this problem is compounded by the fact that time series datasets, by their very nature experience non-stationarity as the presence of factors such as seasonal trends skew the mean and variance. In order to test for stationarity, we use the Dickey-Fuller test. This test works by testing for a unit root in the data where:

Δy(t) = δy(t-1) + u(t)
where Δy(t) is the first difference of y and δ=0 represents our unit root

Our null and alternative hypotheses are as follows:

H0 (Null Hypothesis)

θ = 0 (data is non-stationary and must be differenced to make the data stationary)

HA (Alternative Hypothesis)

θ < 0 (data is stationary)

When we previously looked at the example of autocorrelation testing between oil prices and the S&P 500 stock market index, we saw that our data followed an AR(1) stationary process, i.e. the raw data did not have a constant mean, variance and autocorrelation, but the differenced series did.

Stationarity Testing

In seeking to test for stationarity, we primarily wish to determine if our series is trend stationary or whether a unit root is present. Trend stationary is where a process is fully stationary once the trend component of the time series is removed. This is not the case in a time series that has a unit root present.

no stationarity

There are three particular tests of interest that we can use to determine stationarity, 1) the KPSS test, 2) the Dickey-Fuller test, and 3) the Phillips-Perron test. The null hypothesis of the KPSS test is a unit root, while the alternative is trend stationarity. For the latter two tests, the null hypothesis is non-stationarity, whereas the alternative is the presence of a unit root.

When we run the tests for both the S&P 500 (gspc) and oil time series, we see that when the series are run without differencing, a unit root is indicated to be present. However, first-differencing the series indicates stationarity across these tests:

KPSS

 
> k1<-kpss.test(gspc,null="Trend")
Warning message:
In kpss.test(gspc, null = "Trend") : p-value smaller than printed p-value
 
> k1
    KPSS Test for Trend Stationarity
data:  gspc
KPSS Trend = 0.95907, Truncation lag parameter = 5, p-value = 0.01
 
> k1$statistic
KPSS Trend
 0.9590747
 
> k1diff<-kpss.test(diff_gspc,null="Trend")
Warning message:
In kpss.test(diff_gspc, null = "Trend") :
  p-value greater than printed p-value
 
> k1diff
    KPSS Test for Trend Stationarity
data:  diff_gspc
KPSS Trend = 0.04457, Truncation lag parameter = 5, p-value = 0.1
 
> k1diff$statistic
KPSS Trend
0.04457013
 
> k2<-kpss.test(oil,null="Trend")
Warning message:
In kpss.test(oil, null = "Trend") : p-value smaller than printed p-value
 
> k2
    KPSS Test for Trend Stationarity
data:  oil
KPSS Trend = 1.5315, Truncation lag parameter = 5, p-value = 0.01
 
> k2$statistic
KPSS Trend
  1.531487
 
> k2diff<-kpss.test(diff_oil,null="Trend")
Warning message:
In kpss.test(diff_oil, null = "Trend") :
  p-value greater than printed p-value
 
> k2diff
    KPSS Test for Trend Stationarity
data:  diff_oil
KPSS Trend = 0.065387, Truncation lag parameter = 5, p-value = 0.1
 
> k2diff$statistic
KPSS Trend
0.06538696

Dickey-Fuller

 
> adf.test(gspc)
 
    Augmented Dickey-Fuller Test
 
data:  gspc
Dickey-Fuller = -2.38, Lag order = 7, p-value = 0.4174
alternative hypothesis: stationary

> adf.test(oil)
 
    Augmented Dickey-Fuller Test
 
data:  oil
Dickey-Fuller = -2.1883, Lag order = 7, p-value = 0.4986
alternative hypothesis: stationary
 
> adf.test(diff_gspc)
 
    Augmented Dickey-Fuller Test
 
data:  diff_gspc
Dickey-Fuller = -8.2973, Lag order = 7, p-value = 0.01
alternative hypothesis: stationary
 
Warning message:
In adf.test(diff_gspc) : p-value smaller than printed p-value
 
> adf.test(diff_oil)
 
    Augmented Dickey-Fuller Test
 
data:  diff_oil
Dickey-Fuller = -8.1493, Lag order = 7, p-value = 0.01
alternative hypothesis: stationary
 
Warning message:
In adf.test(diff_oil) : p-value smaller than printed p-value

Phillips-Perron

 
> pp.test(gspc)
 
    Phillips-Perron Unit Root Test
data:  gspc
Dickey-Fuller Z(alpha) = -12.86, Truncation lag parameter = 5, p-value = 0.3923
alternative hypothesis: stationary
 
> pp.test(oil)
 
    Phillips-Perron Unit Root Test
data:  oil
Dickey-Fuller Z(alpha) = -6.6153, Truncation lag parameter = 5, p-value = 0.7407
alternative hypothesis: stationary
 
> pp.test(diff_gspc)
 
    Phillips-Perron Unit Root Test
data:  diff_gspc
Dickey-Fuller Z(alpha) = -488.86, Truncation lag parameter = 5, p-value = 0.01
alternative hypothesis: stationary
 
Warning message:
In pp.test(diff_gspc) : p-value smaller than printed p-value
 
> pp.test(diff_oil)
 
    Phillips-Perron Unit Root Test
data:  diff_oil
Dickey-Fuller Z(alpha) = -522.48, Truncation lag parameter = 5, p-value = 0.01
alternative hypothesis: stationary
 
Warning message:
In pp.test(diff_oil) : p-value smaller than printed p-value

Two-Step Engle Granger Method

On the issue of cointegration, we have already established that this is present when a linear combination of the non-stationary data transforms the same into a stationary series. This means that the time series show correlation that is statistically significant and not simply due to chance.

However, note that simply using a test such as the adf.test to test the residuals of a linear regression is not appropriate on this case. The reason for this is that the critical values will differ for the adf test since residual based critical values are not the same as that for a standard ADF.

In this regard, we use the egcm command built into R. This command runs the two-step Engle-Granger method on our data, where the procedure selects the appropriate values for α, β, and ρ that best fit the following model:

Y [i] = α + β ∗ X[i] + R[i]
R[i] = ρ ∗ R[i − 1] + ε[i]
ε[i] ∼ N(0, σ2)

In other words, given that oil prices and the S&P 500 variable are non-stationary, then cointegration between the two would indicate that a linear combination of these two variables must be stationary. We form a linear combination between these two variables and test for cointegration as follows:

library(egcm)
egcm(x, y) #where x = oil and y = gspc

Output

Y[i] =   6.5421 X[i] + 1768.1278 + R[i], R[i] =   0.9897 R[i-1] + eps[i], eps ~ N(0, 15.2265^2)
        (0.4488)       (21.6567)                (0.0097)
 
R[501] = 55.7788 (t = 0.793)
 
WARNING: X and Y do not appear to be cointegrated.

We see that with a t-statistic of 0.793, oil prices and the S&P 500 are not indicated to be cointegrated.