GARCH Notes

Author

AS

Background: Connecting ADL, ARIMA, and ARCH Models

Although ARIMA, ADL, and ARCH/GARCH models appear different,
they all belong to the same family of linear dynamic models
each describes how a current value depends on past information.


1. ARIMA — Dynamics in the Mean

The ARIMA(p,d,q) model captures persistence in the mean of a time series.

\[ y_t = c + \phi_1 y_{t-1} + \dots + \phi_p y_{t-p} + \theta_1 \varepsilon_{t-1} + \dots + \theta_q \varepsilon_{t-q} + \varepsilon_t \]

  • Focus: Expected value (trend, momentum)
  • Dependence: current value on past values and shocks
  • Example: forecasting GDP, prices, returns, etc.

2. ADL — Dynamics Across Variables

The Autoregressive Distributed Lag (ADL) model extends ARIMA to include other predictors.

\[ y_t = \beta_0 + \sum_{i=1}^{p}\beta_i y_{t-i} + \sum_{j=0}^{q}\gamma_j x_{t-j} + \varepsilon_t \]

  • Focus: Mean relationship between multiple variables
  • Dependence: current \(y_t\) on past \(y\)’s and past \(x\)’s
  • Example: inflation as a function of past inflation and past money growth.

ADL is basically an ARIMA on \(y_t\), but with exogenous regressors \(x_t\).


3. ARCH/GARCH — Dynamics in the Variance

The ARCH(p) and GARCH(p,q) models apply the same dynamic logic to the variance of errors, not the mean.

\[ \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 \]

  • Focus: Volatility dynamics (conditional variance)
  • Dependence: today’s volatility on past squared shocks and past volatility
  • Example: modeling stock return volatility.

In spirit, a GARCH model is an ADL applied to the error variance.


4. The Common Thread

Model Dependent variable What it models Dynamic structure
ARIMA \(y_t\) Mean of a single series Past \(y_t\)’s and shocks
ADL \(y_t\) Mean with external drivers Past \(y_t\)’s and past \(x_t\)’s
ARCH/GARCH \(\sigma_t^2\) Conditional variance Past \(u_t^2\)’s and \(\sigma_t^2\)’s

All three share the same recursive idea:
> “Today depends on yesterday.”
Only the object of interest (mean vs variance) changes.


5. Intuitive Hierarchy

Level Model Focus
1 ADL / ARIMA Predicting the expected level of a series
2 ARCH / GARCH Predicting the expected variability of that series

So, GARCH ≈ ARIMA logic applied to volatility,
and ADL ≈ ARIMA logic extended to multiple variables.


Key Insight

ARIMA → dynamics of the mean

ADL → dynamics between variables

GARCH → dynamics of the variance

All are linear-in-parameters models that explain persistence
in levels (ARIMA), across variables (ADL), or in volatility (GARCH).

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.

NoteWhy Squared Terms in ARCH?

In the ARCH model, we use squared shocks (\(u_{t-i}^2\)) instead of the raw shocks (\(u_{t-i}\)).

There are two main reasons:

  1. Variance must be positive
    Variance (\(\sigma_t^2\)) represents volatility — it cannot be negative.
    Squaring ensures that each term contributes positively: \[ \sigma_t^2 = \alpha_0 + \alpha_1 u_{t-1}^2 + \alpha_2 u_{t-2}^2 + \dots + \alpha_p u_{t-p}^2, \quad \text{where } \alpha_0 > 0, \; \alpha_i \ge 0. \]

  2. We care about the magnitude, not the direction, of shocks
    Both large positive and large negative shocks increase volatility.
    Squaring \(u_t\) removes the sign and keeps only the size of the movement.


Small Demonstration in R
# Simulate 100 random shocks 
set.seed(123) 
u_t <- rnorm(100, mean = 0, sd = 1)

#Compute squared shocks
u_t2 <- u_t^2

