Atlas
statminds
Time Series (Volatility Model)The underlying model family class (e.g. GLM, linear model, categorical matrix, log-linear).Parametric ReferenceStatistical methods that assume a specific probability distribution family (typically normal).12-stage workflow

ARCH/GARCH Models

The engine for Volatility Discovery. This model audits the 'Clustering' of uncertainty, revealing how current volatility depends on previous shocks and previous variance, essential for high-fidelity risk forensics.

Model familyTime Series (Volatility Model)
Hypothesisvolatility_modeling
AliasesGARCH(p,q) · Conditional Heteroscedasticity Model · Volatility Cluster Engine
G1
Volatility Pulse Audit
Decipher the 'Persistence' of uncertainty—identifying periods where high variance clusters together.
G2
Risk Forensics Mapping
Construct a mathematical engine that forecasts the 'Width' of future outcomes rather than just the average.
G3
Heteroscedastic Neutralization
Mathematically model time-varying variance to ensure the reliability of p-values in unstable temporal fields.
Visual Overview Dashboard
1

What is it?

ARCH/GARCH Models analyzes sequences of data points ordered chronologically over time to extract patterns, model trends, and make forecasts.

The engine for Volatility Discovery. This model audits the 'Clustering' of uncertainty, revealing how current volatility depends on previous shocks and previous variance, essential for high-fidelity risk forensics.

2

Goals & Indications

  • Volatility Pulse Audit: Decipher the 'Persistence' of uncertainty—identifying periods where high variance clusters together.
  • Risk Forensics Mapping: Construct a mathematical engine that forecasts the 'Width' of future outcomes rather than just the average.
  • Heteroscedastic Neutralization: Mathematically model time-varying variance to ensure the reliability of p-values in unstable temporal fields.
3

Core Idea Diagram

Volatility Clustering (ARCH/GARCH)
4

Claims tested

H₀: H₀: No ARCH effects present (constant conditional variance)
Hₐ: Hₐ: ARCH effects present (time-varying conditional variance with volatility clustering)
5

How it works

  1. Fit mean equation (ARIMA or constant) to time series and obtain residuals.
  2. Check squared residuals for autocorrelation to confirm ARCH effects.
  3. Fit ARCH/GARCH model parameters using Maximum Likelihood Estimation.
  4. Compute predicted conditional variances to capture volatility bounds.
6

Assumptions

Mean equation correctly specified: Conditional mean model captures all autocorrelation in returns
Conditional heteroskedasticity present: Variance is time-varying and predictable from past squared residuals
Volatility clustering in returns: Large returns (positive or negative) tend to be followed by large returns
7

Important Note

ARCH/GARCH models focus on modeling conditional variance (volatility) of returns. Key insight: volatility is predictable and clusters over time - high volatility periods tend to be followed by high volatility. ARCH(q): variance depends on q past squared residuals. GARCH(p,q): variance depends on p past variances + q past squared residuals (more parsimonious). GARCH(1,1) most common: σ²_t = ω + α·ε²_{t-1} + β·σ²_{t-1}. Extensions: EGARCH (asymmetry/leverage), GJR-GARCH (threshold), TGARCH. Typical workflow: (1) Model mean equation (ARIMA/regression), (2) Test residuals for ARCH effects (LM test), (3) Fit GARCH to conditional variance, (4) Forecast volatility and VaR. Unlike ARIMA which models conditional mean, GARCH models conditional variance.

8

Worked Example

ParameterEstimateStd. Errort-statp-value
omega (ω)0.0510.0124.25<0.001
alpha (α)0.1520.0453.38<0.001
beta (β)0.7830.06212.63<0.001
Interactive Sandbox

Volatility Clustering & GARCH(1,1) Laboratory

Observe how the GARCH parameters controls persistence. Higher parameters (α + β) lead to prolonged clusters of high/low returns volatility.

Constant Variance (ω)0.10
ARCH parameter (α - shock impact)0.20
GARCH parameter (β - persistence)0.70
Model Indicators
Persistence (α + β): 0.9
Unconditional Variance: 1.0000
Unconditional SD (σ): 1.0000
Simulated Returns & Volatility Bounds (±2σt)
3.1-3.5
The 12-Stage Precision Workflow
01Volatility Parity
Hypotheses
We test the null of 'Constant Variance' against the discovery of a systematic, temporal pulse in uncertainty.
02Heavy Tails
Assumptions
Accounting for 'Leptokurtosis'—the tendency of volatile series to show extreme shocks more often than the normal curve predicts.
03ARCH Effects Audit
Diagnostics
Utilizing the LM Test on squared residuals to prove that variance is indeed clustered before committing to the GARCH path.
04focus
Auditing the volatility of daily app engagement after a major FlowMotion software update—mapping the 'Shock-Recovery' cycle.
05EGARCH Pivot
Alternatives
Knowing when to switch to Exponential GARCH (EGARCH) if 'Negative Shocks' (Bad News) cause more volatility than 'Positive Shocks' (Good News).
06Parameter Stability
Significance
Executing t-strikes on the Alpha (shocks) and Beta (persistence) terms—the two drivers of the volatility engine.
07Persistence Sum (α+β)
Effect Size
Calculating the sum of coefficients: if it's near 1.0, uncertainty is extremely persistent; shocks will linger for a long time.
08High-D Requirement
Sample Size
Ensuring a minimum of 500-1000 timepoints—GARCH math requires massive data to stabilize the variance estimation.
09Conditional SD
Reporting
Reporting the 'Conditional Standard Deviation' alongside the forecast—visualizing the 'Cloud of Uncertainty' around the mean.
10rugarch Logic
Software
Executing 'ugarchfit()' commands, ensuring the specification (p,q) and the distribution (norm, sstd) are optimized for discovery.
11focus
Avoiding the error of a non-stationary variance—where α+β ≥ 1, leading to an infinite-variance model that collapses mathematically.
12focus
Tracing the model back to Robert Engle (Nobel 2003) and the foundational revolution in modeling 'Uncertainty that Matters'.
01Hypothesis test logic

Hypotheses

Pragmatic null and alternative hypotheses defined in mathematical notation.

A hypothesis is a question sharpened to a point. Ambiguity is the enemy of inference.
Logic Core
Null · H₀

H₀: No ARCH effects present (constant conditional variance)

Alternative · Hₐ

Hₐ: ARCH effects present (time-varying conditional variance with volatility clustering)

Why it matters volatility_modeling

ARCH/GARCH models focus on modeling conditional variance (volatility) of returns. Key insight: volatility is predictable and clusters over time - high volatility periods tend to be followed by high volatility. ARCH(q): variance depends on q past squared residuals. GARCH(p,q): variance depends on p past variances + q past squared residuals (more parsimonious). GARCH(1,1) most common: σ²_t = ω + α·ε²_{t-1} + β·σ²_{t-1}. Extensions: EGARCH (asymmetry/leverage), GJR-GARCH (threshold), TGARCH. Typical workflow: (1) Model mean equation (ARIMA/regression), (2) Test residuals for ARCH effects (LM test), (3) Fit GARCH to conditional variance, (4) Forecast volatility and VaR. Unlike ARIMA which models conditional mean, GARCH models conditional variance.

