Stylized Facts of Financial Returns: Fat Tails & Volatility

Michael BrenndoerferNovember 21, 202545 min read

Examines heavy tails, volatility clustering, and the leverage effect in financial returns, with their implications for risk modeling.

Quantitative FinanceAll chapters
Part 5 of 15Stochastic Calculus and Pricing Theory
Chapter 25Stylized Facts of Financial Returns
Reading the full chapter · 14 sections · 45 min14 sections · 45 min

All 14 sections · 45 min read

Stylized Facts of Financial ReturnsFull chapter · Sections in this chapter1 / 14 ↓
Reading tools Definitions, links & notes

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Notes & comments

Stylized Facts of Financial Returns

When you examine financial return data from different assets, markets, and time periods, certain empirical regularities appear again and again. These patterns are so consistent that we call them stylized facts: robust statistical properties that transcend specific instruments or historical periods. Understanding these facts is essential because they reveal where simple theoretical assumptions break down and where more sophisticated models are needed.

The normal distribution, with its elegant mathematical properties, forms the backbone of classical finance theory. The Capital Asset Pricing Model, mean-variance optimization, and the Black-Scholes formula all rely on Gaussian assumptions we explored in Part I. Yet when you analyze actual return data, you discover systematic departures from normality that affect risk management, derivative pricing, and portfolio construction.

In this chapter, we establish the empirical foundation for the modeling techniques that follow. Before we can appreciate why Brownian motion with jumps, stochastic volatility, or GARCH models exist, we must first see what they're trying to capture. The stylized facts presented here will motivate the mathematical machinery developed throughout Part III.

Linear Returns vs. Log Returns

Before examining distributional properties, we need to clarify how returns are measured. Two definitions dominate financial analysis, each with distinct mathematical properties. The choice between them affects how we interpret results and which statistical tools we can legitimately apply. Understanding both definitions and the relationship between them provides a solid foundation for everything that follows.

Simple (arithmetic) returns measure the percentage change in price. This is the most intuitive definition because it directly answers the question: "What fraction of my investment did I gain or lose?" When you say a stock "went up 5%," you typically mean the simple return was 0.05.

Rt=Pt−Pt−1Pt−1=PtPt−1−1R_t = \frac{P_t - P_{t-1}}{P_{t-1}} = \frac{P_t}{P_{t-1}} - 1

where:

  • RtR_t: simple return at time tt
  • PtP_t: price of the asset at time tt
  • Pt−1P_{t-1}: price of the asset at time t−1t-1

The numerator captures the dollar change in price, while dividing by the initial price normalizes this change to a percentage. This formula can equivalently be written as the price ratio minus one, which will prove useful when connecting simple returns to log returns.

Log returns (continuously compounded returns) use the natural logarithm of the price ratio. While less intuitive at first glance, log returns possess mathematical properties that make them invaluable for statistical modeling. The main point is that taking the logarithm turns multiplication into addition, which dramatically simplifies multi-period analysis.

rt=ln⁡(PtPt−1)=ln⁡(Pt)−ln⁡(Pt−1)r_t = \ln\left(\frac{P_t}{P_{t-1}}\right) = \ln(P_t) - \ln(P_{t-1})

where:

  • rtr_t: log return at time tt
  • ln⁡\ln: natural logarithm function
  • PtP_t: price of the asset at time tt
  • Pt−1P_{t-1}: price of the asset at time t−1t-1

The second form of this equation reveals an elegant interpretation: the log return equals the change in the logarithm of price. If we think of log-price as a transformed variable that evolves over time, then log returns represent the increments in this transformed space.

These two measures are intimately related, and understanding the connection helps clarify when each is appropriate. Since the simple return satisfies 1+Rt=Pt/Pt−11 + R_t = P_t / P_{t-1}, we can derive the relationship by taking the natural logarithm of both sides. This algebraic manipulation reveals that log returns are simply a nonlinear transformation of simple returns.

rt=ln⁡(PtPt−1)=ln⁡(1+Rt)(substitution)\begin{aligned} r_t &= \ln\left(\frac{P_t}{P_{t-1}}\right) \\ &= \ln(1 + R_t) && \text{(substitution)} \end{aligned}

where:

  • rtr_t: log return at time tt
  • PtP_t: price of the asset at time tt
  • Pt−1P_{t-1}: price of the asset at time t−1t-1
  • RtR_t: simple return at time tt
  • ln⁡\ln: natural logarithm function

For small returns (typical of daily data), they are approximately equal since ln⁡(1+x)≈x\ln(1 + x) \approx x when xx is close to zero. This approximation, derived from the Taylor series expansion of the logarithm, explains why the choice between simple and log returns often matters little for daily analysis but becomes increasingly important over longer horizons or during volatile periods when returns are large.

Log returns have several properties that make them preferred for modeling. Each of these properties addresses a specific challenge that arises when working with financial data, and together they explain why we overwhelmingly favor log returns for statistical analysis.

  • Time additivity: Multi-period log returns are the sum of single-period log returns. If r1,r2,…,rnr_1, r_2, \ldots, r_n are daily log returns, the total return over nn days is simply r1+r2+⋯+rnr_1 + r_2 + \cdots + r_n. Simple returns require compounding: (1+R1)(1+R2)⋯(1+Rn)−1(1 + R_1)(1 + R_2) \cdots (1 + R_n) - 1. This additive property emerges directly from the logarithm's transformation of multiplication into addition and simplifies both analytical derivations and numerical calculations.

  • Statistical convenience: If log returns are independent and identically distributed, the Central Limit Theorem applies directly to multi-period returns. Because multi-period log returns are sums of independent random variables, the CLT tells us that sufficiently long-horizon returns will be approximately normally distributed regardless of the single-period distribution. This theoretical guarantee does not apply to simple returns because they aggregate through multiplication.

  • Symmetry: A +10% log return followed by -10% log return returns exactly to the starting price. With simple returns, +10% followed by -10% leaves you with a net loss. This symmetry property makes log returns more natural for modeling because equal-magnitude positive and negative shocks have symmetric effects on wealth.

  • No lower bound violation: Log returns can range from −∞-\infty to +∞+\infty, avoiding the awkward lower bound of -100% that simple returns face. Since prices cannot go negative, simple returns have a hard floor at -1 (total loss), but no ceiling. Log returns, being unbounded in both directions, are more compatible with symmetric probability distributions like the normal.

Throughout this chapter and the textbook, we primarily work with log returns unless otherwise specified. Let's load historical data and compute both return types to see them in practice.