#Plot
par(mfrow = c(2,1), mar = c(3,4,2,1)) 
plot(u_t, 
     type = "h", 
     col = "steelblue", 
     main = "Raw shocks (u_t)", 
     ylab = "u_t") 

plot(u_t2, 
     type = "h", 
     col = "firebrick", 
     main = "Squared shocks (u_t^2)", 
     ylab = "u_t^2")

#Reset layout
par(mfrow = c(1,1))

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)

Textbook (Theoretical) Notation

The GARCH(1,1) model is written as:

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

\[ \sigma_t^2 = \alpha_0 + \alpha_1 u_{t-1}^2 + \phi_1 \sigma_{t-1}^2 \]

where:

  • \(R_t\) :return (e.g., percentage change in price)
  • \(u_t\) : innovation or residual (shock) at time \(t\)
  • \(\sigma_t^2\) : conditional variance (volatility at time \(t\) given information up to \(t-1\))

Parameter Definitions

Symbol Meaning Expected Sign
\(\beta_0\) Constant (mean of returns) Any
\(\alpha_0\) Long-run average variance \(> 0\)
\(\alpha_1\) Reaction to last period’s shock (ARCH effect) \(\ge 0\)
\(\phi_1\) Volatility persistence (GARCH effect) \(\ge 0\)

Interpretation

Mean (return) equation:

Describes the average return level — how returns behave on average over time.

  • \(\beta_0\) represents the average return (constant mean component).

(Conditional) Variance equation:

Captures the time-varying volatility — how uncertainty evolves over time.

  • \(\alpha_0\) is the long-run average variance, representing the baseline or steady-state risk level.
  • \(\alpha_1\) measures how strongly volatility reacts to new shocks (the ARCH effect).
  • \(\phi_1\) measures how persistent volatility is over time (the GARCH effect).
  • The sum \(\alpha_1 + \phi_1\) reflects volatility persistence:
    • If close to 1 → volatility decays slowly (long memory).
    • If much less than 1 → volatility fades quickly (short memory).
  • The model is stationary if \(\alpha_1 + \phi_1 < 1\).

Chapter 16.4 of Econometrics with R

This discussion focuses on 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:

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
Warning: package 'ggplot2' was built under R version 4.5.2
Warning: package 'dplyr' was built under R version 4.5.2
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.0     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   4.0.2     ✔ 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
conflicted::conflicts_prefer(dplyr::lag)
[conflicted] Will prefer dplyr::lag over any other package.
conflicted::conflicts_prefer(dplyr::last)
[conflicted] Will prefer dplyr::last over any other package.
conflicted::conflicts_prefer(dplyr::filter)
[conflicted] Will prefer dplyr::filter over any other package.
?tq_get
# Get Netflix stock prices
df_ts <- tq_get("MSFT", 
                get = "stock.prices",
                from = "1990-01-01"
                )

str(df_ts)
tibble [9,145 × 8] (S3: tbl_df/tbl/data.frame)
 $ symbol  : chr [1:9145] "MSFT" "MSFT" "MSFT" "MSFT" ...
 $ date    : Date[1:9145], format: "1990-01-02" "1990-01-03" ...
 $ open    : num [1:9145] 0.606 0.622 0.62 0.635 0.622 ...
 $ high    : num [1:9145] 0.616 0.627 0.639 0.639 0.632 ...
 $ low     : num [1:9145] 0.598 0.615 0.616 0.622 0.615 ...
 $ close   : num [1:9145] 0.616 0.62 0.638 0.622 0.632 ...
 $ volume  : num [1:9145] 5.30e+07 1.14e+08 1.26e+08 6.96e+07 5.90e+07 ...
 $ adjusted: num [1:9145] 0.376 0.378 0.389 0.379 0.385 ...