02Model diagnostics

Assumptions

The core mathematical criteria needed to ensure that statistical testing remains unbiased and valid.

Stationarity is the prerequisite of prediction. You cannot forecast a system that is fundamentally changing its rules.
Integrity Shield
8
Assumptions
5
Critical / High Severity
How to check
Quick
Fit mean equation first (ARMA, regression, or constant). Check residuals: plot ACF, should show no autocorrelation but may show volatility clustering (periods of high/low variance). If ACF shows spikes: mean model inadequate. If squared residuals show autocorrelation: ARCH effects present
Rigorous
Test mean equation residuals: Ljung-Box test on residuals (should be white noise, p>0.05). Plot ACF/PACF of residuals: no significant spikes. Test for remaining autocorrelation. THEN test squared residuals: Ljung-Box test on squared residuals (if p<0.05, ARCH effects present). ARCH-LM test: regress squared residuals on lagged squared residuals, test joint significance (p<0.05 indicates ARCH). McLeod-Li test. Mean equation MUST be correct before GARCH; otherwise GARCH captures autocorrelation not variance
If violated
If mean equation inadequate: improve it first before GARCH. Add AR/MA terms if ACF shows autocorrelation. Add regressors if relevant (ARMAX). Ensure residuals are white noise. Re-test until Ljung-Box p>0.05 on residuals. Only then proceed to GARCH for variance. If mean model wrong, GARCH estimates biased. Sequential approach: first model mean (ARIMA), then model variance (GARCH) of residuals. Some software allows joint estimation (ARMA-GARCH)
How to check
Quick
Visual check: plot squared residuals or absolute residuals over time. Look for clustering: periods of high volatility grouped together, periods of low volatility grouped together. If volatility appears constant over time: no ARCH effects, GARCH not needed. Calculate rolling standard deviation: if varies substantially over time, suggests ARCH
Rigorous
ARCH-LM test (Engle 1982): regress squared residuals ε²_t on lagged ε²_{t-1},...,ε²_{t-q}. Test H₀: all coefficients=0 using F-test or LM statistic = n·R². If p<0.05: reject H₀, ARCH effects present. Ljung-Box test on squared residuals: tests autocorrelation in ε²_t. If p<0.05: variance autocorrelated (ARCH). Test at multiple lags (q=5,10,20). Both tests should agree. If no ARCH: constant variance adequate (OLS standard errors valid)
If violated
If no ARCH effects detected (p>0.05 in LM test): GARCH unnecessary, use constant variance model. Standard OLS/ARIMA adequate. Robust standard errors handle mild heteroskedasticity. If ARCH effects weak: consider if GARCH complexity justified. GARCH most useful for high-frequency financial data with strong volatility clustering. For low-frequency data (annual) or weak ARCH: simple models often sufficient. Always test FIRST before fitting GARCH; don't fit GARCH blindly
How to check
Quick
Plot absolute or squared returns over time: visual clustering pattern (high volatility episodes cluster). Calculate autocorrelation of squared returns: if significant positive autocorrelation, volatility clusters. Financial returns often show: mean≈0, high kurtosis (fat tails), volatility clustering. If returns IID: GARCH not needed
Rigorous
Compute ACF of squared returns or absolute returns: significant positive autocorrelation indicates clustering. Test with Ljung-Box on |r_t| or r²_t. Estimate sample kurtosis: excess kurtosis>0 common with clustering (fat tails). BDS test for IID: if rejects, suggests nonlinear dependence (volatility clustering). Compare unconditional variance (sample variance) vs conditional variance from GARCH: if similar, weak clustering. Strong clustering: conditional variance varies substantially over time
If violated
If no clustering: returns may be IID, GARCH unnecessary. Check if: (1) Data frequency too low (annual): clustering less pronounced. (2) Sample period unusual: crisis vs calm. (3) Asset type: bonds less clustering than equities. (4) Mean equation captures all dependence: no variance dynamics left. If clustering weak: simpler models (ARCH(1), constant variance with robust SE) may suffice. GARCH most useful when strong, persistent clustering present. Don't force GARCH where inappropriate
How to check
Quick
Plot squared residuals or rolling volatility over time: check for sudden persistent shifts in volatility level (e.g., pre/post financial crisis). If clear regime change: structural break present. CUSUM test on squared residuals for stability. Compare first half vs second half variance: if drastically different, may indicate break
Rigorous
Formal break tests: ICSS test (Inclan-Tiao) detects multiple volatility shifts. Bai-Perron test for structural breaks in variance. Chow test for known break date. Estimate GARCH on subsamples: if parameters drastically different (α,β change), suggests instability. Check parameter constancy: recursive estimation, rolling windows. If breaks detected: use dummy variables for regimes, separate models by period, or regime-switching GARCH (Markov-switching)
If violated
If structural breaks present: (1) Include dummies in variance equation for known breaks (e.g., 2008 crisis): σ²_t = ω + α·ε²_{t-1} + β·σ²_{t-1} + γ·D_t. (2) Fit separate GARCH models for each regime. (3) Use regime-switching GARCH (Markov-switching): allows parameters to switch between states. (4) Component GARCH: separates transient vs permanent volatility. (5) Restrict sample to stable period. Breaks cause parameter instability, poor forecasts. Account for breaks explicitly
How to check
Quick
Check sample size n. GARCH requires more data than ARIMA: minimum n≥500, prefer n≥1000. Daily data: ≥2 years. Weekly: ≥10 years. For extensions (EGARCH, GJR): even more data. Small samples: parameters unstable, poor forecasts, convergence issues. Compare standard errors: large SE relative to estimates suggests insufficient data
Rigorous
Bootstrap standard errors: if very large, insufficient data. Estimate GARCH on subsamples: if parameters vary wildly, sample too small for stability. Monte Carlo simulation: generate GARCH process with known parameters, estimate from n observations, check bias and variance of estimates. Literature: GARCH(1,1) needs n≥500 for reasonably accurate estimates. Complex models (EGARCH, multivariate): n≥1000. Parameter persistence (α+β near 1) requires more data
If violated
If n<500: (1) Use simpler models: ARCH(1) instead of GARCH, or constant variance with robust SE. (2) Bayesian GARCH with informative priors (incorporates external information). (3) Shrinkage estimators. (4) Use higher frequency data if available (daily instead of weekly). (5) RiskMetrics (exponential smoothing for variance) requires no estimation. (6) Acknowledge limitation: report uncertainty, wide confidence intervals. NEVER fit complex GARCH to small samples: unstable, unreliable forecasts
How to check
Quick
NEVER apply GARCH to price levels (non-stationary). ALWAYS use returns: r_t = log(P_t) - log(P_{t-1}) (log returns) or (P_t - P_{t-1})/P_{t-1} (simple returns). Test returns for stationarity: ADF test (p<0.05). Plot returns: should fluctuate around constant mean (≈0), no trend. If levels used: spurious results
Rigorous
Formal stationarity tests on returns: ADF test (H₀=unit root), KPSS test (H₀=stationary). Returns should be I(0). Check ACF of returns: should decay quickly. If returns non-stationary (rare): further differencing or detrending needed. Verify mean-reversion: returns should revert to mean≈0. GARCH assumes stationary mean process with time-varying variance. For prices (non-stationary): difference first to get returns
If violated
If modeling prices (non-stationary): STOP. Convert to returns first: log returns preferred (r_t = ln(P_t/P_{t-1})). If returns still non-stationary (unusual): check data quality, test for drift, consider deterministic trend removal. Some financial series (exchange rates under peg): different behavior, check institutional regime. GARCH requires stationary mean equation. If persistent trend in returns: remove trend before GARCH. Standard: GARCH on demeaned returns or ARMA-GARCH on returns
How to check
Quick
Plot standardized residuals: ε_t/σ_t from fitted GARCH. Look for extreme values (|z|>5). Financial returns have fat tails (expect some large values), but massive outliers (crashes, flash crashes) can distort estimates. Check for isolated extreme events. Count observations with |z|>4: if many, distribution may be misspecified (use t-distribution)
Rigorous
Formal outlier detection: GARCH with robust estimation (LAD instead of MLE). Estimate GARCH, compute standardized residuals, test for outliers using robust measures (MAD). Identify dates of extremes: match to events (crashes, announcements). Test distribution assumption: Jarque-Bera test, Q-Q plot of standardized residuals vs assumed distribution (normal, t). If fat tails: use Student-t or skewed-t distribution. Estimate GARCH with/without outliers: if parameters drastically change, outliers influential
If violated
If extreme outliers present: (1) Use robust distributions: Student-t GARCH (df parameter for fat tails), skewed-t (asymmetry). (2) Robust estimation: LAD-GARCH, median-based. (3) Explicitly model jumps: GARCH-Jump model (separate jump component from diffusion volatility). (4) Additive outlier intervention: dummy variables for crisis dates. (5) Trim outliers cautiously (only if data errors). Fat tails: t-distribution much better than normal for financial returns. Robust GARCH less sensitive to extremes
How to check
Quick
After fitting GARCH, standardize residuals: z_t = ε_t/σ_t. These should follow assumed distribution (N(0,1) if normal, t(df) if Student-t). Plot histogram of z_t: check if matches. Q-Q plot: standardized residuals vs theoretical quantiles. If fat tails or skewness visible: wrong distribution
Rigorous
Formal distributional tests on standardized residuals: Jarque-Bera test (H₀=normality), Shapiro-Wilk. Estimate kurtosis: excess kurtosis>0 indicates fat tails (use t-distribution). Test skewness: if negative (common in equity returns), use skewed-t. Compare models: fit GARCH with normal, t, skewed-t; compare log-likelihood or AIC. t-distribution usually better for financial data. Check VaR violations: if too many exceedances, distribution wrong
If violated
If normality violated (common): (1) Student-t distribution: adds df parameter for fat tails. Typically df=5-15 for financial returns. (2) Skewed-t: adds skewness parameter for asymmetry. (3) GED (generalized error distribution): shape parameter for tail thickness. (4) Empirical distribution: non-parametric. Wrong distribution: VaR estimates biased (underestimate risk), prediction intervals wrong. t-distribution standard for financial GARCH. Compare log-likelihoods: t almost always better than normal
03Residual Forensics