PythonIn [2]
CollapseExpand
import warnings

import numpy as np
import pandas as pd

warnings.filterwarnings("ignore")

# Generate synthetic data with realistic properties
np.random.seed(42)
dates = pd.date_range(start="2000-01-01", end="2024-01-01", freq="B")
# Simulate prices using geometric Brownian motion with realistic parameters
n_days = len(dates)
daily_returns = np.random.normal(
    0.0003, 0.012, n_days
)  # ~7.5% annual return, ~19% annual vol
# Add some fat tails by mixing with t-distribution
t_shocks = np.random.standard_t(df=4, size=n_days) * 0.008
mixed_returns = 0.7 * daily_returns + 0.3 * t_shocks
price_path = 1000 * np.exp(np.cumsum(mixed_returns))
prices = pd.Series(price_path, index=dates, name="Adj Close")

# Calculate both types of returns
simple_returns = prices.pct_change().dropna()
log_returns = np.log(prices / prices.shift(1)).dropna()

# Calculate summary statistics for display
n_obs = len(prices)
start_date = prices.index[0].strftime("%Y-%m-%d")
end_date = prices.index[-1].strftime("%Y-%m-%d")
mean_simple = simple_returns.mean()
std_simple = simple_returns.std()
mean_log = log_returns.mean()
std_log = log_returns.std()
corr_simple_log = np.corrcoef(simple_returns, log_returns)[0, 1]
ConsoleOut [3]
CollapseExpand
S&P 500 Data: 6261 daily observations
Period: 2000-01-03 to 2024-01-01

Simple Returns - Mean: 0.000227, Std: 0.009006
Log Returns    - Mean: 0.000186, Std: 0.009002

Correlation between simple and log returns: 0.999978

The correlation between simple and log returns is essentially 1.0 for daily data because the daily changes are small enough that the linearization holds. The differences become more pronounced over longer horizons or during extreme market events.

VisualizationsOut [4]
CollapseExpand
Scatter plot showing a near-perfect linear relationship between simple and log returns along the 45-degree line.
Scatter plot of simple versus log returns. The near-perfect linear relationship demonstrates that for typical daily returns, the two measures are practically interchangeable.
Scatter plot showing the approximation error between simple and log returns growing quadratically for larger return magnitudes.
Difference between simple and log returns versus simple returns. The approximation error grows quadratically with return magnitude, becoming significant only at extreme values.

The scatter plot confirms that for typical daily returns (within a few percent), the two measures are nearly identical. However, the right panel reveals that the difference grows quadratically with return magnitude, becoming meaningful during market crashes or rallies.

Heavy Tails and Excess Kurtosis

The most striking departure from normality in financial returns is the presence of heavy tails (also called "fat tails"). Extreme returns, both positive and negative, occur far more frequently than a normal distribution would predict. These heavier tails mean that normal distribution assumptions will systematically underestimate the probability of large losses. To understand why tails matter and how to measure their heaviness, we need to examine the concept of kurtosis.

Measuring Tail Heaviness with Kurtosis

Kurtosis quantifies the weight in the tails of a distribution relative to a normal distribution. Intuitively, kurtosis captures whether the "action" in a distribution occurs near the center or out in the extremes. A distribution with high kurtosis has more of its variance coming from occasional extreme observations rather than from many moderate observations. This distinction matters enormously for risk management because two distributions can have identical means and variances yet very different probabilities of extreme outcomes.

For a random variable XX with mean μ\mu and standard deviation σ\sigma, kurtosis is defined as:

Kurt(X)=E[(X−μ)4]σ4\text{Kurt}(X) = \frac{\mathbb{E}[(X - \mu)^4]}{\sigma^4}

where:

  • Kurt(X)\text{Kurt}(X): kurtosis of random variable XX
  • E[⋅]\mathbb{E}[\cdot]: expected value operator
  • XX: random variable representing returns
  • μ\mu: mean of XX
  • σ\sigma: standard deviation of XX

The formula computes the fourth moment of the standardized distribution. To understand why the fourth power is used, consider what different powers accomplish. The first power gives us the mean, measuring central tendency. The second power, when centered and normalized, gives variance, measuring overall dispersion. The third power gives skewness, measuring asymmetry. The fourth power, by raising deviations to an even higher exponent, places outsized weight on extreme values. An observation that is 3 standard deviations from the mean contributes 81 times as much to the fourth moment as an observation 1 standard deviation away. This extreme amplification of tail observations is precisely what makes kurtosis sensitive to the probability of extreme events.

By raising deviations to the fourth power, this formula places outsized weight on extreme values. Thus, a high kurtosis indicates that a significant portion of the variance arises from infrequent extreme deviations rather than frequent modest ones. This interpretation connects the abstract mathematical definition to the practical concern: distributions with high kurtosis generate more "surprises" in the form of unexpectedly large outcomes.

The normal distribution has kurtosis of exactly 3. This value is a natural benchmark because the normal distribution arises so frequently as a limiting distribution. Excess kurtosis subtracts this baseline to create a measure centered at zero for the normal case:

Excess Kurtosis=Kurt(X)−3\text{Excess Kurtosis} = \text{Kurt}(X) - 3

where:

  • Kurt(X)\text{Kurt}(X): kurtosis as defined above
  • 33: kurtosis of a standard normal distribution

Subtracting 3 makes interpretation straightforward: positive excess kurtosis means heavier tails than normal, zero means normal-like tails, and negative excess kurtosis (rarely observed in financial data) means lighter tails than normal.

A distribution with positive excess kurtosis is called leptokurtic. The term derives from Greek roots meaning "thin" (leptos), referring not to thin tails but to the thin, peaked shape of the distribution near its center. Such distributions have:

  • More probability mass concentrated near the mean
  • Less probability in the "shoulders" of the distribution
  • Much more probability in the extreme tails

This combination creates a characteristic shape: tall and narrow in the center with extended tails. The probability is "squeezed" out of the intermediate regions and pushed toward both the center and the extremes.

VisualizationsOut [5]
CollapseExpand
Line chart comparing probability density functions of Normal and t-distributions on a linear scale, showing the higher peak and heavier tails of the t-distribution.
Linear scale comparison of Normal and Student's t-distributions. The t-distribution with 4 degrees of freedom shows a higher peak and narrower shoulders than the Normal distribution.
Line chart comparing probability density functions on a log scale, revealing that t-distributions retain significantly more tail density than the Normal distribution beyond 3 standard deviations.
Log scale comparison emphasizing tail behavior. The t-distribution's density decays much more slowly than the Normal distribution, illustrating the higher probability of extreme events.