# 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.376     NA    
 2 MSFT   1990-01-03 0.622 0.627 0.615 0.620 113774400    0.378      0.564
 3 MSFT   1990-01-04 0.620 0.639 0.616 0.638 125740800    0.389      2.94 
 4 MSFT   1990-01-05 0.635 0.639 0.622 0.622  69566400    0.379     -2.45 
 5 MSFT   1990-01-08 0.622 0.632 0.615 0.632  58982400    0.385      1.53 
 6 MSFT   1990-01-09 0.632 0.639 0.627 0.630  70300800    0.384     -0.275
 7 MSFT   1990-01-10 0.625 0.634 0.612 0.613 103766400    0.374     -2.75 
 8 MSFT   1990-01-11 0.616 0.622 0.590 0.601  95774400    0.366     -1.98 
 9 MSFT   1990-01-12 0.591 0.606 0.583 0.598 148910400    0.365     -0.433
10 MSFT   1990-01-15 0.595 0.604 0.592 0.598  62467200    0.365      0    
# Plot closing prices over time
ggplot(data = df_ts, 
       mapping = 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)"
  )

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

We see that autocorrelations are weak - so that it is difficult to predict future outcomes using, e.g., an AR model.

  • The tall bar at lag 0 = 1 is expected — every ACF plot has it.

  • The other bars (lags 1–25) hover near zero, meaning autocorrelation is weak. → The series behaves like white noise — difficult to predict using an AR model.

Estimation

