Week 14 Discussion

Author

Tin Vu

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

#packages
library(fpp3)
library(fGarch)
library(knitr)
library(kableExtra)
#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"
)
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"
)
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"
)
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.