Diagnostics

Checking residual plots and indices to examine model deviations and ensure standard error integrity.

White noise is the goal. If your residuals have a pattern, you have left information on the table.
System Health
Essential checks
  1. ARCH-LM test on residuals to verify the presence of volatility clustering.
  2. Ljung-Box test on squared standardized residuals to ensure volatility modeling is complete.
  3. Significance audit of Alpha (shock) and Beta (persistence) coefficients.
  4. Log-Likelihood comparison between GARCH(1,1) and higher-order models.
  5. Nyblom test for parameter stability over time.
Recommended checks
  1. Distributional fit audit: Comparing Normal vs. Student-t vs. GED error models.
  2. Value-at-Risk (VaR) Backtesting using Kupiec’s Proportion of Failures test.
  3. News Impact Curve analysis to audit symmetry of shock reactions.
  4. Robustness check against EGARCH or GJR-GARCH if leverage effects are suspected.
  5. Standardized residual Q-Q plot to identify 'Fat Tails' (Leptokurtosis).
04Live Instances

Applied Minds

Review concrete study examples, data layout guidelines, and copy executable syntax scripts.

Theory is the map. Practice is the terrain. Simulation bridges the gap.
Applied Wisdom
Example 01

Stock Return Volatility Modeling with GARCH(1,1)

Model daily stock return volatility (n=1500 daily returns, ≈6 years) using GARCH framework. Demonstrates complete volatility modeling workflow: return calculation, exploratory volatility analysis, ARCH effect testing, mean equation specification (ARMA), GARCH(1,1) estimation with normal and Student-t distributions, extended models (EGARCH, GJR-GARCH for leverage effects), comprehensive residual diagnostics (ARCH-LM test, standardized residuals), volatility forecasting, VaR estimation and backtesting, news impact curves for asymmetry. Compares symmetric vs asymmetric GARCH models, tests leverage hypothesis, validates VaR predictions using Kupiec and Christoffersen tests.

# ============================================================================
# ARCH/GARCH MODELS: Stock Return Volatility Modeling
# ============================================================================
# Demonstrates: GARCH(1,1), EGARCH, GJR-GARCH, VaR forecasting
# Data: 1500 daily returns (≈6 years) with volatility clustering and leverage
# ============================================================================

library(rugarch)       # GARCH estimation and forecasting
library(FinTS)         # ARCH test
library(forecast)      # ARMA models
library(ggplot2)       # visualization
library(gridExtra)     # multiple plots

set.seed(123)

# ============================================================================
# 1. DATA GENERATION: Stock returns with volatility clustering
# ============================================================================

cat("=", rep("=", 79), "\n", sep="")
cat("GARCH MODELS: Stock Return Volatility Analysis\n")
cat("=", rep("=", 79), "\n\n", sep="")

# Simulate GARCH(1,1) process with leverage (GJR-GARCH)
n <- 1500  # Daily returns (≈6 years of trading days)

# True parameters (GJR-GARCH to create leverage effect)
omega <- 0.00001
alpha <- 0.08
beta <- 0.90
gamma <- 0.04  # Leverage: negative shocks increase volatility more

returns <- numeric(n)
variance <- numeric(n)
variance[1] <- omega / (1 - alpha - beta - gamma/2)  # Unconditional variance
returns[1] <- rnorm(1, 0, sqrt(variance[1]))

for (t in 2:n) {
  # GJR-GARCH variance equation
  I_negative <- ifelse(returns[t-1] < 0, 1, 0)
  variance[t] <- omega + alpha * returns[t-1]^2 + 
                 gamma * returns[t-1]^2 * I_negative + 
                 beta * variance[t-1]
  returns[t] <- rnorm(1, 0, sqrt(variance[t]))
}

# Convert to percentage returns
returns <- returns * 100
volatility <- sqrt(variance) * 100