Modeling Conditional Variance:

  • Fit an ARCH or GARCH model to your series using R (for example, the fGarch or 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.

I. fGarch

Univariate or multivariate GARCH time series fitting. Estimates the parameters of a univariate ARMA-GARCH/APARCH process.

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")
??garchFit

# estimate GARCH(1,1) model of daily percentage changes
GARCH_MSFT <- garchFit(data = df_monthly$pct_change,
                       trace = F  # optimization process of fitting the model parameters should be printed ?   
                       )

summary(GARCH_MSFT)

Title:
 GARCH Modelling 

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

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

Conditional Distribution:
 norm 

Coefficient(s):
      mu     omega    alpha1     beta1  
1.903408  3.001870  0.094128  0.861356  

Std. Errors:
 based on Hessian 

Error Analysis:
        Estimate  Std. Error  t value Pr(>|t|)    
mu       1.90341     0.35333    5.387 7.16e-08 ***
omega    3.00187     1.28565    2.335 0.019548 *  
alpha1   0.09413     0.02762    3.407 0.000656 ***
beta1    0.86136     0.03656   23.561  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Log Likelihood:
 -1517.292    normalized:  -3.488028 

Description:
 Sat Apr 25 06:33:49 2026 by user:  


Standardised Residuals Tests:
                                 Statistic      p-Value
 Jarque-Bera Test   R    Chi^2  31.1494600 1.721792e-07
 Shapiro-Wilk Test  R    W       0.9843064 1.188851e-04
 Ljung-Box Test     R    Q(10)   9.6067976 4.756403e-01
 Ljung-Box Test     R    Q(15)  12.8346510 6.150678e-01
 Ljung-Box Test     R    Q(20)  15.5665872 7.431222e-01
 Ljung-Box Test     R^2  Q(10)   8.6068224 5.697789e-01
 Ljung-Box Test     R^2  Q(15)  10.6720941 7.754739e-01
 Ljung-Box Test     R^2  Q(20)  16.5910105 6.793489e-01
 LM Arch Test       R    TR^2   11.2992237 5.034642e-01

Information Criterion Statistics:
     AIC      BIC      SIC     HQIC 
6.994446 7.031921 6.994279 7.009237 
Caution

After running the GARCH model, you need to interpret two linked equations — the mean returns equation and the conditional heteroskedasticity equation (the two-equation system). Part 2, the heteroskedasticity component, can become more complex depending on the chosen GARCH(p, q) specification.

Caution

First, I write both equations using Greek symbols, and then replace the Greeks with the estimated coefficients from the model output. Be aware that different software packages use different notation, so it is important to interpret the parameters carefully.

I have adjusted some coefficient symbols from the textbook to match the notation used by the garchFit() command in R.

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

Where:

  • 1.97218 is the constant mean return per period. This is \(mu\) term in the garcgFit, but called \(\beta_0\) in textbook system of equations 16.3 (see screenshot above).
  • \(\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 = 3.03537 + 0.09266 \epsilon_{t-1}^2 + 0.86307 \sigma_{t-1}^2 \]

Where:

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

  • \(\alpha_1\) = 0.09266: Impact of the most recent shock. A large \(\mu_{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.

II. rugarch

Another popular way to implement the GARCH.

The rugarch package aims to provide a flexible and rich univariate GARCH modelling and testing environment. Modelling is a simple process of defining a specification and fitting the data.

  • Mean equation parameters will be expressed as:

  • Volatility equation parameters will be expressed as:

Loading required package: parallel
?rugarch

??ugarchspec
?fGarch::garchSpec  

# Specify and fit a GARCH(1,1) model
spec <- ugarchspec(
  variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
  mean.model     = list(armaOrder = c(0, 0), include.mean = TRUE),
  distribution.model = "norm"  # standard normal distribution 
)

fit <- ugarchfit(spec = spec, 
                 data = df_monthly$pct_change
                 )

show(fit)

*---------------------------------*
*          GARCH Model Fit        *
*---------------------------------*

Conditional Variance Dynamics   
-----------------------------------
GARCH Model : sGARCH(1,1)
Mean Model  : ARFIMA(0,0,0)
Distribution    : norm 

Optimal Parameters
------------------------------------
        Estimate  Std. Error  t value Pr(>|t|)
mu      1.903204    0.353323   5.3866 0.000000
omega   3.004190    1.288633   2.3313 0.019738
alpha1  0.093746    0.027526   3.4057 0.000660
beta1   0.861397    0.036658  23.4981 0.000000

Robust Standard Errors:
        Estimate  Std. Error  t value Pr(>|t|)
mu      1.903204    0.334554   5.6888 0.000000
omega   3.004190    1.325636   2.2662 0.023438
alpha1  0.093746    0.024863   3.7705 0.000163
beta1   0.861397    0.031791  27.0955 0.000000

LogLikelihood : -1517.282 

Information Criteria
------------------------------------
                   
Akaike       6.9944
Bayes        7.0319
Shibata      6.9942
Hannan-Quinn 7.0092

Weighted Ljung-Box Test on Standardized Residuals
------------------------------------
                        statistic p-value
Lag[1]                      1.800  0.1798
Lag[2*(p+q)+(p+q)-1][2]     1.839  0.2909
Lag[4*(p+q)+(p+q)-1][5]     3.178  0.3754
d.o.f=0
H0 : No serial correlation

Weighted Ljung-Box Test on Standardized Squared Residuals
------------------------------------
                        statistic p-value
Lag[1]                     0.8623  0.3531
Lag[2*(p+q)+(p+q)-1][5]    3.6017  0.3081
Lag[4*(p+q)+(p+q)-1][9]    5.1747  0.4042
d.o.f=2

Weighted ARCH LM Tests
------------------------------------
            Statistic Shape Scale P-Value
ARCH Lag[3]     4.042 0.500 2.000 0.04438
ARCH Lag[5]     4.794 1.440 1.667 0.11464
ARCH Lag[7]     5.255 2.315 1.543 0.20002

Nyblom stability test
------------------------------------
Joint Statistic:  0.7445
Individual Statistics:             
mu     0.2689
omega  0.2169
alpha1 0.3561
beta1  0.3315

Asymptotic Critical Values (10% 5% 1%)
Joint Statistic:         1.07 1.24 1.6
Individual Statistic:    0.35 0.47 0.75

Sign Bias Test
------------------------------------
                   t-value   prob sig
Sign Bias           0.8231 0.4109    
Negative Sign Bias  0.9544 0.3404    
Positive Sign Bias  0.9623 0.3364    
Joint Effect        1.9077 0.5918    


Adjusted Pearson Goodness-of-Fit Test:
------------------------------------
  group statistic p-value(g-1)
1    20     21.87       0.2906
2    30     29.34       0.4472
3    40     42.70       0.3151
4    50     46.49       0.5753


Elapsed time : 0.1655369 
Warning

Note sGARCH is standard GARCH, not seasonal GARCH.

There are lots of GARCH models - EGARCH, APARCH, TGARCH, QGARCH, GJRGARCH, IGARCH, AVGARCH, PGARCH, GARCH-M and the standard GARCH.

You can add refinement/structure to the mean model and variance model by changing the parameters.

TipModel Variations to Explore

1. Add an AR term in the mean equation

Try including an autoregressive (AR) term in the mean equation and observe how the estimated mean equation changes.
Because the residuals (\(u_t\)) are derived from the mean model, this change will also affect the variance equation indirectly.

   # Specify and fit a GARCH(1,1) model with an AR(1) mean equation
   spec2 <- ugarchspec(
     variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
     mean.model     = list(armaOrder = c(1, 0), include.mean = TRUE),
     distribution.model = "norm"   # standard normal innovations
   )

   fit2 <- ugarchfit(
     spec = spec2,
     data = df_monthly$pct_change
   )

   show(fit2)

*---------------------------------*
*          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      1.891334    0.331066   5.7129 0.000000
ar1    -0.074256    0.051786  -1.4339 0.151602
omega   2.904610    1.267033   2.2925 0.021880
alpha1  0.092093    0.027265   3.3777 0.000731
beta1   0.864348    0.036214  23.8678 0.000000

Robust Standard Errors:
        Estimate  Std. Error  t value Pr(>|t|)
mu      1.891334    0.331378   5.7075 0.000000
ar1    -0.074256    0.046562  -1.5948 0.110760
omega   2.904610    1.264056   2.2978 0.021570
alpha1  0.092093    0.024303   3.7894 0.000151
beta1   0.864348    0.030277  28.5479 0.000000

LogLikelihood : -1516.261 

Information Criteria
------------------------------------
                   
Akaike       6.9943
Bayes        7.0411
Shibata      6.9940
Hannan-Quinn 7.0128

Weighted Ljung-Box Test on Standardized Residuals
------------------------------------
                        statistic p-value
Lag[1]                   0.002757  0.9581
Lag[2*(p+q)+(p+q)-1][2]  0.031865  1.0000
Lag[4*(p+q)+(p+q)-1][5]  1.371195  0.8769
d.o.f=1
H0 : No serial correlation

Weighted Ljung-Box Test on Standardized Squared Residuals
------------------------------------
                        statistic p-value
Lag[1]                     0.7962  0.3722
Lag[2*(p+q)+(p+q)-1][5]    3.0348  0.4007
Lag[4*(p+q)+(p+q)-1][9]    4.5334  0.5010
d.o.f=2

Weighted ARCH LM Tests
------------------------------------
            Statistic Shape Scale P-Value
ARCH Lag[3]     3.061 0.500 2.000 0.08022
ARCH Lag[5]     3.972 1.440 1.667 0.17647
ARCH Lag[7]     4.433 2.315 1.543 0.28834

Nyblom stability test
------------------------------------
Joint Statistic:  0.8387
Individual Statistics:             
mu     0.2992
ar1    0.1019
omega  0.2176
alpha1 0.3420
beta1  0.3202

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           0.9006 0.3683    
Negative Sign Bias  1.1876 0.2357    
Positive Sign Bias  1.0064 0.3148    
Joint Effect        2.5776 0.4614    


Adjusted Pearson Goodness-of-Fit Test:
------------------------------------
  group statistic p-value(g-1)
1    20     15.90       0.6642
2    30     27.28       0.5568
3    40     34.06       0.6945
4    50     46.72       0.5659


Elapsed time : 0.02385712 

Estimated GARCH(1,1) Model

The estimated equations based on the optimal parameters are as follows:

Mean equation:

\[ r_t = 0.3006 + 0.0928\,r_{t-1} + u_t \]

Conditional variance equation:

\[ \sigma_t^2 = 0.2561 + 0.4093\,u_{t-1}^2 + 0.3689\,\sigma_{t-1}^2 \]


Interpretation

  • The mean equation includes both a constant term (\(\mu = 0.3006\)) and an autoregressive term (\(\text{AR}(1) = 0.0928\)).
    This implies a small positive autocorrelation in returns — today’s return depends slightly on yesterday’s return.

  • The ARCH term (\(\alpha_1 = 0.4093\)) shows how strongly volatility reacts to recent shocks (\(u_{t-1}^2\)).
    Larger shocks yesterday lead to higher variance today.

  • The GARCH term (\(\beta_1 = 0.3689\)) captures volatility persistence — how much of yesterday’s volatility carries forward to today.

  • The total persistence is: \[ \alpha_1 + \beta_1 = 0.7782 \] which is less than 1, meaning volatility is mean-reverting (it gradually returns to normal after shocks).

  • The long-run (unconditional) variance is: \[ \frac{\omega}{1 - \alpha_1 - \beta_1} = \frac{0.2561}{1 - 0.7782} \approx 1.15 \] giving a long-run volatility of \(\sqrt{1.15} \approx 1.07\).


Summary

Term Symbol Value Interpretation
Mean (intercept) \(\mu\) 0.3006 Average return
AR(1) term \(\phi_1\) 0.0928 Dependence on \(r_{t-1}\)
Constant (variance intercept) \(\omega\) 0.2561 Baseline variance
ARCH(1) \(\alpha_1\) 0.4093 Reaction to new shocks (\(u_{t-1}^2\))
GARCH(1) \(\beta_1\) 0.3689 Persistence of volatility (\(\sigma_{t-1}^2\))

In short:
The model suggests modest return autocorrelation and strong but decaying volatility persistence —
periods of high volatility subside gradually toward a long-run variance of about 1.15.

2. Experiment with higher-order volatility terms

Increase the lag orders in the variance equation to estimate a more complex GARCH(\(p\), \(q\)) model. This allows volatility to depend on multiple past shocks and lagged variances.

    # Specify and fit a GARCH(3,2) model
    spec2 <- ugarchspec(
      variance.model = list(model = "sGARCH", garchOrder = c(3, 2)),
      mean.model     = list(armaOrder = c(0, 0), include.mean = TRUE),
      distribution.model = "norm"  # standard normal distribution 
    )

    fit2 <- ugarchfit(spec = spec2, 
                     data = df_monthly$pct_change
                     )

    show(fit2)

*---------------------------------*
*          GARCH Model Fit        *
*---------------------------------*

Conditional Variance Dynamics   
-----------------------------------
GARCH Model : sGARCH(3,2)
Mean Model  : ARFIMA(0,0,0)
Distribution    : norm 

Optimal Parameters
------------------------------------
        Estimate  Std. Error  t value Pr(>|t|)
mu      1.848021    0.354857  5.20779 0.000000
omega   4.767716    2.538761  1.87797 0.060385
alpha1  0.023211    0.043637  0.53191 0.594790
alpha2  0.061486    0.057574  1.06794 0.285548
alpha3  0.068209    0.067514  1.01029 0.312356
beta1   0.467978    0.471725  0.99206 0.321170
beta2   0.308263    0.404023  0.76298 0.445473

Robust Standard Errors:
        Estimate  Std. Error  t value Pr(>|t|)
mu      1.848021    0.324523  5.69457 0.000000
omega   4.767716    2.662384  1.79077 0.073330
alpha1  0.023211    0.036440  0.63696 0.524154
alpha2  0.061486    0.056787  1.08274 0.278924
alpha3  0.068209    0.056103  1.21579 0.224064
beta1   0.467978    0.229252  2.04133 0.041218
beta2   0.308263    0.180175  1.71091 0.087097

LogLikelihood : -1515.913 

Information Criteria
------------------------------------
                   
Akaike       7.0019
Bayes        7.0675
Shibata      7.0014
Hannan-Quinn 7.0278

Weighted Ljung-Box Test on Standardized Residuals
------------------------------------
                        statistic p-value
Lag[1]                      2.152  0.1424
Lag[2*(p+q)+(p+q)-1][2]     2.179  0.2348
Lag[4*(p+q)+(p+q)-1][5]     3.538  0.3175
d.o.f=0
H0 : No serial correlation

Weighted Ljung-Box Test on Standardized Squared Residuals
------------------------------------
                         statistic p-value
Lag[1]                   0.0008041  0.9774
Lag[2*(p+q)+(p+q)-1][14] 5.0864548  0.7587
Lag[4*(p+q)+(p+q)-1][24] 8.9539061  0.8009
d.o.f=5

Weighted ARCH LM Tests
------------------------------------
             Statistic Shape Scale P-Value
ARCH Lag[6]      0.361 0.500 2.000  0.5479
ARCH Lag[8]      1.328 1.480 1.774  0.6758
ARCH Lag[10]     1.935 2.424 1.650  0.7831

Nyblom stability test
------------------------------------
Joint Statistic:  1.072
Individual Statistics:             
mu     0.2592
omega  0.1856
alpha1 0.2865
alpha2 0.3782
alpha3 0.3206
beta1  0.3157
beta2  0.3177

Asymptotic Critical Values (10% 5% 1%)
Joint Statistic:         1.69 1.9 2.35
Individual Statistic:    0.35 0.47 0.75

Sign Bias Test
------------------------------------
                   t-value   prob sig
Sign Bias           0.8727 0.3833    
Negative Sign Bias  1.4511 0.1475    
Positive Sign Bias  0.4502 0.6528    
Joint Effect        2.3732 0.4986    


Adjusted Pearson Goodness-of-Fit Test:
------------------------------------
  group statistic p-value(g-1)
1    20     17.46       0.5587
2    30     22.31       0.8071
3    40     39.39       0.4524
4    50     47.87       0.5188


Elapsed time : 0.03780007 

Estimated GARCH(3,2) Model

The estimated equations based on the optimal parameters are as follows:

Mean equation:

\[ r_t = 1.894470 + u_t \]

Conditional variance equation:

\[ \begin{aligned} \sigma_t^2 &= 4.514070 + 0.022001\,u_{t-1}^2 + 0.059165\,u_{t-2}^2 + 0.066420\,u_{t-3}^2 \\ &\quad + 0.485763\,\sigma_{t-1}^2 + 0.296979\,\sigma_{t-2}^2 \end{aligned} \]


Interpretation

  • The mean equation indicates an average return level of 1.894, with shocks captured by \(u_t\).

  • The ARCH terms (\(\alpha_1 = 0.022\), \(\alpha_2 = 0.059\), \(\alpha_3 = 0.066\)) measure how recent shocks affect current volatility.
    Each squared residual \(u_{t-i}^2\) represents the impact of past return shocks on today’s variance.

  • The GARCH terms (\(\beta_1 = 0.486\), \(\beta_2 = 0.297\)) measure the persistence of volatility — how much past volatility carries over into the current period.

  • The total persistence is: \[ \alpha_1 + \alpha_2 + \alpha_3 + \beta_1 + \beta_2 = 0.9303 \] which is less than 1, implying that volatility is mean-reverting but decays slowly.

  • The long-run (unconditional) variance is: \[ \frac{\omega}{1 - \sum \alpha_i - \sum \beta_j} = \frac{4.514070}{1 - 0.930328} \approx 64.79 \] giving a long-run volatility of \(\sqrt{64.79} \approx 8.05\).

Term Symbol Value Interpretation
Mean (intercept) \(\mu\) 1.894 Average return
Constant (variance intercept) \(\omega\) 4.514 Baseline variance
ARCH(1) \(\alpha_1\) 0.022 Response to \(u_{t-1}^2\)
ARCH(2) \(\alpha_2\) 0.059 Response to \(u_{t-2}^2\)
ARCH(3) \(\alpha_3\) 0.066 Response to \(u_{t-3}^2\)
GARCH(1) \(\beta_1\) 0.486 Persistence of \(\sigma_{t-1}^2\)
GARCH(2) \(\beta_2\) 0.297 Persistence of \(\sigma_{t-2}^2\)

In short:
The model captures moderate short-term shock effects and strong volatility persistence,
suggesting that periods of high volatility decay gradually toward a long-run average variance of about 64.8.

In GARCH models, we don’t assume that shocks are always normally distributed — financial data often show fat tails (extreme events more likely than under normality) and sometimes asymmetry (negative shocks having different effects from positive ones).

So we can specify how the conditional errors are distributed —

  • “norm”: simplest; if residuals’ histogram looks bell-shaped.

  • “std”: use if you see fat tails in residuals (high kurtosis, large outliers).

  • “sstd”: use if both fat tails and asymmetry appear (negative shocks produce larger volatility).

  • “ged”/“sged”: slightly less common but can fine-tune tail behavior.

Summary

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:

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

Limitation: Needs many lags to capture persistent volatility


GARCH (1986)

Adds lagged variance terms to make it efficient:

\[ \sigma_t^2 = \alpha_0 + \alpha_1 u_{t-1}^2 + \phi_1 \sigma_{t-1}^2 \]


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_t^2 = \alpha_0 + \alpha_1 u_{t-1}^2 + \phi_1 \sigma_{t-1}^2 \]

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

Two components:

  • ARCH part (\(\alpha_1 u_{t-1}^2\)): reacts to recent shocks
  • GARCH part (\(\phi_1 \sigma_{t-1}^2\)): captures persistence/memory

GARCH(1,1) — Most Common

\[ \sigma_t^2 = \alpha_0 + \alpha_1 u_{t-1}^2 + \phi_1 \sigma_{t-1}^2 \]

Term What it does
\(\alpha_0\) Baseline variance / minimum level of volatility that exists even when there are no shocks
\(\alpha_1\) Reaction to new shocks
Big shock yesterday → higher variance today
\(\phi_1\) Persistence of volatility
High variance yesterday → stays high today

Condition for stability: \(\alpha_1 + \phi_1 < 1\).


Key Concepts

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

  • Persistence: \(\alpha_1 + \phi_1\) measures how long volatility stays elevated

    • Close to 1 → long-lasting volatility clusters
    • Must be < 1 for stability
  • Long-run variance:
    \[ \frac{\alpha_0}{1 - \alpha_1 - \phi_1} \]
    gives the average variance over time. It accounts for both the baseline level and the persistence of volatility.

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


Wave Analogy

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

Two-Part Structure

  1. Mean equation (ARIMA, AR, etc.): Models expected returns — gives residuals \(u_t\)

  2. Variance equation (GARCH): Models expected volatility — uses those \(u_t\) to predict \(\sigma_t^2\)

Warning

Historical note:
The parameter name omega originates from Bollerslev’s (1986) original formulation of the GARCH model.
In his notation, the conditional variance equation was written as
\[ \sigma_t^2 = \omega + \alpha_1 u_{t-1}^2 + \beta_1 \sigma_{t-1}^2, \]
where \(\omega\) represents the constant term — the baseline or “intercept” in the variance equation.

Later textbooks often replaced \(\omega\) with \(\alpha_0\) for consistency with the ARCH model notation,
but most software packages (including garchFit() and rugarch) retained omega to stay true to Bollerslev’s original paper.