Skip to content

Commit

Permalink
vol surface
Browse files Browse the repository at this point in the history
  • Loading branch information
lsbardel committed Jul 6, 2023
1 parent 82a8dfc commit b71640e
Show file tree
Hide file tree
Showing 8 changed files with 495 additions and 36 deletions.
2 changes: 2 additions & 0 deletions notebooks/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ format: jb-book
root: index
chapters:
- file: levy
- file: poisson
- file: inversion
- file: option_pricing
- file: heston
- file: dsp
- file: calibration
- file: volatility_surface
- file: contributing
- file: biblio
34 changes: 34 additions & 0 deletions notebooks/hurst.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.14.7
kernelspec:
display_name: Python 3 (ipykernel)
language: python
name: python3
---

# Hurst Exponent

The [Hurst exponent](https://en.wikipedia.org/wiki/Hurst_exponent) is used as a measure of long-term memory of time series. It relates to the autocorrelations of the time series, and the rate at which these decrease as the lag between pairs of values increases.

It is a statistics which can be used to test if a time-series is mean reverting or it is trending.

```{code-cell} ipython3
from quantflow.sp.cir import CIR
p = CIR(kappa=1, sigma=1)
```

# Links

* [Wikipedia](https://en.wikipedia.org/wiki/Hurst_exponent)
* [Hurst Exponent for Algorithmic Trading
](https://robotwealth.com/demystifying-the-hurst-exponent-part-1/)

```{code-cell} ipython3
```
16 changes: 6 additions & 10 deletions notebooks/dsp.md → notebooks/poisson.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ The library includes the Exponential Poisson Process, a compound Poisson process
```{code-cell} ipython3
from quantflow.sp.poisson import ExponentialPoissonProcess
p = ExponentialPoissonProcess(rate=1, decay=1)
p
pr = ExponentialPoissonProcess(rate=1, decay=10)
pr
```

```{code-cell} ipython3
pr.paths(10, t=1, steps=1000).plot()
```

## Doubly Stochastic Poisson Process
Expand Down Expand Up @@ -87,11 +91,3 @@ The intensity function of a DSPP is given by:
\begin{equation}
{\mathbb P}\left(N_T - N_t = n\right) = {\mathbb E}_t\left[e^{-\Lambda_{t,T}} \frac{\Lambda_{t, T}^n}{n!}\right] = \frac{1}{n!}
\end{equation}

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

```{code-cell} ipython3
```
79 changes: 79 additions & 0 deletions notebooks/volatility_surface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.14.7
kernelspec:
display_name: Python 3 (ipykernel)
language: python
name: python3
---

# Volatility Surface

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.

First thing, fetch the data

```{code-cell} ipython3
from quantflow.data.client import HttpClient
deribit_url = "https://test.deribit.com/api/v2/public/get_book_summary_by_currency"
async with HttpClient() as cli:
futures = await cli.get(deribit_url, params=dict(currency="BTC", kind="future"))
options = await cli.get(deribit_url, params=dict(currency="BTC", kind="option"))
```

```{code-cell} ipython3
from decimal import Decimal
from quantflow.options.surface import VolSurfaceLoader
from datetime import timezone
from dateutil.parser import parse
def parse_maturity(v: str):
return parse(v).replace(tzinfo=timezone.utc, hour=8)
loader = VolSurfaceLoader()
for future in futures["result"]:
if (bid := future["bid_price"]) and (ask := future["ask_price"]):
maturity = future["instrument_name"].split("-")[-1]
if maturity == "PERPETUAL":
loader.add_spot(future, bid=Decimal(bid), ask=Decimal(ask))
else:
loader.add_forward(parse_maturity(maturity), future, bid=Decimal(bid), ask=Decimal(ask))
for option in options["result"]:
if (bid := option["bid_price"]) and (ask := option["ask_price"]):
_, maturity, strike, ot = option["instrument_name"].split("-")
call = ot == "C"
bid = Decimal(bid)
ask = Decimal(ask)
loader.add_option(Decimal(strike), parse_maturity(maturity), call, option, bid=Decimal(bid), ask=Decimal(ask))
```

Once we have loaded the data, lets create the surface and display the term-structure of forwards

```{code-cell} ipython3
vs = loader.surface()
vs.term_structure()
```

This method allows to inspect bid/ask for call options at a given cross section

```{code-cell} ipython3
vs.options_df(index=2)
```

```{code-cell} ipython3
vs.bs(index=2).options_df(index=2)
```

```{code-cell} ipython3
len(r)
```

```{code-cell} ipython3
```
21 changes: 9 additions & 12 deletions quantflow/utils/bs.py → quantflow/options/bs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
from scipy.optimize import newton
from scipy.stats import norm

from .types import Vector


def black_call(k: Vector, sigma: float, t: float) -> Vector:
def black_call(k: np.ndarray, sigma: np.ndarray, t: np.ndarray) -> np.ndarray:
"""Calculate the Black call option price from the log strike,
volatility and time to maturity
"""
Expand All @@ -16,7 +14,7 @@ def black_call(k: Vector, sigma: float, t: float) -> Vector:
return norm.cdf(d1) - np.exp(k) * norm.cdf(d2)


def black_vega(k: Vector, sigma: float, t: float) -> Vector:
def black_vega(k: np.ndarray, sigma: np.ndarray, t: np.ndarray) -> np.ndarray:
"""Calculate the Black call option vega from the log strike,
volatility and time to maturity
"""
Expand All @@ -27,17 +25,16 @@ def black_vega(k: Vector, sigma: float, t: float) -> Vector:


def implied_black_volatility(
k: Vector, price: Vector, t: float, initial_sigma: float = 0.5
) -> Vector:
k: np.ndarray, price: np.ndarray, ttm: np.ndarray, initial_sigma: np.ndarray
) -> np.ndarray:
"""Calculate the implied block volatility from
1) a vector of log strikes/spot
2) a corresponding vector of call prices
1) a vector of log(strikes/forward)
2) a corresponding vector of call_price/forward
3) time to maturity and
4) initial volatility guess
"""
sigma_0 = initial_sigma * np.ones(np.shape(price))
return newton(
lambda x: black_call(k, x, t) - price,
sigma_0,
fprime=lambda x: black_vega(k, x, t),
lambda x: black_call(k, x, ttm) - price,
initial_sigma,
fprime=lambda x: black_vega(k, x, ttm),
)
Loading

0 comments on commit b71640e

Please sign in to comment.