Skip to content

Jump diffusion and hestonj use the same parameters #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"args": [
"-x",
"-vvv",
"quantflow_tests/test_utils.py",
"quantflow_tests/test_jump_diffusion.py",
]
},
]
Expand Down
8 changes: 0 additions & 8 deletions notebooks/api/sp/jump_diffusion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,3 @@ The most famous jump-diffusion model is the Merton model, which was introduced b
:member-order: groupwise
:autosummary:
:autosummary-nosignatures:



.. autoclass:: Merton
:members:
:member-order: groupwise
:autosummary:
:autosummary-nosignatures:
15 changes: 9 additions & 6 deletions notebooks/examples/heston_vol_surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@ kernelspec:
name: python3
---

# Heston Volatility Surface
# HestonJ Volatility Surface

Here we study the Implied volatility surface of the Heston model. The Heston model is a stochastic volatility model that is widely used in the finance industry to price options.
Here we study the Implied volatility surface of the Heston model with jumps.
The Heston model is a stochastic volatility model that is widely used in the finance industry to price options.

```{code-cell} ipython3
from quantflow.sp.heston import HestonJ
from quantflow.utils.distributions import DoubleExponential
from quantflow.options.pricer import OptionPricer

pricer = OptionPricer(model=HestonJ.exponential(
pricer = OptionPricer(model=HestonJ.create(
DoubleExponential,
vol=0.5,
kappa=2,
rho=0.0,
sigma=0.6,
rho=-0.2,
sigma=0.8,
jump_fraction=0.5,
jump_asymmetry=1.0
jump_asymmetry=0.2
))
pricer
```
Expand Down
2 changes: 1 addition & 1 deletion notebooks/models/bns.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This means that the characteristic function of $y_t$ can be represented as
&= {\mathbb E}\left[\exp{\left(-\tau_t \phi_{w, u} + i u \rho z_{\kappa t}\right)}\right]
\end{align}

$\phi_{w, u}$ is the characteristic exponent of $w_1$. The second equivalence is a consequence of $w$ and $\tau$ being independent, as discussed in [the time-changed Lévy](./levy.md) process section.
$\phi_{w, u}$ is the characteristic exponent of $w_1$. The second equivalence is a consequence of $w$ and $\tau$ being independent, as discussed in [the time-changed Lévy](../theory/levy.md) process section.

```{code-cell}
from quantflow.sp.bns import BNS
Expand Down
28 changes: 14 additions & 14 deletions notebooks/models/heston.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jupytext:
format_version: 0.13
jupytext_version: 1.16.6
kernelspec:
display_name: Python 3 (ipykernel)
display_name: .venv
language: python
name: python3
---
Expand All @@ -31,20 +31,20 @@ This means that the characteristic function of $y_t=x_{\tau_t}$ can be represent
&= e^{-a_{t,u} - b_{t,u} \nu_0}
\end{align}

```{code-cell}
```{code-cell} ipython3
from quantflow.sp.heston import Heston
pr = Heston.create(vol=0.6, kappa=2, sigma=1.5, rho=-0.1)
pr
```

```{code-cell}
```{code-cell} ipython3
# check that the variance CIR process is positive
pr.variance_process.is_positive, pr.variance_process.marginal(1).std()
```

## Characteristic Function

```{code-cell}
```{code-cell} ipython3
from quantflow.utils import plot
m = pr.marginal(0.1)
plot.plot_characteristic(m)
Expand All @@ -58,26 +58,26 @@ The immaginary part of the characteristic function is given by the correlation c

Here we compare the marginal distribution at a time in the future $t=1$ with a normal distribution with the same standard deviation.

```{code-cell}
```{code-cell} ipython3
plot.plot_marginal_pdf(m, 128, normal=True, analytical=False)
```

Using log scale on the y axis highlighs the probability on the tails much better

```{code-cell}
```{code-cell} ipython3
plot.plot_marginal_pdf(m, 128, normal=True, analytical=False, log_y=True)
```

## Option pricing

```{code-cell}
```{code-cell} ipython3
from quantflow.options.pricer import OptionPricer
from quantflow.sp.heston import Heston
pricer = OptionPricer(Heston.create(vol=0.6, kappa=2, sigma=0.8, rho=-0.2))
pricer
```