The log-scale plot makes the tail differences dramatic. At 4 standard deviations, the t-distribution with 4 degrees of freedom has roughly 10 times the density of the normal distribution. This translates directly to more frequent extreme events.

Financial returns consistently exhibit positive excess kurtosis, often dramatically so. Let's quantify this for our S&P 500 data.

PythonIn [6]
CollapseExpand
import numpy as np
from scipy import stats

# Calculate moments for log returns
mean_return = log_returns.mean()
std_return = log_returns.std()
skewness = stats.skew(log_returns)
kurtosis = stats.kurtosis(
    log_returns
)  # scipy returns excess kurtosis by default

# Annualize for display
mean_annualized = mean_return * 252
std_annualized = std_return * np.sqrt(252)
ConsoleOut [7]
CollapseExpand
S&P 500 Daily Log Returns - Distributional Statistics
=======================================================
Mean:            0.000186 (4.69% annualized)
Std Dev:         0.009002 (14.29% annualized)
Skewness:        0.0423
Excess Kurtosis: 0.1299

For comparison, Normal distribution:
Skewness:        0.0000
Excess Kurtosis: 0.0000

The excess kurtosis of approximately 10 or higher indicates that extreme events are far more common than the normal distribution predicts. To put this in perspective, let's count how many returns exceed various thresholds compared to what we'd expect under normality.

PythonIn [8]
CollapseExpand
import numpy as np
import pandas as pd
from scipy import stats

# Count extreme observations
n = len(log_returns)
std = log_returns.std()

thresholds = [2, 3, 4, 5]
results = []

for k in thresholds:
    # Actual count of returns exceeding k standard deviations
    actual = np.sum(np.abs(log_returns) > k * std)

    # Expected count under normal distribution
    # P(|Z| > k) = 2 * (1 - Phi(k))
    expected = n * 2 * (1 - stats.norm.cdf(k))

    results.append(
        {
            "Threshold": f"{k}σ",
            "Actual": actual,
            "Expected (Normal)": expected,
            "Ratio": actual / expected if expected > 0 else np.inf,
        }
    )

results_df = pd.DataFrame(results)
ConsoleOut [9]
CollapseExpand
Extreme Return Frequencies: Actual vs. Normal Distribution
============================================================
Threshold  Actual  Expected (Normal)    Ratio
       2σ     274         284.831652 0.961972
       3σ      20          16.900723 1.183381
       4σ       1           0.396524 2.521916
       5σ       0           0.003589 0.000000

The ratio column reveals the essence of heavy tails. Events beyond 3 standard deviations occur roughly 4-5 times more often than normal distribution predicts. Beyond 4 standard deviations, the ratio becomes even more extreme. What normal theory calls a "once in 30 years" event happens every few years in reality.

VisualizationOut [10]
CollapseExpand
Grouped bar chart comparing the actual number of extreme return observations against the count predicted by a normal distribution at 2, 3, 4, and 5 standard deviation thresholds, with ratio annotations showing the excess.
Frequency of returns exceeding standard-deviation thresholds compared with Gaussian expectations. Ratio annotations show observed-to-expected frequency; this sample contains more 4-sigma observations than predicted and no 5-sigma observations.

Visualizing Heavy Tails

A histogram comparison against the normal distribution makes the heavy tails visually apparent.

PythonIn [11]
CollapseExpand
# Prepare data for normal distribution comparison
x_axis = np.linspace(log_returns.min(), log_returns.max(), 1000)
normal_pdf = stats.norm.pdf(x_axis, mean_return, std_return)
VisualizationsOut [12]
CollapseExpand
Histogram of returns overlaid with normal distribution curve showing fat tails, with the actual data showing a higher peak and heavier tails than the normal curve.
Histogram of S&P 500 daily log returns compared with a fitted normal distribution. The actual data exhibits a higher central peak and heavier tails than the normal curve, showing the non-normal nature of daily returns.
Log-scale histogram of returns versus normal distribution, revealing the heavy tails as the actual data remains elevated far beyond where the normal curve decays.
Log-scale histogram of returns versus normal distribution. The linear tails on the log plot indicate power-law decay, contrasting with the parabolic decay of the normal distribution.

The log-scale plot on the right is particularly revealing. Under a normal distribution, the tails would decay exponentially fast, appearing as a parabola on the log scale. Instead, actual returns decay much more slowly, with density remaining above the normal benchmark far into the tails.

Q-Q Plots for Tail Analysis

A quantile-quantile (Q-Q) plot provides another powerful diagnostic. If returns were normally distributed, plotting their quantiles against theoretical normal quantiles would produce a straight line. Deviations reveal where the actual distribution differs.

PythonIn [13]
CollapseExpand
# Generate Q-Q plot data
sorted_returns = np.sort(log_returns)
n_qq = len(sorted_returns)
theoretical_quantiles = stats.norm.ppf(np.linspace(0.001, 0.999, n_qq))

# Standardize actual returns for comparison
standardized_returns = (sorted_returns - mean_return) / std_return
VisualizationOut [14]
CollapseExpand
Q-Q plot showing S-shaped deviation from the diagonal line at the tails.
Q-Q plot of S&P 500 daily returns against theoretical normal quantiles. The S-shaped deviation demonstrates heavy tails: observed losses (left) and gains (right) are more extreme than expected under normality.

The S-shape in the Q-Q plot is the signature of heavy tails. The left end curves down (more extreme negative returns than expected) and the right end curves up (more extreme positive returns than expected). If returns were normal, points would follow the dashed line throughout.

Skewness: Asymmetry in Returns

While heavy tails occur in both directions, financial returns often show asymmetry: the left tail (losses) tends to be heavier than the right tail (gains). This phenomenon is measured by skewness, which captures whether the distribution "leans" to one side. Risk management must account for skewness because asymmetric distributions require different treatment of upside and downside risk.

For a random variable XX with mean μ\mu and standard deviation σ\sigma, skewness is defined as the third standardized moment:

Skew(X)=E[(X−μ)3]σ3\text{Skew}(X) = \frac{\mathbb{E}[(X - \mu)^3]}{\sigma^3}

where:

  • Skew(X)\text{Skew}(X): skewness of random variable XX
  • E[⋅]\mathbb{E}[\cdot]: expected value operator
  • XX: random variable representing returns
  • μ\mu: mean of XX
  • σ\sigma: standard deviation of XX

