Simulating Stock Prices with Geometric Brownian Motion in Python
Introduction
Imagine you want to test an algorithmic trading strategy, but you don‘t have access to real historical stock market data. Or maybe you want to simulate potential future stock price paths to evaluate an options trade or hedge a portfolio. In cases like these, it would be very useful to have an easy way to generate realistic-looking stock price data. This is where geometric Brownian motion comes in.
In this article, we‘ll learn exactly what geometric Brownian motion (GBM) is, how it works, and how to implement it in Python to create your own simulated stock market. By the end, you‘ll be able to generate thousands of synthetic stock price paths with just a few lines of code!
We‘ll cover the basic theory behind GBM and stochastic differential equations, but keep the math at a high level. The focus will be on the intuition and practical application. This article assumes you‘re already comfortable with Python and have a basic familiarity with statistics and calculus. Some prior exposure to quantitative finance is helpful but not necessary – we‘ll explain all the key concepts from scratch.
What is Geometric Brownian Motion?
Geometric Brownian motion is a stochastic process often used to model stock prices. It‘s a continuous-time analogue to the familiar discrete-time stochastic process known as a random walk.
In a one-dimensional random walk, the value of a variable changes each time step by a random amount, drawn from some probability distribution. In the classic symmetric random walk, at each time step the variable has a 50% chance of increasing by 1 and a 50% chance of decreasing by 1.
GBM generalizes this to continuous time – instead of discrete integer time steps, the variable evolves continuously and we track its value at any real-valued point in time. The random increments are drawn from a normal distribution and scaled by the current value of the process. This is where the "geometric" part comes from – the relative changes are the same regardless of the current level.
Mathematically, a geometric Brownian motion process $S_t$ is defined by the following stochastic differential equation:
$$dS_t = \mu S_t dt + \sigma S_t dW_t$$
Here, $\mu$ and $\sigma$ are constants representing the drift (average trend) and volatility of the process, and $W_t$ is a Wiener process (also known as standard Brownian motion). You can think of the $dW_t$ term as contributing random normally-distributed noise, scaled by the volatility.
The solution to this stochastic differential equation, derived using Itô‘s lemma, gives the current value of the process at time $t$ as a function of the initial value $S_0$:
$$S_t = S_0 \exp \left(\left(\mu – \frac{\sigma^2}{2} \right)t + \sigma W_t \right)$$
The key thing to notice is the exponential function – this is why GBM is appropriate for modeling stock prices, which are always positive and exhibit exponential growth over long time horizons. The random noise from the Wiener process causes the short-term fluctuations.
Implementing GBM in Python
Now that we have a high-level understanding of what GBM is, let‘s see how to simulate it in Python! We‘ll use NumPy and matplotlib for this example.
First, we need to import the necessary libraries:
import numpy as np
import matplotlib.pyplot as plt
Next, we‘ll define the parameters of the GBM process we want to simulate:
# Initial stock price
S0 = 100
# Drift coefficient (average annual return)
mu = 0.07
# Diffusion coefficient (volatility)
sigma = 0.2
# Time horizon in years
T = 1
# Number of time steps
N = 252 # typical number of trading days in a year
Here we‘re simulating a stock that starts at a price of 100, has an average annual return of 7%, an annual volatility of 20%, over a time horizon of 1 year with daily time steps (252 trading days in a typical year).
Now we can actually generate the stock price path:
# Time step size
dt = T/N
# Initialize array for stock prices
S = np.zeros(N+1)
# Set initial stock price
S[0] = S0
# Initialize Wiener process
W = np.random.standard_normal(N+1)
W = np.cumsum(W) * np.sqrt(dt)
# Generate stock price path using GBM equation
for i in range(1, N+1):
S[i] = S[i-1] * np.exp((mu - sigma**2/2)*dt + sigma*W[i])
Let‘s break this down. First we calculate the time step size by dividing the total time horizon by the number of steps. Then we initialize an array to store the stock prices, setting the first value to the initial price.
Next, we generate a Wiener process path using NumPy‘s standard_normal function to generate an array of independent normally distributed random variables with mean 0 and variance 1. We take the cumulative sum to get the Brownian motion and scale by the square root of the time step size. This is an approximation to the true Wiener process which becomes exact in the limit as the time step size goes to zero.
Finally, we loop through the time steps and calculate the stock price at each one using the GBM solution equation from before. The np.exp function applies the exponential elementwise.
We now have the complete stock price path! Let‘s plot it and see what it looks like:
# Plot simulated stock price path
plt.figure(figsize=(10,6))
plt.plot(S)
plt.xlabel(‘Time (days)‘)
plt.ylabel(‘Stock Price ($)‘)
plt.title(‘Simulated Stock Price Path with GBM‘)
plt.show()

