GARCH Notes

Author

AS

The Problem GARCH Solves

In ordinary regression or ARIMA models, we assume that the variance of the errors is constant:

\[u_t \sim N (0, \sigma^2)\]

That’s called homoskedasticity. But in real-world financial or economic data (returns, inflation, exchange rates, etc.), you often see volatility clustering — periods of calm and periods of turbulence.

Example:

  • When markets are stable → small changes day after day
  • When crises hit → large swings for many days

So the variance (volatility) is changing over time. That’s called heteroskedasticity.

From ARIMA to ARCH

Engle (1982) introduced the ARCH model (Autoregressive Conditional Heteroskedasticity).

Idea: Let’s model the variance itself as something that depends on past squared shocks.

\[\sigma_t^2 = \alpha_0 + \alpha_1 u_{t-1}^2 + \alpha_2 u_{t-2}^2 + \dots + \alpha_p u_{t-p}^2\]

Here:

  • \(u_t\) is the residual (shock) at time \(t\)
  • \(u_t^2\) is the squared shock (proxy for magnitude of volatility)
  • \(\sigma_t^2\) is the conditional variance — variance given past information

So volatility today depends on how big shocks were yesterday, the day before, etc.

But ARCH Has a Limitation

If volatility persists for a long time (as in financial data), ARCH needs many lags (\(p\)) to capture that persistence.

That means too many parameters → not efficient.

Enter GARCH — Generalized ARCH (Bollerslev, 1986)

GARCH solves that by adding lagged variances themselves:

\[\sigma_t^2 = \alpha_0 + \sum_{i=1}^{p}\alpha_i u_{t-i}^2 + \sum_{j=1}^{q}\phi_j \sigma_{t-j}^2\]

This means volatility depends both on:

  • recent shocks (ARCH part), and
  • its own past values (GARCH part)

This Week’s Discussion: Chapters 11 and 12 of Forecasting: Principles and Practice (3rd ed.) and Chapter 16.4 of Econometrics with R

This week’s discussion focuses on hierarchical and grouped time series forecasting as well as modeling volatility clustering with ARCH and GARCH. These topics equip you with advanced tools for working with structured data and financial or economic series that exhibit time-varying variance.

Required Readings:

Part 3: Volatility Modeling with ARCH and GARCH (Required)

Exploring Volatility Clustering:

  • Read Chapter 16.4 of Econometrics with R for an introduction to volatility clustering and the motivation behind ARCH and GARCH models.

  • Select or simulate a time series where you suspect time-varying volatility, such as financial returns, commodity prices, or any series with fluctuating variance.

I select MSFT monthly returns and fit a GARCH model from fGarch library.

Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
── Attaching core tidyquant packages ─────────────────────── tidyquant 1.0.11 ──
✔ PerformanceAnalytics 2.0.8      ✔ TTR                  0.24.4
✔ quantmod             0.4.28     ✔ xts                  0.14.1
── Conflicts ────────────────────────────────────────── tidyquant_conflicts() ──
✖ zoo::as.Date()                 masks base::as.Date()
✖ zoo::as.Date.numeric()         masks base::as.Date.numeric()
✖ PerformanceAnalytics::legend() masks graphics::legend()
✖ quantmod::summary()            masks base::summary()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   4.0.0     ✔ tibble    3.3.0
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.1.0     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::first()  masks xts::first()
✖ dplyr::lag()    masks stats::lag()
✖ dplyr::last()   masks xts::last()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
?tq_get
# Get Netflix stock prices
df_ts <- tq_get("MSFT", get = "stock.prices", from = "1990-01-01")

str(df_ts)
tibble [9,029 × 8] (S3: tbl_df/tbl/data.frame)
 $ symbol  : chr [1:9029] "MSFT" "MSFT" "MSFT" "MSFT" ...
 $ date    : Date[1:9029], format: "1990-01-02" "1990-01-03" ...
 $ open    : num [1:9029] 0.606 0.622 0.62 0.635 0.622 ...
 $ high    : num [1:9029] 0.616 0.627 0.639 0.639 0.632 ...
 $ low     : num [1:9029] 0.598 0.615 0.616 0.622 0.615 ...
 $ close   : num [1:9029] 0.616 0.62 0.638 0.622 0.632 ...
 $ volume  : num [1:9029] 5.30e+07 1.14e+08 1.26e+08 6.96e+07 5.90e+07 ...
 $ adjusted: num [1:9029] 0.377 0.379 0.39 0.381 0.387 ...
