LJDSimulatePathsQ

class quantmetrics.price_calculators.ljd_pricing.ljd_paths_Q.LJDSimulatePathsQ(model: LevyModel, option: Option)[source]

Bases: object

Implements the paths simulation for a lognormal jump-diffusion (LJD) model under the risk-neutral measure.

Parameters

modelLevyModel

A LevyModel object specifying the underlying asset’s model and its parameters.

optionOption

An Option object specifying the option parameters: interest rate, strike price, time to maturity, dividend yield and the equivalent martingale measure.

simulate(num_timesteps: int, num_paths: int, seed: int) Dict[str, ndarray][source]

Generate paths for the lognormal jump-diffusion model.

Parameters

num_timestepsint

Number of time steps.

num_pathsint

Number of simulated paths.

seedint

Seed for random number generator.

Returns

dict

A dictionary containing:

  • time_steps (np.ndarray): The simulated time steps.

  • S_exact (np.ndarray): The simulated LJD paths using the exact solution.

  • S_euler (np.ndarray): The simulated LJD paths using the Euler-Maruyama discretization.

Notes

The Euler-Maruyama discretization for the \(i^{th}\) timestep and \(j^{th}\) path, reads:

\[s_{i+1, j} \approx s_{i,j} + (r-q - \lambda^\mathbb{Q} \kappa^\mathbb{Q}) s_{i,j} \Delta t + \sigma s_{i,j} (W_{i+1, j} - W_{i,j}) + J s_{i,j} (N_{i+1,j} -N_{i,j}),\]

with \(\Delta t = t_{i+1} - t_i\), for any \(i=1,2,\cdots , m, \ s_0 = S(t_0)=S_0\), \(j = 1,2,\cdots, N\), \(W_{i+1, j} - W_{i,j} \sim \mathcal{N}(0, \Delta t)\), \(J \sim \mathcal{N}(\mu_J, \sigma_J^2)\) and \(N_{i+1,j} -N_{i,j} \sim \mathcal{Poi}(\lambda^\mathbb{Q} \Delta t)\).

The LJD process has as exact solution in the time interval \([t_i, t_{i+1}]\),

\[S(t_{i+1})=S(t_i)\exp\left\{(r-q-\frac{\sigma^2}{2}- \lambda^\mathbb{Q} \kappa^\mathbb{Q})\Delta t + \sigma [W(t_{i+1}) - W(t_i)] + J [N(t_{i+1}) - N(t_i)] \right\}\]

where

  • \(S_0\) is the underlying price.

  • \(r\) is the risk-free interest rate.

  • \(q\) is the dividend yield.

  • \(\sigma\) is the volatility.

  • \(\mu_J\) is the mean of the jump sizes.

  • \(\sigma_J\) is the standard deviation of the jump sizes.

  • \(\lambda\) is the jump intensity rate.

The parameters \(\lambda^\mathbb{Q}\) and \(\kappa^\mathbb{Q}\) depend on the choice of the equivalent martingale measure.

If emm = "mean-correcting" then

\[\lambda^\mathbb{Q} = \lambda \quad \text{and} \quad \kappa^\mathbb{Q} = \kappa = \exp \left(\mu_J + \frac{\sigma_J^2}{2} \right) - 1\]

If emm = "Esscher" then

\[\lambda^\mathbb{Q} = \lambda f(\theta) \quad \text{and} \quad \kappa^\mathbb{Q} = \frac{f(\theta +1) }{f(\theta)} - 1 = \left[ \left(\kappa +1 \right)e^{\theta \sigma_J^2}\right]^{\frac{1}{g(\psi)}} -1\]

where

\[f(y) = \frac{1}{\sqrt{g(\psi)}} \exp \left[\frac{1}{g(\psi)} \left(\mu_J y + \frac{\sigma_J^2}{2} y^2 + \psi \mu_J^2 \right) \right],\quad g(\psi) = 1 - 2\psi \sigma_J^2\]

with

\[\psi < \frac{1}{2\sigma_J^2}\]

The first-order Esscher parameter \(\theta\) is the risk premium (market price of risk) and which is the unique solution to the martingale equation for each \(\psi\) which is the second-order Esscher parameter. See the documentation of the RiskPremium class for the martingale equation and refer to [1] for more details.

Examples

>>> from quantmetrics.levy_models import LJD
>>> from quantmetrics.option_pricing import Option
>>> from quantmetrics.price_calculators.ljd_pricing.ljd_paths_Q import LJDSimulatePathsQ
>>> ljd = LJD() # S0=50, sigma=0.2, lambda_=1, muJ=-0.1, sigmaJ=0.1
>>> option = Option(K=np.array([20,50,80]), T = 20/252) # r=0.05, q=0.02
>>> paths = LJDSimulatePathsQ(ljd, option).simulate(num_timesteps=200, num_paths=10000,seed=42)
>>> payoff = np.maximum(paths["S_exact"][:,-1].reshape(-1,1) - option.K, 0)
>>> option_price = np.mean(np.exp(-option.r*option.T) * payoff, axis=0)
>>> option_price
array([30.01448984,  1.32307021,  0.        ])

References