Day 2 Part 1: Simulating Volatility Processes

Zero to Hero Bootcamp - Time Series Econometrics in R

Author

Dr Christian Engels

Last updated

November 22, 2024

Introduction

In this session, we will simulate various volatility processes using different GARCH models. By specifying and simulating data from these models, we aim to understand how they capture the dynamics of financial time series, particularly the behavior of volatility over time.

Loading Required Libraries

First, we load the necessary R packages that will be used throughout this analysis.

library(tidyverse)         # Data manipulation and visualization
library(tidyfinance)       # Financial data tools
library(tsibble)           # Time series data manipulation
library(feasts)            # Time series analysis tools
library(tseries)           # Time series analysis
library(broom)             # Tidying statistical outputs
library(PortfolioAnalytics) # Portfolio optimization
library(rugarch)           # GARCH models

Setting Simulation Parameters

We set the number of observations for our simulations.

n_sim <- 1000  # Number of time periods to simulate

Specifying GARCH Models

We will specify four different GARCH models:

  1. Standard GARCH (sGARCH)
  2. GJR-GARCH (gjrGARCH)
  3. Exponential GARCH (eGARCH)
  4. Asymmetric Power ARCH (apARCH)

1. Standard GARCH Model

The standard GARCH model, as proposed by Bollerslev (1986), can be mathematically represented as follows:

\sigma_t^2 = \omega + \sum_{j=1}^q \alpha_j \epsilon_{t-j}^2 + \sum_{j=1}^p \beta_j \sigma_{t-j}^2

Where:

  • \sigma_t^2: Conditional variance at time t
  • \omega: Intercept term
  • \alpha_j: Coefficients for lagged error terms (ARCH terms)
  • \beta_j: Coefficients for lagged variance terms (GARCH terms)

This model captures volatility clustering, a characteristic often observed in financial time series, where periods of high volatility tend to be followed by more high volatility. We specify a standard GARCH(1,1) model using the ugarchspec function from the rugarch package. This model includes an AR(1) term in the mean equation and GARCH(1,1) terms in the variance equation.

s_garch <-
  ugarchspec(
      variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
      mean.model = list(armaOrder = c(1, 0)),
      fixed.pars =
        c(
          mu = 0.1,      # Intercept of the mean equation
          ar1 = 0.9,     # AR(1) coefficient
          omega = 0.1,   # Intercept of the variance equation
          alpha1 = 0.7,  # ARCH coefficient
          beta1 = 0.1    # GARCH coefficient
          ),
      distribution.model = "norm"
    )
s_garch

*---------------------------------*
*       GARCH Model Spec          *
*---------------------------------*

Conditional Variance Dynamics   
------------------------------------
GARCH Model     : sGARCH(1,1)
Variance Targeting  : FALSE 

Conditional Mean Dynamics
------------------------------------
Mean Model      : ARFIMA(1,0,0)
Include Mean        : TRUE 
GARCH-in-Mean       : FALSE 

Conditional Distribution
------------------------------------
Distribution    :  norm 
Includes Skew   :  FALSE 
Includes Shape  :  FALSE 
Includes Lambda :  FALSE 

2. GJR-GARCH Model

The GJR-GARCH model, introduced by Glosten, Jagannathan, and Runkle (1993), extends the standard GARCH model by allowing for asymmetry in the volatility response to positive and negative shocks. The model is represented by:

\sigma_t^2 = \omega + \sum_{j=1}^q \left( \alpha_j \epsilon_{t-j}^2 + \gamma_j I(\epsilon_{t-j} < 0) \epsilon_{t-j}^2 \right) + \sum_{j=1}^p \beta_j \sigma_{t-j}^2

Where:

  • \gamma_j: Represents the leverage effect, capturing the impact of negative shocks
  • I(\epsilon_{t-j} < 0): Indicator function that equals 1 if the lagged error term is negative, otherwise 0

This model allows volatility to react differently to positive and negative shocks, which is often observed in financial markets (e.g., bad news tends to increase volatility more than good news). We specify the GJR-GARCH model as follows:

gjr_garch <-
  ugarchspec(
      variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
      mean.model = list(armaOrder = c(1, 0)),
      fixed.pars =
        c(
          mu = 0.1,       # Intercept of the mean equation
          ar1 = 0.9,      # AR(1) coefficient
          omega = 0.1,    # Intercept of the variance equation
          alpha1 = 0.5,   # ARCH(1) coefficient
          beta1 = 0.1,    # GARCH(1) coefficient
          gamma1 = 0.1    # Asymmetry term
          ),
      distribution.model = "norm"
    )
gjr_garch

*---------------------------------*
*       GARCH Model Spec          *
*---------------------------------*

Conditional Variance Dynamics   
------------------------------------
GARCH Model     : gjrGARCH(1,1)
Variance Targeting  : FALSE 

Conditional Mean Dynamics
------------------------------------
Mean Model      : ARFIMA(1,0,0)
Include Mean        : TRUE 
GARCH-in-Mean       : FALSE 

Conditional Distribution
------------------------------------
Distribution    :  norm 
Includes Skew   :  FALSE 
Includes Shape  :  FALSE 
Includes Lambda :  FALSE 

3. Exponential GARCH Model

The Exponential GARCH (eGARCH) model, proposed by Nelson (1991), captures leverage effects by modeling the logarithm of the conditional variance:

\log(\sigma_t^2) = \omega + \sum_{j=1}^q \left( \alpha_j z_{t-j} + \gamma_j (|z_{t-j}| - E|z_{t-j}|) \right) + \sum_{j=1}^p \beta_j \log(\sigma_{t-j}^2)

Where:

  • z_t: Standardized residuals
  • \alpha_j: Captures the sign effect (impact of positive/negative shocks)
  • \gamma_j: Captures the size effect (impact of the magnitude of shocks)

This model naturally ensures positive variance without requiring parameter restrictions and effectively models asymmetric volatility. We specify the eGARCH model as follows:

e_garch <-
  ugarchspec(
      variance.model = list(model = "eGARCH", garchOrder = c(1, 1)),
      mean.model = list(armaOrder = c(1, 0)),
      fixed.pars =
        c(
          mu = 0.1,       # Intercept of the mean equation
          ar1 = 0.9,      # AR(1) coefficient
          omega = 0.1,    # Intercept of the variance equation
          alpha1 = 0.5,   # ARCH(1) coefficient
          beta1 = 0.4,    # GARCH(1) coefficient
          gamma1 = 0.1    # Leverage term
          ),
      distribution.model = "norm"
    )
e_garch

*---------------------------------*
*       GARCH Model Spec          *
*---------------------------------*

Conditional Variance Dynamics   
------------------------------------
GARCH Model     : eGARCH(1,1)
Variance Targeting  : FALSE 

Conditional Mean Dynamics
------------------------------------
Mean Model      : ARFIMA(1,0,0)
Include Mean        : TRUE 
GARCH-in-Mean       : FALSE 

Conditional Distribution
------------------------------------
Distribution    :  norm 
Includes Skew   :  FALSE 
Includes Shape  :  FALSE 
Includes Lambda :  FALSE 

4. Asymmetric Power ARCH Model

The Asymmetric Power ARCH (apARCH) model, introduced by Ding, Granger, and Engle (1993), allows for both leverage and power effects in the volatility equation:

\sigma_t^\delta = \omega + \sum_{j=1}^q \alpha_j (|\epsilon_{t-j}| - \gamma_j \epsilon_{t-j})^\delta + \sum_{j=1}^p \beta_j \sigma_{t-j}^\delta

Where:

  • \delta: Power parameter, allowing for flexibility in modeling the distribution of volatility
  • \gamma_j: Leverage term, similar to the GJR-GARCH model

This model captures the observed behavior where volatility can respond asymmetrically to past shocks and allows for different power transformations of volatility. We specify the apARCH model as follows:

ap_arch <-
  ugarchspec(
      variance.model = list(model = "apARCH", garchOrder = c(1, 1)),
      mean.model = list(armaOrder = c(1, 0)),
      fixed.pars =
        c(
          mu = 0.1,       # Intercept of the mean equation
          ar1 = 0.9,      # AR(1) coefficient
          omega = 0.1,    # Intercept of the variance equation
          alpha1 = 0.5,   # ARCH(1) coefficient
          beta1 = 0.4,    # GARCH(1) coefficient
          gamma1 = 0.1,   # Asymmetry term
          delta = 1       # Power parameter
          ),
      distribution.model = "norm"
    )
ap_arch

*---------------------------------*
*       GARCH Model Spec          *
*---------------------------------*

Conditional Variance Dynamics   
------------------------------------
GARCH Model     : apARCH(1,1)
Variance Targeting  : FALSE 

Conditional Mean Dynamics
------------------------------------
Mean Model      : ARFIMA(1,0,0)
Include Mean        : TRUE 
GARCH-in-Mean       : FALSE 

Conditional Distribution
------------------------------------
Distribution    :  norm 
Includes Skew   :  FALSE 
Includes Shape  :  FALSE 
Includes Lambda :  FALSE 

Compiling the Model Specifications

We compile all the model specifications into a list for easy reference and manipulation.

volatility_specs <-
  list(
    s_garch = s_garch,
    gjr_garch = gjr_garch,
    e_garch = e_garch,
    ap_arch = ap_arch
  )

Simulating Data from the GARCH Models

We simulate time series data from each of the specified GARCH models and combine the results into a single data frame.

sim_data <-
  map(
    names(volatility_specs),
    function(model_name) {
      spec <- volatility_specs[[model_name]]
      simulation <- ugarchpath(spec = spec, n.sim = n_sim)
      tibble(
        time = 1:n_sim,
        series = as.numeric(simulation@path$seriesSim),
        sigma = as.numeric(simulation@path$sigmaSim),
        model = model_name
      )
    }
  ) %>%
  list_rbind()
sim_data
# A tibble: 4,000 × 4
    time  series sigma model  
   <int>   <dbl> <dbl> <chr>  
 1     1  0.0549 0.387 s_garch
 2     2  0.144  0.341 s_garch
 3     3 -0.319  0.341 s_garch
 4     4 -1.08   0.509 s_garch
 5     5 -1.74   0.760 s_garch
 6     6 -0.459  0.765 s_garch
 7     7 -0.120  1.00  s_garch
 8     8  0.651  0.507 s_garch
 9     9  0.363  0.720 s_garch
10    10 -0.197  0.436 s_garch
# ℹ 3,990 more rows

Visualizing the Simulated Data

We visualize the simulated series and their corresponding volatilities for each model.

sim_data %>%
  pivot_longer(c(series, sigma)) %>%
  ggplot(aes(time, value, color = model)) +
  geom_line() +
  facet_wrap(~name, scales = "free", ncol=2) +
  theme(legend.position = "bottom")

Figure: Simulated time series and volatility from different GARCH models.

Analyzing the Volatility Processes

To further understand the volatility processes generated by each model, we will examine the time series properties of the volatility series.

Defining a Plotting Function

We define a function plot_tsdisplay that creates time series plots along with the autocorrelation function (ACF) and partial autocorrelation function (PACF) for the volatility series.

plot_tsdisplay <-
  function(model_name) {
    sim_data %>%
      filter(model == model_name) %>%
      as_tsibble(index = time) %>%
      gg_tsdisplay(sigma, plot_type = "partial")
  }

Analyzing Each Model

Standard GARCH Model

plot_tsdisplay("s_garch")

GJR-GARCH Model

plot_tsdisplay("gjr_garch")

Exponential GARCH Model

plot_tsdisplay("e_garch")

Asymmetric Power ARCH Model

plot_tsdisplay("ap_arch")

Figures: Time series, ACF, and PACF plots of the volatility series for each GARCH model.

Conclusion

In this exercise, we simulated and analyzed different GARCH models to understand how they capture volatility in time series data. By comparing the simulated series and their volatility processes, we observed the characteristics and differences among the models. This hands-on approach enhances our understanding of volatility modeling in financial econometrics.