A time-series model that captures volatility clustering — the tendency for large price moves to follow other large moves — by modeling variance as a function of past shocks and past variance.
In Plain English
Stock volatility does not stay constant. Markets go through calm periods where daily moves are small and predictable, followed by turbulent periods where price swings are large and erratic. And crucially, turbulence tends to cluster: if the market drops 3% today, there's a much higher chance of another large move tomorrow than there would be on a typical day. This phenomenon — volatility clustering — is one of the most robust and reproducible patterns in financial data.
GARCH (Generalized Autoregressive Conditional Heteroskedasticity) is the workhorse model for capturing this behavior. Don't let the intimidating name put you off. The core idea is simple: tomorrow's variance is a weighted combination of today's unexpected return (surprise) and today's variance (current volatility level). Large surprises and currently high volatility both increase the forecast for tomorrow's volatility.
Imagine filling a bathtub. GARCH says: the amount of water that will drain through tomorrow depends partly on how much you splashed in today (the shock) and partly on how full the tub currently is (current variance). A big splash combined with an already-full tub means a lot will drain. A small splash in an empty tub barely matters.
For risk managers, this means volatility estimates should not be static. Using the same 30-day historical volatility figure for options pricing, position sizing, or VaR calculations regardless of what's happening in the market is dangerously naive. GARCH provides a time-varying, forward-looking volatility estimate that responds to recent market conditions.
Technical Definition
The GARCH(p,q) model specifies the conditional variance h_t of a return series r_t = μ + ε_t, where ε_t = √h_t × z_t and z_t ~ i.i.d. N(0,1):
h_t = ω + Σᵢ₌₁ᵖ αᵢε²_\{t-i\} + Σⱼ₌₁ᵍ βⱼh_\{t-j\}
The most common specification is GARCH(1,1):
h_t = ω + αε²_\{t-1\} + βh_\{t-1\}
where:
- ω > 0: long-run variance floor
- α ≥ 0: reaction coefficient (weight on most recent shock)
- β ≥ 0: persistence coefficient (weight on recent variance)
- α + β < 1 for stationarity; typical values α ≈ 0.05-0.15, β ≈ 0.80-0.92
Long-run (unconditional) variance: σ² = ω / (1 − α − β)
Multi-step forecasts: h_\{t+k|t\} mean-reverts toward σ² at rate (α + β)^k.
Extensions: EGARCH (asymmetric — negative shocks increase volatility more than positive shocks), GJR-GARCH (leverage effect), GARCH-M (volatility in the mean equation), DCC-GARCH (multivariate dynamic conditional correlations).
How VectorFin Uses This
VectorFin's signals/volatility table provides three GARCH-derived forecast horizons for each ticker, computed nightly from daily return history:
garch_vol_1d: next-day annualized volatility forecastgarch_vol_5d: 5-day ahead annualized volatility forecastgarch_vol_21d: 21-day ahead (approximately 1-month) forecast
These are stored with full bitemporal history — you can retrieve the forecast that would have been available on any past date, which is essential for realistic strategy backtesting.
GET https://api.vectorfinancials.com/v1/signals/volatility/{ticker}?date=2024-10-01The regime signal in signals/regime is partly derived from GARCH volatility regimes: when garch_vol_21d exceeds a rolling 90th percentile threshold, the regime classifier assigns higher probability to the "volatile" regime state.
Code Example
import requests
import pandas as pd
import numpy as np
API_BASE = "https://api.vectorfinancials.com"
API_KEY = "vf_your_api_key_here"
# Fetch GARCH volatility forecasts for options pricing
resp = requests.get(
f"{API_BASE}/v1/signals/volatility/TSLA",
params={"start": "2024-01-01", "end": "2024-12-31"},
headers={"X-API-Key": API_KEY},
)
vol_data = pd.DataFrame(resp.json()["data"])
vol_data["date"] = pd.to_datetime(vol_data["date"])
vol_data = vol_data.set_index("date")
print(vol_data[["garch_vol_1d", "garch_vol_5d", "garch_vol_21d"]].describe())
# Vol regime classification based on GARCH forecasts
vol_data["vol_regime"] = pd.cut(
vol_data["garch_vol_21d"],
bins=[0, 0.25, 0.50, 0.75, float("inf")],
labels=["low", "medium", "high", "extreme"]
)
print("\nVol regime distribution (TSLA 2024):")
print(vol_data["vol_regime"].value_counts(normalize=True).round(3))
# Position sizing: inverse vol weighting
vol_data["position_weight"] = 0.20 / vol_data["garch_vol_21d"] # target 20% portfolio vol
vol_data["position_weight"] = vol_data["position_weight"].clip(0.5, 3.0)
print(f"\nMean position weight: {vol_data['position_weight'].mean():.2f}x")Related Terms
External References
Put GARCH to work in your pipeline
Access AI-ready financial data — embeddings, signals, Iceberg tables.