import numpy as np import pandas as pd import param import panel as pn import hvplot import hvplot.pandas class GBM(param.Parameterized): # interface mean = param.Number(default=5, bounds=(.0, 25.0)) volatility = param.Number(default=5, bounds=(.0, 50.0)) maturity = param.Integer(default=1, bounds=(0, 25)) n_observations = param.Integer(default=10, bounds=(2, 100)) n_simulations = param.Integer(default=20, bounds=(1, 500)) refresh = pn.widgets.Button(name="Refresh", button_type='primary') def __init__(self, **params): super(GBM, self).__init__(**params) # update the plot for every changes # @param.depends('mean', 'volatility', 'maturity', 'n_observations', 'n_simulations', watch=True) # refresh the plot only on button refresh click @param.depends('refresh.clicks') def update_plot(self, **kwargs): df_s = pd.DataFrame(index=range(0, self.n_observations)) for s in range(0, self.n_simulations): name_s = f"stock_{s}" df_s[name_s] = self.gbm(spot=100, mean=self.mean/100, vol=self.volatility/100, dt=self.maturity / self.n_observations, n_obs=self.n_observations) return df_s.hvplot(grid=True, colormap='Paired', value_label="Level", legend=False) @staticmethod def gbm(spot: float, mean: float, vol: float, dt: float, n_obs: int) -> np.ndarray: """ Geometric Brownian Motion :param spot: spot value :param mean: mean annualised value :param vol: volatility annualised value :param dt: time steps :param n_obs: number of observation to return :return: a geometric brownian motion np.array() """ # generate normal random rand = np.random.standard_normal(n_obs) # initialize the parameters S = np.zeros_like(rand) S[0] = spot # loop to generate the brownian motion for t in range(1, n_obs): S[t] = S[t - 1] * np.exp((mean - (vol ** 2) / 2) * dt + vol * rand[t] * np.sqrt(dt)) # return the geometric brownian motion return S