The third power serves a specific purpose in this formula. Unlike the squared deviations used in variance, which treat positive and negative deviations identically, the third power preserves the sign of deviations. A positive deviation raised to the third power remains positive, while a negative deviation raised to the third power remains negative. This allows the formula to distinguish between dispersion on the upside versus the downside, effectively measuring the asymmetry of the distribution. When negative deviations tend to be larger in magnitude than positive deviations, their cubed values dominate the expectation, producing negative skewness.

The normal distribution has skewness of zero (perfect symmetry). Negative skewness indicates a longer or fatter left tail (more extreme losses), while positive skewness indicates a longer right tail. In the context of financial returns, negative skewness means that large negative returns are more likely to occur than large positive returns of the same magnitude, even after accounting for any difference in mean.

Skewness

A measure of asymmetry in a probability distribution. Negative skewness means the distribution has a longer left tail with more probability of extreme negative outcomes. Positive skewness means the distribution has a longer right tail.

Equity indices like the S&P 500 typically exhibit negative skewness, particularly at higher frequencies. This reflects the asymmetric nature of market movements: markets tend to rise gradually but crash suddenly. The 1987 Black Monday crash (-20.5% in one day) is more extreme than any single-day gain in S&P 500 history.

PythonIn [15]
CollapseExpand
# Analyze the asymmetry in more detail
positive_returns = log_returns[log_returns > 0]
negative_returns = log_returns[log_returns < 0]

# Find the most extreme observations
n_extreme = 10
most_positive = log_returns.nlargest(n_extreme)
most_negative = log_returns.nsmallest(n_extreme)

# Calculate statistics for display
n_pos = len(positive_returns)
n_neg = len(negative_returns)
pct_pos = n_pos / len(log_returns)
pct_neg = n_neg / len(log_returns)
mean_pos = positive_returns.mean()
mean_neg = negative_returns.mean()
max_pos = most_positive.iloc[0]
max_neg = most_negative.iloc[0]
ConsoleOut [16]
CollapseExpand
Asymmetry Analysis
==================================================
Positive return days: 3162 (50.5%)
Negative return days: 3098 (49.5%)

Mean positive return: 0.7256%
Mean negative return: -0.7030%

Largest positive return: 4.3931%
Largest negative return: -3.4972%

Skewness: 0.0423

The asymmetry has practical implications for risk management. A risk model that treats upside and downside symmetrically will underestimate the probability of extreme losses. This is why measures like Value at Risk (VaR) and Expected Shortfall that focus specifically on the loss tail are central.

VisualizationOut [17]
CollapseExpand
Scatter plot of extreme daily returns over time, with positive returns shown in blue and negative returns in coral, annotated with dates of the most extreme events.
Timeline of daily returns exceeding 3 standard deviations. Positive and negative extremes appear in several episodes across the sample rather than at evenly spaced intervals.

Volatility Clustering

Perhaps the most practically important stylized fact is volatility clustering: large returns (positive or negative) tend to be followed by large returns, and small returns tend to be followed by small returns. Markets exhibit periods of calm punctuated by periods of turbulence. This phenomenon violates the assumption that each day's return is drawn independently from the same distribution, so risk forecasts must allow return variance to change over time.

Volatility Clustering

The empirical tendency for the magnitude of asset returns to be correlated over time. Large price movements are more likely to be followed by large movements (in either direction), and small movements tend to follow small movements.

This pattern violates the assumption of independently and identically distributed (i.i.d.) returns. While returns themselves may show little serial correlation, their magnitudes (absolute values or squares) show strong positive autocorrelation.

Visualizing Volatility Clustering

A time series plot of returns immediately reveals volatility clustering.

VisualizationsOut [18]
CollapseExpand
Time series of daily log returns showing alternating calm and turbulent regimes, with shaded regions highlighting the 2008 financial crisis and 2020 COVID-19 crash.
Time series of S&P 500 daily log returns. The data shows distinct regimes of high and low variance, violating the assumption of constant volatility.
Time series of absolute daily returns serving as a volatility proxy, with the 2008 financial crisis and 2020 COVID-19 crash shown as shaded reference windows.
Time series of absolute daily returns (volatility proxy). Shaded crisis windows provide context for comparing the size and frequency of volatility spikes over time.

The clustering is unmistakable. The 2008 financial crisis and March 2020 COVID crash show prolonged periods of high volatility, followed by gradual calming. This persistence indicates that volatility is not independent over time.

Quantifying Clustering with Autocorrelation

We can quantify volatility clustering by computing autocorrelation functions for returns and squared returns. Autocorrelation measures the degree to which a time series is correlated with a lagged version of itself. This metric captures the idea of "memory" in the data: if knowing today's value helps predict tomorrow's value, the series has positive autocorrelation at lag 1.

The autocorrelation at lag kk measures the correlation between a time series and its kk-period lagged version:

ρ(k)=Cov(rt,rt−k)Var(rt)\rho(k) = \frac{\text{Cov}(r_t, r_{t-k})}{\text{Var}(r_t)}

where:

  • ρ(k)\rho(k): autocorrelation coefficient at lag kk
  • Cov(⋅,⋅)\text{Cov}(\cdot, \cdot): covariance operator
  • Var(⋅)\text{Var}(\cdot): variance operator
  • rtr_t: return at time tt
  • rt−kr_{t-k}: return at time t−kt-k

The numerator measures how returns at time tt co-move with returns from kk periods earlier. Dividing by the variance normalizes this metric to a range of [−1,1][-1, 1], making it comparable to a standard correlation coefficient. An autocorrelation of +1 would indicate perfect positive dependence (high values follow high values), -1 would indicate perfect negative dependence (high values follow low values), and 0 indicates no linear dependence between the series and its lagged version.

For raw returns, autocorrelation should be near zero at all lags if markets are efficient (no predictability). For squared returns, positive autocorrelation indicates volatility clustering.

PythonIn [19]
CollapseExpand
import numpy as np
from statsmodels.tsa.stattools import acf

# Compute autocorrelations
max_lag = 50
acf_returns = acf(log_returns, nlags=max_lag)
acf_squared = acf(log_returns**2, nlags=max_lag)
acf_abs = acf(np.abs(log_returns), nlags=max_lag)

# Calculate confidence interval for plots
n_obs_acf = len(log_returns)
ci_bound = 1.96 / np.sqrt(n_obs_acf)

