Log-likelyhood calculation of price paths
This notebook demonstrates the application of a Brownian Motion Model to compute and visualize the negative log-likelihood (NLL) function. The Brownian Motion Model is widely used in finance to model the random movement of prices over time. The NLL function can be used in the parameter estimation process, helping to quantify how well a given set of model parameters explains the observed data.
In this demonstration, we show how different combinations of drift and volatility parameters affect the NLL function. By creating a 2D surface plot of the NLL function, we can visualize the landscape of the parameter space and identify regions where the model fits the data well (i.e., regions with lower NLL values).
In [1]:
import plotly
import plotly.express as px
import plotly.figure_factory as ff
import plotly.graph_objects as go
plotly.offline.init_notebook_mode()
import numpy as np
from quantfinlib.sim import BrownianMotion
Generate an example price path
In this step, we generate a sample price path using the Brownian Motion model with specified parameters for drift and volatility. The generated path simulates the daily prices of an asset over a one-year period (252 trading days), starting from an initial price.
The drift is the expected rate of return of the asset. In this example, the drift is set to 0.05, indicating a 5% expected return over the period. The volatility is set to 0.30, which assumes a 30% annualized standard deviation of returns.
In [2]:
params = {'drift':0.05, 'vol':0.30}
model = BrownianMotion(**params)
path = model.path_sample(x0=100, dt=1/252, num_steps=252)
fig = px.line(path, width=600, height=400)
fig.show()
Compute the NLL of this path for various drift values
In this step, we evaluate how the negative log-likelihood (NLL) of the generated price path changes as we vary the drift parameter of the Brownian Motion model. By computing the NLL for a range of drift values, we can understand the sensitivity of the model’s fit to this parameter and identify the drift value that best explains the observed data.
In [3]:
model = BrownianMotion(**params)
drifts = np.linspace(-5, 5, 100)
drifs_nlls = []
for drift in drifts:
model.drift = drift
drifs_nlls.append(model.nll(path))
fig = px.line(
x=drifts,
y=drifs_nlls,
width=600,
height=400,
title='negative log-likelihood as function of drift',
labels={'x': 'drift', 'y': 'negative log-likelihood'}
)
fig.show()
Compute the NLL of this path for various volatility values
Here we do the same for the volatilty parameter.
In [4]:
model = BrownianMotion(**params)
vols = np.linspace(0.15, 1.0, 100)
vols_nlls = []
for vol in vols:
model.vol = vol
vols_nlls.append(model.nll(path))
fig = px.line(
x=vols,
y=vols_nlls,
width=600,
height=400,
title='negative log-likelihood as function of volatility',
labels={'x': 'vol', 'y': 'negative log-likelihood'}
)
fig.show()
Compute the NLL of this path for a drift and volatilty grid
In this step, we create a 2D surface plot to visualize the negative log-likelihood (NLL) as a function of both drift and volatility parameters of the Brownian Motion model. By evaluating the NLL over a grid of drift and volatility values, we can explore the combined effect of these parameters on the model’s fit to the observed data.
In [5]:
model = BrownianMotion(**params)
# Parameter grid
drifts = np.linspace(-5, 5, 25)
vols = np.linspace(0.15, 1.0, 25)
# Create a 2D array to store the negative log-likelihoods
nll_values = np.zeros((len(drifts), len(vols)))
# Compute the negative log-likelihood for each combination of drift and vol
for i, drift in enumerate(drifts):
for j, vol in enumerate(vols):
model.drift = drift
model.vol = vol
nll_values[i, j] = model.nll(path)
# Create the surface plot
fig = go.Figure(data=[go.Surface(z=nll_values, x=drifts, y=vols)])
# Update layout for better visualization
fig.update_layout(
title='Negative Log-Likelihood Surface Plot',
scene=dict(
xaxis_title='Drift',
yaxis_title='Volatility',
zaxis_title='Negative Log-Likelihood'
),
width=600,
height=600
)
# Show the plot
fig.show()