# Create time series
date_seq <- seq.Date(from = as.Date("2018-01-01"), by = "day", length.out = n)
returns_ts <- xts::xts(returns, order.by = date_seq)

cat("Data generated: n =", n, "daily returns\n")
cat("Mean return:", round(mean(returns), 4), "%\n")
cat("SD(volatility):", round(sd(returns), 4), "%\n")
cat("Skewness:", round(moments::skewness(returns), 3), "\n")
cat("Kurtosis:", round(moments::kurtosis(returns), 3), "(>3 = fat tails)\n\n")

# ============================================================================
# 2. EXPLORATORY ANALYSIS
# ============================================================================

cat("=== EXPLORATORY VOLATILITY ANALYSIS ===\n\n")

# Visualizations
par(mfrow = c(3, 2), mar = c(4, 4, 3, 1))

# Returns over time
plot(date_seq, returns, type="l", col="steelblue", lwd=0.5,
     main="Daily Returns", xlab="Date", ylab="Return(%)")
abline(h = 0, col = "red", lty = 2)

# Squared returns (proxy for volatility)
plot(date_seq, returns^2, type="l", col="darkred", lwd=0.5,
     main="Squared Returns(Volatility Proxy)", xlab="Date", ylab="Squared Return")

# Histogram
hist(returns, breaks = 50, col = "lightblue", probability = TRUE,
     main = "Return Distribution", xlab = "Return(%)")
curve(dnorm(x, mean(returns), sd(returns)), add = TRUE, col = "red", lwd = 2)
legend("topright", "Normal", col="red", lwd=2, bty="n")

# Q-Q plot
qqnorm(returns, main = "Q-Q Plot: Returns vs Normal")
qqline(returns, col = "red", lwd = 2)

# ACF of returns
acf(returns, lag.max = 40, main = "ACF: Returns")

# ACF of squared returns (ARCH test)
acf(returns^2, lag.max = 40, main = "ACF: Squared Returns(ARCH effects)")

par(mfrow = c(1, 1))

cat("Visual inspection:\n")
cat("  - Returns show volatility clustering(episodes of high/low volatility)\n")
cat("  - Squared returns show autocorrelation(ARCH effects)\n")
cat("  - Fat tails evident in histogram and Q-Q plot\n\n")

# ============================================================================
# 3. TEST FOR ARCH EFFECTS
# ============================================================================

cat("=== ARCH EFFECT TESTING ===\n\n")

# Ljung-Box test on squared returns
lb_squared <- Box.test(returns^2, lag = 20, type = "Ljung-Box")
cat("Ljung-Box test on squared returns(lag=20):\n")
cat("  Test statistic:", round(lb_squared$statistic, 4), "\n")
cat("  p-value:", format.pval(lb_squared$p.value, digits=4), "\n")
if (lb_squared$p.value < 0.05) {
  cat("  Conclusion: ARCH effects PRESENT(p<0.05) - GARCH appropriate\n\n")
} else {
  cat("  Conclusion: No ARCH effects - constant variance adequate\n\n")
}

# ARCH-LM test
arch_test <- ArchTest(returns, lags = 12)
cat("ARCH-LM test(Engle 1982):\n")
print(arch_test)
if (arch_test$p.value < 0.05) {
  cat("\n  Conclusion: ARCH effects PRESENT - proceed with GARCH\n\n")
}

# ============================================================================
# 4. MEAN EQUATION SPECIFICATION
# ============================================================================

cat("=== MEAN EQUATION SPECIFICATION ===\n\n")

# Check if returns have autocorrelation
lb_returns <- Box.test(returns, lag = 20, type = "Ljung-Box")
cat("Ljung-Box test on returns(lag=20):\n")
cat("  p-value:", format.pval(lb_returns$p.value, digits=4), "\n")

if (lb_returns$p.value < 0.05) {
  cat("  Autocorrelation present - use ARMA mean equation\n")
  # Auto-select ARMA order
  arma_model <- auto.arima(returns, max.p=5, max.q=5, seasonal=FALSE, 
                          ic="aic", stepwise=TRUE, trace=FALSE)
  arma_order <- arimaorder(arma_model)
  cat("  Selected ARMA order:", paste0("(", arma_order[1], ",", arma_order[3], ")\n\n"))
  mean_spec <- list(armaOrder = c(arma_order[1], arma_order[3]))
} else {
  cat("  No significant autocorrelation - use constant mean\n\n")
  mean_spec <- list(armaOrder = c(0, 0))
}

# ============================================================================
# 5. GARCH(1,1) ESTIMATION - Normal Distribution
# ============================================================================

cat("=== GARCH(1,1) ESTIMATION ===\n\n")

# Specify GARCH(1,1) with normal distribution
spec_garch11 <- ugarchspec(
  variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
  mean.model = mean_spec,
  distribution.model = "norm"
)

# Fit model
fit_garch11 <- ugarchfit(spec = spec_garch11, data = returns)

cat("GARCH(1,1) with Normal distribution:\n")
print(fit_garch11)

# Extract parameters
params <- coef(fit_garch11)
omega_est <- params["omega"]
alpha_est <- params["alpha1"]
beta_est <- params["beta1"]

cat("\nKey parameters:\n")
cat("  omega(ω):", round(omega_est, 8), "\n")
cat("  alpha(α):", round(alpha_est, 4), "(ARCH effect)\n")
cat("  beta(β):", round(beta_est, 4), "(GARCH effect)\n")
cat("  α + β:", round(alpha_est + beta_est, 4), "(persistence)\n")

# Unconditional variance
if (alpha_est + beta_est < 1) {
  uncond_var <- omega_est / (1 - alpha_est - beta_est)
  cat("  Unconditional variance:", round(uncond_var, 6), "\n")
  cat("  Unconditional volatility:", round(sqrt(uncond_var), 4), "%\n")
}

# Half-life
half_life <- log(0.5) / log(alpha_est + beta_est)
cat("  Half-life of shocks:", round(half_life, 2), "days\n\n")

# Information criteria
cat("Model fit:\n")
cat("  Log-likelihood:", round(likelihood(fit_garch11), 2), "\n")
cat("  AIC:", round(infocriteria(fit_garch11)[1], 2), "\n")
cat("  BIC:", round(infocriteria(fit_garch11)[2], 2), "\n\n")

# ============================================================================
# 6. GARCH(1,1) with Student-t Distribution
# ============================================================================

cat("=== GARCH(1,1) with Student-t ===\n\n")

# Specify with Student-t
spec_garch_t <- ugarchspec(
  variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
  mean.model = mean_spec,
  distribution.model = "std"  # Student-t
)

fit_garch_t <- ugarchfit(spec = spec_garch_t, data = returns)

cat("GARCH(1,1) with Student-t distribution:\n")
cat("  Degrees of freedom:", round(coef(fit_garch_t)["shape"], 2), "\n")
cat("  AIC:", round(infocriteria(fit_garch_t)[1], 2), "\n")
cat("  BIC:", round(infocriteria(fit_garch_t)[2], 2), "\n\n")

if (infocriteria(fit_garch_t)[1] < infocriteria(fit_garch11)[1]) {
  cat("  Student-t provides BETTER fit(lower AIC)\n")
  cat("  Fat tails present - t-distribution recommended\n\n")
}

