Source code for torchquantlib.models.stochastic_volatility.heston

import torch
from models.stochastic_model import StochasticModel

[docs] class Heston(StochasticModel): """ Heston stochastic volatility model. This model describes the evolution of an asset price and its variance using two coupled stochastic differential equations: dS = μSdt + √vSdW_S dv = κ(θ - v)dt + σ_v√vdW_v where: S is the asset price v is the variance μ is the drift of the asset price κ is the rate of mean reversion of variance θ is the long-term mean of variance σ_v is the volatility of variance ρ is the correlation between the two Wiener processes W_S and W_v """
[docs] def __init__(self, kappa_init=1.0, theta_init=0.04, sigma_v_init=0.5, rho_init=-0.5, v0_init=0.04, mu_init=0.0): """ Initialize the Heston model. Args: kappa_init (float): Initial value for rate of mean reversion of variance. theta_init (float): Initial value for long-term mean of variance. sigma_v_init (float): Initial value for volatility of variance. rho_init (float): Initial value for correlation between asset and variance processes. v0_init (float): Initial value for variance. mu_init (float): Initial value for drift of asset price. """ params = { 'kappa': torch.tensor(kappa_init, requires_grad=True), 'theta': torch.tensor(theta_init, requires_grad=True), 'sigma_v': torch.tensor(sigma_v_init, requires_grad=True), 'rho': torch.tensor(rho_init, requires_grad=True), 'v0': torch.tensor(v0_init, requires_grad=True), 'mu': torch.tensor(mu_init, requires_grad=True) } super().__init__(params)
[docs] def simulate(self, S0, T, N, steps=100): """ Simulate asset price paths using the Heston model. Args: S0 (float): Initial asset price. T (float): Time horizon for simulation. N (int): Number of simulation paths. steps (int): Number of time steps in each path. Returns: torch.Tensor: Simulated asset prices at time T. """ dt = T / steps mu = self.params['mu'] kappa = self.params['kappa'] theta = self.params['theta'] sigma_v = self.params['sigma_v'] rho = torch.clamp(self.params['rho'], min=-0.999, max=0.999) v0 = self.params['v0'] S0 = torch.tensor(S0, device=self.device) dt = torch.tensor(dt, device=self.device) N = int(N) steps = int(steps) # Ensure parameters are positive theta = torch.clamp(theta, min=1e-6) sigma_v = torch.clamp(sigma_v, min=1e-6) v0 = torch.clamp(v0, min=1e-6) # Initialize asset price and variance paths S = torch.zeros(N, steps, device=self.device) v = torch.zeros(N, steps, device=self.device) S[:, 0] = S0 v[:, 0] = v0 for t in range(1, steps): # Generate correlated random numbers Z1 = torch.randn(N, device=self.device) Z2 = torch.randn(N, device=self.device) W_S = Z1 * torch.sqrt(dt) W_v = (rho * Z1 + torch.sqrt(1 - rho ** 2) * Z2) * torch.sqrt(dt) v_t_minus = torch.relu(v[:, t - 1]) # Ensure non-negative variance # Update variance dv = kappa * (theta - v_t_minus) * dt + sigma_v * torch.sqrt(v_t_minus) * W_v v[:, t] = v_t_minus + dv # Update asset price dS = S[:, t - 1] * (mu * dt + torch.sqrt(v_t_minus) * W_S) S[:, t] = S[:, t - 1] + dS return S[:, -1]
[docs] def option_price(self, S0, K, T, r, option_type='call', N=10000, steps=100): """ Price a European option using Monte Carlo simulation under the Heston model. Args: S0 (float): Initial asset price. K (float): Strike price. T (float): Time to maturity. r (float): Risk-free interest rate. option_type (str): 'call' or 'put'. N (int): Number of simulation paths. steps (int): Number of time steps in simulation. Returns: float: Option price. """ S_T = self.simulate(S0, T, N, steps) if option_type.lower() == 'call': payoff = torch.relu(S_T - K) elif option_type.lower() == 'put': payoff = torch.relu(K - S_T) else: raise ValueError("option_type must be 'call' or 'put'") price = torch.exp(-r * T) * torch.mean(payoff) return price.item()
[docs] def _apply_constraints(self): """ Apply constraints to model parameters to ensure they remain in valid ranges. """ self.params['theta'].data.clamp_(min=1e-6) self.params['sigma_v'].data.clamp_(min=1e-6) self.params['v0'].data.clamp_(min=1e-6) self.params['rho'].data.clamp_(min=-0.999, max=0.999)