Skip to content

Commit 4b3c8ab

Browse files
authored
Fix docs (#27)
1 parent fd81b94 commit 4b3c8ab

File tree

12 files changed

+163
-52
lines changed

12 files changed

+163
-52
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.defaultInterpreterPath": ".venv/bin/python"
3+
}

notebooks/api/utils/distributions.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Distributions
44

55
.. module:: quantflow.utils.distributions
66

7+
.. autoclass:: Distribution1D
8+
:members:
9+
:member-order: groupwise
10+
:autosummary:
11+
:autosummary-nosignatures:
12+
13+
714
.. autoclass:: Exponential
815
:members:
916
:member-order: groupwise

notebooks/applications/volatility_surface.md

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ 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
---
1313

1414
# Volatility Surface
1515

16-
In this notebook we illustrate the use of the Volatility Surface tool in the library. We use [deribit](https://docs.deribit.com/) options on BTCUSD as example.
16+
In this notebook we illustrate the use of the Volatility Surface tool in the library. We use [deribit](https://docs.deribit.com/) options on ETHUSD as example.
1717

1818
First thing, fetch the data
1919

@@ -28,7 +28,7 @@ Once we have loaded the data, we create the surface and display the term-structu
2828

2929
```{code-cell} ipython3
3030
vs = loader.surface()
31-
vs.maturities = vs.maturities[1:]
31+
vs.maturities = vs.maturities
3232
vs.term_structure()
3333
```
3434

@@ -58,7 +58,22 @@ df
5858
The plot function is enabled only if [plotly](https://plotly.com/python/) is installed
5959

6060
```{code-cell} ipython3
61-
vs.plot().update_layout(height=500, title="BTC Volatility Surface")
61+
from plotly.subplots import make_subplots
62+
63+
# consider 6 expiries
64+
vs6 = vs.trim(6)
65+
66+
titles = []
67+
for row in range(2):
68+
for col in range(3):
69+
index = row * 3 + col
70+
titles.append(f"Expiry {vs6.maturities[index].maturity}")
71+
fig = make_subplots(rows=2, cols=3, subplot_titles=titles).update_layout(height=600, title="ETH Volatility Surface")
72+
for row in range(2):
73+
for col in range(3):
74+
index = row * 3 + col
75+
vs6.plot(index=index, fig=fig, showlegend=False, fig_params=dict(row=row+1, col=col+1))
76+
fig
6277
```
6378

6479
The `moneyness_ttm` is defined as
@@ -70,24 +85,26 @@ The `moneyness_ttm` is defined as
7085
where $T$ is the time-to-maturity.
7186

7287
```{code-cell} ipython3
73-
vs.plot3d().update_layout(height=800, title="BTC Volatility Surface", scene_camera=dict(eye=dict(x=1, y=-2, z=1)))
88+
vs6.plot3d().update_layout(height=800, title="ETH Volatility Surface", scene_camera=dict(eye=dict(x=1, y=-2, z=1)))
7489
```
7590

7691
## Model Calibration
7792

7893
We can now use the Vol Surface to calibrate the Heston stochastic volatility model.
7994

8095
```{code-cell} ipython3
81-
from quantflow.options.calibration import HestonCalibration, OptionPricer
82-
from quantflow.sp.heston import Heston
96+
from quantflow.options.calibration import HestonJCalibration, OptionPricer
97+
from quantflow.utils.distributions import DoubleExponential
98+
from quantflow.sp.heston import HestonJ
8399
84-
pricer = OptionPricer(Heston.create(vol=0.5))
85-
cal = HestonCalibration(pricer=pricer, vol_surface=vs, moneyness_weight=-0)
100+
model = HestonJ.create(DoubleExponential, vol=0.8, sigma=1.5, kappa=0.5, rho=0.1, jump_intensity=50, jump_fraction=0.3)
101+
pricer = OptionPricer(model=model)
102+
cal = HestonJCalibration(pricer=pricer, vol_surface=vs6, moneyness_weight=-0)
86103
len(cal.options)
87104
```
88105

89106
```{code-cell} ipython3
90-
cal.model
107+
cal.model.model_dump()
91108
```
92109

93110
```{code-cell} ipython3
@@ -99,7 +116,7 @@ pricer.model
99116
```
100117

101118
```{code-cell} ipython3
102-
cal.plot(index=6, max_moneyness_ttm=1)
119+
cal.plot(index=5, max_moneyness_ttm=1)
103120
```
104121

105122
##

notebooks/models/poisson.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ The most common process is the Poisson process.
1919

2020
## Poisson Process
2121

22-
The Poisson Process $N_t$ with intensity parameter $\lambda > 0$ is a Lévy process with values in $N$ such that each $N_t$ has a [Poisson distribution](https://en.wikipedia.org/wiki/Poisson_distribution) with parameter $\lambda t$, that is
22+
The Poisson Process $n_t$ with intensity parameter $\lambda > 0$ is a Lévy process with values in ${\mathbb N}$ such that each $n_t$ has a [Poisson distribution](https://en.wikipedia.org/wiki/Poisson_distribution) with parameter $\lambda t$, that is
2323

2424
\begin{equation}
25-
P\left(N_t=n\right) = \frac{\left(\lambda t\right)^n}{n!}e^{-\lambda t}
25+
{\mathbb P}_{n_t}\left(n_t=n\right) = \frac{\left(\lambda t\right)^n}{n!}e^{-\lambda t}
2626
\end{equation}
2727

28-
The characteristic exponent is given by
28+
The [](characteristic-exponent) is given by
2929

3030
\begin{equation}
31-
\phi_{N_t, u} = t \lambda \left(1 - e^{iu}\right)
31+
\phi_{n_t, u} = t \lambda \left(1 - e^{iu}\right)
3232
\end{equation}
3333

3434
```{code-cell} ipython3

notebooks/models/weiner.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ In this document, we use the term Weiner process $w_t$ to indicate a Brownian mo
1818
1. $w_t$ is Lévy process
1919
2. $d w_t = w_{t+dt}-w_t \sim N\left(0, \sigma dt\right)$ where $N$ is the normal distribution
2020

21-
The characteristic exponent of $w$ is
21+
The [](characteristic-exponent) of $w$ is
2222
\begin{equation}
2323
\phi_{w, u} = \frac{\sigma^2 u^2}{2}
2424
\end{equation}

notebooks/reference/glossary.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,30 @@ kernelspec:
1515

1616
## Characteristic Function
1717

18-
The characteristic function of a random variable $X$ is the Fourier transform of $f_X$, where $f_X$ is the probability density function
19-
of $X$
18+
The [characteristic function](../theory/characteristic.md) of a random variable $x$ is the Fourier transform of ${\mathbb P}_x$,
19+
where ${\mathbb P}_x$ is the distrubution measure of $x$.
20+
2021
\begin{equation}
21-
\Phi_{X,u} = {\mathbb E}\left[e^{i u X_t}\right] = \int e^{i u x} f_X\left(x\right) dx
22+
\Phi_{x,u} = {\mathbb E}\left[e^{i u x}\right] = \int e^{i u s} {\mathbb P}_x\left(d s\right)
2223
\end{equation}
2324

25+
If $x$ is a continuous random variable, than the characteristic function is the Fourier transform of the PDF $f_x$.
26+
27+
\begin{equation}
28+
\Phi_{x,u} = {\mathbb E}\left[e^{i u x}\right] = \int e^{i u s} f_x\left(s\right) ds
29+
\end{equation}
30+
31+
2432
## Cumulative Distribution Function (CDF)
2533

2634
The cumulative distribution function (CDF), or just distribution function,
27-
of a real-valued random variable $X$ is the function given by
35+
of a real-valued random variable $x$ is the function given by
2836
\begin{equation}
29-
F_X(x) = P(X \leq x)
37+
F_x(s) = {\mathbb P}_x(x \leq s)
3038
\end{equation}
3139

40+
where ${\mathbb P}_x$ is the distrubution measure of $x$.
41+
3242
## Hurst Exponent
3343

3444
The Hurst exponent is a measure of the long-term memory of time series. The Hurst exponent is a measure of the relative tendency of a time series either to regress strongly to the mean or to cluster in a direction.
@@ -66,5 +76,5 @@ The [probability density function](https://en.wikipedia.org/wiki/Probability_den
6676
(PDF), or density, of a continuous random variable, is a function that describes the relative likelihood for this random variable to take on a given value. It is related to the CDF by the formula
6777

6878
\begin{equation}
69-
F_X(x) = \int_{-\infty}^x f_X(s) ds
79+
F_x(x) = \int_{-\infty}^x f_x(s) ds
7080
\end{equation}

notebooks/theory/characteristic.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ kernelspec:
1313

1414
# Characteristic Function
1515

16-
The library makes heavy use of characteristic function concept and therefore, it is useful to familiarize with it.
16+
The library makes heavy use of [characteristic function](https://en.wikipedia.org/wiki/Characteristic_function_(probability_theory))
17+
concept and therefore, it is useful to familiarize with it.
1718

1819
## Definition
1920

20-
The characteristic function of a random variable $x$ is the Fourier (inverse) transform of $P^x$, where $P^x$ is the distrubution measure of $x$
21+
The characteristic function of a random variable $x$ is the Fourier (inverse) transform of ${\mathbb P}_x$, where ${\mathbb P}_x$ is the distrubution measure of $x$
2122
\begin{equation}
22-
\Phi_{x,u} = {\mathbb E}\left[e^{i u x_t}\right] = \int e^{i u x} P^x\left(dx\right)
23+
\Phi_{x,u} = {\mathbb E}\left[e^{i u x}\right] = \int e^{i u s} {\mathbb P}_x\left(ds\right)
2324
\end{equation}
2425

2526
## Properties
@@ -30,6 +31,7 @@ The characteristic function of a random variable $x$ is the Fourier (inverse) tr
3031
* it is continuous
3132
* characteristic function of a symmetric random variable is real-valued and even
3233
* moments of $x$ are given by
34+
3335
\begin{equation}
3436
{\mathbb E}\left[x^n\right] = i^{-n} \left.\frac{\Phi_{x, u}}{d u}\right|_{u=0}
3537
\end{equation}
@@ -45,10 +47,13 @@ The characteristic function is a great tool for working with linear combination
4547
\end{equation}
4648

4749
* which means, if $x$ and $y$ are independent, the characteristic function of $x+y$ is the product
50+
4851
\begin{equation}
4952
\Phi_{x+x,u} = \Phi_{x,u}\Phi_{y,u}
5053
\end{equation}
54+
5155
* The characteristic function of $ax+b$ is
56+
5257
\begin{equation}
5358
\Phi_{ax+b,u} = e^{iub}\Phi_{x,au}
5459
\end{equation}
@@ -62,18 +67,27 @@ There is a one-to-one correspondence between cumulative distribution functions a
6267
The inversion formula for these distributions is given by
6368

6469
\begin{equation}
65-
{\mathbb P}\left(x\right) = \frac{1}{2\pi}\int_{-\infty}^\infty e^{-iuk}\Phi_{x, u} du
70+
{\mathbb P}_x\left(x=s\right) = \frac{1}{2\pi}\int_{-\infty}^\infty e^{-ius}\Phi_{s, u} du
6671
\end{equation}
6772

6873
### Discrete distributions
6974

70-
In these distributions, the random variable $x$ takes integer values. For example, the Poisson distribution is discrete.
75+
In these distributions, the random variable $x$ takes integer values $k$. For example, the Poisson distribution is discrete.
7176
The inversion formula for these distributions is given by
7277

7378
\begin{equation}
74-
{\mathbb P}\left(x=k\right) = \frac{1}{2\pi}\int_{-\pi}^\pi e^{-iuk}\Phi_{x, u} du
79+
{\mathbb P}_x\left(x=k\right) = \frac{1}{2\pi}\int_{-\pi}^\pi e^{-iuk}\Phi_{k, u} du
7580
\end{equation}
7681

7782
```{code-cell}
7883
7984
```
85+
86+
(characteristic-exponent)=
87+
## Characteristic Exponent
88+
89+
The characteristic exponent $\phi_{x,u}$ is defined as
90+
91+
\begin{equation}
92+
\Phi_{x,u} = e^{-\phi_{x,u}}
93+
\end{equation}

notebooks/theory/levy.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ The independence and stationarity of the increments of the Lévy process imply t
3434
\Phi_{x_t, u} = {\mathbb E}\left[e^{i u x_t}\right] = e^{-\phi_{x_t, u}} = e^{-t \phi_{x_1,u}}
3535
\end{equation}
3636

37-
where the **characteristic exponent** $\phi_{x_1,u}$ is given by the [Lévy–Khintchine formula](https://en.wikipedia.org/wiki/L%C3%A9vy_process).
37+
where the [](characteristic-exponent) $\phi_{x_1,u}$ is given by the [Lévy–Khintchine formula](https://en.wikipedia.org/wiki/L%C3%A9vy_process).
3838

39-
There are several Lévy processes in the literature, including, importantly, the [Poisson process](../models/poisson.md), the compound Poisson process, and the Brownian motion.
39+
There are several Lévy processes in the literature, including, the [Poisson process](../models/poisson.md), the compound Poisson process
40+
and the [Brownian motion](../models/weiner.md).
4041

4142
+++
4243

quantflow/options/calibration.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,31 @@ def get_bounds(self) -> Sequence[Bounds] | None:
253253
vol_range = self.implied_vol_range()
254254
vol_lb = 0.5 * vol_range.lb[0]
255255
vol_ub = 1.5 * vol_range.ub[0]
256-
return Bounds(
257-
[vol_lb * vol_lb, vol_lb * vol_lb, 0.0, 0.0, -0.9],
258-
[vol_ub * vol_ub, vol_ub * vol_ub, np.inf, np.inf, 0.0],
259-
)
256+
lower = [
257+
(0.5 * vol_lb) ** 2, # rate
258+
(0.5 * vol_lb) ** 2, # theta
259+
0.001, # kappa - mean reversion speed
260+
0.001, # sigma - vol of vol
261+
-0.9, # correlation
262+
1.0, # jump intensity
263+
(0.01 * vol_lb) ** 2, # jump variance
264+
]
265+
upper = [
266+
(1.5 * vol_ub) ** 2, # rate
267+
(1.5 * vol_ub) ** 2, # theta
268+
np.inf, # kappa
269+
np.inf, # sigma
270+
0.0, # correlation
271+
np.inf, # jump intensity
272+
(0.5 * vol_ub) ** 2, # jump variance
273+
]
274+
try:
275+
self.model.jumps.jumps.asymmetry()
276+
lower.append(-2.0) # jump asymmetry
277+
upper.append(2.0)
278+
except NotImplementedError:
279+
pass
280+
return Bounds(lower, upper)
260281

261282
def get_params(self) -> np.ndarray:
262283
params = [

quantflow/options/surface.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import enum
44
import warnings
5-
from dataclasses import dataclass, field
5+
from dataclasses import dataclass, field, replace
66
from datetime import datetime, timedelta
77
from decimal import Decimal
8-
from typing import Any, Generic, Iterator, NamedTuple, Protocol, TypeVar
8+
from typing import Any, Generic, Iterator, NamedTuple, Protocol, Self, TypeVar
99

1010
import numpy as np
1111
import pandas as pd
@@ -430,6 +430,10 @@ def term_structure(self, frequency: float = 0) -> pd.DataFrame:
430430
cross.info_dict(self.ref_date, self.spot) for cross in self.maturities
431431
)
432432

433+
def trim(self, num_maturities: int) -> Self:
434+
"""Create a new volatility surface with the last `num_maturities` maturities"""
435+
return replace(self, maturities=self.maturities[-num_maturities:])
436+
433437
def option_prices(
434438
self,
435439
*,

quantflow/utils/distributions.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,26 @@ def from_variance_and_asymmetry(cls, variance: float, asymmetry: float) -> Self:
2424
raise NotImplementedError
2525

2626
def asymmetry(self) -> float:
27-
"""Asymmetry of the distribution"""
27+
"""Asymmetry of the distribution, 0 for symmetric
28+
29+
Implemented by distributions that have asymmetry
30+
"""
2831
raise NotImplementedError
2932

3033
def set_variance(self, variance: float) -> None:
3134
"""Set the variance of the distribution"""
3235
raise NotImplementedError
3336

3437
def set_asymmetry(self, asymmetry: float) -> None:
35-
"""Set the asymmetry of the distribution"""
38+
"""Set the asymmetry of the distribution
39+
40+
Implemented by distributions that have asymmetry
41+
"""
3642
raise NotImplementedError
3743

3844

3945
class Exponential(Distribution1D):
40-
r"""A :class:`.Marginal1D` for the `Exponential distribution`_
46+
r"""A :class:`.Distribution1D` for the `Exponential distribution`_
4147
4248
The exponential distribution is a continuous probability distribution with PDF
4349
given by
@@ -90,8 +96,21 @@ def cdf(self, x: FloatArrayLike) -> FloatArrayLike:
9096

9197

9298
class Normal(Distribution1D):
99+
r"""A :class:`.Distribution1D` for the `Normal distribution`_
100+
101+
The normal distribution is a continuous probability distribution with PDF
102+
given by
103+
104+
.. math::
105+
f(x) = \frac{e^{-\frac{\left(x - \mu\right)^2}{2\sigma^2}}}{\sqrt{2\pi\sigma^2}}
106+
107+
.. _Normal distribution: https://en.wikipedia.org/wiki/Normal_distribution
108+
"""
109+
93110
mu: float = Field(default=0, description="mean")
111+
r"""The mean :math:`\mu` of the normal distribution"""
94112
sigma: float = Field(default=1, gt=0, description="standard deviation")
113+
r"""The standard deviation :math:`\sigma` of the normal distribution"""
95114

96115
@classmethod
97116
def from_variance_and_asymmetry(cls, variance: float, asymmetry: float) -> Self:
@@ -188,7 +207,8 @@ def characteristic(self, u: Vector) -> Vector:
188207
r"""Characteristic function of the double exponential distribution
189208
190209
.. math::
191-
\phi(u) = \frac{e^{i u \mu}}{1 - \sigma^2 u^2}
210+
\phi(u) = \frac{e^{i u m}}{\left(1 + \frac{i u \kappa}{\lambda}\right)
211+
\left(1 - \frac{i u}{\lambda \kappa}\right)}
192212
"""
193213
den = (1.0 + 1j * u * self.kappa / self.decay) * (
194214
1.0 - 1j * u / (self.kappa * self.decay)

0 commit comments

Comments
 (0)