Skip to content

Commit a76798f

Browse files
committed
More docs
1 parent 27b3544 commit a76798f

File tree

17 files changed

+189
-15
lines changed

17 files changed

+189
-15
lines changed

notebooks/api/data/deribit.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
================
2+
Deribit
3+
================
4+
5+
.. currentmodule:: quantflow.data.deribit
6+
7+
.. autoclass:: Deribit
8+
:members:
9+
:member-order: groupwise
10+
:autosummary:
11+
:autosummary-nosignatures:

notebooks/api/data/fmp.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
================
2+
FMP
3+
================
4+
5+
.. currentmodule:: quantflow.data.fmp
6+
7+
.. autoclass:: FMP
8+
:members:
9+
:member-order: groupwise
10+
:autosummary:
11+
:autosummary-nosignatures:

notebooks/api/data/fred.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
================
2+
Fred
3+
================
4+
5+
.. currentmodule:: quantflow.data.fred
6+
7+
.. autoclass:: Fred
8+
:members:
9+
:member-order: groupwise
10+
:autosummary:
11+
:autosummary-nosignatures:

notebooks/api/data/index.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,15 @@ Data fetching
44

55
.. currentmodule:: quantflow.data
66

7+
The :mod:`quantflow.data` module provides classes and functions for fetching data from various sources.
8+
To use the module the package must be installed with the optional `data` extra.
9+
```
10+
pip install quantflow[data]
11+
```
12+
13+
.. toctree::
14+
:maxdepth: 1
15+
16+
fmp
17+
fred
18+
deribit

notebooks/api/sp/heston.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ Heston process
1010
:autosummary:
1111
:autosummary-nosignatures:
1212

13+
14+
.. autoclass:: HestonJ
15+
:members:
16+
:member-order: groupwise
17+
:autosummary:
18+
:autosummary-nosignatures:

notebooks/reference/glossary.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,20 @@ Moneyness is used in the context of option pricing and it is defined as
4545

4646
where $K$ is the strike and $F$ is the Forward price. A positive value implies strikes above the forward, which means put options are in the money and call options are out of the money.
4747

48-
```{code-cell}
4948

50-
```
49+
## Moneyness Time Adjusted
50+
51+
The time-adjusted moneyness is used in the context of option pricing in order to compare options with different maturities. It is defined as
52+
53+
\begin{equation}
54+
\frac{1}{\sqrt{T}}\ln\frac{K}{F}
55+
\end{equation}
56+
57+
where $K$ is the strike and $F$ is the Forward price and $T$ is the time to maturity.
58+
59+
The key reason for dividing by the square root of time-to-maturity is related to how volatility and price movement behave over time.
60+
The price of the underlying asset is subject to random fluctuations, if these fluctuations follow a Brownian motion than the
61+
standard deviation of the price movement will increase with the square root of time.
5162

5263
## Probability Density Function (PDF)
5364

poetry.lock

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ aio-fluid = {version = "^1.2.1", extras=["http"], optional = true}
2424
rich = {version = "^13.9.4", optional = true}
2525
click = {version = "^8.1.7", optional = true}
2626
holidays = {version = "^0.63", optional = true}
27+
async-cache = {version = "^1.1.1", optional = true}
2728

2829
[tool.poetry.group.dev.dependencies]
2930
black = "^24.1.1"
@@ -37,7 +38,14 @@ isort = "^5.13.2"
3738

3839
[tool.poetry.extras]
3940
data = ["aio-fluid"]
40-
cli = ["asciichartpy", "prompt-toolkit", "rich", "click", "holidays"]
41+
cli = [
42+
"asciichartpy",
43+
"async-cache",
44+
"prompt-toolkit",
45+
"rich",
46+
"click",
47+
"holidays"
48+
]
4149

4250
[tool.poetry.group.book]
4351
optional = true
@@ -89,6 +97,7 @@ warn_no_return = true
8997
[[tool.mypy.overrides]]
9098
module = [
9199
"asciichartpy.*",
100+
"cache.*",
92101
"quantflow_tests.*",
93102
"IPython.*",
94103
"pandas.*",

quantflow/cli/commands/base.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,10 @@ class options:
115115
show_default=True,
116116
help="Historical period",
117117
)
118+
index = click.option(
119+
"-i",
120+
"--index",
121+
type=int,
122+
default=-1,
123+
help="maturity index",
124+
)

quantflow/cli/commands/crypto.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import click
66
import pandas as pd
77
from asciichartpy import plot
8+
from cache import AsyncTTL
89
from ccy.cli.console import df_to_rich
910

