library(fpp3)
library(fredr)
library(rugarch)Module 14 - ARCH/GARCH (v2)
Part I: Model Equations and Connections
ARIMA Model
The ARIMA model stands for Autoregressive Integrated Moving Average. It has three components: an AR part that regresses the variable on its own lags, a differencing step that makes the series stationary, and an MA part that models the error as a linear combination of past forecast errors. The general ARIMA\((p,d,q)\) equation is:
\[\phi(B)(1 - B)^d y_t = c + \theta(B)\varepsilon_t\]
where \(\phi(B) = 1 - \phi_1 B - \cdots - \phi_p B^p\) is the AR polynomial, \(\theta(B) = 1 + \theta_1 B + \cdots + \theta_q B^q\) is the MA polynomial, \(B\) is the backshift operator, \(d\) is the number of differences applied, and \(\varepsilon_t \sim \text{WN}(0, \sigma^2)\) is a white noise error with constant variance.
ADL Model
The Autoregressive Distributed Lag model, or ADL\((p,q)\), extends the AR idea by bringing in current and lagged values of one or more external explanatory variables. The simplest ADL\((1,1)\) with one regressor \(x_t\) is:
\[y_t = \alpha + \phi_1 y_{t-1} + \beta_0 x_t + \beta_1 x_{t-1} + \varepsilon_t\]
The key difference from a pure ARIMA model is that ARIMA only uses the history of \(y_t\) itself, while ADL adds exogenous variables \(x_t\) and their lags. This is the same idea as the dynamic regression (ARIMAX) model from fpp3, except that ADL keeps the errors as white noise rather than allowing them to follow an ARMA process.
ARCH Model
The Autoregressive Conditional Heteroskedasticity model, or ARCH\((q)\), was introduced by Engle (1982). It models the variance of the error term as time-varying. The model has two equations:
Mean equation:
\[y_t = \mu + \varepsilon_t, \qquad \varepsilon_t = \sigma_t z_t, \qquad z_t \sim N(0,1)\]
Variance equation:
\[\sigma_t^2 = \omega + \alpha_1 \varepsilon_{t-1}^2 + \alpha_2 \varepsilon_{t-2}^2 + \cdots + \alpha_q \varepsilon_{t-q}^2\]
where \(\omega > 0\) and \(\alpha_i \geq 0\) to guarantee a positive variance. A large shock \(\varepsilon_{t-1}\) in either direction inflates \(\sigma_t^2\), producing volatility clustering.
GARCH Model
The Generalized ARCH model, or GARCH\((p,q)\), was introduced by Bollerslev (1986). It extends ARCH by adding lagged values of the conditional variance itself:
Mean equation:
\[y_t = \mu + \varepsilon_t, \qquad \varepsilon_t = \sigma_t z_t, \qquad z_t \sim N(0,1)\]
Variance equation:
\[\sigma_t^2 = \omega + \sum_{i=1}^{q} \alpha_i \varepsilon_{t-i}^2 + \sum_{j=1}^{p} \beta_j \sigma_{t-j}^2\]
where \(\omega > 0\), \(\alpha_i \geq 0\), \(\beta_j \geq 0\), and for covariance stationarity we require \(\sum \alpha_i + \sum \beta_j < 1\). The simplest and most common case is GARCH\((1,1)\):
\[\sigma_t^2 = \omega + \alpha_1 \varepsilon_{t-1}^2 + \beta_1 \sigma_{t-1}^2\]
Connections Between the Models
| Model | Handles | Variance assumption |
|---|---|---|
| ARIMA | Conditional mean only | Constant (\(\sigma^2\)) |
| ADL | Conditional mean + exogenous regressors | Constant (\(\sigma^2\)) |
| ARCH | Simple mean; variance depends on past squared shocks | Time-varying |
| GARCH | Simple mean; variance depends on past shocks AND past variance | Time-varying, parsimonious |
ARIMA and ADL model the conditional mean. ARCH and GARCH model the conditional variance. These ideas combine naturally: rugarch lets you set an ARMA structure for the mean equation and a GARCH structure for the variance equation in the same model.
Part II: GARCH Model on S&P 500 Daily Returns
Data
Daily S&P 500 closing levels from FRED (series
SP500) from January 2015 to January 2025converted levels to log returns (log returns are approximately stationary)
sp500_raw <- fredr(
series_id = "SP500",
observation_start = as.Date("2015-01-01"),
observation_end = as.Date("2025-01-01"),
frequency = "d"
)
sp500 <- sp500_raw |>
mutate(date = as.Date(date)) |>
arrange(date) |>
drop_na(value) |>
mutate(log_return = difference(log(value))) |>
drop_na(log_return) |>
as_tsibble(index = date)Time Series Plot
sp500 |>
autoplot(log_return) +
labs(
title = "S&P 500 Daily Log Returns (2015-2025)",
y = "Log Return",
x = NULL
)The plot shows clear volatility clustering: calm stretches alternate with bursts of large positive and negative returns (notably March 2020 and 2022). This is the primary motivation for using a GARCH model.
Model Specification: Equations with Greek Coefficients
I fit a GARCH(1,1) model with an AR(1) mean equation. Both \(p = 1\) and \(q = 1\) are greater than zero, satisfying the assignment requirement.
Mean equation
The mean of the return series follows an AR(1) process:
\[y_t = \mu + \phi_1 y_{t-1} + \varepsilon_t, \qquad \varepsilon_t = \sigma_t z_t, \qquad z_t \overset{\text{iid}}{\sim} N(0,1)\]
- \(\mu\) is the unconditional mean return.
- \(\phi_1\) is the AR(1) coefficient capturing first-order autocorrelation in returns.
- \(\varepsilon_t\) is the shock, decomposed into a time-varying scale \(\sigma_t\) and a standardized noise \(z_t\).
Variance equation
\[\sigma_t^2 = \omega + \alpha_1 \varepsilon_{t-1}^2 + \beta_1 \sigma_{t-1}^2\]
- \(\omega > 0\) is the baseline (long-run) variance intercept.
- \(\alpha_1 \geq 0\) is the ARCH effect: how much yesterday’s squared shock feeds into today’s variance.
- \(\beta_1 \geq 0\) is the GARCH effect: how much yesterday’s conditional variance persists into today.
Model Estimation
returns_vec <- sp500$log_return
# Specify GARCH(1,1) with AR(1) mean, normal innovations
spec <- ugarchspec(
mean.model = list(armaOrder = c(1, 0), include.mean = TRUE),
variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
distribution.model = "norm"
)
fit <- ugarchfit(spec = spec, data = returns_vec)
# Full model output
fit
*---------------------------------*
* GARCH Model Fit *
*---------------------------------*
Conditional Variance Dynamics
-----------------------------------
GARCH Model : sGARCH(1,1)
Mean Model : ARFIMA(1,0,0)
Distribution : norm
Optimal Parameters
------------------------------------
Estimate Std. Error t value Pr(>|t|)
mu 0.000856 0.000171 5.0062 0.000001
ar1 -0.052911 0.024001 -2.2046 0.027485
omega 0.000004 0.000003 1.2739 0.202694
alpha1 0.193011 0.023905 8.0741 0.000000
beta1 0.779551 0.029429 26.4893 0.000000
Robust Standard Errors:
Estimate Std. Error t value Pr(>|t|)
mu 0.000856 0.001071 0.79952 0.423989
ar1 -0.052911 0.022728 -2.32799 0.019912
omega 0.000004 0.000034 0.11246 0.910461
alpha1 0.193011 0.160846 1.19998 0.230149
beta1 0.779551 0.273058 2.85490 0.004305
LogLikelihood : 7241.365
Information Criteria
------------------------------------
Akaike -6.6511
Bayes -6.6380
Shibata -6.6511
Hannan-Quinn -6.6463
Weighted Ljung-Box Test on Standardized Residuals
------------------------------------
statistic p-value
Lag[1] 1.400 0.2367
Lag[2*(p+q)+(p+q)-1][2] 1.438 0.4725
Lag[4*(p+q)+(p+q)-1][5] 2.468 0.5755
d.o.f=1
H0 : No serial correlation
Weighted Ljung-Box Test on Standardized Squared Residuals
------------------------------------
statistic p-value
Lag[1] 0.01728 0.8954
Lag[2*(p+q)+(p+q)-1][5] 0.73407 0.9163
Lag[4*(p+q)+(p+q)-1][9] 1.84909 0.9222
d.o.f=2
Weighted ARCH LM Tests
------------------------------------
Statistic Shape Scale P-Value
ARCH Lag[3] 0.05539 0.500 2.000 0.8139
ARCH Lag[5] 1.37764 1.440 1.667 0.6251
ARCH Lag[7] 2.02540 2.315 1.543 0.7119
Nyblom stability test
------------------------------------
Joint Statistic: 7.922
Individual Statistics:
mu 0.06883
ar1 0.47752
omega 0.19459
alpha1 0.30488
beta1 0.75767
Asymptotic Critical Values (10% 5% 1%)
Joint Statistic: 1.28 1.47 1.88
Individual Statistic: 0.35 0.47 0.75
Sign Bias Test
------------------------------------
t-value prob sig
Sign Bias 3.39620 0.0006956 ***
Negative Sign Bias 0.44126 0.6590668
Positive Sign Bias 0.06894 0.9450434
Joint Effect 17.58373 0.0005359 ***
Adjusted Pearson Goodness-of-Fit Test:
------------------------------------
group statistic p-value(g-1)
1 20 114.1 1.397e-15
2 30 120.3 4.338e-13
3 40 138.5 4.555e-13
4 50 145.2 1.833e-11
Elapsed time : 0.091398
coef(fit) mu ar1 omega alpha1 beta1
8.561239e-04 -5.291104e-02 3.877763e-06 1.930113e-01 7.795509e-01
Updated Equations with Numerical Coefficients
Mean equation:
\[y_t = 0.000856 - 0.0529 \, y_{t-1} + \varepsilon_t\]
Variance equation:
\[\sigma_t^2 = 0.00000388 + 0.1930 \, \varepsilon_{t-1}^2 + 0.7796 \, \sigma_{t-1}^2\]
Interpretation of Coefficients
alpha_hat <- coef(fit)["alpha1"]
beta_hat <- coef(fit)["beta1"]
omega_hat <- coef(fit)["omega"]
persistence <- alpha_hat + beta_hat
long_run_var <- omega_hat / (1 - persistence)
long_run_vol <- sqrt(long_run_var * 252) # annualized (252 trading days)
cat("Persistence (alpha + beta):", round(persistence, 4), "\n")Persistence (alpha + beta): 0.9726
cat("Long-run daily variance: ", round(long_run_var, 8), "\n")Long-run daily variance: 0.00014133
cat("Long-run annualized vol: ", round(long_run_vol * 100, 2), "%\n")Long-run annualized vol: 18.87 %
Volatility Clustering
The estimated \(\alpha_1 = 0.1930\) is positive and significant, confirming that a large return shock on day \(t-1\) raises the conditional variance on day \(t\), regardless of its sign. This is volatility clustering: big moves tend to be followed by more big moves, and quiet days tend to be followed by more quiet days. The return plot shows this clearly in the COVID-19 crash of March 2020 and the 2022 sell-off.
Persistence
Persistence is measured by \(\alpha_1 + \beta_1 = 0.1930 + 0.7796 = 0.9726\). A value this close to 1 means that shocks to variance dissipate very slowly. After a volatility spike, roughly 97% of the elevated variance carries into the next day, so it can take weeks or months to return to normal levels.
Long-Run Variance
Because persistence is less than 1, the process is covariance stationary and the variance has a finite unconditional level it gravitates toward:
\[\bar{\sigma}^2 = \frac{\omega}{1 - \alpha_1 - \beta_1} = \frac{0.00000388}{1 - 0.9726} = 0.0001416\]
Annualized, this implies a long-run volatility of about 18.9%, which is consistent with the historical average volatility of the S&P 500.
Mean Reversion
The mean reversion speed is governed by the gap \(1 - (\alpha_1 + \beta_1) = 0.0274\). Because this gap is small, reversion to the long-run variance is gradual rather than sharp. The model does not predict that volatility snaps back quickly after a crisis; it predicts a slow, steady decay back toward the 18.9% long-run level.
Summary Table
| Concept | Value |
|---|---|
| ARCH effect (alpha1) | 0.193 |
| GARCH effect (beta1) | 0.7796 |
| Persistence (alpha + beta) | 0.9726 |
| Long-run daily variance | 0.00014133 |
| Long-run annualized volatility | 18.87% |
| Mean reversion gap (1 - persistence) | 0.0274 |