# Calculate daily percentage change
df_ts <- df_ts %>%
  mutate(
    pct_change = (close - lag(close)) / lag(close) * 100
  )

# Preview
head(df_ts, 10)
# A tibble: 10 × 9
   symbol date        open  high   low close    volume adjusted pct_change
   <chr>  <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>      <dbl>
 1 MSFT   1990-01-02 0.606 0.616 0.598 0.616  53035200    0.377     NA    
 2 MSFT   1990-01-03 0.622 0.627 0.615 0.620 113774400    0.379      0.564
 3 MSFT   1990-01-04 0.620 0.639 0.616 0.638 125740800    0.390      2.94 
 4 MSFT   1990-01-05 0.635 0.639 0.622 0.622  69566400    0.381     -2.45 
 5 MSFT   1990-01-08 0.622 0.632 0.615 0.632  58982400    0.387      1.53 
 6 MSFT   1990-01-09 0.632 0.639 0.627 0.630  70300800    0.386     -0.275
 7 MSFT   1990-01-10 0.625 0.634 0.612 0.613 103766400    0.375     -2.75 
 8 MSFT   1990-01-11 0.616 0.622 0.590 0.601  95774400    0.368     -1.98 
 9 MSFT   1990-01-12 0.591 0.606 0.583 0.598 148910400    0.366     -0.433
