Skip to content

Note

Click here to download the full example code

Correlated geometric Brownian motions

Two asset prices follow geometric Brownian motions driven by the two processes of one WienerProcess, whose covariance gives them the correlation rho = 0.7. The prices wander apart on their own drifts and volatilities, but they rise and fall together, and their log returns are correlated with rho.

The model is created by name from the catalog with prices of 100, drifts of 5 and 8 percent, and volatilities of 20 and 30 percent a year. It is simulated for three years in frames of 0.02 with the Euler-Maruyama scheme. The default blueprint shows both prices in one time series view. The WienerProcess that both motions bind is no component and draws no view.

import matplotlib.pyplot as plt
import numpy as np

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

MODEL = 'correlated_geometric_brownian_motion'
RHO = 0.7

system = create(MODEL, rho=RHO)
observer = RerunObserver(MODEL, save_path=f'{MODEL}.rrd', blueprint='default')
solver = EulerMaruyamaSolver(dt=0.001)
simulation = (
    Simulation(system, dt=0.02, solver=solver, observers=[observer], random_state=0).check().prepare().run(until=3)
)

plot correlated geometric brownian motion

Open the recording in the Rerun viewer

Correlated log returns

Over one frame the log return of each asset is its volatility times its Wiener increment plus a small drift, so the sample correlation of the two series of log returns should be close to rho, and their scatter should be an ellipse tilted along the diagonal.

trajectory = simulation.trajectory_
first, second = (np.diff(np.log(trajectory.values(f'{label}.price'))) for label in ('first', 'second'))
correlation = np.corrcoef(first, second)[0, 1]
fig, (paths, returns) = plt.subplots(1, 2, figsize=(10, 4))
paths.plot(trajectory.times, trajectory.values('first.price'), label='first')
paths.plot(trajectory.times, trajectory.values('second.price'), label='second')
paths.set_xlabel('time (years)')
paths.set_ylabel('price')
paths.set_title('Prices that move together')
paths.legend()
returns.scatter(first, second, s=6, alpha=0.6)
returns.set_xlabel('log return of the first asset')
returns.set_ylabel('log return of the second asset')
returns.set_title(f'Sample correlation {correlation:.2f}, rho = {RHO}')
fig.tight_layout()
plt.show()

Prices that move together, Sample correlation 0.70, rho = 0.7

Download Python source code: plot_correlated_geometric_brownian_motion.py

Download Jupyter notebook: plot_correlated_geometric_brownian_motion.ipynb

Gallery generated by mkdocs-gallery

About the model

Two assets whose prices follow geometric Brownian motions driven by correlated Wiener processes.

References

  • Black and Scholes 1973
  • Merton 1973