#packages
library(fpp3)
library(fGarch)
library(knitr)
library(kableExtra)Week 14 Discussion
Part I
ARIMA, ADL, and GARCH are all time series models since they apply past information to explain what is happening in the present/future. The main differences between them is what part of the series they are modeling. ARIMA and ADL both model the mean of the series while ARCH and GARCH model the variance of the errors.
ARIMA
An ARIMA model uses past values of the variable, differencing if needed, and past errors. An ARIMA equation could be:
\[ y_t^ \prime = c \ + \ \phi_1 y_{t-1}^ \prime \ + \ ... \ + \ \phi_p y_{t-p}^ \prime \ + \ \theta_1 \epsilon_{t-1} \ + \ \theta_q\epsilon_{t-q} \ + \ \epsilon_t \]
\[ \text{ Where }y_t^ \prime = (1-B)^d y_t \]
p is the AR order, d is the differencing, and q is the MA order. These are necessary since ARIMA combines autoregressive terms, differencing, and moving average error terms.
ADL
An ADL model is similar to an AR model but also includes another variable and its lag. An ADL equation could be:
\[ y_t = \beta_0 \ + \ \sum_{i=1}^{p} \beta_i y_{t-i} \ + \ \sum_{j=0}^{q} \gamma_j x_{t-j} \ + \ u_t \]
Additional differences are that ADL models use both past y’s and past x’s.
ARCH
An ARCH model more so focuses on the variance of the error term instead of the mean. This allows volatility today to depend on past squared shocks.
\[ R_t = \mu \ + \ u_{t}, \ \ u_t \sim N(0,\sigma_{t}^2) \]
\[ \sigma_{t}^2 = \alpha_0 \ + \ \alpha_1u_{t-1}^2 \ + \ \alpha_2 u_{t-2}^2 \ + \ ... \ + \ \alpha_p u_{t-p}^2 \]
The squared shocks are useful because volatility depends on the size of the shock and not by the sign. Squaring also helps by keeping the variance postive.
GARCH
A GARCH model expands on ARCH by adding lagged variance terms. So GARCH equation could look like:
\[ R_t = \mu \ + \ u_{t}, \ \ u_t \sim N(0,\sigma_{t}^2) \]
\[ \sigma_{t}^2 = w \ + \ \sum_{i=1}^p \alpha_i u_{t-i}^2 \ + \ \sum_{j=1}^q \beta_j \sigma_{t-j}^2 \]
The ARCH portion, \(\alpha_i u_{t-i}^2\), shows how volatility reacts to recent shocks while the GARCH portion, \(\beta_j \sigma_{t-j}^2\), shows how persistent volatility is over time. So the main difference is that ARCH is mainly focuses on past shocks while GARCH includes both past shocks and past volatility.
Part II
#getting data set from FPP3, using APPLE stocks
aapl_returns <- gafa_stock |>
filter(Symbol == "AAPL") |>
arrange(Date) |>
mutate(Return = 100 * (Close / lag(Close) - 1)) |>
filter(!is.na(Return)) |>
select(Symbol, Date, Close, Return)
head(aapl_returns)# A tsibble: 6 x 4 [!]
# Key: Symbol [1]
Symbol Date Close Return
<chr> <date> <dbl> <dbl>
1 AAPL 2014-01-03 77.3 -2.20
2 AAPL 2014-01-06 77.7 0.545
3 AAPL 2014-01-07 77.1 -0.715
4 AAPL 2014-01-08 77.6 0.633
5 AAPL 2014-01-09 76.6 -1.28
6 AAPL 2014-01-10 76.1 -0.667
#Time series plot
aapl_returns |>
autoplot(Return) +
labs(
title = "Apple Daily Percentage Returns",
x = "Date",
y = "Daily percentage return"
) +
theme_minimal()The plot shows Apple daily percentage returns over time. The returns fluctuate around zero, but the size of the fluctuations changes across the sample. Some periods have small movements, while other periods have much larger positive and negative returns. This pattern suggests volatility clustering, which means high-volatility periods tend to group together and low-volatility periods tend to group together. This is exactly the type of behavior that a GARCH model is designed to capture.
#ACF check for volatility clustering
acf(
aapl_returns$Return,
main = "ACF of Apple Daily Returns"
)acf(
aapl_returns$Return^2,
main = "ACF of Squared Apple Daily Returns"
)#estimate GARCH(1,1) model
garch_aapl <- garchFit(
formula = ~ garch(1, 1),
data = aapl_returns$Return,
trace = FALSE
)
summary(garch_aapl)
Title:
GARCH Modelling
Call:
garchFit(formula = ~garch(1, 1), data = aapl_returns$Return,
trace = FALSE)
Mean and Variance Equation:
data ~ garch(1, 1)
<environment: 0x0000015f30c63530>
[data = aapl_returns$Return]
Conditional Distribution:
norm
Coefficient(s):
mu omega alpha1 beta1
0.12553 0.27625 0.12746 0.75741
Std. Errors:
based on Hessian
Error Analysis:
Estimate Std. Error t value Pr(>|t|)
mu 0.12553 0.03886 3.231 0.00123 **
omega 0.27625 0.06937 3.982 6.82e-05 ***
alpha1 0.12746 0.02996 4.255 2.09e-05 ***
beta1 0.75741 0.04959 15.273 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Log Likelihood:
-2250.753 normalized: -1.790575
Description:
Thu Apr 30 14:54:04 2026 by user: darkm
Standardised Residuals Tests:
Statistic p-Value
Jarque-Bera Test R Chi^2 1061.7749539 0.0000000
Shapiro-Wilk Test R W 0.9524109 0.0000000
Ljung-Box Test R Q(10) 9.7225709 0.4651610
Ljung-Box Test R Q(15) 12.2497509 0.6600349
Ljung-Box Test R Q(20) 17.1488356 0.6432890
Ljung-Box Test R^2 Q(10) 1.6620783 0.9983355
Ljung-Box Test R^2 Q(15) 2.7859385 0.9997468
Ljung-Box Test R^2 Q(20) 3.5964773 0.9999808
LM Arch Test R TR^2 1.7613631 0.9996935
Information Criterion Statistics:
AIC BIC SIC HQIC
3.587515 3.603860 3.587495 3.593658
#coefficient table and volatility persistance
coef_vec <- garch_aapl@fit$coef
mu_hat <- coef_vec["mu"]
omega_hat <- coef_vec["omega"]
alpha1_hat <- coef_vec["alpha1"]
beta1_hat <- coef_vec["beta1"]
coef_table <- tibble(
Term = c("mu", "omega", "alpha1", "beta1"),
Estimate = c(mu_hat, omega_hat, alpha1_hat, beta1_hat)
)
kable(
coef_table,
digits = 5,
caption = "Estimated GARCH(1,1) Parameters for Apple Daily Returns"
)| Term | Estimate |
|---|---|
| mu | 0.12553 |
| omega | 0.27625 |
| alpha1 | 0.12746 |
| beta1 | 0.75741 |
coef_table# A tibble: 4 × 2
Term Estimate
<chr> <dbl>
1 mu 0.126
2 omega 0.276
3 alpha1 0.127
4 beta1 0.757
persistence <- alpha1_hat + beta1_hat
persistence_table <- tibble(
Measure = "Volatility persistence",
Formula = "alpha1 + beta1",
Value = persistence
)
kable(
persistence_table,
digits = 5,
caption = "GARCH Volatility Persistence"
)| Measure | Formula | Value |
|---|---|---|
| Volatility persistence | alpha1 + beta1 | 0.88487 |
persistence_table# A tibble: 1 × 3
Measure Formula Value
<chr> <chr> <dbl>
1 Volatility persistence alpha1 + beta1 0.885
#long run variance and long run volatility
long_run_variance <- omega_hat / (1 - alpha1_hat - beta1_hat)
long_run_volatility <- sqrt(long_run_variance)
long_run_table <- tibble(
Measure = c("Long-run variance", "Long-run volatility"),
Value = c(long_run_variance, long_run_volatility)
)
kable(
long_run_table,
digits = 5,
caption = "Long-Run Variance and Volatility"
)| Measure | Value |
|---|---|
| Long-run variance | 2.39949 |
| Long-run volatility | 1.54903 |
The long-run variance gives the average level of variance that the model returns to over time. The long-run volatility is the square root of that variance, so it is easier to interpret because it is in the same units as the daily percentage returns. If \(\alpha_1 + \beta_1 < 1\), the model is mean-reverting, meaning volatility eventually moves back toward its long-run level after a shock. If \(\alpha_1 + \beta_1\) is close to 1, volatility shocks fade slowly.
#conditional volatility
cond_sd <- garch_aapl@sigma.t
plot(
x = aapl_returns$Date,
y = aapl_returns$Return,
type = "l",
col = "steelblue",
ylab = "Daily percentage return",
xlab = "Date",
main = "Apple Returns with GARCH Conditional Volatility Bands",
cex.main = 0.8,
lwd = 0.4
)
abline(h = mu_hat, col = "black", lwd = 1)
lines(
x = aapl_returns$Date,
y = mu_hat + cond_sd,
col = "darkred",
lwd = 0.7
)
lines(
x = aapl_returns$Date,
y = mu_hat - cond_sd,
col = "darkred",
lwd = 0.7
)
abline(h = mu_hat + long_run_volatility, col = "gray40", lty = 2)
abline(h = mu_hat - long_run_volatility, col = "gray40", lty = 2)
legend(
"topright",
legend = c("Returns", "Mean", "+/- Conditional SD", "+/- Long-run SD"),
col = c("steelblue", "black", "darkred", "gray40"),
lty = c(1, 1, 1, 2),
lwd = c(1, 1, 1, 1),
bty = "n",
cex = 0.75
)The blue line shows Apple daily percentage returns. The red lines show the GARCH conditional volatility bands. These bands change over time because the GARCH model allows volatility to depend on past shocks and past volatility. During calm periods, the red bands become narrower. During turbulent periods, the red bands become wider. The gray dashed lines show the long-run volatility level, which is constant over time. This comparison shows why GARCH is useful: it gives a time-varying measure of risk instead of assuming the same variance for every period.