```{code-cell}
```{code-cell} ipython3
import plotly.express as px
import plotly.graph_objects as go
from quantflow.options.bs import black_call
Expand All @@ -89,7 +89,7 @@ fig.add_trace(go.Scatter(x=r.moneyness_ttm, y=b.time_value, name=b.name, line=di
fig.show()
```

```{code-cell}
```{code-cell} ipython3
fig = None
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):
fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
Expand All @@ -102,17 +102,17 @@ The simulation of the Heston model is heavily dependent on the simulation of the

The code implements algorithms from {cite:p}heston-simulation

```{code-cell}
```{code-cell} ipython3
from quantflow.sp.heston import Heston
pr = Heston.create(vol=0.6, kappa=2, sigma=0.8, rho=-0.4)
pr
```

```{code-cell}
```{code-cell} ipython3
pr.sample(20, time_horizon=1, time_steps=1000).plot().update_traces(line_width=0.5)
```

```{code-cell}
```{code-cell} ipython3
import pandas as pd
from quantflow.utils import plot

Expand All @@ -122,12 +122,12 @@ df = pd.DataFrame(mean, index=paths.time)
plot.plot_lines(df)
```

```{code-cell}
```{code-cell} ipython3
std = dict(std=pr.marginal(paths.time).std(), simulated=paths.std())
df = pd.DataFrame(std, index=paths.time)
plot.plot_lines(df)
```

```{code-cell}
```{code-cell} ipython3

```
20 changes: 14 additions & 6 deletions notebooks/models/heston_jumps.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,41 +30,49 @@ where $j_t$ is a double exponential Compound Poisson process which adds three ad
* the jump percentage (fraction) contribution to the total variance
* the jump asymmetry is defined as a parameter greater than 0; 1 means jump are symmetric

The jump process is independent of the other Brownian motions.
The jump process is independent from the Brownian motions. See [HestonJ](../api/sp/heston.rst#quantflow.sp.heston.HestonJ) for python
API documentation.

```{code-cell} ipython3
from quantflow.sp.heston import HestonJ
pr = HestonJ.exponential(
from quantflow.utils.distributions import DoubleExponential
pr = HestonJ.create(
DoubleExponential,
vol=0.6,
kappa=2,
sigma=0.8,
rho=-0.2,
rho=-0.0,
jump_intensity=50,
jump_fraction=0.2,
jump_asymmetry=1.2
jump_asymmetry=0.0
)
pr
```

```{code-cell} ipython3
from quantflow.utils import plot
plot.plot_marginal_pdf(pr.marginal(0.1), 128, normal=True, analytical=False)
plot.plot_marginal_pdf(pr.marginal(0.5), 128, normal=True, analytical=False)
```

```{code-cell} ipython3
from quantflow.options.pricer import OptionPricer
from quantflow.sp.heston import Heston
pricer = OptionPricer(pr)
pricer
```

```{code-cell} ipython3

fig = None
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):

fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
fig.update_layout(title="Implied black vols", height=500)
```

```{code-cell} ipython3

```

```{code-cell} ipython3

```
57 changes: 39 additions & 18 deletions notebooks/models/jump_diffusion.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jupytext:
format_version: 0.13
jupytext_version: 1.16.6
kernelspec:
display_name: Python 3 (ipykernel)
display_name: .venv
language: python
name: python3
---
Expand All @@ -17,47 +17,52 @@ The library allows to create a vast array of jump-diffusion models. The most fam

## Merton Model

```{code-cell}
from quantflow.sp.jump_diffusion import Merton
```{code-cell} ipython3
from quantflow.sp.jump_diffusion import JumpDiffusion
from quantflow.utils.distributions import Normal

pr = Merton.create(diffusion_percentage=0.2, jump_intensity=50, jump_skew=-0.5)
pr
merton = JumpDiffusion.create(Normal, jump_fraction=0.8, jump_intensity=50)
```

### Marginal Distribution

```{code-cell}
m = pr.marginal(0.02)
```{code-cell} ipython3
m = merton.marginal(0.02)
m.std(), m.std_from_characteristic()
```

```{code-cell}
```{code-cell} ipython3
m2 = jd.marginal(0.02)
m2.std(), m2.std_from_characteristic()
```

```{code-cell} ipython3
from quantflow.utils import plot

plot.plot_marginal_pdf(m, 128, normal=True, analytical=False, log_y=True)
```

### Characteristic Function

```{code-cell}
```{code-cell} ipython3
plot.plot_characteristic(m)
```

### Option Pricing

We can price options using the `OptionPricer` tooling.

```{code-cell}
```{code-cell} ipython3
from quantflow.options.pricer import OptionPricer
pricer = OptionPricer(pr)
pricer = OptionPricer(merton)
pricer
```

```{code-cell}
```{code-cell} ipython3
fig = None
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):
fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
fig.update_layout(title="Implied black vols", height=500)
fig.update_layout(title="Implied black vols - Merton", height=500)
```

This term structure of volatility demostrates one of the principal weakness of the Merton's model, and indeed of all jump diffusion models based on Lévy processes, namely the rapid flattening of the volatility surface as time-to-maturity increases.
Expand All @@ -67,14 +72,30 @@ For very short time-to-maturities, however, the model has no problem in producin

### MC paths

```{code-cell}
pr.sample(20, time_horizon=1, time_steps=1000).plot().update_traces(line_width=0.5)
```{code-cell} ipython3
merton.sample(20, time_horizon=1, time_steps=1000).plot().update_traces(line_width=0.5)
```

## Exponential Jump Diffusion

This is a variation of the Mertoin model, where the jump distribution is a double exponential, one for the negative jumps and one for the positive jumps.
This is a variation of the Mertoin model, where the jump distribution is a double exponential.
The advantage of this model is that it allows for an asymmetric jump distribution, which can be useful in some cases, for example options prices with a skew.

```{code-cell} ipython3
from quantflow.utils.distributions import DoubleExponential

jd = JumpDiffusion.create(DoubleExponential, jump_fraction=0.8, jump_intensity=50, jump_asymmetry=0.2)
pricer = OptionPricer(jd)
pricer
```

```{code-cell} ipython3
fig = None
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):
fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
fig.update_layout(title="Implied black vols - Double-exponential Jump Diffusion ", height=500)
```

```{code-cell} ipython3

```{code-cell}
from
```
Loading
Loading