QF-Learn

Geometric Brownian motion: the model behind stock price simulations

Geometric Brownian motion (GBM) is the standard model of a stock price in quantitative finance. It says the price grows at a steady average rate (the drift, μ) plus random shocks whose size is set by the volatility (σ), with both applied in percentage terms, so the price can never fall below zero.

GBM is the assumption underneath the Black-Scholes model, and it is what most Monte Carlo simulations of stock prices draw from.

The GBM equation

As a stochastic differential equation, GBM is:

dSt = μ·St·dt + σ·St·dWt

The first term is the drift: in a small time dt the price grows by μ·dt per cent on average. The second is the noise: dWt is the increment of a Brownian motion, a normal random variable with mean 0 and variance dt. Its solution, found with Itô’s lemma, is:

St = S0·exp((μ − σ²/2)·t + σ·Wt)

So the log of the price is normally distributed and the price itself is lognormal. The −σ²/2 term surprises most people. It appears because the exponential is convex: random ups add more than equal downs take away, so the typical (median) path grows at μ − σ²/2 while the average grows at the full μ.

Simulated GBM paths

These are twenty one-year paths starting at 100, with 8% drift, simulated day by day. Move the volatility to see the fan widen:

Twenty simulated stock price pathsTwenty paths of geometric Brownian motion starting at 100, with 8% drift and 20% volatility over 252 trading days. They fan out over the year, and none goes below zero.80100120140160050100150200250Trading dayStock price

Simulating GBM in Python, and checking it

Because the solution is known, each day can be simulated exactly with one normal draw. This simulates 100,000 paths and checks them against the theory:

Python
import numpy as np

S0, mu, sigma, T, steps, n_paths = 100.0, 0.08, 0.20, 1.0, 252, 100_000
dt = T / steps
rng = np.random.default_rng(seed=7)

# Exact GBM step: S(t+dt) = S(t) * exp((mu - sigma^2/2) dt + sigma sqrt(dt) Z)
Z = rng.standard_normal((n_paths, steps))
log_steps = (mu - 0.5 * sigma**2) * dt + sigma * np.sqrt(dt) * Z
S = S0 * np.exp(np.cumsum(log_steps, axis=1))
ST = S[:, -1]

print(f"mean of S(T)      = {ST.mean():.2f}   (theory {S0 * np.exp(mu * T):.2f})")
print(f"median of S(T)    = {np.median(ST):.2f}   (theory {S0 * np.exp((mu - 0.5 * sigma**2) * T):.2f})")
print(f"share ending below 100 = {(ST < S0).mean():.1%}")
Output
mean of S(T)      = 108.15   (theory 108.33)
median of S(T)    = 106.02   (theory 106.18)
share ending below 100 = 38.5%

The simulated mean and median land within a fraction of a per cent of eμT and e(μ − σ²/2)T. And although the stock is expected to gain 8%, about 38% of paths end below where they started. Theory gives N(−(μ − σ²/2)√T/σ) = N(−0.3) ≈ 38.2%.

Where GBM falls short

Even so, GBM is the right first model: simple enough to solve exactly, and close enough that the volatility traders quote, implied volatility, is defined through it.

Learn this on your phone, one short lesson at a time

QF-Learn turns topics like this into five-minute lessons with quizzes, finance games and certificates. It is free, and it is coming to Android and iOS. Leave your email and you will be first to get it.