quantflow 0.3.2__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quantflow-0.3.2 → quantflow-0.4.0}/LICENSE +1 -1
- {quantflow-0.3.2 → quantflow-0.4.0}/PKG-INFO +15 -15
- {quantflow-0.3.2 → quantflow-0.4.0}/pyproject.toml +30 -38
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/__init__.py +1 -1
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/commands/crypto.py +31 -3
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/commands/stocks.py +14 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/data/deribit.py +84 -27
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/data/fed.py +3 -8
- quantflow-0.4.0/quantflow/data/fiscal_data.py +42 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/data/fmp.py +37 -28
- quantflow-0.4.0/quantflow/options/inputs.py +72 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/options/surface.py +167 -90
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/dates.py +9 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/numbers.py +5 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/plot.py +5 -5
- quantflow-0.3.2/quantflow/options/inputs.py +0 -51
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/app.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/commands/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/commands/base.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/commands/fred.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/commands/vault.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/script.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/cli/settings.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/data/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/data/fred.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/data/vault.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/options/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/options/bs.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/options/calibration.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/options/pricer.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/py.typed +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/base.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/bns.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/cir.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/copula.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/dsp.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/heston.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/jump_diffusion.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/ou.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/poisson.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/sp/weiner.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/ta/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/ta/base.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/ta/ohlc.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/ta/paths.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/__init__.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/bins.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/distributions.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/functions.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/interest_rates.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/marginal.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/transforms.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/quantflow/utils/types.py +0 -0
- {quantflow-0.3.2 → quantflow-0.4.0}/readme.md +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: quantflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: quantitative analysis
|
|
5
5
|
License: BSD-3-Clause
|
|
6
|
-
Author: Luca
|
|
6
|
+
Author: Luca Sbardella
|
|
7
7
|
Author-email: luca@quantmind.com
|
|
8
|
-
Requires-Python: >=3.11
|
|
8
|
+
Requires-Python: >=3.11,<4.0
|
|
9
9
|
Classifier: License :: OSI Approved :: BSD License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -13,18 +13,18 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Provides-Extra: cli
|
|
15
15
|
Provides-Extra: data
|
|
16
|
-
Requires-Dist: aio-fluid[http] (>=1.2.1
|
|
17
|
-
Requires-Dist: asciichartpy (>=1.5.25
|
|
18
|
-
Requires-Dist: async-cache (>=1.1.1
|
|
19
|
-
Requires-Dist: ccy (>=1.7.1
|
|
20
|
-
Requires-Dist: click (>=8.1.7
|
|
21
|
-
Requires-Dist: holidays (>=0.63
|
|
22
|
-
Requires-Dist: polars[pandas,pyarrow] (>=1.11.0
|
|
23
|
-
Requires-Dist: prompt-toolkit (>=3.0.43
|
|
24
|
-
Requires-Dist: pydantic (>=2.0.2
|
|
25
|
-
Requires-Dist: python-dotenv (>=1.0.1
|
|
26
|
-
Requires-Dist: rich (>=13.9.4
|
|
27
|
-
Requires-Dist: scipy (>=1.14.1
|
|
16
|
+
Requires-Dist: aio-fluid[http] (>=1.2.1) ; extra == "data"
|
|
17
|
+
Requires-Dist: asciichartpy (>=1.5.25) ; extra == "cli"
|
|
18
|
+
Requires-Dist: async-cache (>=1.1.1) ; extra == "cli"
|
|
19
|
+
Requires-Dist: ccy (>=1.7.1)
|
|
20
|
+
Requires-Dist: click (>=8.1.7) ; extra == "cli"
|
|
21
|
+
Requires-Dist: holidays (>=0.63) ; extra == "cli"
|
|
22
|
+
Requires-Dist: polars[pandas,pyarrow] (>=1.11.0)
|
|
23
|
+
Requires-Dist: prompt-toolkit (>=3.0.43) ; extra == "cli"
|
|
24
|
+
Requires-Dist: pydantic (>=2.0.2)
|
|
25
|
+
Requires-Dist: python-dotenv (>=1.0.1)
|
|
26
|
+
Requires-Dist: rich (>=13.9.4) ; extra == "cli"
|
|
27
|
+
Requires-Dist: scipy (>=1.14.1)
|
|
28
28
|
Project-URL: Documentation, https://quantmind.github.io/quantflow/
|
|
29
29
|
Project-URL: Homepage, https://github.com/quantmind/quantflow
|
|
30
30
|
Project-URL: Repository, https://github.com/quantmind/quantflow
|
|
@@ -1,52 +1,48 @@
|
|
|
1
|
-
[
|
|
1
|
+
[project]
|
|
2
2
|
name = "quantflow"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "quantitative analysis"
|
|
5
|
-
authors = ["Luca
|
|
5
|
+
authors = [{ name = "Luca Sbardella", email = "luca@quantmind.com" }]
|
|
6
6
|
license = "BSD-3-Clause"
|
|
7
7
|
readme = "readme.md"
|
|
8
|
+
requires-python = ">=3.11,<4.0"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"scipy>=1.14.1",
|
|
11
|
+
"pydantic>=2.0.2",
|
|
12
|
+
"ccy>=1.7.1",
|
|
13
|
+
"python-dotenv>=1.0.1",
|
|
14
|
+
"polars[pandas,pyarrow]>=1.11.0",
|
|
15
|
+
]
|
|
8
16
|
|
|
9
|
-
[
|
|
17
|
+
[project.urls]
|
|
10
18
|
Homepage = "https://github.com/quantmind/quantflow"
|
|
11
19
|
Repository = "https://github.com/quantmind/quantflow"
|
|
12
20
|
Documentation = "https://quantmind.github.io/quantflow/"
|
|
13
21
|
|
|
14
|
-
[
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
data = ["aio-fluid[http]>=1.2.1"]
|
|
24
|
+
cli = [
|
|
25
|
+
"asciichartpy>=1.5.25",
|
|
26
|
+
"async-cache>=1.1.1",
|
|
27
|
+
"prompt-toolkit>=3.0.43",
|
|
28
|
+
"rich>=13.9.4",
|
|
29
|
+
"click>=8.1.7",
|
|
30
|
+
"holidays>=0.63",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
qf = "quantflow.cli.script:main"
|
|
35
|
+
|
|
28
36
|
|
|
29
37
|
[tool.poetry.group.dev.dependencies]
|
|
30
38
|
black = "^25.1.0"
|
|
31
39
|
pytest-cov = "^6.0.0"
|
|
32
40
|
mypy = "^1.14.1"
|
|
33
41
|
ghp-import = "^2.0.2"
|
|
34
|
-
ruff = "^0.
|
|
35
|
-
pytest-asyncio = "^0.
|
|
42
|
+
ruff = "^0.12.2"
|
|
43
|
+
pytest-asyncio = "^1.0.0"
|
|
36
44
|
isort = "^6.0.1"
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
[tool.poetry.extras]
|
|
40
|
-
data = ["aio-fluid"]
|
|
41
|
-
cli = [
|
|
42
|
-
"asciichartpy",
|
|
43
|
-
"async-cache",
|
|
44
|
-
"prompt-toolkit",
|
|
45
|
-
"rich",
|
|
46
|
-
"click",
|
|
47
|
-
"holidays"
|
|
48
|
-
]
|
|
49
|
-
|
|
50
46
|
[tool.poetry.group.book]
|
|
51
47
|
optional = true
|
|
52
48
|
|
|
@@ -62,8 +58,6 @@ sphinx-autosummary-accessors = "^2023.4.0"
|
|
|
62
58
|
sphinx-copybutton = "^0.5.2"
|
|
63
59
|
autodocsumm = "^0.2.14"
|
|
64
60
|
|
|
65
|
-
[tool.poetry.scripts]
|
|
66
|
-
qf = "quantflow.cli.script:main"
|
|
67
61
|
|
|
68
62
|
[build-system]
|
|
69
63
|
requires = ["poetry-core>=1.0.0"]
|
|
@@ -74,9 +68,7 @@ formats = "ipynb,myst"
|
|
|
74
68
|
|
|
75
69
|
[tool.pytest.ini_options]
|
|
76
70
|
asyncio_mode = "auto"
|
|
77
|
-
testpaths = [
|
|
78
|
-
"quantflow_tests"
|
|
79
|
-
]
|
|
71
|
+
testpaths = ["quantflow_tests"]
|
|
80
72
|
|
|
81
73
|
[tool.isort]
|
|
82
74
|
profile = "black"
|
|
@@ -102,7 +94,7 @@ module = [
|
|
|
102
94
|
"IPython.*",
|
|
103
95
|
"pandas.*",
|
|
104
96
|
"plotly.*",
|
|
105
|
-
"scipy.*"
|
|
97
|
+
"scipy.*",
|
|
106
98
|
]
|
|
107
99
|
ignore_missing_imports = true
|
|
108
100
|
disallow_untyped_defs = false
|
|
@@ -8,7 +8,7 @@ from asciichartpy import plot
|
|
|
8
8
|
from cache import AsyncTTL
|
|
9
9
|
from ccy.cli.console import df_to_rich
|
|
10
10
|
|
|
11
|
-
from quantflow.data.deribit import Deribit
|
|
11
|
+
from quantflow.data.deribit import Deribit, InstrumentKind
|
|
12
12
|
from quantflow.options.surface import VolSurface
|
|
13
13
|
from quantflow.utils.numbers import round_to_step
|
|
14
14
|
|
|
@@ -24,13 +24,34 @@ def crypto() -> None:
|
|
|
24
24
|
ctx.set_as_section()
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
@crypto.command()
|
|
28
|
+
@click.argument("currency")
|
|
29
|
+
@click.option(
|
|
30
|
+
"-k",
|
|
31
|
+
"--kind",
|
|
32
|
+
type=click.Choice(list(InstrumentKind)),
|
|
33
|
+
default=InstrumentKind.spot.value,
|
|
34
|
+
)
|
|
35
|
+
def instruments(currency: str, kind: str) -> None:
|
|
36
|
+
"""Provides information about instruments
|
|
37
|
+
|
|
38
|
+
Instruments for given cryptocurrency from Deribit API"""
|
|
39
|
+
ctx = QuantContext.current()
|
|
40
|
+
data = asyncio.run(get_instruments(ctx, currency, kind))
|
|
41
|
+
df = pd.DataFrame(data)
|
|
42
|
+
ctx.qf.print(df_to_rich(df))
|
|
43
|
+
|
|
44
|
+
|
|
27
45
|
@crypto.command()
|
|
28
46
|
@click.argument("currency")
|
|
29
47
|
@options.length
|
|
30
48
|
@options.height
|
|
31
49
|
@options.chart
|
|
32
50
|
def volatility(currency: str, length: int, height: int, chart: bool) -> None:
|
|
33
|
-
"""Provides information about historical volatility
|
|
51
|
+
"""Provides information about historical volatility
|
|
52
|
+
|
|
53
|
+
Historical volatility for given cryptocurrency from Deribit API
|
|
54
|
+
"""
|
|
34
55
|
ctx = QuantContext.current()
|
|
35
56
|
df = asyncio.run(get_volatility(ctx, currency))
|
|
36
57
|
df["volatility"] = df["volatility"].map(lambda p: round_to_step(p, "0.01"))
|
|
@@ -109,9 +130,16 @@ def prices(symbol: str, height: int, length: int, chart: bool, frequency: str) -
|
|
|
109
130
|
)
|
|
110
131
|
|
|
111
132
|
|
|
133
|
+
async def get_instruments(ctx: QuantContext, currency: str, kind: str) -> list[dict]:
|
|
134
|
+
async with Deribit() as client:
|
|
135
|
+
return await client.get_instruments(
|
|
136
|
+
currency=currency, kind=InstrumentKind(kind)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
112
140
|
async def get_volatility(ctx: QuantContext, currency: str) -> pd.DataFrame:
|
|
113
141
|
async with Deribit() as client:
|
|
114
|
-
return await client.get_volatility(
|
|
142
|
+
return await client.get_volatility(currency)
|
|
115
143
|
|
|
116
144
|
|
|
117
145
|
@AsyncTTL(time_to_live=10)
|
|
@@ -24,6 +24,15 @@ def stocks() -> None:
|
|
|
24
24
|
ctx.set_as_section()
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
@stocks.command()
|
|
28
|
+
def indices() -> None:
|
|
29
|
+
"""Search companies"""
|
|
30
|
+
ctx = QuantContext.current()
|
|
31
|
+
data = asyncio.run(get_indices(ctx))
|
|
32
|
+
df = pd.DataFrame(data)
|
|
33
|
+
ctx.qf.print(df_to_rich(df))
|
|
34
|
+
|
|
35
|
+
|
|
27
36
|
@stocks.command()
|
|
28
37
|
@click.argument("symbol")
|
|
29
38
|
def profile(symbol: str) -> None:
|
|
@@ -78,6 +87,11 @@ def sectors(period: str) -> None:
|
|
|
78
87
|
ctx.qf.print(df_to_rich(df))
|
|
79
88
|
|
|
80
89
|
|
|
90
|
+
async def get_indices(ctx: QuantContext) -> list[dict]:
|
|
91
|
+
async with ctx.fmp() as cli:
|
|
92
|
+
return await cli.indices()
|
|
93
|
+
|
|
94
|
+
|
|
81
95
|
async def get_prices(ctx: QuantContext, symbol: str, frequency: str) -> pd.DataFrame:
|
|
82
96
|
async with ctx.fmp() as cli:
|
|
83
97
|
return await cli.prices(symbol, frequency)
|
|
@@ -1,65 +1,116 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
from dataclasses import dataclass
|
|
1
3
|
from datetime import datetime, timezone
|
|
2
4
|
from decimal import Decimal
|
|
3
5
|
from typing import Any, cast
|
|
4
6
|
|
|
5
7
|
import pandas as pd
|
|
6
8
|
from dateutil.parser import parse
|
|
9
|
+
from fluid.utils.data import compact_dict
|
|
7
10
|
from fluid.utils.http_client import AioHttpClient, HttpResponse, HttpResponseError
|
|
8
11
|
|
|
12
|
+
from quantflow.options.inputs import OptionType
|
|
9
13
|
from quantflow.options.surface import VolSecurityType, VolSurfaceLoader
|
|
10
|
-
from quantflow.utils.numbers import
|
|
14
|
+
from quantflow.utils.numbers import (
|
|
15
|
+
Number,
|
|
16
|
+
round_to_step,
|
|
17
|
+
to_decimal,
|
|
18
|
+
to_decimal_or_none,
|
|
19
|
+
)
|
|
11
20
|
|
|
12
21
|
|
|
13
22
|
def parse_maturity(v: str) -> datetime:
|
|
14
23
|
return parse(v).replace(tzinfo=timezone.utc, hour=8)
|
|
15
24
|
|
|
16
25
|
|
|
26
|
+
class InstrumentKind(enum.StrEnum):
|
|
27
|
+
"""Instrument kind for Deribit API."""
|
|
28
|
+
|
|
29
|
+
future = enum.auto()
|
|
30
|
+
option = enum.auto()
|
|
31
|
+
spot = enum.auto()
|
|
32
|
+
future_combo = enum.auto()
|
|
33
|
+
option_combo = enum.auto()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
17
37
|
class Deribit(AioHttpClient):
|
|
18
38
|
"""Deribit API client
|
|
19
39
|
|
|
20
|
-
Fetch market and static data from `Deribit`_.
|
|
40
|
+
Fetch market and static data from `Deribit`_ API.
|
|
21
41
|
|
|
22
42
|
.. _Deribit: https://docs.deribit.com/
|
|
23
43
|
"""
|
|
24
44
|
|
|
25
|
-
url = "https://www.deribit.com/api/v2"
|
|
45
|
+
url: str = "https://www.deribit.com/api/v2"
|
|
26
46
|
|
|
27
|
-
async def get_book_summary_by_instrument(
|
|
28
|
-
|
|
47
|
+
async def get_book_summary_by_instrument(
|
|
48
|
+
self,
|
|
49
|
+
instrument_name: str,
|
|
50
|
+
**kw: Any,
|
|
51
|
+
) -> list[dict]:
|
|
52
|
+
"""Get the book summary for a given instrument."""
|
|
53
|
+
kw.update(params=dict(instrument_name=instrument_name), callback=self.to_result)
|
|
29
54
|
return cast(
|
|
30
55
|
list[dict],
|
|
31
56
|
await self.get_path("public/get_book_summary_by_instrument", **kw),
|
|
32
57
|
)
|
|
33
58
|
|
|
34
|
-
async def get_book_summary_by_currency(
|
|
35
|
-
kw
|
|
59
|
+
async def get_book_summary_by_currency(
|
|
60
|
+
self, currency: str, kind: InstrumentKind | None = None, **kw: Any
|
|
61
|
+
) -> list[dict]:
|
|
62
|
+
"""Get the book summary for a given currency."""
|
|
63
|
+
kw.update(
|
|
64
|
+
params=compact_dict(currency=currency, kind=kind), callback=self.to_result
|
|
65
|
+
)
|
|
36
66
|
return cast(
|
|
37
67
|
list[dict], await self.get_path("public/get_book_summary_by_currency", **kw)
|
|
38
68
|
)
|
|
39
69
|
|
|
40
|
-
async def get_instruments(
|
|
41
|
-
|
|
70
|
+
async def get_instruments(
|
|
71
|
+
self,
|
|
72
|
+
currency: str,
|
|
73
|
+
kind: InstrumentKind | None = None,
|
|
74
|
+
expired: bool | None = None,
|
|
75
|
+
**kw: Any,
|
|
76
|
+
) -> list[dict]:
|
|
77
|
+
"""Get the list of instruments for a given currency."""
|
|
78
|
+
kw.update(
|
|
79
|
+
params=compact_dict(currency=currency, kind=kind, expired=expired),
|
|
80
|
+
callback=self.to_result,
|
|
81
|
+
)
|
|
42
82
|
return cast(list[dict], await self.get_path("public/get_instruments", **kw))
|
|
43
83
|
|
|
44
|
-
async def get_volatility(self, **kw: Any) -> pd.DataFrame:
|
|
45
|
-
|
|
84
|
+
async def get_volatility(self, currency: str, **kw: Any) -> pd.DataFrame:
|
|
85
|
+
"""Provides information about historical volatility for given cryptocurrency"""
|
|
86
|
+
kw.update(params=dict(currency=currency), callback=self.to_df)
|
|
46
87
|
return await self.get_path("public/get_historical_volatility", **kw)
|
|
47
88
|
|
|
48
|
-
async def volatility_surface_loader(
|
|
89
|
+
async def volatility_surface_loader(
|
|
90
|
+
self,
|
|
91
|
+
currency: str,
|
|
92
|
+
*,
|
|
93
|
+
exclude_open_interest: Number | None = None,
|
|
94
|
+
exclude_volume: Number | None = None,
|
|
95
|
+
) -> VolSurfaceLoader:
|
|
49
96
|
"""Create a :class:`.VolSurfaceLoader` for a given crypto-currency"""
|
|
50
|
-
loader = VolSurfaceLoader(
|
|
97
|
+
loader = VolSurfaceLoader(
|
|
98
|
+
asset=currency,
|
|
99
|
+
exclude_open_interest=to_decimal_or_none(exclude_open_interest),
|
|
100
|
+
exclude_volume=to_decimal_or_none(exclude_volume),
|
|
101
|
+
)
|
|
51
102
|
futures = await self.get_book_summary_by_currency(
|
|
52
|
-
|
|
103
|
+
currency=currency, kind=InstrumentKind.future
|
|
53
104
|
)
|
|
54
105
|
options = await self.get_book_summary_by_currency(
|
|
55
|
-
|
|
106
|
+
currency=currency, kind=InstrumentKind.option
|
|
56
107
|
)
|
|
57
|
-
instruments = await self.get_instruments(
|
|
108
|
+
instruments = await self.get_instruments(currency=currency)
|
|
58
109
|
instrument_map = {i["instrument_name"]: i for i in instruments}
|
|
59
110
|
min_tick_size = Decimal("inf")
|
|
60
|
-
for
|
|
61
|
-
if (bid_ :=
|
|
62
|
-
name =
|
|
111
|
+
for entry in futures:
|
|
112
|
+
if (bid_ := entry["bid_price"]) and (ask_ := entry["ask_price"]):
|
|
113
|
+
name = entry["instrument_name"]
|
|
63
114
|
meta = instrument_map[name]
|
|
64
115
|
tick_size = to_decimal(meta["tick_size"])
|
|
65
116
|
min_tick_size = min(min_tick_size, tick_size)
|
|
@@ -70,8 +121,8 @@ class Deribit(AioHttpClient):
|
|
|
70
121
|
VolSecurityType.spot,
|
|
71
122
|
bid=bid,
|
|
72
123
|
ask=ask,
|
|
73
|
-
open_interest=
|
|
74
|
-
volume=
|
|
124
|
+
open_interest=to_decimal(entry["open_interest"]),
|
|
125
|
+
volume=to_decimal(entry["volume_usd"]),
|
|
75
126
|
)
|
|
76
127
|
else:
|
|
77
128
|
maturity = pd.to_datetime(
|
|
@@ -84,15 +135,15 @@ class Deribit(AioHttpClient):
|
|
|
84
135
|
maturity=maturity,
|
|
85
136
|
bid=bid,
|
|
86
137
|
ask=ask,
|
|
87
|
-
open_interest=
|
|
88
|
-
volume=
|
|
138
|
+
open_interest=to_decimal(entry["open_interest"]),
|
|
139
|
+
volume=to_decimal(entry["volume_usd"]),
|
|
89
140
|
)
|
|
90
141
|
loader.tick_size_forwards = min_tick_size
|
|
91
142
|
|
|
92
143
|
min_tick_size = Decimal("inf")
|
|
93
|
-
for
|
|
94
|
-
if (bid_ :=
|
|
95
|
-
name =
|
|
144
|
+
for entry in options:
|
|
145
|
+
if (bid_ := entry["bid_price"]) and (ask_ := entry["ask_price"]):
|
|
146
|
+
name = entry["instrument_name"]
|
|
96
147
|
meta = instrument_map[name]
|
|
97
148
|
tick_size = to_decimal(meta["tick_size"])
|
|
98
149
|
min_tick_size = min(min_tick_size, tick_size)
|
|
@@ -104,9 +155,15 @@ class Deribit(AioHttpClient):
|
|
|
104
155
|
unit="ms",
|
|
105
156
|
utc=True,
|
|
106
157
|
).to_pydatetime(),
|
|
107
|
-
|
|
158
|
+
option_type=(
|
|
159
|
+
OptionType.call
|
|
160
|
+
if meta["option_type"] == "call"
|
|
161
|
+
else OptionType.put
|
|
162
|
+
),
|
|
108
163
|
bid=round_to_step(bid_, tick_size),
|
|
109
164
|
ask=round_to_step(ask_, tick_size),
|
|
165
|
+
open_interest=to_decimal(entry["open_interest"]),
|
|
166
|
+
volume=to_decimal(entry["volume_usd"]),
|
|
110
167
|
)
|
|
111
168
|
loader.tick_size_options = min_tick_size
|
|
112
169
|
return loader
|
|
@@ -6,12 +6,7 @@ import numpy as np
|
|
|
6
6
|
import pandas as pd
|
|
7
7
|
from fluid.utils.http_client import AioHttpClient
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
"https://www.federalreserve.gov/datadownload/Output.aspx?"
|
|
11
|
-
"rel=H15&series=bf17364827e38702b42a58cf8eaa3f78&lastobs=&"
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
maturities = [
|
|
9
|
+
MATURITIES = (
|
|
15
10
|
"month_1",
|
|
16
11
|
"month_3",
|
|
17
12
|
"month_6",
|
|
@@ -23,7 +18,7 @@ maturities = [
|
|
|
23
18
|
"year_10",
|
|
24
19
|
"year_20",
|
|
25
20
|
"year_30",
|
|
26
|
-
|
|
21
|
+
)
|
|
27
22
|
|
|
28
23
|
|
|
29
24
|
@dataclass
|
|
@@ -52,7 +47,7 @@ class FederalReserve(AioHttpClient):
|
|
|
52
47
|
params.update(series="bf17364827e38702b42a58cf8eaa3f78", rel="H15")
|
|
53
48
|
data = await self._get_text(params)
|
|
54
49
|
df = pd.read_csv(data, header=5, index_col=None, parse_dates=True)
|
|
55
|
-
df.columns =
|
|
50
|
+
df.columns = list(("date",) + MATURITIES) # type: ignore
|
|
56
51
|
df = df.set_index("date").replace("ND", np.nan)
|
|
57
52
|
return df.dropna(axis=0, how="all").reset_index()
|
|
58
53
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import date, timedelta
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from fluid.utils.http_client import AioHttpClient
|
|
6
|
+
|
|
7
|
+
from quantflow.utils.dates import as_date
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class FiscalData(AioHttpClient):
|
|
12
|
+
"""Fiscal Data API client.
|
|
13
|
+
|
|
14
|
+
THis class is used to fetch data from the
|
|
15
|
+
[fiscal data api](https://fiscaldata.treasury.gov/api-documentation/)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
url: str = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
|
|
19
|
+
|
|
20
|
+
async def securities(self, record_date: date | None = None) -> pd.DataFrame:
|
|
21
|
+
"""Get treasury constant maturities rates"""
|
|
22
|
+
rd = as_date(record_date)
|
|
23
|
+
pm = rd.replace(day=1) - timedelta(days=1)
|
|
24
|
+
params = {"filter": f"record_date:eq:{pm.isoformat()}"}
|
|
25
|
+
data = await self.get_all("/v1/debt/mspd/mspd_table_3_market", params)
|
|
26
|
+
return pd.DataFrame(data)
|
|
27
|
+
|
|
28
|
+
async def get_all(self, path: str, params: dict[str, str]) -> list:
|
|
29
|
+
"""Get all data from the API"""
|
|
30
|
+
next_url: str | None = f"{self.url}{path}"
|
|
31
|
+
full_data = []
|
|
32
|
+
while next_url:
|
|
33
|
+
payload = await self.get(next_url, params=params)
|
|
34
|
+
full_data.extend(payload["data"])
|
|
35
|
+
if links := payload.get("links"):
|
|
36
|
+
if next_path := links.get("next"):
|
|
37
|
+
next_url = f"{self.url}{next_path}"
|
|
38
|
+
else:
|
|
39
|
+
next_url = None
|
|
40
|
+
else:
|
|
41
|
+
next_url = None
|
|
42
|
+
return full_data
|