# ============================================================================
# 7. EGARCH for Leverage Effects
# ============================================================================

cat("=== EGARCH(1,1) - Asymmetric Model ===\n\n")

# Specify EGARCH
spec_egarch <- ugarchspec(
  variance.model = list(model = "eGARCH", garchOrder = c(1, 1)),
  mean.model = mean_spec,
  distribution.model = "std"
)

fit_egarch <- ugarchfit(spec = spec_egarch, data = returns)

cat("EGARCH(1,1) results:\n")
print(fit_egarch)

gamma_egarch <- coef(fit_egarch)["gamma1"]
cat("\nLeverage parameter(γ):", round(gamma_egarch, 4), "\n")
if (gamma_egarch < 0) {
  cat("  γ < 0: Negative returns INCREASE volatility more(leverage effect)\n")
}
cat("  AIC:", round(infocriteria(fit_egarch)[1], 2), "\n\n")

# ============================================================================
# 8. GJR-GARCH for Leverage Effects
# ============================================================================

cat("=== GJR-GARCH(1,1) - Threshold Model ===\n\n")

# Specify GJR-GARCH
spec_gjr <- ugarchspec(
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
  mean.model = mean_spec,
  distribution.model = "std"
)

fit_gjr <- ugarchfit(spec = spec_gjr, data = returns)

cat("GJR-GARCH(1,1) results:\n")
print(fit_gjr)

gamma_gjr <- coef(fit_gjr)["gamma1"]
cat("\nAsymmetry parameter(γ):", round(gamma_gjr, 4), "\n")
if (gamma_gjr > 0) {
  cat("  γ > 0: Negative returns INCREASE volatility more\n")
  cat("  Total effect of negative shock: α + γ =", 
      round(coef(fit_gjr)["alpha1"] + gamma_gjr, 4), "\n")
}
cat("  AIC:", round(infocriteria(fit_gjr)[1], 2), "\n\n")

# ============================================================================
# 9. MODEL COMPARISON
# ============================================================================

cat("=== MODEL COMPARISON ===\n\n")

model_comp <- data.frame(
  Model = c("GARCH(1,1)-Normal", "GARCH(1,1)-t", "EGARCH(1,1)-t", "GJR-GARCH(1,1)-t"),
  LogLik = c(likelihood(fit_garch11), likelihood(fit_garch_t), 
             likelihood(fit_egarch), likelihood(fit_gjr)),
  AIC = c(infocriteria(fit_garch11)[1], infocriteria(fit_garch_t)[1],
          infocriteria(fit_egarch)[1], infocriteria(fit_gjr)[1]),
  BIC = c(infocriteria(fit_garch11)[2], infocriteria(fit_garch_t)[2],
          infocriteria(fit_egarch)[2], infocriteria(fit_gjr)[2])
)

print(model_comp, row.names=FALSE)

best_model <- which.min(model_comp$AIC)
cat("\nBest model by AIC:", model_comp$Model[best_model], "\n")
cat("Recommendation: Use GJR-GARCH with Student-t for leverage effects\n\n")

# Use GJR-GARCH for further analysis
final_model <- fit_gjr

# ============================================================================
# 10. DIAGNOSTIC CHECKING
# ============================================================================

cat("=== MODEL DIAGNOSTICS ===\n\n")

# Standardized residuals
std_resid <- residuals(final_model, standardize = TRUE)

# ARCH-LM test on standardized residuals
arch_test_resid <- ArchTest(std_resid, lags = 12)
cat("ARCH-LM test on standardized residuals:\n")
cat("  Test statistic:", round(arch_test_resid$statistic, 4), "\n")
cat("  p-value:", format.pval(arch_test_resid$p.value, digits=4), "\n")
if (arch_test_resid$p.value > 0.05) {
  cat("  Conclusion: No remaining ARCH effects - model adequate\n\n")
} else {
  cat("  Conclusion: ARCH effects remain - consider higher order\n\n")
}

# Ljung-Box on standardized residuals
lb_std <- Box.test(std_resid, lag = 20, type = "Ljung-Box")
cat("Ljung-Box test on standardized residuals:\n")
cat("  p-value:", format.pval(lb_std$p.value, digits=4), "\n")
if (lb_std$p.value > 0.05) {
  cat("  Conclusion: No autocorrelation - good\n\n")
}

# Ljung-Box on squared standardized residuals
lb_std_sq <- Box.test(std_resid^2, lag = 20, type = "Ljung-Box")
cat("Ljung-Box test on squared standardized residuals:\n")
cat("  p-value:", format.pval(lb_std_sq$p.value, digits=4), "\n")
if (lb_std_sq$p.value > 0.05) {
  cat("  Conclusion: No remaining ARCH effects - model captures volatility\n\n")
}

# Residual statistics
cat("Standardized residual statistics:\n")
cat("  Mean:", round(mean(std_resid), 4), "(should be ~0)\n")
cat("  SD:", round(sd(std_resid), 4), "(should be ~1)\n")
cat("  Skewness:", round(moments::skewness(std_resid), 3), "\n")
cat("  Kurtosis:", round(moments::kurtosis(std_resid), 3), "\n")
cat("  |z| > 3:", sum(abs(std_resid) > 3), "observations\n\n")

# Plot diagnostics
par(mfrow = c(2, 3))
plot(std_resid, type="l", main="Standardized Residuals", ylab="z_t")
abline(h = c(-3, 0, 3), col = c("red", "black", "red"), lty = c(2, 1, 2))

acf(std_resid, lag.max = 30, main = "ACF: Standardized Residuals")
acf(std_resid^2, lag.max = 30, main = "ACF: Squared Std Residuals")

hist(std_resid, breaks = 50, probability = TRUE, col = "lightblue",
     main = "Histogram: Std Residuals", xlab = "z_t")
curve(dnorm(x, 0, 1), add = TRUE, col = "red", lwd = 2)

qqnorm(std_resid, main = "Q-Q Plot: Std Residuals")
qqline(std_resid, col = "red", lwd = 2)

# Conditional volatility
vol_fitted <- sigma(final_model)
plot(date_seq, vol_fitted, type="l", col="darkred", lwd=1,
     main="Fitted Conditional Volatility", xlab="Date", ylab="Volatility(%)")

par(mfrow = c(1, 1))

# ============================================================================
# 11. NEWS IMPACT CURVE
# ============================================================================

cat("=== NEWS IMPACT CURVE ===\n\n")

ni_curve <- newsimpact(final_model)
plot(ni_curve$zx, ni_curve$zy, type="l", lwd=2, col="darkblue",
     main="News Impact Curve(GJR-GARCH)",
     xlab="Shock(standardized return)", ylab="Next Period Variance")
abline(v = 0, col = "gray", lty = 2)
grid()

cat("News impact curve shows asymmetry:\n")
cat("  Negative shocks(left) have LARGER impact on variance than positive\n")
cat("  This is the leverage effect\n\n")

# ============================================================================
# 12. VOLATILITY FORECASTING
# ============================================================================

cat("=== VOLATILITY FORECASTING ===\n\n")

