Skip to content

Commit d748fd7

Browse files
committed
Jump diffusion and hestonj use the same parameters
1 parent 63c0b59 commit d748fd7

16 files changed

+182
-132
lines changed

.vscode/launch.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"args": [
1515
"-x",
1616
"-vvv",
17-
"quantflow_tests/test_utils.py",
17+
"quantflow_tests/test_jump_diffusion.py",
1818
]
1919
},
2020
]

notebooks/api/sp/jump_diffusion.rst

-8
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,3 @@ The most famous jump-diffusion model is the Merton model, which was introduced b
1414
:member-order: groupwise
1515
:autosummary:
1616
:autosummary-nosignatures:
17-
18-
19-
20-
.. autoclass:: Merton
21-
:members:
22-
:member-order: groupwise
23-
:autosummary:
24-
:autosummary-nosignatures:

notebooks/examples/heston_vol_surface.md

+9-6
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,24 @@ kernelspec:
1111
name: python3
1212
---
1313

14-
# Heston Volatility Surface
14+
# HestonJ Volatility Surface
1515

16-
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.
16+
Here we study the Implied volatility surface of the Heston model with jumps.
17+
The Heston model is a stochastic volatility model that is widely used in the finance industry to price options.
1718

1819
```{code-cell} ipython3
1920
from quantflow.sp.heston import HestonJ
21+
from quantflow.utils.distributions import DoubleExponential
2022
from quantflow.options.pricer import OptionPricer
2123
22-
pricer = OptionPricer(model=HestonJ.exponential(
24+
pricer = OptionPricer(model=HestonJ.create(
25+
DoubleExponential,
2326
vol=0.5,
2427
kappa=2,
25-
rho=0.0,
26-
sigma=0.6,
28+
rho=-0.2,
29+
sigma=0.8,
2730
jump_fraction=0.5,
28-
jump_asymmetry=1.0
31+
jump_asymmetry=0.2
2932
))
3033
pricer
3134
```

notebooks/models/bns.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ This means that the characteristic function of $y_t$ can be represented as
2828
&= {\mathbb E}\left[\exp{\left(-\tau_t \phi_{w, u} + i u \rho z_{\kappa t}\right)}\right]
2929
\end{align}
3030

31-
$\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.
31+
$\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.
3232

3333
```{code-cell}
3434
from quantflow.sp.bns import BNS

notebooks/models/heston.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jupytext:
77
format_version: 0.13
88
jupytext_version: 1.16.6
99
kernelspec:
10-
display_name: Python 3 (ipykernel)
10+
display_name: .venv
1111
language: python
1212
name: python3
1313
---
@@ -31,20 +31,20 @@ This means that the characteristic function of $y_t=x_{\tau_t}$ can be represent
3131
&= e^{-a_{t,u} - b_{t,u} \nu_0}
3232
\end{align}
3333

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

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

4545
## Characteristic Function
4646

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

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

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

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

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

7171
## Option pricing
7272

73-
```{code-cell}
73+
```{code-cell} ipython3
7474
from quantflow.options.pricer import OptionPricer
7575
from quantflow.sp.heston import Heston
7676
pricer = OptionPricer(Heston.create(vol=0.6, kappa=2, sigma=0.8, rho=-0.2))
7777
pricer
7878
```
7979

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

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

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

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

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

115-
```{code-cell}
115+
```{code-cell} ipython3
116116
import pandas as pd
117117
from quantflow.utils import plot
118118
@@ -122,12 +122,12 @@ df = pd.DataFrame(mean, index=paths.time)
122122
plot.plot_lines(df)
123123
```
124124

125-
```{code-cell}
125+
```{code-cell} ipython3
126126
std = dict(std=pr.marginal(paths.time).std(), simulated=paths.std())
127127
df = pd.DataFrame(std, index=paths.time)
128128
plot.plot_lines(df)
129129
```
130130