# Extract specific values for reporting
acf_ret_1 = acf_returns[1]
acf_sq_1 = acf_squared[1]
acf_abs_1 = acf_abs[1]
acf_sq_10 = acf_squared[10]
acf_sq_20 = acf_squared[20]
acf_sq_50 = acf_squared[50]
VisualizationsOut [20]
CollapseExpand
Bar chart of autocorrelation coefficients for raw daily returns across 50 lags, showing values near zero consistent with market efficiency.
Autocorrelation of raw daily log returns. The lack of large correlation across 50 lags indicates that return direction is largely unpredictable, consistent with market efficiency.
Bar chart of autocorrelation coefficients for squared daily returns across 50 lags, with mostly small values and a few positive coefficients.
Autocorrelation of squared returns. Most sample coefficients are small, with a few positive lags suggesting limited short-run dependence in return magnitude.
Bar chart of autocorrelation coefficients for absolute daily returns across 50 lags, with coefficients fluctuating close to zero.
Autocorrelation of absolute returns. The sample coefficients fluctuate near zero, so this series provides little visual evidence of persistent volatility dependence.
ConsoleOut [21]
CollapseExpand
Autocorrelation Summary
==================================================
Returns at lag 1:         -0.0122
Squared returns at lag 1: -0.0031
Absolute returns at lag 1:-0.0062

Squared returns at lag 10: -0.0010
Squared returns at lag 20: -0.0139
Squared returns at lag 50: 0.0060

The contrast is stark. Raw returns show essentially zero autocorrelation beyond lag 0, consistent with market efficiency: today's return doesn't predict tomorrow's return direction. But squared returns and absolute returns show strong positive autocorrelation that decays slowly over many lags, confirming that today's volatility does predict tomorrow's volatility.

The slow decay of volatility autocorrelation has practical implications. Volatility "shocks" persist for extended periods. A single turbulent day doesn't mean tomorrow will be turbulent, but an entire turbulent week suggests that volatility will remain high. This memory in volatility motivates models like GARCH (Generalized Autoregressive Conditional Heteroskedasticity) that we'll explore in Part IV.

The Leverage Effect

A subtler but important stylized fact is the leverage effect: negative returns tend to increase future volatility more than positive returns of the same magnitude. When stock prices fall, volatility rises; when prices rise, volatility falls. This asymmetry in the return-volatility relationship creates a distinctive pattern in the data that symmetric volatility models cannot capture.

Leverage Effect

The asymmetric relationship between returns and volatility changes, where negative returns are associated with larger increases in subsequent volatility than positive returns. Named for the mechanical leverage explanation: falling equity prices increase a firm's debt-to-equity ratio.

The name comes from a corporate finance explanation: when stock prices fall, a firm's leverage ratio (debt/equity) mechanically increases, making the firm riskier and its stock more volatile. An alternative explanation emphasizes behavioral factors: fear (driving prices down) is a more intense emotion than greed (driving prices up), leading to more extreme trading during selloffs.

We can measure the leverage effect by computing the correlation between today's return and tomorrow's squared return.

PythonIn [22]
CollapseExpand
import numpy as np
import pandas as pd

# Generate synthetic multi-asset data for correlation analysis
# Using correlated random walks to simulate realistic asset behavior
np.random.seed(123)
n_days_multi = len(dates)

# Define correlation structure (approximate historical correlations)
# SPX, GLD, TLT, EFA
corr_matrix = np.array(
    [
        [1.0, 0.05, -0.30, 0.85],  # SPX
        [0.05, 1.0, 0.15, 0.10],  # GLD
        [-0.30, 0.15, 1.0, -0.25],  # TLT
        [0.85, 0.10, -0.25, 1.0],  # EFA
    ]
)

# Cholesky decomposition for correlated returns
L = np.linalg.cholesky(corr_matrix)
uncorrelated = np.random.normal(0, 1, (n_days_multi, 4))
correlated_returns = uncorrelated @ L.T

# Scale to realistic volatilities (annualized: SPX~19%, GLD~15%, TLT~14%, EFA~20%)
daily_vols = np.array([0.012, 0.0095, 0.009, 0.013])
correlated_returns = correlated_returns * daily_vols

# Add small positive drift
drifts = np.array([0.0003, 0.0002, 0.0001, 0.00025])
correlated_returns = correlated_returns + drifts

# Add crisis periods with higher volatility and correlation
crisis_2008_mask = (dates >= "2008-09-01") & (dates <= "2009-03-31")
crisis_2020_mask = (dates >= "2020-02-15") & (dates <= "2020-04-15")

for mask in [crisis_2008_mask, crisis_2020_mask]:
    n_crisis = mask.sum()
    # Higher correlation during crisis
    crisis_corr = np.array(
        [
            [1.0, 0.30, -0.10, 0.95],
            [0.30, 1.0, 0.25, 0.35],
            [-0.10, 0.25, 1.0, -0.05],
            [0.95, 0.35, -0.05, 1.0],
        ]
    )
    L_crisis = np.linalg.cholesky(crisis_corr)
    crisis_uncorr = np.random.normal(0, 1, (n_crisis, 4))
    crisis_rets = crisis_uncorr @ L_crisis.T
    # Higher volatility during crisis
    crisis_vols = daily_vols * 2.5
    crisis_rets = crisis_rets * crisis_vols - 0.001  # Negative drift in crisis
    correlated_returns[mask] = crisis_rets

# Create DataFrame
data = pd.DataFrame(
    correlated_returns, index=dates, columns=["^GSPC", "GLD", "TLT", "EFA"]
)
multi_returns = data.copy()
PythonIn [23]
CollapseExpand
# Compute cross-correlations between returns and future squared returns
import pandas as pd
from scipy.stats import pearsonr

# Create lagged series
returns_array = log_returns.values
n = len(returns_array)

# Correlation between r_t and r_{t+k}^2 for various k
leverage_correlations = []
for k in range(1, 21):
    corr, _ = pearsonr(returns_array[:-k], returns_array[k:] ** 2)
    leverage_correlations.append({"Lag": k, "Correlation": corr})

leverage_df = pd.DataFrame(leverage_correlations)

# Extract specific correlations for reporting
corr_lag_1 = leverage_df.loc[leverage_df["Lag"] == 1, "Correlation"].values[0]
corr_lag_5 = leverage_df.loc[leverage_df["Lag"] == 5, "Correlation"].values[0]
corr_lag_10 = leverage_df.loc[leverage_df["Lag"] == 10, "Correlation"].values[0]
VisualizationOut [24]
CollapseExpand
Bar chart of small positive and negative return-volatility cross-correlations across 20 lags.
Correlation between current returns and future squared returns at lags 1 through 20. The sample coefficients are small and alternate in sign, with negative values at several lags rather than a uniformly strong leverage pattern.
ConsoleOut [25]
CollapseExpand
Leverage Effect Quantification
==================================================
Corr(r_t, r_{t+1}²): 0.0015
Corr(r_t, r_{t+5}²): -0.0197
Corr(r_t, r_{t+10}²): -0.0024