# Forecast 20 days ahead
forecast_horizon <- 20
forc <- ugarchforecast(final_model, n.ahead = forecast_horizon)

cat("Volatility forecast(next", forecast_horizon, "days):\n")
vol_forecast <- sigma(forc)
print(head(vol_forecast, 10))

# Plot forecast
par(mfrow = c(1, 1))
vol_historical <- as.numeric(sigma(final_model))
vol_dates <- date_seq[1:length(vol_historical)]
forc_dates <- seq.Date(from = max(vol_dates) + 1, by = "day", length.out = forecast_horizon)

plot(vol_dates, vol_historical, type="l", col="steelblue", lwd=1.5,
     xlim=range(c(vol_dates, forc_dates)), ylim=range(c(vol_historical, vol_forecast)),
     main="Volatility Forecast", xlab="Date", ylab="Volatility(%)")
lines(forc_dates, vol_forecast, col="darkred", lwd=2, lty=2)
abline(v = max(vol_dates), col = "gray", lty = 3)
legend("topright", c("Historical", "Forecast"), col=c("steelblue", "darkred"),
       lwd=c(1.5, 2), lty=c(1, 2), bty="n")

cat("\nVolatility forecasts generated.\n")
cat("Mean forecast volatility:", round(mean(vol_forecast), 4), "%\n\n")

# ============================================================================
# 13. VALUE-AT-RISK (VaR) ESTIMATION
# ============================================================================

cat("=== VALUE-AT-RISK(VaR) ESTIMATION ===\n\n")

# Calculate VaR from GARCH forecasts
alpha_var <- 0.05  # 5% VaR
df_param <- coef(final_model)["shape"]  # t-distribution df

# Quantile from Student-t
q_t <- qt(alpha_var, df = df_param)

# VaR forecast: μ + σ * quantile
mu_forecast <- fitted(forc)  # Mean forecast
var_forecast <- mu_forecast + vol_forecast * q_t

cat("5% VaR forecast(next 10 days):\n")
print(head(var_forecast, 10))

cat("\nInterpretation:\n")
cat("  5% probability that return will be BELOW VaR threshold\n")
cat("  Example: VaR =", round(var_forecast[1], 3), "% means 5% chance of losing more than", 
    round(abs(var_forecast[1]), 3), "%\n\n")

# ============================================================================
# 14. VaR BACKTESTING
# ============================================================================

cat("=== VaR BACKTESTING ===\n\n")

# Use rolling window for backtesting
window_size <- 1000
test_size <- 500

var_violations <- numeric(test_size)
var_estimates <- numeric(test_size)

for (i in 1:test_size) {
  # Rolling window
  train_data <- returns[i:(window_size + i - 1)]
  test_return <- returns[window_size + i]
  
  # Fit GJR-GARCH
  fit_roll <- ugarchfit(spec = spec_gjr, data = train_data, solver="hybrid")
  
  # 1-day ahead forecast
  forc_roll <- ugarchforecast(fit_roll, n.ahead = 1)
  
  # VaR estimate
  mu_1 <- fitted(forc_roll)[1]
  sig_1 <- sigma(forc_roll)[1]
  df_1 <- coef(fit_roll)["shape"]
  var_1 <- mu_1 + sig_1 * qt(alpha_var, df = df_1)
  
  var_estimates[i] <- var_1
  var_violations[i] <- ifelse(test_return < var_1, 1, 0)
}

violation_rate <- mean(var_violations)
expected_rate <- alpha_var

cat("VaR Backtesting Results(5% VaR):\n")
cat("  Expected violation rate:", expected_rate * 100, "%\n")
cat("  Actual violation rate:", round(violation_rate * 100, 2), "%\n")
cat("  Number of violations:", sum(var_violations), "out of", test_size, "\n\n")

# Kupiec test (unconditional coverage)
kupiec_stat <- -2 * (log(expected_rate^sum(var_violations) * 
                    (1-expected_rate)^(test_size-sum(var_violations))) -
                    log(violation_rate^sum(var_violations) * 
                    (1-violation_rate)^(test_size-sum(var_violations))))
kupiec_p <- 1 - pchisq(kupiec_stat, df = 1)

cat("Kupiec Test(Unconditional Coverage):\n")
cat("  Test statistic:", round(kupiec_stat, 4), "\n")
cat("  p-value:", format.pval(kupiec_p, digits=4), "\n")
if (kupiec_p > 0.05) {
  cat("  Conclusion: VaR model is ADEQUATE(p>0.05)\n\n")
} else {
  cat("  Conclusion: VaR model INADEQUATE - violation rate differs from 5%\n\n")
}

# Plot VaR violations
test_dates <- date_seq[(window_size + 1):(window_size + test_size)]
test_returns <- returns[(window_size + 1):(window_size + test_size)]

plot(test_dates, test_returns, type="l", col="steelblue",
     main="VaR Backtesting: 5% VaR Violations",
     xlab="Date", ylab="Return(%)")
lines(test_dates, var_estimates, col="red", lwd=1.5, lty=2)
points(test_dates[var_violations==1], test_returns[var_violations==1],
       col="darkred", pch=19, cex=1.2)
abline(h = 0, col = "gray", lty = 3)
legend("topright", c("Returns", "5% VaR", "Violations"),
       col=c("steelblue", "red", "darkred"), lwd=c(1, 1.5, NA),
       lty=c(1, 2, NA), pch=c(NA, NA, 19), bty="n")

# ============================================================================
# 15. SUMMARY
# ============================================================================

cat("\n=== FINAL SUMMARY ===\n\n")

cat("Data: 1500 daily stock returns\n")
cat("Best model: GJR-GARCH(1,1) with Student-t distribution\n\n")

cat("Key findings:\n")
cat("  - ARCH effects present(p<0.05): volatility clustering confirmed\n")
cat("  - Leverage effect detected(γ>0): negative returns increase volatility more\n")
cat("  - High persistence(α+β≈0.95): shocks decay slowly\n")
cat("  - Student-t fits better than normal: fat tails in returns\n")
cat("  - VaR backtesting successful: violation rate ≈ 5%\n\n")

cat("Model parameters(GJR-GARCH):\n")
cat("  α (ARCH):", round(coef(final_model)["alpha1"], 4), "\n")
cat("  β (GARCH):", round(coef(final_model)["beta1"], 4), "\n")
cat("  γ (Leverage):", round(coef(final_model)["gamma1"], 4), "\n")
cat("  df(Student-t):", round(coef(final_model)["shape"], 2), "\n\n")

cat("Applications:\n")
cat("  - Portfolio risk management(VaR, ES)\n")
cat("  - Option pricing(volatility forecasts)\n")
cat("  - Risk-adjusted returns\n")
cat("  - Regulatory capital requirements\n\n")

cat("GARCH analysis complete.\n")

# ============================================================================
# END
# ============================================================================
05Tactical Pivots

Alternatives

Structured fallback pathways for choosing alternative tests when normality or slopes requirements fail.