1011
from quantflow.data.deribit import Deribit
12+
from quantflow.options.surface import VolSurface
1113

1214
from .base import QuantContext, options, quant_group
1315

@@ -36,6 +38,48 @@ def volatility(currency: str, length: int, height: int, chart: bool) -> None:
3638
ctx.qf.print(df_to_rich(df))
3739

3840

41+
@crypto.command()
42+
@click.argument("currency")
43+
def term_structure(currency: str) -> None:
44+
"""Provides information about the term structure for given cryptocurrency"""
45+
ctx = QuantContext.current()
46+
vs = asyncio.run(get_vol_surface(currency))
47+
ts = vs.term_structure().round({"ttm": 4})
48+
ts["open_interest"] = ts["open_interest"].map("{:,d}".format)
49+
ts["volume"] = ts["volume"].map("{:,d}".format)
50+
ctx.qf.print(df_to_rich(ts))
51+
52+
53+
@crypto.command()
54+
@click.argument("currency")
55+
@options.index
56+
@options.height
57+
@options.chart
58+
def implied_vol(currency: str, index: int, height: int, chart: bool) -> None:
59+
"""Display the Volatility Surface for given cryptocurrency
60+
at a given maturity index
61+
"""
62+
ctx = QuantContext.current()
63+
vs = asyncio.run(get_vol_surface(currency))
64+
index_or_none = None if index < 0 else index
65+
vs.bs(index=index_or_none)
66+
df = vs.options_df(index=index_or_none)
67+
df["implied_vol"] = df["implied_vol"] * 100
68+
df = df.round({"ttm": 4, "moneyness": 4, "moneyness_ttm": 4, "implied_vol": 5})
69+
if chart:
70+
data = df["implied_vol"].tolist()
71+
ctx.qf.print(plot(data, {"height": height}))
72+
else:
73+
ctx.qf.print(df_to_rich(df))
74+
75+
3976
async def get_volatility(ctx: QuantContext, currency: str) -> pd.DataFrame:
4077
async with Deribit() as client:
4178
return await client.get_volatility(params=dict(currency=currency))
79+
80+
81+
@AsyncTTL(time_to_live=10)
82+
async def get_vol_surface(currency: str) -> VolSurface:
83+
async with Deribit() as client:
84+
loader = await client.volatility_surface_loader(currency)
85+
return loader.surface()

quantflow/data/client.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

quantflow/data/deribit.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ def parse_maturity(v: str) -> datetime:
1414

1515

1616
class Deribit(AioHttpClient):
17+
"""Deribit API client
18+
19+
Fetch market and static data from `Deribit`_.
20+
21+
.. _Deribit: https://docs.deribit.com/
22+
"""
23+
1724
url = "https://www.deribit.com/api/v2"
1825

1926
async def get_book_summary_by_instrument(self, **kw: Any) -> list[dict]:
@@ -38,7 +45,7 @@ async def get_volatility(self, **kw: Any) -> pd.DataFrame:
3845
return await self.get_path("public/get_historical_volatility", **kw)
3946