10 MSFT   1990-01-15 0.595 0.604 0.592 0.598  62467200    0.366      0    
# Plot closing prices over time
ggplot(df_ts, aes(x = date, y = pct_change)) +
  geom_line(color = "blue") +
  labs(
    title = "MSFT Daily Price Pct Change Over Time",
    x = "Date",
    y = "Closing Price (USD)"
  ) +
  theme_minimal()
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_line()`).

# Convert to monthly and calculate % change
df_monthly <- df_ts %>%
  group_by(year_month = floor_date(x = date, unit = "month")) %>%
  summarise(close = last(close), .groups = "drop") %>%
  mutate(
    pct_change = (close - lag(close)) / lag(close) * 100
  ) %>% filter(!is.na(pct_change))

# Plot closing prices over time
ggplot(df_monthly, aes(x = year_month, y = pct_change)) +
  geom_line(color = "blue") +
  labs(
    title = "MSFT Monthly Price Pct Change Over Time",
    x = "Date",
    y = "Closing Price (USD)"
  )

Modeling Conditional Variance:

  • Fit an ARCH or GARCH model to your series using R (for example, the rugarch package).

  • Plot the estimated conditional variance and compare it to the unconditional variance from simpler models.

  • Interpret the significance of the parameters and how volatility evolves over time.

# plot sample autocorrelation of daily percentage changes
acf(df_monthly$pct_change, main = "ACF")

NOTE: Packages 'fBasics', 'timeDate', and 'timeSeries' are no longer
attached to the search() path when 'fGarch' is attached.

If needed attach them yourself in your R script by e.g.,
        require("timeSeries")

Attaching package: 'fGarch'
The following objects are masked from 'package:PerformanceAnalytics':

    ES, VaR
The following object is masked from 'package:TTR':

    volatility
??garchFit
# estimate GARCH(1,1) model of daily percentage changes
GARCH_MSFT <- garchFit(data = df_monthly$pct_change, trace = F)
summary(GARCH_MSFT)

Title:
 GARCH Modelling 

Call:
 garchFit(data = df_monthly$pct_change, trace = F) 

Mean and Variance Equation:
 data ~ garch(1, 1)
<environment: 0x12f42d430>
 [data = df_monthly$pct_change]

Conditional Distribution:
 norm 

Coefficient(s):
      mu     omega    alpha1     beta1  
1.950128  2.857909  0.091861  0.864112  

Std. Errors:
 based on Hessian 

Error Analysis:
        Estimate  Std. Error  t value Pr(>|t|)    
mu       1.95013     0.35279    5.528 3.24e-08 ***
omega    2.85791     1.24092    2.303 0.021275 *  
alpha1   0.09186     0.02691    3.413 0.000642 ***
beta1    0.86411     0.03597   24.026  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Log Likelihood:
 -1497.589    normalized:  -3.482765 

Description:
 Thu Nov  6 17:49:31 2025 by user:  


Standardised Residuals Tests:
                                 Statistic      p-Value
 Jarque-Bera Test   R    Chi^2  33.6461530 4.941180e-08
 Shapiro-Wilk Test  R    W       0.9833267 7.443937e-05
 Ljung-Box Test     R    Q(10)  11.3157521 3.334529e-01
 Ljung-Box Test     R    Q(15)  14.0746309 5.198766e-01
 Ljung-Box Test     R    Q(20)  16.7351966 6.700954e-01
 Ljung-Box Test     R^2  Q(10)   8.2253855 6.068320e-01
 Ljung-Box Test     R^2  Q(15)  10.6071164 7.799156e-01
 Ljung-Box Test     R^2  Q(20)  16.5552186 6.816374e-01
 LM Arch Test       R    TR^2   11.6309782 4.757525e-01

Information Criterion Statistics:
     AIC      BIC      SIC     HQIC 
6.984135 7.021938 6.983965 6.999063 

\[ R_t= \beta_0 + \mu_t , \mu_t ∼N(0,\sigma_t^2) \]

\[ \sigma_t^2 = \omega + \alpha \epsilon_{t-1}^2 + \beta \sigma_{t-1}^2 \]

The mean return equation estimated from the GARCH(1,1) model is:

\[ R_t = 1.97218 + \mu_t, \quad \mu_t \sim N(0, \sigma_t^2) \]

Where:

  • \(\beta_0\) = 1.97218 is the constant mean return per period.
  • \(\mu_t\) is the innovation (error term) at time \(t\), which is normally distributed with mean zero and conditional variance \(\sigma_t^2\).
  • The conditional variance \(\sigma_t^2\) evolves according to the GARCH(1,1) specification:

\[ \sigma_t^2 = 2.91377 + 0.09266 \epsilon_{t-1}^2 + 0.86307 \sigma_{t-1}^2 \]

Where:

  • \(\omega\) = 2.91377: Long-run average variance (baseline risk level).

  • \(\alpha\) = 0.09266: Impact of the most recent shock. A large \(\epsilon_{t-1}^2\) will increase \(\sigma_t^2\) in the next period.

  • \(\beta_1\) = 0.86307: Persistence of volatility from the previous period. A high value indicates slow decay of volatility after shocks.

This formulation allows the volatility to change over time, capturing periods of high and low market turbulence.

The persistence parameter:

\[ \alpha_1 + \beta_1 = 0.95573 \]

is close to 1, indicating high volatility persistence — shocks to volatility tend to last for a long time.

# compute deviations of the percentage changes from their mean
dev_mean_MSFT <- df_monthly$pct_change - GARCH_MSFT@fit$coef[1]

# plot deviation of percentage changes from mean
plot(x = df_monthly$year_month, y = dev_mean_MSFT, 
     type = "l", 
     col = "steelblue",
     ylab = "Percent", 
     xlab = "Date",
     main = "Estimated Bands of +- One Conditional Standard Deviation",
     cex.main=0.8,
     lwd = 0.2)

# add horizontal line at y = 0
abline(0, 0)

# add GARCH(1,1) confidence bands (one standard deviation) to the plot
lines(x = df_monthly$year_month, 
      GARCH_MSFT@fit$coef[1] + GARCH_MSFT@sigma.t, 
      col = "darkred", 
      lwd = 0.5)

lines(x = df_monthly$year_month, 
      GARCH_MSFT@fit$coef[1] - GARCH_MSFT@sigma.t, , 
      col = "darkred", 
      lwd = 0.5)

  • The light blue line appears to be the actual returns or residuals from a financial time series (likely % deviations from a mean).

  • The two red lines represent the estimated bands of ± 1 conditional standard deviation from a volatility model (likely a GARCH-type model).

  • Conditional variance changes over time based on recent information. In GARCH models, this means periods of high volatility widen the bands, while quiet periods narrow them.

  • Unconditional variance assumes volatility is constant over time — from a simple model like historical variance. This would be a flat horizontal band (same width everywhere).

  • Comparison:

    • If you plotted the unconditional variance, it would likely underestimate volatility during high-stress periods (e.g., late 1990s, 2008) and overestimate during calm periods.

    • The GARCH conditional variance adapts to spikes in volatility and periods of calm, making it better for risk estimation.

Discussion Questions:

  • In your dataset, how did the ARCH/GARCH model improve the understanding of volatility compared to traditional constant-variance models?

  • How would you incorporate volatility modeling into forecasting workflows alongside ETS or ARIMA models?

How ARCH/GARCH Improved Understanding of Volatility

The GARCH(1,1) model:

  • Captured volatility clustering

    • The plot shows that conditional standard deviation bands widen during turbulent market periods (e.g., dot-com bubble, 2008 financial crisis, COVID-19 shock) and narrow during calm periods.

    • A constant-variance model would have used one average variance level for all periods, missing this dynamic.

  • Quantified persistence of volatility

    • α₁ (0.09266) → About 9% of last period’s shock size carries into today’s volatility.

    • β₁ (0.86307) → About 86% of yesterday’s volatility persists today.

    • Persistence α₁ + β₁ ≈ 0.956 → Shocks have long-lasting effects.

    • Constant-variance models cannot measure or use this persistence in risk estimates.

  • Improved risk measurement

    • Prediction intervals adapt to market conditions — wide when volatility is high, narrow when low — unlike ARIMA/ETS with fixed-width intervals.

    • This improves Value-at-Risk (VaR) and stress-testing accuracy.

  • Better model diagnostics

    • Ljung–Box and ARCH–LM tests show no remaining autocorrelation in squared residuals → volatility structure is well captured.

    • Constant-variance models leave significant autocorrelation in squared residuals, meaning they systematically miss volatility patterns.

Incorporating Volatility Modeling with ETS/ARIMA

ARIMA–GARCH Hybrid (Finance Standard)

  • Step 1: Fit ARIMA to model the conditional mean of returns.

  • Step 2: Fit GARCH to ARIMA residuals to model conditional variance.

  • Step 3: Forecast mean & volatility jointly.

    • ARIMA forecast → central path.

    • GARCH forecast → time-varying prediction intervals or VaR.


Response Guidelines

Initial Post:

  • Share your results, including R code, visualizations, and interpretations.

  • Highlight differences between hierarchical, grouped, and volatility modeling approaches.

  • Discuss how reconciliation and volatility modeling improved forecast reliability and risk assessment.

Peer Responses:

  • Engage with at least two classmates by comparing their modeling approaches and parameter choices.

  • Suggest enhancements or alternative ways to reconcile forecasts or model conditional variance.

Reflection Question:

  • Which forecasting approach—hierarchical, grouped, or volatility modeling—was most effective for your dataset, and why?

Tip for Students:
If you haven’t used GARCH models before, here’s an example using the rugarch package:

r

CopyEdit

library(rugarch) spec <- ugarchspec( variance.model = list(model = "sGARCH", garchOrder = c(1, 1)), mean.model = list(armaOrder = c(1, 0)) ) fit <- ugarchfit(spec = spec, data = returns_data) show(fit)

Feel free to ask questions if you need help installing packages or interpreting output.

Appendix

Week 6 Discussion, Hierarchical / VAR+VEC / GARCH

This Week’s Discussion: Chapters 11 and 12 of Forecasting: Principles and Practice (3rd ed.) and Chapter 16.4 of Econometrics with R

This week’s discussion focuses on hierarchical and grouped time series forecasting as well as modeling volatility clustering with ARCH and GARCH. These topics equip you with advanced tools for working with structured data and financial or economic series that exhibit time-varying variance.

Required Readings:


Instructions


Part 1: Hierarchical Time Series Forecasting

Exploring Hierarchical Structures:

  • Select a hierarchical dataset from the fpp3 package (e.g., tourism, PBS, or aus_livestock).

  • Visualize the hierarchy or grouping structure, highlighting different levels (e.g., region, state, or product).

Modeling and Forecasting Hierarchical Data:

  • Apply bottom-up, top-down, and middle-out approaches to forecast data at different hierarchical levels.

  • Compare the forecasts produced by each approach.

  • Evaluate forecast accuracy at each level using RMSE and MAPE.

Discussing Reconciliation Techniques:

  • Test forecast reconciliation methods, such as OLS reconciliation and MinT reconciliation, to ensure forecasts at different levels are consistent.

  • Explain how these methods balance accuracy and coherence across hierarchical levels.


Part 2: Grouped Time Series Forecasting

Exploring Grouped Data Structures:

  • Choose a grouped time series dataset from fpp3 (e.g., aus_retail or insurance) that can be grouped along multiple dimensions, such as location and product type.

  • Create visualizations to highlight different group structures in the data.

Modeling and Forecasting Grouped Data:

  • Fit models for each group using ETS, ARIMA, or dynamic regression methods.

  • Reconcile the forecasts using grouping strategies and evaluate their performance across groups.

  • Assess whether grouped forecasts outperform flat, non-grouped models.

Scenario Analysis:

  • Imagine you are forecasting product sales across different regions. Discuss how forecasts for one region might influence others and how reconciliation methods can improve reliability when multiple categories are involved.

Part 3: Volatility Modeling with ARCH and GARCH (Required)

Exploring Volatility Clustering:

  • Read Chapter 16.4 of Econometrics with R for an introduction to volatility clustering and the motivation behind ARCH and GARCH models.

  • Select or simulate a time series where you suspect time-varying volatility, such as financial returns, commodity prices, or any series with fluctuating variance.

Modeling Conditional Variance:

  • Fit an ARCH or GARCH model to your series using R (for example, the rugarch package).

  • Plot the estimated conditional variance and compare it to the unconditional variance from simpler models.

  • Interpret the significance of the parameters and how volatility evolves over time.

Discussion Questions:

  • In your dataset, how did the ARCH/GARCH model improve the understanding of volatility compared to traditional constant-variance models?

  • How would you incorporate volatility modeling into forecasting workflows alongside ETS or ARIMA models?


Response Guidelines

Initial Post:

  • Share your results, including R code, visualizations, and interpretations.

  • Highlight differences between hierarchical, grouped, and volatility modeling approaches.

  • Discuss how reconciliation and volatility modeling improved forecast reliability and risk assessment.

Peer Responses:

  • Engage with at least two classmates by comparing their modeling approaches and parameter choices.

  • Suggest enhancements or alternative ways to reconcile forecasts or model conditional variance.

Reflection Question:

  • Which forecasting approach—hierarchical, grouped, or volatility modeling—was most effective for your dataset, and why?

Tip for Students:
If you haven’t used GARCH models before, here’s an example using the rugarch package:

r

CopyEdit

library(rugarch) spec <- ugarchspec( variance.model = list(model = "sGARCH", garchOrder = c(1, 1)), mean.model = list(armaOrder = c(1, 0)) ) fit <- ugarchfit(spec = spec, data = returns_data) show(fit)

Feel free to ask questions if you need help installing packages or interpreting output.

Appendix

The Problem

  • Financial data shows volatility clustering: calm periods alternate with turbulent periods
  • Traditional models assume constant variance (homoskedasticity)
  • Reality: variance changes over time (heteroskedasticity)
  • Need models that capture time-varying volatility

ARCH (1982)

Variance depends on past squared shocks:

\(σ²_t = α_₀ + α_₁u²_{t-1} + α_₂u²_{t-2} + ...\)

Limitation: Needs many lags to capture persistent volatility

GARCH (1986)

Adds lagged variance terms to make it efficient:

\(σ²_t = α_₀ + α_₁u²_{t-1} + φ_₁σ²_{t-1}\)

Full GARCH Model Structure

Mean equation: \[r_t = \mu + u_t\]

Shock structure: \[u_t = \sigma_t \cdot \varepsilon_t, \quad \varepsilon_t \sim N(0,1)\]

Variance equation (GARCH): \[\sigma^2_t = \alpha_0 + \alpha_1 u^2_{t-1} + \phi_1 \sigma^2_{t-1}\]

Therefore: \(u_t \sim N(0, \sigma_t)\) where \(\sigma_t\) is time-varying and predicted by GARCH!

Two components:

  • ARCH part (\(α_₁u²_{t-1}\)): react to recent shocks

  • GARCH part ( \(φ_₁σ²_{t-1}\)): persistence/memory

GARCH(1,1) — Most Common

\(σ²_t = α_₀ + α_₁u²_{t-1} + φ_₁σ²_{t-1}\)

Term What it does
\(α_₀\) Baseline variance
\(α_₁u²_{t-1}\) Big shock yesterday → higher variance today
\(φ_₁σ²_{t-1}\) High variance yesterday → stays high today

Key Concepts

Volatility Clustering: Large changes follow large changes; small follow small

Persistence: \(α_₁ + φ_₁\) measures how long volatility stays elevated - Close to 1 = long-lasting volatility clusters - Must be < 1 for stability

Long-run variance: \(\dfrac{α₀}{(1 - α₁ - φ₁)}\) gives average variance over time

Mean reversion: After a shock, variance gradually returns to long-run average

Wave Analogy

  • ARCH: Each shock creates a wave
  • GARCH: Wave doesn’t vanish immediately—it rolls over and decays slowly

Two-Part Structure

Mean equation (ARIMA, AR, etc.): Models expected returns - Gives residuals \(u_t\)

Variance equation (GARCH): Models expected volatility - Uses those \(u_t\) to predict \(σ²_t\)

Why It Matters

  • Captures realistic volatility behavior in financial markets
  • Used for risk management (VaR), option pricing, portfolio optimization
  • Foundation for extensions (EGARCH, GJR-GARCH for asymmetric effects)