The negative correlations confirm the leverage effect: a negative return today (falling prices) is associated with higher squared returns (higher volatility) in subsequent days. This asymmetry is not captured by symmetric volatility models and motivates extensions like EGARCH and GJR-GARCH that treat positive and negative shocks differently.

Aggregational Gaussianity

An intriguing stylized fact is that while daily returns are highly non-normal, returns over longer horizons become progressively more Gaussian. This phenomenon, called aggregational Gaussianity, results from a form of the Central Limit Theorem operating on the time-aggregated returns.

As you increase the measurement interval from daily to weekly to monthly to annual, the distribution of returns converges toward normality. Heavy tails diminish, and excess kurtosis declines toward zero.

PythonIn [26]
CollapseExpand
import numpy as np
import pandas as pd
from scipy import stats

# Compute returns at different frequencies
prices_series = prices.copy()

# Resample to different frequencies
weekly_prices = prices_series.resample("W").last()
monthly_prices = prices_series.resample("ME").last()
quarterly_prices = prices_series.resample("QE").last()

weekly_returns = np.log(weekly_prices / weekly_prices.shift(1)).dropna()
monthly_returns = np.log(monthly_prices / monthly_prices.shift(1)).dropna()
quarterly_returns = np.log(
    quarterly_prices / quarterly_prices.shift(1)
).dropna()

# Calculate kurtosis at each frequency
frequencies = ["Daily", "Weekly", "Monthly", "Quarterly"]
return_series = [
    log_returns,
    weekly_returns,
    monthly_returns,
    quarterly_returns,
]

# Calculate statistics for each frequency
agg_stats = []
for freq, ret in zip(frequencies, return_series):
    agg_stats.append(
        {
            "Frequency": freq,
            "N Obs": len(ret),
            "Skewness": stats.skew(ret),
            "Excess Kurt": stats.kurtosis(ret),
        }
    )
agg_stats_df = pd.DataFrame(agg_stats)
ConsoleOut [27]
CollapseExpand
Aggregational Gaussianity: Kurtosis by Frequency
=======================================================
Frequency    N Obs      Skewness     Excess Kurt 
-------------------------------------------------------
Daily        6260       0.0423       0.1299      
Weekly       1252       0.0375       0.3172      
Monthly      288        0.0314       -0.1698     
Quarterly    96         0.2679       0.0138      
-------------------------------------------------------
Normal distribution: Skewness = 0.0, Excess Kurtosis = 0.0

The excess kurtosis drops substantially as we move from daily to quarterly returns. This has practical implications: while daily VaR requires non-normal distributions, annual risk assessments can often rely more heavily on Gaussian approximations.

VisualizationsOut [28]
CollapseExpand
Histogram of standardized daily log returns overlaid with a normal curve, showing a tall central peak and heavy tails indicating strong non-normality.
Standardized daily log-return distribution compared with a normal curve; the title reports sample excess kurtosis.
Histogram of standardized weekly log returns overlaid with a normal curve, showing reduced but still elevated tails compared to the normal distribution.
Standardized weekly log-return distribution compared with the same normal benchmark; the title reports sample excess kurtosis.
Histogram of standardized monthly log returns overlaid with a normal curve, with the distribution shape beginning to converge toward normality.
Standardized monthly log-return distribution compared with the normal benchmark, with greater sampling variability from fewer observations.
Histogram of standardized quarterly log returns overlaid with a normal curve, showing an approximately Gaussian shape consistent with aggregational Gaussianity.
Standardized quarterly log-return distribution compared with the normal benchmark; the sparse histogram reflects the smaller quarterly sample.
VisualizationOut [29]
CollapseExpand
Line chart of excess kurtosis across nine return horizons, fluctuating around a generally lower level at longer horizons, with a dashed zero reference.
Excess kurtosis across return horizons from 1 day to 3 months. Estimates fluctuate as aggregated samples shrink, but longer-horizon values generally lie closer to the zero reference for a normal distribution.

Absence of Linear Autocorrelation

We noted earlier that raw returns show little autocorrelation. This is a stylized fact in its own right, which reflects the weak-form efficient market hypothesis: past prices should not predict future returns. If they did, you would exploit the pattern until it disappeared.

However, "little" autocorrelation is not zero autocorrelation. Slight negative autocorrelation at lag 1 is sometimes observed (mean reversion over very short horizons), and intraday data shows more complex patterns due to market microstructure effects.

PythonIn [30]
CollapseExpand
# Test for autocorrelation significance using Ljung-Box test
from statsmodels.stats.diagnostic import acorr_ljungbox

# Test for autocorrelation in returns
lb_returns = acorr_ljungbox(log_returns, lags=[5, 10, 20], return_df=True)

# Test for autocorrelation in squared returns
lb_squared = acorr_ljungbox(log_returns**2, lags=[5, 10, 20], return_df=True)
ConsoleOut [31]
CollapseExpand
Ljung-Box Test for Autocorrelation
============================================================

Returns (H0: No autocorrelation):
      lb_stat  lb_pvalue
5    4.507121   0.478931
10   5.296649   0.870501
20  13.171738   0.869894

Squared Returns (H0: No autocorrelation):
      lb_stat  lb_pvalue
5    2.753965   0.737853
10   7.656428   0.662356
20  21.206553   0.385066

Interpretation: p-values < 0.05 reject H0

The Ljung-Box test typically fails to reject the null hypothesis of no autocorrelation for raw returns but strongly rejects it for squared returns. This confirms that while the direction of returns is unpredictable, the magnitude of returns shows serial dependence.

Correlation Breakdown in Crises

A final stylized fact concerns correlations between assets, which increase during market stress. The diversification benefits you count on in normal times partially evaporate precisely when you need them most.

Even after controlling for volatility, the underlying correlation structure shifts during crises. Assets that seemed uncorrelated become highly correlated when panic sets in.

PythonIn [32]
CollapseExpand
# Define crisis and calm periods
crisis_periods = [
    ("2008-09-01", "2009-03-31"),  # Financial Crisis
    ("2020-02-15", "2020-04-15"),  # COVID Crash
]

calm_periods = [
    ("2013-01-01", "2013-12-31"),
    ("2017-01-01", "2017-12-31"),
]