There it is – a realistic looking stock chart, generated from pure math and randomness! Of course, this is just one possible path. Every time you run the code, you‘ll get a different price history, since the Wiener process is randomly sampled. Let‘s generate multiple price paths on the same chart to visualize this:
# Number of simulations
num_sims = 10
# Initialize array to store results
S_sims = np.zeros((num_sims, N+1))
# Run multiple simulations
for i in range(num_sims):
# Initialize Wiener process
W = np.random.standard_normal(N+1)
W = np.cumsum(W) * np.sqrt(dt)
# Set initial stock price
S_sims[i,0] = S0
# Generate stock price path using GBM equation
for j in range(1, N+1):
S_sims[i,j] = S_sims[i,j-1] * np.exp((mu - sigma**2/2)*dt + sigma*W[j])
# Plot results
plt.figure(figsize=(10,6))
for i in range(num_sims):
plt.plot(S_sims[i])
plt.xlabel(‘Time (days)‘)
plt.ylabel(‘Stock Price ($)‘)
plt.title(f‘{num_sims} Simulated Stock Price Paths with GBM‘)
plt.show()

Now we can clearly see the randomness – each run follows the same general trend and long-term drift, but the day-to-day movements are different every time. This is a key feature of geometric Brownian motion.
Applications and Limitations
Being able to easily simulate realistic stock price data has a variety of uses. Here are a few examples:
- Backtesting trading strategies on synthetic data before trying them on real markets
- Generating potential future price paths for risk analysis and options pricing
- As a component in agent-based market simulation models
- Creating an interactive demo or educational tool to teach quantitative finance concepts
However, it‘s important to recognize that GBM is a highly simplified model of real asset price dynamics. It makes several key assumptions that often don‘t hold in practice:
- Continuously compounded returns are normally distributed
- Volatility is constant over time
- Price movements have no memory (Markov property) and are independent from one time step to the next
- No transaction costs or other market frictions
In reality, asset returns often have heavy tails (higher probability of extreme events), time-varying and stochastic volatility, mean reversion and momentum effects, and jumps due to news and other discrete events. More sophisticated models try to account for these stylized facts.
Despite its limitations, GBM remains a very useful model due to its simplicity and analytic tractability. It was a key building block in the derivation of the famous Black-Scholes options pricing formula, for which Myron Scholes and Robert Merton won the Nobel Prize in Economics in 1997. Many more complex models used today in quantitative finance start with GBM and add extra components from there.
Next Steps
I encourage you to play with the Python code we developed in this article and see how changing the parameters affects the simulated price paths. Here are some ideas for extensions:
- Add a time-varying drift term $\mu(t)$ to model bull and bear market regimes
- Include a jump component to simulate the impact of significant news events
- Use a stochastic volatility model like Heston to allow for volatility clustering effects
- Simulate multiple correlated asset price paths for a portfolio
- Apply this simulated data to evaluate a pairs trading strategy or test an options pricing model
I‘ve only scratched the surface of what‘s possible! GBM is a fantastic gateway to learning about stochastic calculus and its applications in finance. For those who want to dive deeper into the theory behind it all, I highly recommend the following resources:
- Hull, John C. Options, Futures, and Other Derivatives.
- Shreve, Steven. Stochastic Calculus for Finance I & II.
- Klebaner, Fima C. Introduction to Stochastic Calculus with Applications.
- Glasserman, Paul. Monte Carlo Methods in Financial Engineering.
I hope this has been an enlightening introduction to the power of stochastic simulation for modeling financial markets. With the tools of geometric Brownian motion and Python at your disposal, you‘re well on your way to exploring the fascinating world of quantitative finance!