131-
```{code-cell}
131+
```{code-cell} ipython3
132132
133133
```

notebooks/models/heston_jumps.md

+14-6
Original file line numberDiff line numberDiff line change
@@ -30,41 +30,49 @@ where $j_t$ is a double exponential Compound Poisson process which adds three ad
3030
* the jump percentage (fraction) contribution to the total variance
3131
* the jump asymmetry is defined as a parameter greater than 0; 1 means jump are symmetric
3232

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

3536
```{code-cell} ipython3
3637
from quantflow.sp.heston import HestonJ
37-
pr = HestonJ.exponential(
38+
from quantflow.utils.distributions import DoubleExponential
39+
pr = HestonJ.create(
40+
DoubleExponential,
3841
vol=0.6,
3942
kappa=2,
4043
sigma=0.8,
41-
rho=-0.2,
44+
rho=-0.0,
4245
jump_intensity=50,
4346
jump_fraction=0.2,
44-
jump_asymmetry=1.2
47+
jump_asymmetry=0.0
4548
)
4649
pr
4750
```
4851

4952
```{code-cell} ipython3
5053
from quantflow.utils import plot
51-
plot.plot_marginal_pdf(pr.marginal(0.1), 128, normal=True, analytical=False)
54+
plot.plot_marginal_pdf(pr.marginal(0.5), 128, normal=True, analytical=False)
5255
```
5356

5457
```{code-cell} ipython3
5558
from quantflow.options.pricer import OptionPricer
56-
from quantflow.sp.heston import Heston
5759
pricer = OptionPricer(pr)
5860
pricer
5961
```
6062

6163
```{code-cell} ipython3
64+
6265
fig = None
6366
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):
67+
6468
fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
6569
fig.update_layout(title="Implied black vols", height=500)
6670
```
6771

6872
```{code-cell} ipython3
6973
7074
```
75+
76+
```{code-cell} ipython3
77+
78+
```

notebooks/models/jump_diffusion.md

+39-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jupytext:
66
format_version: 0.13
77
jupytext_version: 1.16.6
88
kernelspec:
9-
display_name: Python 3 (ipykernel)
9+
display_name: .venv
1010
language: python
1111
name: python3
1212
---
@@ -17,47 +17,52 @@ The library allows to create a vast array of jump-diffusion models. The most fam
1717

1818
## Merton Model
1919

20-
```{code-cell}
21-
from quantflow.sp.jump_diffusion import Merton
20+
```{code-cell} ipython3
21+
from quantflow.sp.jump_diffusion import JumpDiffusion
22+
from quantflow.utils.distributions import Normal
2223
23-
pr = Merton.create(diffusion_percentage=0.2, jump_intensity=50, jump_skew=-0.5)
24-
pr
24+
merton = JumpDiffusion.create(Normal, jump_fraction=0.8, jump_intensity=50)
2525
```
2626

2727
### Marginal Distribution
2828

29-
```{code-cell}
30-
m = pr.marginal(0.02)
29+
```{code-cell} ipython3
30+
m = merton.marginal(0.02)
3131
m.std(), m.std_from_characteristic()
3232
```
3333

34-
```{code-cell}
34+
```{code-cell} ipython3
35+
m2 = jd.marginal(0.02)
36+
m2.std(), m2.std_from_characteristic()
37+
```
38+
39+
```{code-cell} ipython3
3540
from quantflow.utils import plot
3641
3742
plot.plot_marginal_pdf(m, 128, normal=True, analytical=False, log_y=True)
3843
```
3944

4045
### Characteristic Function
4146

42-
```{code-cell}
47+
```{code-cell} ipython3
4348
plot.plot_characteristic(m)
4449
```
4550

4651
### Option Pricing
4752

4853
We can price options using the `OptionPricer` tooling.
4954

50-
```{code-cell}
55+
```{code-cell} ipython3
5156
from quantflow.options.pricer import OptionPricer
52-
pricer = OptionPricer(pr)
57+
pricer = OptionPricer(merton)
5358
pricer
5459
```
5560

56-
```{code-cell}
61+
```{code-cell} ipython3
5762
fig = None
5863
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):
5964
fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
60-
fig.update_layout(title="Implied black vols", height=500)
65+
fig.update_layout(title="Implied black vols - Merton", height=500)
6166
```
6267

6368
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.
@@ -67,14 +72,30 @@ For very short time-to-maturities, however, the model has no problem in producin
6772

6873
### MC paths
6974

70-
```{code-cell}
71-
pr.sample(20, time_horizon=1, time_steps=1000).plot().update_traces(line_width=0.5)
75+
```{code-cell} ipython3
76+
merton.sample(20, time_horizon=1, time_steps=1000).plot().update_traces(line_width=0.5)
7277
```
7378

7479
## Exponential Jump Diffusion
7580

76-
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.
81+
This is a variation of the Mertoin model, where the jump distribution is a double exponential.
82+
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.
83+
84+
```{code-cell} ipython3
85+
from quantflow.utils.distributions import DoubleExponential
86+
87+
jd = JumpDiffusion.create(DoubleExponential, jump_fraction=0.8, jump_intensity=50, jump_asymmetry=0.2)
88+
pricer = OptionPricer(jd)
89+
pricer
90+
```
91+
92+
```{code-cell} ipython3
93+
fig = None
94+
for ttm in (0.05, 0.1, 0.2, 0.4, 0.6, 1):
95+
fig = pricer.maturity(ttm).plot(fig=fig, name=f"t={ttm}")
96+
fig.update_layout(title="Implied black vols - Double-exponential Jump Diffusion ", height=500)
97+
```
98+
99+
```{code-cell} ipython3
77100
78-
```{code-cell}
79-
from
80101
```

0 commit comments

Comments
 (0)