Skip to content
All library documents

Simulating Kou Double-Exponential Jumps and Checking Risk-Neutral Prices

Article Quant Q&A · Author: AnonymousJ

Summary

The document describes simulating jump increments from Kou’s asymmetric double-exponential model. Its proposed procedure draws a Poisson number of jumps, splits them into upward and downward counts with a binomial draw, then models the total jump size on each side with exponential random variables. It also raises a pricing sanity check: simulated at-the-money put and call prices differ when jumps are included, despite the expected put-call parity relationship under the stated setup.

The accepted response recommends checking simulated means and variances against analytic values and testing asymmetric parameter choices. That is a useful diagnostic, but the displayed NumPy code has a key implementation issue: the exponential scale should represent the size of an individual jump, while the number of jumps determines the gamma-distributed sum; using the count as the scale does not implement that sum. The document does not resolve the risk-neutral drift or parity discrepancy, so its pricing results should be treated as a prompt for further validation, not confirmation of correctness.

Key ideas

  • A Kou jump increment combines upward and downward exponential jump sizes with Poisson-distributed arrival counts.
  • The number of jumps on each side can be allocated with a binomial draw based on the upward-jump probability.
  • For multiple jumps, total jump magnitudes follow gamma distributions rather than exponentials with a count-scaled parameter.
  • Comparing empirical moments with analytic moments can help identify simulation errors.
  • Put-call parity can serve as a pricing diagnostic, but the document does not resolve its reported discrepancy.

Tags

Full text
# Simulating Kou's Asymmetric Double Exponential Random Variable


# Simulating Kou's Asymmetric Double Exponential Random Variable












In Python, I import NumPy module to generate Kou's a vector of Asymmetric Double Exponential Random Variables (ADERV). I attempt to apply Glasserman's method for simulating the aforementioned from his 2004 book Monte Carlo Methods in Financial Engineering on page 139, which is the following (with slight difference in notation):

- generate $N \sim \text{Poisson}(\lambda (t_{i+1}-t_{i}))$ where $\lambda$ is the number of jumps per annum

- generate $K \sim \text{Binomial(N,p)}$ where $p$ is the probability of upward jumps

- generate $R_{1} \sim \text{Exponential}(K / \eta_{1})$ and $R_{2} \sim \text{Exponential}((N-K) / \eta_{2})$ where $1/\eta_{1}$ and $1/\eta_{2}$ are the magnitude of up and down jumps, respectively.

- set $M=R_{1} - R_{2}$ where $M$ is the ADERV

Given $t_{i+1}-t_{i} = 10 / 252$, below is the code to generate ADERVs

```
import numpy as np
import seaborn as sns import
import matplotlib.pyplot as plt

n = np.random.poisson(lam=20 * (10 / 252), size=100_000)
k = np.random.binomial(n=n, p=0.50)
r1 = np.random.exponential(scale=k / 25)
r2 = np.random.exponential(scale=(n - k) / 25)
m = r1 - r2

sns.displot(m, kind='kde')
```

Question is is the above code a correct implementation?

-----Further discussion

I discretize $\frac{dS_{t}}{S_{t-}} = \left[r - \left(\frac{p}{\eta_{1}} - \frac{q}{\eta_{2}} \right) \lambda \right]dt + \sigma dW_{t}^{\mathbb{Q}} + d\left(\sum_{j=1}^{N_{t}} V_{j} - 1 \right)$ where $W_{t}^{\mathbb{Q}}$ is a Brownian motion under risk-neutral measure, $N_{t}$ is a Poisson process with intensity rate $\lambda > 0$, and $\{V_{j}\}$ is a series of IID non-negative r.v. s.t. $\Upsilon = \log(V_{j})$ has an asymmetric double exponential distribution to simulate MC paths to price a contingent claim $h(X)$.

As an easier pricing exercise and to sanity check, I define $h(X)$ to be an AtM Vanilla European put with $K=100$ and price it with $r=0$, $\lambda=20$, $p=q=0.5$, $\sigma=0.3$, $\eta_{1}=\eta_{2}=25$, and $T=10/252$. I use MC to simulate 100k paths. Lastly, I do the same thing but define $h(X)$ to be AtM Vanilla European call with same strike as the put. The random number generator is Mersenne Twister with seed number 20240101 in NumPy library.

The put price is 2.9566 and the call is 3.0876. Per put-call parity, I expect equivalent (or very close). However, if I assume $\lambda=0$, then the put price and call is roughly inline (call 2.3745 vs. put 2.3887). It could be I'm compensating for the jumps incorrectly (i.e., the drift).

## Answer by Andrea (score 0, accepted)

https://quant.stackexchange.com/a/81318

I think it is good (with the missing imports).

A good way to check is if the mean and variance of each `r1` and `r2` are what you expect them to be.

For the up-mean, you can do: `lam * p_up * size_up`, and print `r1.mean()` and so on.

With your values I get 0.015988326898183785 vs 0.015873015873015872 so pretty good.

And you can compute analytic variance for a full check. Make sure you test non symmetric cases too.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.