Skip to content
All library documents

Calibrating Geometric Brownian Motion from Daily Log Returns

Article Quant Q&A · Author: twhale

Summary

The document explains how to estimate the parameters of a geometric Brownian motion model from historical daily stock prices. Because GBM models log price changes as normally distributed, it recommends calculating the sample mean and variance of daily log returns, then converting these daily estimates to the time scale used in the simulation. The annualized volatility scales with the square root of the number of trading periods, while the price drift also accounts for the half-variance term in the GBM equation.

It distinguishes the mean log return from the model’s drift parameter and points out that using simple returns or the standard deviation of log prices does not match the stated GBM calibration. The answer suggests using a daily time unit to avoid unnecessary annualization. Its formulas assume the GBM framework and a consistent time-step convention; the example does not address estimation uncertainty, dividends, changing volatility, or whether historical parameters are suitable forecasts.

Key ideas

  • GBM models log returns as normally distributed increments.
  • Estimate the daily mean and variance from consecutive log price ratios.
  • Convert daily estimates to the simulation time unit before using them as drift and volatility.
  • The GBM price drift includes a half-variance adjustment relative to mean log growth.
  • Using the standard deviation of log price levels does not estimate GBM volatility.

Tags

Full text
# This is the 'normal' way of calculating mu and sigma


# Simulate stock prices with Geometric Brownian Motion motion with mu and signa based on 'normal' or continuous compounding?












I have written a simple script for modelling stock prices using Geometric Brownian Motion. The time series I am downloading are daily adjusted closing prices. My aim is to be able to change the prediction period and all other variables.

However, I am trying to understand the price prediction differences between calculating the mu (average returns) and sigma (variance) using a linear or standard methods versus using a log approach. The log approach consistently generates a higher predicted stock price. My code is below.

I have scavenged the internet and read whatever I could find. There are several helpful articles on this forum as well, such as here and here. But nothing really covers my question.

My question is, which approach is the most appropriate?

(I am using Python 3.)

```
from math import log, e
import matplotlib.pyplot as plt
from pandas_datareader import data
from datetime import date, timedelta
import datetime

stock = 'AAPL' # Enter the name of the stock
start = '2015/1/1'
apple = data.DataReader(stock, 'yahoo', start)

# This is the 'normal' way of calculating mu and sigma
close = apple[:]['Adj Close']
mu = (close[-1]/close[1])** (252.0/len(close)) - 1
sigma = (close/close.shift(1)-1)[1:].std()*np.sqrt(252)

# This is the 'log' way of calculating mu and sigma
apple['log_price'] = np.log(apple['Adj Close'])
apple['log_return'] = apple['log_price'].diff()
mu = apple.log_return.sum() -1
sigma = np.std(apple.log_price)

s0 = close[-1]
T = 18/12
delta_t = 0.001
num_reps = 1000
steps = T/delta_t
plt.figure(figsize=(15,10))
closing_prices = []
for j in range(num_reps):
    price_path = [s0]
    st = s0
    for i in range(int(steps)):
        drift = (mu - 0.5 * sigma**2) * delta_t
        diffusion = sigma * np.sqrt(delta_t) * np.random.normal(0, 1)
        st = st*e**(drift + diffusion)
        price_path.append(st)
        closing_prices.append(price_path[-1])
    plt.plot(price_path)
plt.ylabel('stock price',fontsize=15)
plt.xlabel('steps',fontsize=15)
plt.axhline(y = s0, color = 'r', linestyle = '-') # print latest price TW
plt.show()

mean_end_price = round(np.mean(closing_prices),2)
print("Expected price in 12 months: $", str(mean_end_price))
```

## Answer by Jan Stuller (score 5, accepted)

https://quant.stackexchange.com/a/55222

The drift in your code is:

```
drift = (mu - 0.5 * sigma**2) * delta_t
```

So I assume you are using the Geometric Brownian Motion to simulate your stock price, not just plain Brownian motion. Therefore your model is Lognormal, not Normal. Also, I assume that the time series that you're downloading is daily closing prices.

The solution to the GBM model is the following (below $\delta t:=(t_i)-(t_{i-1})$ & $Z\sim~N(0,1)$):

$$ ln(S_{t_i}) - ln(S_{t_{i-1}}) = (\mu - 0.5\sigma^2)\delta t+\sigma\sqrt{\delta t}Z $$

Note that the log-returns above are distributed normally:

$$ln(S_{t_i}) - ln(S_{t_{i-1}}) \sim N\left(\tilde{\mu} := (\mu - 0.5\sigma^2)\delta t;\tilde{\sigma}:=\sqrt{\delta t}\sigma\right)$$

If we're using daily time series, then $\delta t = \frac{1}{260}$.

If you wanna calibrate the above model based on historical daily data, your task is to calibrate $\tilde{\mu}$ and $\tilde{\sigma}$:

$$(i): \tilde{\mu}=\frac{1}{n}\sum_{i=1}^{n} ln\left( \frac{S_{t_i}}{S_{t_{i-1}}}\right)$$

$$ (ii): \tilde{\sigma}^2 = \frac{1}{n-1} \sum_{i=1}^{n} \left( \left[ ln\left( \frac{S_{t_i}}{S_{t_{i-1}}}\right) - \tilde{\mu} \right]^2\right) $$

Note that in (i) above, you computed $\tilde{\mu}$ and NOT $\mu$. In your simulation, you need $\mu$, so first do the following:

$$ \sigma = \tilde{\sigma}*\frac{1}{\sqrt{\delta t}}=\tilde{\sigma}*\sqrt{260} $$

$$\mu = \frac{1}{\delta t}*\tilde{\mu}+0.5{\sigma}^2=260*\tilde{\mu}+0.5{\sigma}^2$$

That is the $\mu$ you should use in your simulation.

The next point is: why do you have the following line in your code?

```
mu = apple.log_return.sum() -1
```

Why subtract the 1? If your log-returns are daily, to get $\mu$, your code should read:

```
mu = apple.log_return.sum()/apple.log_return.count()
mu = mu*260 + 0.5*apple.log_return.var()*sqrt(260)
```

To get the $\mu$ in line with the formulas I described above.

If you are using GBM to simulate your stock price, you should not be using regular returns to calibrate your model: so what you call "normal" way is the wrong way to calibrate your model.

Ps: if you have daily time series to start with, you can choose one day to be your unit of time if you want to simulate with daily granularity. That will make your task significantly easier, because you can work with $\tilde{\sigma}$ and $\tilde{\mu}$ directly, rather than having to annualize them: i.e. to convert them into $\sigma$ and $\mu$.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.