At1uri/quantitative-research-vault / jump_diffusion_calibrator.py
At1uri's picture
download
raw
2.79 kB
"""
Non-Gaussian Stochastic Diffusions & Jump-Diffusion Calibration Engine
Author: Ramprasad Atluri (@At1uri)
License: MIT
"""
import math
import numpy as np
class MertonJumpDiffusionEngine:
"""
Implements Robert C. Merton's (1976) Jump-Diffusion Model:
dS_t / S_{t-} = (mu - lambda * k) dt + sigma dW_t + (Y - 1) dN_t
where ln(Y) ~ N(gamma, delta^2) and N_t is a Poisson process with intensity lambda.
"""
def __init__(self, s0=100.0, r=0.04, sigma=0.18, lam=0.75, gamma=-0.05, delta=0.12):
self.s0 = s0
self.r = r
self.sigma = sigma
self.lam = lam # Jump intensity (expected jumps per year)
self.gamma = gamma # Expected jump log-size
self.delta = delta # Jump size dispersion
self.k = math.exp(self.gamma + 0.5 * (self.delta ** 2)) - 1.0 # Drift compensator
def characteristic_function(self, u, t):
"""
Closed-form characteristic function: Phi(u, t) = E[exp(i * u * ln(S_t / S_0))]
under risk-neutral measure Q.
"""
i = 1j
drift_comp = (self.r - 0.5 * (self.sigma ** 2) - self.lam * self.k)
diffusion_part = i * u * drift_comp * t - 0.5 * (u ** 2) * (self.sigma ** 2) * t
jump_part = self.lam * t * (np.exp(i * u * self.gamma - 0.5 * (u ** 2) * (self.delta ** 2)) - 1.0)
return np.exp(diffusion_part + jump_part)
def simulate_paths(self, t_years=1.0, steps=252, n_paths=1000, seed=42):
"""Vectorized Euler-Maruyama simulation with Poisson jump compounding."""
np.random.seed(seed)
dt = t_years / float(steps)
paths = np.zeros((n_paths, steps + 1))
paths[:, 0] = self.s0
drift = (self.r - 0.5 * (self.sigma ** 2) - self.lam * self.k) * dt
for t in range(steps):
# Brownian increments
z = np.random.normal(0, 1, n_paths)
diffusion = self.sigma * math.sqrt(dt) * z
# Poisson jump arrivals
n_jumps = np.random.poisson(self.lam * dt, n_paths)
jump_magnitudes = np.zeros(n_paths)
# Compound jump sizes
jump_mask = n_jumps > 0
if np.any(jump_mask):
for idx in np.where(jump_mask)[0]:
j_count = n_jumps[idx]
jump_magnitudes[idx] = np.sum(np.random.normal(self.gamma, self.delta, j_count))
ret = drift + diffusion + jump_magnitudes
paths[:, t + 1] = paths[:, t] * np.exp(ret)
return paths
if __name__ == "__main__":
engine = MertonJumpDiffusionEngine()
sims = engine.simulate_paths(steps=60, n_paths=500)
print(f"Merton Jump-Diffusion | Initial S0: 100 | Mean Terminal Price: {np.mean(sims[:, -1]):.2f}")

Xet Storage Details

Size:
2.79 kB
·
Xet hash:
e73eae9497e0941fbb0fcc0afaa0b9ac56489f7b022f7c3805d88d265395a53b

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.