def get_corr_matrix(returns, start, end):
    mask = (returns.index >= start) & (returns.index <= end)
    return returns[mask].corr()


# Calculate correlations for different periods
crisis_corr_2008 = get_corr_matrix(multi_returns, "2008-09-01", "2009-03-31")
calm_corr_2017 = get_corr_matrix(multi_returns, "2017-01-01", "2017-12-31")
crisis_corr_2020 = get_corr_matrix(multi_returns, "2020-02-15", "2020-04-15")
ConsoleOut [33]
CollapseExpand
Correlation Structure: Crisis vs. Calm Periods
============================================================

Financial Crisis (Sep 2008 - Mar 2009):
       ^GSPC    GLD    TLT    EFA
^GSPC  1.000  0.394 -0.013  0.945
GLD    0.394  1.000  0.196  0.448
TLT   -0.013  0.196  1.000  0.037
EFA    0.945  0.448  0.037  1.000

Calm Period (2017):
       ^GSPC    GLD    TLT    EFA
^GSPC  1.000  0.063 -0.351  0.862
GLD    0.063  1.000  0.153  0.101
TLT   -0.351  0.153  1.000 -0.310
EFA    0.862  0.101 -0.310  1.000

COVID Crash (Feb - Apr 2020):
       ^GSPC    GLD    TLT    EFA
^GSPC  1.000  0.050 -0.156  0.928
GLD    0.050  1.000  0.178  0.088
TLT   -0.156  0.178  1.000 -0.069
EFA    0.928  0.088 -0.069  1.000

During the financial crisis and COVID crash, correlations between S&P 500 and other assets shift compared to calm periods. The correlation between US and international equities (EFA) typically spikes during crises, reducing the diversification benefit of global equity allocation exactly when losses are largest.

VisualizationsOut [34]
CollapseExpand
Heatmap of a 4x4 asset correlation matrix for SPX, GLD, TLT, and EFA during the calm 2017 period, with moderate to low off-diagonal values.
Correlation matrix of asset returns during a calm market period in 2017. Correlations between the S&P 500 and other asset classes are moderate to low, allowing for effective portfolio diversification.
Heatmap of a 4x4 asset correlation matrix for SPX, GLD, TLT, and EFA during the 2020 COVID crash, with noticeably higher off-diagonal correlations than the calm period.
Correlation matrix during the 2020 COVID-19 crash. The strongest equity pair, SPX and EFA, rises from 0.86 to 0.93, while other pairs change by different amounts and directions.

Implications for Financial Modeling

The stylized facts we've documented directly affect model choice and risk estimates in quantitative finance.

Limitations of the Normal Distribution

The normal distribution, despite its mathematical elegance, fails to capture the essential features of financial returns. Using normal assumptions leads to systematic underestimation of tail risk. The Black-Scholes model, which we'll derive in upcoming chapters, assumes log returns follow a normal distribution and volatility is constant. In light of what we've learned, these assumptions are clearly violated.

This doesn't mean Black-Scholes is useless. It remains the foundation of options pricing. But you must understand its limitations and adjust accordingly. The implied volatility smile we'll study in Part III arises precisely because the market prices in fat tails that Black-Scholes ignores.

Alternative Distributions

Several distributions better capture the heavy-tailed nature of financial returns:

  • Student's t-distribution: Adds a degrees-of-freedom parameter that controls tail heaviness. As degrees of freedom decrease, tails become fatter.
  • Generalized hyperbolic distributions: A flexible family that nests many special cases, allowing calibration to both skewness and kurtosis.
  • Stable distributions: Capture the possibility of infinite variance, relevant for highly fat-tailed data.
PythonIn [35]
CollapseExpand
import numpy as np
from scipy import stats

# Fit t-distribution to returns
params = stats.t.fit(log_returns)
df_fitted, loc_fitted, scale_fitted = params

# Compare tail probabilities
x_threshold = 4 * log_returns.std()

# Actual probability
actual_prob = np.mean(np.abs(log_returns) > x_threshold)

# Normal probability
normal_prob = 2 * (
    1
    - stats.norm.cdf(
        x_threshold, loc=log_returns.mean(), scale=log_returns.std()
    )
)

# t-distribution probability
t_prob = 2 * (
    1 - stats.t.cdf(x_threshold, df_fitted, loc=loc_fitted, scale=scale_fitted)
)

# Calculate percentages for display
actual_prob_pct = actual_prob * 100
normal_prob_pct = normal_prob * 100
t_prob_pct = t_prob * 100
ConsoleOut [36]
CollapseExpand
Distribution Fit Comparison
==================================================
Fitted t-distribution degrees of freedom: 54.85

Probability of |return| > 4σ:
  Actual:       0.000160 (0.0160%)
  Normal:       0.000069 (0.0069%)
  t-dist:       0.000160 (0.0160%)

The fitted t-distribution with its low degrees of freedom captures the tail behavior much better than the normal distribution. A degrees of freedom parameter around 3-5 is typical for daily equity returns.

Volatility Modeling

Volatility clustering motivates conditional heteroskedasticity models where volatility is modeled as a time-varying process. The ARCH (Autoregressive Conditional Heteroskedasticity) model introduced by Robert Engle and the GARCH generalization by Tim Bollerslev explicitly model how volatility evolves over time. These models are essential for:

We'll explore these models in detail in Part IV on Time Series Models.

Risk Management Implications

Traditional risk measures based on normal distributions dramatically underestimate tail risk. Consider Value at Risk (VaR) at the 99% confidence level:

PythonIn [37]
CollapseExpand
import numpy as np
from scipy import stats

# Calculate VaR under different distributional assumptions
confidence = 0.99

# Historical VaR (non-parametric)
historical_var = -np.percentile(log_returns, 100 * (1 - confidence))

# Normal VaR
normal_var = -stats.norm.ppf(1 - confidence) * log_returns.std()

# t-distribution VaR
t_var = -stats.t.ppf(1 - confidence, df_fitted, loc=0, scale=scale_fitted)

# Count actual exceedances
exceedances_historical = np.sum(log_returns < -historical_var)
exceedances_normal = np.sum(log_returns < -normal_var)
exceedances_t = np.sum(log_returns < -t_var)
expected_exceedances = len(log_returns) * (1 - confidence)
ConsoleOut [38]
CollapseExpand
Value at Risk Comparison (99% confidence)
=======================================================
Method               VaR          Exceedances  Expected  
-------------------------------------------------------
Historical           2.1186%   63           62.6
Normal               2.0941%   66           62.6
t-distribution       2.1171%   63           62.6

