ARCH Models

Today let's understand the ARCH model, which describes how the variance of a return series depends on the shocks that came just before it.

Our example is the DAX, the German stock index. R's built-in EuStockMarkets data holds its closing price on 1,860 business days, which gives us 1,859 daily returns. Take the average return away from each one and what is left is that day's shock.

The chart below plots the shock on 220 days in a row, days 1521 to 1740.

The shocks are small on some days and large on others, and the two kinds arrive in runs. The standard deviation of all 220 shocks is 1.51. But cut them into 11 blocks of 20 days, and the standard deviation of a block goes from 0.88 to 2.35.

That changing spread is what an ARCH model describes. In this lesson we write its equation, simulate a series from it, test the DAX for it and then fit it.

In the chart above, a bunch of tall spikes is followed by a stretch of short ones.

What is the conditional variance of a return?

We start by turning the DAX prices into returns. The return on a day is the change in the log price from the day before, times 100, which is close to the percentage change. Press Run.

RInteractive R
# Build the DAX daily returns and the shocks from the built-in EuStockMarkets data dax_price <- as.numeric(EuStockMarkets[, "DAX"]) dax_ret <- 100 * diff(log(dax_price)) e <- dax_ret - mean(dax_ret) # Summarise the returns length(dax_ret) round(c(mean = mean(dax_ret), sd = sd(dax_ret), min = min(dax_ret), max = max(dax_ret)), 4) #> [1] 1859 #> mean sd min max #> 0.0652 1.0301 -9.6277 5.0760

  

There are 1,859 returns, with a mean of 0.0652 and a standard deviation of 1.0301. The biggest one-day fall is -9.6277.

The mean is tiny next to a daily spread of about 1. So we treat it as a constant \(\mu\) and write each return as that mean plus a shock:

\[ r_t = \mu + e_t \]

Here \(r_t\) is the return on day \(t\), and \(e_t\) is the shock, the part of the return that the mean does not explain. In the code, e holds the 1,859 shocks.

Next, we write the shock as a standard deviation times random noise:

\[ e_t = \sigma_t z_t \]

The noise \(z_t\) is drawn from a standard Normal distribution (mean 0, variance 1), and \(\sigma_t\) is the standard deviation on day \(t\). So \(\sigma_t^2\) is the variance of the shock on day \(t\).

But which variance? It is the variance of the shock given the shocks before day \(t\):

\[ \sigma_t^2 = \mathrm{Var}(e_t \mid e_{t-1}, e_{t-2}, \dots) \]

The bar reads "given". This is the conditional variance: the variance of today's shock once you know what happened up to yesterday. And it is free to change from day to day.

Compare that with the ordinary variance of all 1,859 shocks, which is one number for every day. The code below computes the variance of all the shocks and the standard deviation over every 250-day window, and adds the kurtosis of the shocks.

RInteractive R
# Compare the variance of all days with the 250-day standard deviation, and measure the tails kurt <- function(x) mean((x - mean(x))^4) / mean((x - mean(x))^2)^2 roll_sd <- sapply(250:length(e), function(i) sd(e[(i - 249):i])) round(var(e), 4) round(range(roll_sd), 2) round(kurt(e), 2) #> [1] 1.0611 #> [1] 0.63 1.52 #> [1] 9.28

  

The variance of all the shocks is 1.0611, a standard deviation of 1.03. But the standard deviation over a 250-day window moves between 0.63 and 1.52. So one variance for all days does not describe any particular stretch well.

The last number is the kurtosis, which measures how heavy the tails of a series are. It is the average fourth power of the deviations from the mean, divided by the squared variance, and R has no built-in function for it, so kurt() computes it. A Normal series has a kurtosis of 3, and heavier tails give a larger number. The DAX shocks have 9.28, so very large shocks are much more common than in a Normal series with the same variance.