When the path is blocked, pivot. Rigor is not rigidity; it is the intelligent adaptation to reality.
Adaptive Strategy
Measurement Precision Ladder Ideal · Volatile Continuous Stream
Ratio
Maintain GARCH logic. Optimal for auditing the 'Width' of uncertainty in high-frequency markers.
Peak Sensitivity
Interval
Ideal for Risk Forensics. Ensure the 'Persistence' parameter (Alpha+Beta) is less than 1.0.
Standard Precision
Temporal Trajectory Audit Dynamic Volatility Flow
Volatility Pulse
Conditional variance.
Stay with GARCH. Capture the 'Shock-Recovery' cycle of uncertainty.
Stable Pulse
Constant variance.
Simplify to ARIMA or OLS if the ARCH-LM test confirms no volatility clustering.
Adaptive Technical Safeguards · adaptive safeguards
asymmetric shocks detected
  • EGARCH Strike — Pivot to the Exponential GARCH to model why 'Negative News' creates more noise than 'Positive News'.
  • GJR-GARCH — An alternative standard for modeling leverage effects in volatile systems.
non normal tails
  • Student-t GARCH — The mandatory pivot when residuals follow a heavy-tailed 'Leptokurtic' distribution.
  • GED-GARCH — Use the Generalized Error Distribution to capture extreme clinical shocks.
volatility feedback
  • GARCH-in-Mean (GARCH-M) — Explicitly model how the 'Risk' level influences the 'Return' or mean trajectory.
06Adjusted Comparisons

Post-hoc

Group mean comparisons and correction controls (e.g. Tukey HSD, Bonferroni) to protect against Family-Wise Error Rates.

The omnibus test opens the door; post-hoc analysis explores the room.
Forensic Detail
Adjusted Comparisons
  • Test standardized residuals for remaining ARCH effects
  • Compare different error distributions (normal, t, GED)
  • Ljung-Box test on squared standardized residuals
  • Examine persistence: alpha + beta close to 1 indicates high persistence
  • Value-at-Risk backtesting for risk applications
Interpretation Guidelines

ARCH/GARCH models volatility clustering. Post-hoc involves model comparison and diagnostics.

07Standardized scale impact

Effect Size