The normal distribution VaR typically shows more exceedances than expected (more days with losses exceeding the VaR threshold), indicating underestimation of risk. The t-distribution and historical approaches provide more conservative and accurate estimates.

VisualizationOut [39]
CollapseExpand
Histogram of negative daily returns with three vertical lines marking the 99% VaR thresholds under historical, normal, and t-distribution assumptions, showing the normal VaR is the least conservative.
Comparison of 99% Value at Risk thresholds using historical, normal, and t-distribution methods. The normal VaR threshold is less conservative than the alternatives, which shows how Gaussian assumptions can lead to an underestimation of tail risk.

Key Parameters

The key parameters for the statistical models and risk measures used in this chapter are:

  • Confidence Level (1−α1-\alpha): The probability that losses will not exceed the VaR threshold (e.g., 99%). Higher confidence levels result in more conservative (larger) VaR estimates.
  • Degrees of Freedom (ν\nu): A parameter of the Student's t-distribution controlling tail heaviness. Lower values (e.g., 3-5) indicate fatter tails; as ν→∞\nu \to \infty, the distribution converges to Normal.
  • Lag (kk): The time shift used in autocorrelation calculations. Significant autocorrelation at lag kk implies predictability based on observations kk periods ago.

Universality Across Markets

A remarkable aspect of these stylized facts is their universality. They appear in:

  • Different asset classes (equities, bonds, currencies, commodities)
  • Different geographic markets (US, Europe, Asia, emerging markets)
  • Different time periods (pre-WWII, post-WWII, modern era)
  • Different frequencies (minute, hourly, daily, weekly)

While the specific parameter values vary (emerging market equities have higher kurtosis than developed markets, currencies show less skewness than equities), the qualitative features persist. This universality suggests these patterns reflect fundamental aspects of how markets aggregate information and how participants behave, rather than artifacts of specific market structures.

The persistence of these facts across diverse settings reinforces their importance for financial modeling. Any model that ignores heavy tails, volatility clustering, or the leverage effect will systematically misjudge risk and misprice derivatives across virtually all financial markets.

Summary

This chapter established the empirical foundation for quantitative modeling by documenting the robust statistical properties of financial returns:

Heavy tails and excess kurtosis represent the most dramatic departure from normality. Extreme returns occur far more frequently than the normal distribution predicts, with daily equity returns typically showing excess kurtosis of 5-15. This has direct implications for tail risk measurement and derivative pricing.

Negative skewness characterizes many equity return distributions, which reflects the asymmetric nature of market movements: gradual rises and sudden crashes. Risk models must account for this asymmetry in the loss tail.

Volatility clustering means that market turbulence is persistent. Today's volatility strongly predicts tomorrow's volatility, with autocorrelation in squared returns remaining significant for many weeks. This violates the i.i.d. assumption underlying many classical models.

The leverage effect introduces asymmetry in volatility dynamics: negative returns increase future volatility more than positive returns. This correlation between returns and volatility changes has implications for option pricing and hedging.

Aggregational Gaussianity provides a silver lining: returns become more normal at longer horizons. Daily returns require careful non-normal treatment, but annual risk assessments can rely more heavily on Gaussian approximations.

These stylized facts motivate the sophisticated modeling techniques developed throughout the remainder of this textbook. The Brownian motion framework of the next chapter provides a mathematical foundation for continuous-time price processes, but you'll now understand why extensions like jump-diffusions and stochastic volatility are necessary to capture market reality. The gap between elegant theory and messy reality is precisely where quantitative finance earns its value.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about the stylized facts of financial returns.

Stylized Facts of Financial Returns

Question 1 of 80 of 8 completed
Which property of log returns makes them particularly useful for multi-period analysis?
Join the discussionAsk a question or share what you learned.

Comments

Add to the conversation

A question, a correction, or an example from your own work.

No comments yet. Be the first to share your thoughts!

A different angle
All writing
Quantitative Finance · Vol. 2

Implied Volatility and Volatility Smile

Compute implied volatility using Newton-Raphson and bisection methods. Examines volatility smile, skew patterns, and the VIX index with Python code.

54 min read
Quantitative Finance · Vol. 2

The Greeks and Option Risk Management: Delta, Gamma & More

Covers option Greeks: delta, gamma, theta, vega, and rho. Topics include sensitivity analysis, delta hedging, and portfolio risk management techniques.

59 min read
Quantitative Finance · Vol. 2

Black-Scholes Formula: European Option Pricing & Greeks

Covers the Black-Scholes formula for European options with Python implementation. Topics include derivation, the Greeks, put-call parity.

58 min read

About the author

Reference

Citation details

Cite or share this article.

BIBTEXAcademic
@misc{brenndoerfer2025stylizedfacts, author = {Michael Brenndoerfer}, title = {Stylized Facts of Financial Returns: Fat Tails & Volatility}, year = {2025}, url = {https://mbrenndoerfer.com/writing/stylized-facts-financial-returns-fat-tails-volatility-clustering}, organization = {mbrenndoerfer.com}, note = {Accessed: 2026-10-28} }
APAAcademic
Michael Brenndoerfer (2025). Stylized Facts of Financial Returns: Fat Tails & Volatility. Retrieved from https://mbrenndoerfer.com/writing/stylized-facts-financial-returns-fat-tails-volatility-clustering
MLAAcademic
Michael Brenndoerfer. "Stylized Facts of Financial Returns: Fat Tails & Volatility." 2026. Web. October 28, 2026. <https://mbrenndoerfer.com/writing/stylized-facts-financial-returns-fat-tails-volatility-clustering>.
CHICAGOAcademic
Michael Brenndoerfer. "Stylized Facts of Financial Returns: Fat Tails & Volatility." Accessed October 28, 2026. https://mbrenndoerfer.com/writing/stylized-facts-financial-returns-fat-tails-volatility-clustering.
HARVARDAcademic
Michael Brenndoerfer (2025) 'Stylized Facts of Financial Returns: Fat Tails & Volatility'. Available at: https://mbrenndoerfer.com/writing/stylized-facts-financial-returns-fat-tails-volatility-clustering (Accessed: October 28, 2026).
SimpleBasic
Michael Brenndoerfer (2025). Stylized Facts of Financial Returns: Fat Tails & Volatility. https://mbrenndoerfer.com/writing/stylized-facts-financial-returns-fat-tails-volatility-clustering
Newsletter

Stay up to date

Get new articles, book updates, and notes on AI and technology.

Unsubscribe at any time. Privacy policy