4047
async def volatility_surface_loader(self, currency: str) -> VolSurfaceLoader:
41-
"""Create the volatility surface loader for a given crypto-currency"""
48+
"""Create a :class:`.VolSurfaceLoader` for a given crypto-currency"""
4249
loader = VolSurfaceLoader()
4350
futures = await self.get_book_summary_by_currency(
4451
params=dict(currency=currency, kind="future")

quantflow/data/fmp.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@
88
import inflection
99
import pandas as pd
1010
from fluid.utils.data import compact_dict
11+
from fluid.utils.http_client import AioHttpClient
1112

1213
from quantflow.utils.dates import isoformat
1314
from quantflow.utils.numbers import to_decimal
1415

15-
from .client import AioHttpClient
16-
1716

1817
@dataclass
1918
class FMP(AioHttpClient):
19+
"""Financial Modeling Prep API client
20+
21+
Fetch market and financial data from `Financial Modeling Prep`_.
22+
23+
.. _Financial Modeling Prep: https://financialmodelingprep.com/developer/docs/
24+
"""
25+
2026
url: str = "https://financialmodelingprep.com/api"
2127
key: str = field(default_factory=lambda: os.environ.get("FMP_API_KEY", ""))
2228

quantflow/data/fred.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@
44
from typing import Any, cast
55

66
import pandas as pd
7-
8-
from .client import AioHttpClient
7+
from fluid.utils.http_client import AioHttpClient
98

109

1110
@dataclass
1211
class Fred(AioHttpClient):
12+
"""Federal Reserve Economic Data API client
13+
14+
Fetch economic data from `FRED`_.
15+
16+
.. _FRED: https://fred.stlouisfed.org/
17+
"""
18+
1319
url: str = "https://api.stlouisfed.org/fred"
1420
key: str = field(default_factory=lambda: os.environ.get("FRED_API_KEY", ""))
1521

@@ -25,15 +31,19 @@ class freq(StrEnum):
2531
a = "a"
2632

2733
async def categiories(self, **kw: Any) -> dict:
34+
"""Get categories"""
2835
return await self.get_path("category", **kw)
2936

3037
async def subcategories(self, **kw: Any) -> dict:
38+
"""Get subcategories of a given category"""
3139
return await self.get_path("category/children", **kw)
3240

3341
async def series(self, **kw: Any) -> dict:
42+
"""Get series of a given category"""
3443
return await self.get_path("category/series", **kw)
3544

3645
async def serie_data(self, *, to_date: bool = False, **kw: Any) -> pd.DataFrame:
46+
"""Get series data frame"""
3747
data = await self.get_path("series/observations", **kw)
3848
df = pd.DataFrame(data["observations"])
3949
df["value"] = pd.to_numeric(df["value"])

quantflow/options/surface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ def bs(
456456
index: int | None = None,
457457
initial_vol: float = INITIAL_VOL,
458458
) -> list[OptionPrice]:
459-
"""calculate Black-Scholes implied volatilities for all options
459+
"""calculate Black-Scholes implied volatility for all options
460460
in the surface"""
461461
d = self.as_array(
462462
select=select, index=index, initial_vol=initial_vol, converged=False

quantflow/sp/heston.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,29 @@ def sample_from_draws(self, path1: Paths, *args: Paths) -> Paths:
8080

8181

8282
class HestonJ(Heston):
83+
r"""The Heston stochastic volatility model with jumps
84+
85+
The Heston model with jumps is an extension of the classical square-root
86+
stochastic volatility model of Heston (1993) with the addition of jump
87+
processes. The jumps are modeled as compound Poisson processes with
88+
exponential jump sizes.
89+
90+
.. math::
91+
d x_t &= d w^1_t + d N^+_t - d N^-_t\\
92+
d v_t &= \kappa (\theta - v_t) dt + \nu \sqrt{v_t} dw^2_t \\
93+
\rho dt &= {\tt E}[dw^1 dw^2]
94+
"""
95+
8396
jumps_up: CompoundPoissonProcess[Exponential] = Field(
8497
description="positive jumps process"
8598
)
99+
"""Positive jumps process driven by a compound Poisson process with jumps
100+
sizes which follow an exponential distribution"""
86101
jumps_down: CompoundPoissonProcess[Exponential] = Field(
87102
description="negative jumps process"
88103
)
104+
"""jumps process driven by a compound Poisson process with jumps
105+
sizes which follow an exponential distribution"""
89106

90107
@classmethod
91108
def create(
@@ -99,6 +116,7 @@ def create(
99116
jump_fraction: float = 0.1, # percentage of variance due to jumps
100117
jump_asymmetry: float = 1,
101118
) -> HestonJ:
119+
"""Create an Heston model with jumps by specifying the jump parameters"""
102120
if jump_fraction <= 0 or jump_fraction >= 1:
103121
raise ValueError("jump_percentage must be between 0 and 1")
104122
total_variance = vol * vol
@@ -127,6 +145,8 @@ def create(
127145
)
128146

129147
def characteristic_exponent(self, t: FloatArrayLike, u: Vector) -> Vector:
148+
"""The characteristic exponent is given by the sum of the exponent of the
149+
classic Heston model and the exponent of the jumps"""
130150
return (
131151
super().characteristic_exponent(t, u)
132152
+ self.jumps_up.characteristic_exponent(t, u)

readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ pip install quantflow
2525
* [quantflow.data](https://github.com/quantmind/quantflow/tree/main/quantflow/data) data APIs (requires `quantflow[data]`)
2626
* [quantflow.options](https://github.com/quantmind/quantflow/tree/main/quantflow/options) option pricing and calibration
2727
* [quantflow.sp](https://github.com/quantmind/quantflow/tree/main/quantflow/sp) stochastic process primitives
28+
* [quantflow.ta](https://github.com/quantmind/quantflow/tree/main/quantflow/ta) timeseries analysis tools
29+
* [quantflow.utils](https://github.com/quantmind/quantflow/tree/main/quantflow/utils) utilities and helpers
30+
2831

2932

3033
## Command line tools

0 commit comments

Comments
 (0)