Understanding effect sizes (e.g., Cohen's d, Partial Eta-Squared) and clinical impact benchmarks.

Significance is noise. Magnitude is the signal. Measure the impact, not just the probability.
Impact Magnitude
N/A
Recommended Measure
08Statistical Power

Sample Size

Guidelines for minimum sample requirements and power analysis parameters.

An underpowered study is an ethical failure. Respect the data by collecting enough of it.
Power Protocol
Floor Requirements

The 'Massive-D' Requirement: A minimum of 500-1000 timepoints is essential. Volatility models (GARCH) are extremely data-hungry; they must 'See' several clusters of high and low variance to stabilize the α/β estimates.

Effect SizeParametersRequired n
Small EffectLow Persistence (α+β=0.5)n ≈ 2000
Medium EffectModerate Persistence (α+β=0.8)n ≈ 1000
Large EffectHigh Persistence (α+β=0.95)n ≈ 500
Key considerations

The 'Non-Normal' Tax: If your temporal data has 'Heavy Tails' (extreme shocks), the GARCH math becomes even more unstable. Quadruple your sample size or use a Student-t error distribution to maintain statistical authority.

G*Power StrategyBenchmark: Conditional Heteroscedasticity. Parameters: Persistence (α+β), Error distribution, α = .05, Power = .80. Note: Power in GARCH is defined as the 'Detection of Volatility Clustering'.
09APA narrative blueprint

Reporting

How to compile statistical results into publication prose matching APA and journal style guides.

Data does not speak for itself. It requires a translator. Be clear, be precise, be honest.
Narrative Arc
10Exhibit Builder

Manuscript Lab

Copy standard summary tables and forensic reporting grids to outline analysis details.

Table 1: GARCH(1,1) Model for Financial Volatility
Model PartTermEstimateSEtp
Mean EquationConstant (mu)0.0050.0022.50.012
Variance EquationOmega (Baseline)0.0120.0043.00.003
Variance EquationAlpha (Shock)0.1500.0453.33.002
Variance EquationBeta (Persistence)0.8200.05215.77< .001
Note. Outcome: Daily Log Returns. Error Distribution: Standardized Student-t.
Beta (0.82)High Volatility Clustering. Market fear decays slowly; if today was highly volatile, there is an 82% chance tomorrow will be as well.
Alpha + Beta (0.97)Identifies Stability Boundary. The sum is < 1.0, proving the series is 'covariance stationary'—it will eventually return to its baseline volatility.
Header glossary

The 'Sensitivity' to News. Measures how much current volatility spikes in response to a sudden market swing.

The 'Memory' of Fear. Measures how long high volatility lasts before settling back to normal. Values near 1.0 indicate long-lasting market turbulence.

11Algorithmic Logic

Command Center

Syntax libraries and function parameters for executing calculations in stats packages.

Code is the modern laboratory. Clean execution ensures reproducible discovery.
Execution Engine
# 1. Specify GARCH(1,1) Model
spec <- rugarch::ugarchspec(variance.model = list(model = 'sGARCH', garchOrder = c(1, 1)))

# 2. Fit Model
model <- rugarch::ugarchfit(spec = spec, data = returns)
print(model)

# 3. Forecast Future Volatility
forecast <- rugarch::ugarchforecast(model, n.ahead = 10)
plot(forecast)
Library stack
R
rugarchfGarch
Python
arch
Elite Forensic Strike

Traditional models assume returns are 'Normal'. They aren't. Always use a 'Student-t' or 'skew-GED' error distribution in GARCH to account for 'Fat Tails' (extreme market crashes).

# Audit for Fat Tails
# Re-specify model with distribution = 'std'
12The Over-adjustment Trap

Common Mistakes

Analytical caveats and corrections to maintain modeling integrity.

Wisdom is learning from the failures of others. Anticipate the error before it occurs.
Defensive Logic
Why it's wrong
If no ARCH effects present (constant variance), GARCH is unnecessary and adds complexity without benefit. ARCH-LM test must confirm heteroskedasticity. Fitting GARCH to constant variance data: overfitting, unstable estimates, no forecasting improvement. Wastes computational resources
The correction
ALWAYS test for ARCH effects FIRST using ARCH-LM test or Ljung-Box on squared residuals. H₀=no ARCH effects. If p>0.05: no ARCH, use constant variance (OLS with robust SE). If p<0.05: ARCH present, proceed with GARCH. Visual check: plot squared residuals for clustering. Test is prerequisite for GARCH. Never fit GARCH blindly without testing
Why it's wrong
Price levels are non-stationary (unit root), violate GARCH stationarity assumption. Results spurious, parameters meaningless. GARCH requires stationary mean process. Financial theory: returns (not prices) have time-varying volatility. Prices have trending volatility (spurious)
The correction
ALWAYS use returns, not prices. Calculate log returns: r_t = ln(P_t/P_{t-1}) or simple returns: (P_t - P_{t-1})/P_{t-1}. Log returns preferred (time-additive, symmetric). Test returns for stationarity (ADF test). Returns typically stationary with mean≈0, time-varying variance. GARCH models conditional variance of returns. This is fundamental: GARCH on returns, never on price levels
Why it's wrong
Equity returns show leverage effect: negative shocks increase volatility MORE than positive shocks of same magnitude. Standard GARCH(1,1) symmetric: assumes equal impact. Ignoring asymmetry: model misspecified, biased volatility forecasts, underestimated downside risk, poor VaR estimates
The correction
Test for leverage effects: sign bias test, news impact curve. If present (common in equities): use asymmetric models. EGARCH: allows γ<0 for leverage, ln(σ²_t) = ω + α|z_{t-1}| + γ·z_{t-1} + β·ln(σ²_{t-1}). GJR-GARCH: adds threshold term γ·ε²_{t-1}·I_{ε<0}. Compare AIC: asymmetric model typically better for stocks. Bonds/FX: leverage weaker, symmetric GARCH may suffice. Always test and compare
Why it's wrong
GARCH(1,1) captures volatility clustering in most financial data. Higher orders (p>1, q>2): overfitting, numerical instability, parameter redundancy, poor out-of-sample forecasts. Violates parsimony. Estimation often fails to converge. High orders rarely justified theoretically
The correction
Start with GARCH(1,1): most parsimonious, captures persistence. If diagnostics fail: try GARCH(1,2) or GARCH(2,1), but rarely need p,q>2. Use information criteria (AIC/BIC) to compare. Check if higher-order parameters significant. Literature: GARCH(1,1) adequate 90%+ of time. If GARCH(1,1) inadequate: consider alternative models (EGARCH, component GARCH, regime-switching) rather than high p,q
Why it's wrong
Financial returns have fat tails (high kurtosis), more extreme events than normal. Normal GARCH underestimates tail risk, gives poor VaR estimates (too optimistic), misses extreme losses. Student-t distribution fits much better. Normal assumption: prediction intervals too narrow, risk underestimated
The correction
Use Student-t distribution for GARCH: accommodates fat tails via df parameter. Typical df=5-15 for financial data. Compare: fit GARCH with normal and t, check AIC/log-likelihood. t almost always superior. For extreme asymmetry: skewed-t distribution. Alternative: GED (generalized error). Check Q-Q plot of standardized residuals: if heavy deviation from normal line, use t. This is critical for risk management (VaR, ES)
Why it's wrong
GARCH models variance of residuals from mean equation. If mean model wrong (autocorrelation remains), GARCH captures mean structure not variance, parameters biased. Must have white noise residuals in mean before modeling variance. Sequence matters: mean THEN variance
The correction
Correct workflow: (1) Specify mean equation: constant, ARMA, or regression. (2) Estimate mean model, extract residuals. (3) Test residuals: Ljung-Box test (p>0.05 = white noise). (4) Test squared residuals for ARCH effects. (5) If ARCH present, apply GARCH to residuals. Some software does joint ARMA-GARCH estimation. Never apply GARCH if mean residuals autocorrelated: fix mean model first
Why it's wrong
GARCH requires large samples for stable parameter estimation. Small n: high variance in estimates, poor convergence, unreliable forecasts. GARCH(1,1) needs ≥500 observations, complex models ≥1000. Persistence parameter (α+β) particularly sensitive to sample size. Short series: estimates unstable
The correction
Check sample size: n≥500 minimum for GARCH(1,1), n≥1000 for EGARCH/GJR, n≥2000 for multivariate GARCH. If insufficient data: (1) Use higher frequency (daily instead of weekly). (2) Simpler models: ARCH(1), exponential smoothing for variance. (3) RiskMetrics (no estimation, exponential smoothing). (4) Acknowledge limitation, report wide confidence intervals. Never fit complex GARCH to small samples
Why it's wrong
GARCH models conditional variance: σ²_t|I_{t-1} (variance given information up to t-1). Unconditional variance: E[σ²_t] = ω/(1-α-β) if α+β<1. These are different. Unconditional variance is long-run average. Forecasting uses conditional variance (time-varying). Mixing them causes interpretation errors
The correction
Understand distinction: Conditional variance σ²_t varies over time (GARCH output), depends on recent shocks and past variance. Unconditional variance is constant (long-run average), exists only if α+β<1. For forecasting: use conditional variance. For long-term risk: unconditional variance. Compare: E[σ²_t] vs sample variance. If α+β≈1 (IGARCH): unconditional variance undefined, only conditional variance meaningful. Always specify which variance you're reporting
Why it's wrong
In-sample fit doesn't guarantee good forecasts. GARCH used for risk management (VaR), must validate forecasts. Without backtesting: unknown if VaR estimates accurate. Overconfident risk measures lead to underestimation of losses. Regulatory requirement: VaR models must be backtested
The correction
ALWAYS backtest VaR: (1) Rolling window: estimate GARCH, forecast 1-day VaR, compare to actual return. (2) Count violations: actual return < VaR. (3) 5% VaR should have ≈5% violation rate. (4) Kupiec test: tests if violation rate = nominal level (p>0.05 = adequate). (5) Christoffersen test: tests violation independence. If too many violations: model underestimates risk. Report backtesting results alongside VaR forecasts. This validates model credibility
Why it's wrong
GARCH(1,1) common but not universal. Data may have: leverage effects (need EGARCH/GJR), long memory (need FIGARCH), structural breaks (need regime-switching), multiple components (need component GARCH). Blindly using GARCH(1,1): may miss important features, biased forecasts. One-size-fits-all approach fails
The correction
Systematic model selection: (1) Start with GARCH(1,1) baseline. (2) Test for leverage: sign bias test. If significant: try EGARCH/GJR-GARCH. (3) Check persistence: if α+β≈1, try IGARCH or FIGARCH. (4) Test for breaks: CUSUM test. If breaks: regime dummies or Markov-switching. (5) Compare models via AIC/BIC and forecast performance. (6) Run diagnostics: ARCH-LM test on residuals. Choose model based on data characteristics and forecast accuracy, not convention
Why it's wrong
Persistence (α+β) is key metric, not individual α, β. High persistence (α+β≈0.95-0.99): shocks decay slowly, long volatility memory, forecasts converge slowly to long-run mean. Low persistence: quick decay. α+β≈1 (IGARCH): infinite persistence. Focusing only on α or β misses the dynamic picture
The correction
Always report and interpret α+β (persistence). α: immediate response to shock. β: how much past variance carries forward. α+β: total persistence. High persistence (>0.95): volatility shocks very persistent (common in finance). Calculate half-life: ln(0.5)/ln(α+β) days for shock to decay 50%. Example: α+β=0.98 → half-life≈35 days. Unconditional variance: ω/(1-α-β). If α+β→1: unconditional variance very large or undefined. Persistence drives forecast dynamics
13Academic Lineage

References

Scholarly lineage and citation keys grounding the statistical framework.

We stand on the shoulders of giants. Honor the source of the method.
Academic Lineage
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
In a volatile world, the mean is often irrelevant. It is the width of the story that contains the most information. Use GARCH to measure the volume of the noise.
The Interpretive Rigor Directive
statminds · ARCH/GARCHMind reference · v2.2 · updated 2026-01-1715 of 15 sections