Skip to content

Note

Click here to download the full example code

Geometric Brownian motion

The price of an asset follows dS = mu S dt + sigma S dW, the model behind Black and Scholes' option pricing. The returns are proportional to the price, so the price stays positive and wanders on a logarithmic scale, and the log-price is a Brownian motion with drift mu - sigma^2 / 2.

The price starts at 100 with a drift of 5 percent and a volatility of 20 percent a year, and is simulated for ten years in steps of 0.05. The default blueprint shows one path of the price.

import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

from skcomplex.engine.runtime import Simulation
from skcomplex.engine.viz import RerunObserver
from skcomplex.models import create

MODEL = 'geometric_brownian_motion'
PRICE, MU, SIGMA, YEARS, DT = 100.0, 0.05, 0.2, 10, 0.05

observer = RerunObserver(MODEL, save_path=f'{MODEL}.rrd', blueprint='default', interval=1)
system = create(MODEL, price=PRICE, mu=MU, sigma=SIGMA)
simulation = Simulation(system, dt=DT, observers=[observer], random_state=0).check().prepare().run(until=YEARS)

plot geometric brownian motion

Open the recording in the Rerun viewer

Log returns

The log returns over a lag tau are independent and normal with mean (mu - sigma^2 / 2) tau and variance sigma^2 tau. Along one path of 200 years, the variance of the log returns should grow linearly with the lag, and the one-step log returns should follow that normal density.

long_run = (
    Simulation(create(MODEL, price=PRICE, mu=MU, sigma=SIGMA), dt=DT, random_state=1).check().prepare().run(until=200)
)
logs = np.log(long_run.trajectory_.values('asset.price'))
lags = np.unique(np.logspace(0, 2.5, 20).astype(int))
returns = logs[1:] - logs[:-1]
grid = np.linspace(returns.min(), returns.max(), 200)
fig, (scaling, density) = plt.subplots(1, 2, figsize=(10, 4))
scaling.loglog(lags * DT, [np.var(logs[lag:] - logs[:-lag]) for lag in lags], 'o', label='simulation')
scaling.loglog(lags * DT, SIGMA**2 * lags * DT, 'k--', lw=0.8, label='sigma^2 tau')
scaling.set_xlabel('lag tau (years)')
scaling.set_ylabel('variance of log return')
scaling.set_title('Diffusive growth of the log-price')
scaling.legend()
density.hist(returns, bins=50, density=True, alpha=0.5, label='simulation')
mean, std = (MU - SIGMA**2 / 2) * DT, SIGMA * np.sqrt(DT)
density.plot(grid, stats.norm.pdf(grid, mean, std), 'k', label='normal')
density.set_xlabel(f'log return over dt = {DT}')
density.set_ylabel('density')
density.set_title('Normal log returns')
density.legend()
fig.tight_layout()
plt.show()

Diffusive growth of the log-price, Normal log returns

About the model

An asset whose price follows geometric Brownian motion.

References

  • Black and Scholes 1973

Total running time of the script: ( 0 minutes 6.032 seconds)

Download Python source code: plot_geometric_brownian_motion.py

Download Jupyter notebook: plot_geometric_brownian_motion.ipynb

Gallery generated by mkdocs-gallery