mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-06-15 07:53:58 +08:00
[Feature] Add Deribit Provider Extension For Crypto Options Data (#6985)
* add deribit provider and make some small changes to the standard model to allow for fractional volume and size * linter * typehint * more lint * more touchup * update test * remove line in test * maybe we need that after all..?
This commit is contained in:
@@ -150,10 +150,13 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
option_type: List[str] = Field(description="Call or Put.")
|
||||
open_interest: List[Union[int, None]] = Field(
|
||||
contract_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list, description="Number of underlying units per contract."
|
||||
)
|
||||
open_interest: List[Union[int, float, None]] = Field(
|
||||
default_factory=list, description="Open interest on the contract."
|
||||
)
|
||||
volume: List[Union[int, None]] = Field(
|
||||
volume: List[Union[int, float, None]] = Field(
|
||||
default_factory=list, description=DATA_DESCRIPTIONS.get("volume", "")
|
||||
)
|
||||
theoretical_price: List[Union[float, None]] = Field(
|
||||
@@ -166,7 +169,7 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
description="Last trade price of the option.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
last_trade_size: List[Union[int, None]] = Field(
|
||||
last_trade_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list, description="Last trade size of the option."
|
||||
)
|
||||
last_trade_time: List[Union[datetime, None]] = Field(
|
||||
@@ -182,7 +185,7 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
description="Current bid price for the option.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
bid_size: List[Union[int, None]] = Field(
|
||||
bid_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list, description="Bid size for the option."
|
||||
)
|
||||
bid_time: List[Union[datetime, None]] = Field(
|
||||
@@ -197,7 +200,7 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
description="Current ask price for the option.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
ask_size: List[Union[int, None]] = Field(
|
||||
ask_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list, description="Ask size for the option."
|
||||
)
|
||||
ask_time: List[Union[datetime, None]] = Field(
|
||||
@@ -262,7 +265,7 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
description=DATA_DESCRIPTIONS.get("close", ""),
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
close_size: List[Union[int, None]] = Field(
|
||||
close_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The closing trade size for the option that day.",
|
||||
)
|
||||
@@ -275,7 +278,7 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
description="The closing bid price for the option that day.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
close_bid_size: List[Union[int, None]] = Field(
|
||||
close_bid_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The closing bid size for the option that day.",
|
||||
)
|
||||
@@ -287,7 +290,7 @@ class OptionsChainsData(OptionsChainsProperties):
|
||||
default_factory=list,
|
||||
description="The closing ask price for the option that day.",
|
||||
)
|
||||
close_ask_size: List[Union[int, None]] = Field(
|
||||
close_ask_size: List[Union[int, float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The closing ask size for the option that day.",
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# pylint: disable=too-many-lines, too-many-arguments, too-many-locals, too-many-statements, too-many-positional-arguments
|
||||
|
||||
from datetime import datetime
|
||||
from functools import cached_property
|
||||
from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union
|
||||
|
||||
from openbb_core.app.model.abstract.error import OpenBBError
|
||||
@@ -41,7 +42,7 @@ class OptionsChainsProperties(Data):
|
||||
if hasattr(self, "_last_price"):
|
||||
del self._last_price
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def dataframe(self) -> "DataFrame":
|
||||
"""Return all data as a Pandas DataFrame,
|
||||
with additional computed columns (Breakeven, GEX, DEX) if available.
|
||||
@@ -72,13 +73,13 @@ class OptionsChainsProperties(Data):
|
||||
raise OpenBBError("Error: No validated data was found.")
|
||||
|
||||
if "dte" not in chains_data.columns and "eod_date" in chains_data.columns:
|
||||
_date = to_datetime(chains_data["eod_date"])
|
||||
_date = to_datetime(chains_data.eod_date)
|
||||
temp = DatetimeIndex(chains_data.expiration)
|
||||
temp_ = temp - _date # type: ignore
|
||||
chains_data.loc[:, "dte"] = [Timedelta(_temp_).days for _temp_ in temp_]
|
||||
|
||||
if "dte" in chains_data.columns:
|
||||
chains_data = DataFrame(chains_data[chains_data["dte"] >= 0])
|
||||
chains_data = DataFrame(chains_data[chains_data.dte >= 0])
|
||||
|
||||
if "dte" not in chains_data.columns and "eod_date" not in chains_data.columns:
|
||||
today = datetime.today().date()
|
||||
@@ -86,51 +87,75 @@ class OptionsChainsProperties(Data):
|
||||
|
||||
# Add the breakeven price for each option, and the DEX and GEX for each option, if available.
|
||||
try:
|
||||
last_price = chains_data.underlying_price.iloc[0]
|
||||
_calls = DataFrame(chains_data[chains_data["option_type"] == "call"])
|
||||
_puts = DataFrame(chains_data[chains_data["option_type"] == "put"])
|
||||
_ask = self._identify_price_col(
|
||||
_calls = DataFrame(chains_data[chains_data.option_type == "call"])
|
||||
_puts = DataFrame(chains_data[chains_data.option_type == "put"])
|
||||
_ask = self._identify_price_col( # pylint: disable=W0212
|
||||
chains_data, "call", "ask"
|
||||
) # pylint: disable=W0212
|
||||
_calls.loc[:, ("Breakeven")] = (
|
||||
_calls.loc[:, ("strike")] + _calls.loc[:, (_ask)]
|
||||
)
|
||||
_puts.loc[:, ("Breakeven")] = (
|
||||
_puts.loc[:, ("strike")] - _puts.loc[:, (_ask)]
|
||||
)
|
||||
|
||||
_calls.loc[:, ("Breakeven")] = _calls.strike + _calls.loc[:, (_ask)]
|
||||
_puts.loc[:, ("Breakeven")] = _puts.strike - _puts.loc[:, (_ask)]
|
||||
if "delta" in _calls.columns:
|
||||
_calls.loc[:, ("DEX")] = (
|
||||
(_calls.loc[:, ("delta")] * 100)
|
||||
* (_calls.loc[:, ("open_interest")])
|
||||
* last_price
|
||||
(
|
||||
_calls.delta
|
||||
* (
|
||||
_calls.contract_size
|
||||
if hasattr(_calls, "contract_size")
|
||||
else 100
|
||||
)
|
||||
* _calls.open_interest
|
||||
* _calls.underlying_price
|
||||
)
|
||||
.replace({nan: 0})
|
||||
.astype("int64")
|
||||
)
|
||||
_calls["DEX"] = _calls["DEX"].replace({nan: 0}).astype("int64")
|
||||
_puts.loc[:, ("DEX")] = (
|
||||
(_puts.loc[:, ("delta")] * 100)
|
||||
* (_puts.loc[:, ("open_interest")])
|
||||
* last_price
|
||||
(
|
||||
_puts.delta
|
||||
* (
|
||||
_puts.contract_size
|
||||
if hasattr(_puts, "contract_size")
|
||||
else 100
|
||||
)
|
||||
* _puts.open_interest
|
||||
* _puts.underlying_price
|
||||
)
|
||||
.replace({nan: 0})
|
||||
.astype("int64")
|
||||
)
|
||||
_puts["DEX"] = _puts["DEX"].replace({nan: 0}).astype("int64")
|
||||
|
||||
if "gamma" in _calls.columns:
|
||||
_calls.loc[:, ("GEX")] = (
|
||||
_calls.loc[:, ("gamma")]
|
||||
* 100
|
||||
* _calls.loc[:, ("open_interest")]
|
||||
* (last_price * last_price)
|
||||
* 0.01
|
||||
(
|
||||
_calls.gamma
|
||||
* (
|
||||
_calls.contract_size
|
||||
if hasattr(_calls, "contract_size")
|
||||
else 100
|
||||
)
|
||||
* _calls.open_interest
|
||||
* (_calls.underlying_price * _calls.underlying_price)
|
||||
* 0.01
|
||||
)
|
||||
.replace({nan: 0})
|
||||
.astype("int64")
|
||||
)
|
||||
_calls["GEX"] = _calls["GEX"].replace({nan: 0}).astype("int64")
|
||||
_puts.loc[:, ("GEX")] = (
|
||||
_puts.loc[:, ("gamma")]
|
||||
* 100
|
||||
* _puts.loc[:, ("open_interest")]
|
||||
* (last_price * last_price)
|
||||
* 0.01
|
||||
* (-1)
|
||||
(
|
||||
_puts.gamma
|
||||
* (
|
||||
_puts.contract_size
|
||||
if hasattr(_puts, "contract_size")
|
||||
else 100
|
||||
)
|
||||
* _puts.open_interest
|
||||
* (_puts.underlying_price * _puts.underlying_price)
|
||||
* 0.01
|
||||
* (-1)
|
||||
)
|
||||
.replace({nan: 0})
|
||||
.astype("int64")
|
||||
)
|
||||
_puts["GEX"] = _puts["GEX"].replace({nan: 0}).astype("int64")
|
||||
|
||||
_calls.set_index(keys=["expiration", "strike", "option_type"], inplace=True)
|
||||
_puts.set_index(keys=["expiration", "strike", "option_type"], inplace=True)
|
||||
@@ -371,17 +396,7 @@ class OptionsChainsProperties(Data):
|
||||
from numpy import inf, nan
|
||||
from pandas import DataFrame, concat
|
||||
|
||||
df = DataFrame()
|
||||
|
||||
if metric in ["volume", "open_interest"]:
|
||||
df = DataFrame(
|
||||
self.model_dump(
|
||||
exclude_unset=True,
|
||||
exclude_none=True,
|
||||
)
|
||||
)
|
||||
else:
|
||||
df = self.dataframe
|
||||
df = self.dataframe
|
||||
|
||||
if metric in ["DEX", "GEX"]:
|
||||
if not self.has_greeks:
|
||||
@@ -395,7 +410,7 @@ class OptionsChainsProperties(Data):
|
||||
"Calls": total_calls,
|
||||
"Puts": total_puts,
|
||||
"Total": total_metric,
|
||||
"PCR": round(total_puts / total_calls, 4),
|
||||
"PCR": round(total_puts / total_calls, 4) if total_calls != 0 else 0,
|
||||
}
|
||||
|
||||
df = DataFrame(df[df[metric].notnull()]) # type: ignore
|
||||
@@ -542,6 +557,11 @@ class OptionsChainsProperties(Data):
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
|
||||
if date is not None:
|
||||
date = self._get_nearest_expiration(date)
|
||||
df = df[df.expiration.astype(str) == date]
|
||||
strikes = Series(df.strike.unique().tolist())
|
||||
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
@@ -549,11 +569,6 @@ class OptionsChainsProperties(Data):
|
||||
)
|
||||
strikes = Series(self.strikes)
|
||||
|
||||
if date is not None:
|
||||
date = self._get_nearest_expiration(date)
|
||||
df = df[df.expiration.astype(str) == date]
|
||||
strikes = Series(df.strike.unique().tolist())
|
||||
|
||||
upper = last_price * (1 + moneyness) # type: ignore
|
||||
lower = last_price * (1 - moneyness) # type: ignore
|
||||
nearest_call = (upper - strikes).abs().idxmin()
|
||||
@@ -606,15 +621,14 @@ class OptionsChainsProperties(Data):
|
||||
if days is None:
|
||||
days = 30
|
||||
|
||||
if strike is None:
|
||||
strike = chains.underlying_price.iloc[0]
|
||||
|
||||
dte_estimate = self._get_nearest_expiration(days)
|
||||
df = (
|
||||
chains[chains.expiration.astype(str) == dte_estimate]
|
||||
.query("`option_type` == @option_type")
|
||||
.copy()
|
||||
)
|
||||
if strike is None:
|
||||
strike = df.underlying_price.iloc[0]
|
||||
|
||||
if price_col is not None:
|
||||
df = df[df[price_col].notnull()] # type: ignore
|
||||
@@ -676,16 +690,6 @@ class OptionsChainsProperties(Data):
|
||||
|
||||
chains = self.dataframe
|
||||
|
||||
if not hasattr(chains, "underlying_price") and underlying_price is None:
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
underlying_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if days is None:
|
||||
days = 30
|
||||
|
||||
@@ -696,6 +700,16 @@ class OptionsChainsProperties(Data):
|
||||
|
||||
chains = chains[chains.expiration.astype(str) == dte_estimate]
|
||||
|
||||
if not hasattr(chains, "underlying_price") and underlying_price is None:
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
underlying_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
force_otm = True
|
||||
|
||||
if strike is None and not hasattr(chains, "underlying_price"):
|
||||
@@ -843,6 +857,12 @@ class OptionsChainsProperties(Data):
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
|
||||
underlying_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
strikes = self._get_nearest_otm_strikes(
|
||||
dte_estimate, underlying_price, moneyness
|
||||
)
|
||||
@@ -968,11 +988,6 @@ class OptionsChainsProperties(Data):
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if days is None:
|
||||
days = 30
|
||||
@@ -986,6 +1001,12 @@ class OptionsChainsProperties(Data):
|
||||
"`option_type` == 'call'"
|
||||
)
|
||||
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if bought is None:
|
||||
bought = last_price * 1.0250
|
||||
|
||||
@@ -1103,11 +1124,6 @@ class OptionsChainsProperties(Data):
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if days is None:
|
||||
days = 30
|
||||
@@ -1121,6 +1137,12 @@ class OptionsChainsProperties(Data):
|
||||
"`option_type` == 'put'"
|
||||
)
|
||||
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if bought is None:
|
||||
bought = last_price * 0.9750
|
||||
|
||||
@@ -1226,11 +1248,6 @@ class OptionsChainsProperties(Data):
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if days is None:
|
||||
days = 30
|
||||
@@ -1240,6 +1257,11 @@ class OptionsChainsProperties(Data):
|
||||
|
||||
dte_estimate = self._get_nearest_expiration(days)
|
||||
chains = DataFrame(chains[chains["expiration"].astype(str) == dte_estimate])
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
bid = self._identify_price_col(chains, "put", "bid")
|
||||
ask = self._identify_price_col(chains, "call", "ask")
|
||||
strike_price = last_price if strike == 0 else strike
|
||||
@@ -1329,11 +1351,6 @@ class OptionsChainsProperties(Data):
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if days is None:
|
||||
days = 30
|
||||
@@ -1343,6 +1360,11 @@ class OptionsChainsProperties(Data):
|
||||
|
||||
dte_estimate = self._get_nearest_expiration(days)
|
||||
chains = DataFrame(chains[chains["expiration"].astype(str) == dte_estimate])
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else chains.underlying_price.iloc[0]
|
||||
)
|
||||
bid = self._identify_price_col(chains, "call", "bid")
|
||||
ask = self._identify_price_col(chains, "put", "ask")
|
||||
strike_price = last_price if strike == 0 else strike
|
||||
@@ -1667,11 +1689,6 @@ class OptionsChainsProperties(Data):
|
||||
raise OpenBBError(
|
||||
"Error: underlying_price must be provided if underlying_price is not available"
|
||||
)
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else data.underlying_price.iloc[0]
|
||||
)
|
||||
|
||||
if moneyness is not None and date is None:
|
||||
date = -1
|
||||
@@ -1703,13 +1720,12 @@ class OptionsChainsProperties(Data):
|
||||
if moneyness is not None:
|
||||
atm_call_iv = DataFrame()
|
||||
atm_put_iv = DataFrame()
|
||||
|
||||
for day in days:
|
||||
strikes = self._get_nearest_otm_strikes(
|
||||
date=day, moneyness=moneyness, underlying_price=underlying_price
|
||||
)
|
||||
atm_call_strike = self._get_nearest_strike( # noqa:F841
|
||||
"call", day, last_price, call_price_col, False
|
||||
"call", day, underlying_price, call_price_col, False
|
||||
)
|
||||
call_strike = self._get_nearest_strike( # noqa:F841
|
||||
"call", day, strikes["call"], call_price_col, False
|
||||
@@ -1719,6 +1735,11 @@ class OptionsChainsProperties(Data):
|
||||
.query("`option_type` == 'call'") # type: ignore
|
||||
.copy()
|
||||
)
|
||||
last_price = (
|
||||
underlying_price
|
||||
if underlying_price is not None
|
||||
else _calls.underlying_price.iloc[0]
|
||||
)
|
||||
if len(_calls) > 0:
|
||||
call_iv = _calls[_calls.strike == call_strike][
|
||||
["expiration", "strike", "implied_volatility"]
|
||||
|
||||
@@ -55,6 +55,7 @@ openbb-regulators = { path = "./extensions/regulators", develop = true }
|
||||
openbb-alpha-vantage = { path = "./providers/alpha_vantage", optional = true, develop = true }
|
||||
openbb-biztoc = { path = "./providers/biztoc", optional = true, develop = true }
|
||||
openbb-cboe = { path = "./providers/cboe", optional = true, develop = true }
|
||||
openbb-deribit = { path = "./providers/deribit", optional = true, develop = true }
|
||||
openbb-ecb = { path = "./providers/ecb", optional = true, develop = true }
|
||||
openbb-finra = { path = "./providers/finra", optional = true, develop = true }
|
||||
openbb-finviz = { path = "./providers/finviz", optional = true, develop = true }
|
||||
|
||||
@@ -46,6 +46,7 @@ def headers():
|
||||
({"provider": "cboe", "symbol": "AAPL", "use_cache": False}),
|
||||
({"provider": "tradier", "symbol": "AAPL"}),
|
||||
({"provider": "yfinance", "symbol": "AAPL"}),
|
||||
({"provider": "deribit", "symbol": "BTC"}),
|
||||
(
|
||||
{
|
||||
"provider": "tmx",
|
||||
|
||||
@@ -42,6 +42,7 @@ def obb(pytestconfig):
|
||||
({"provider": "cboe", "symbol": "AAPL", "use_cache": False}),
|
||||
({"provider": "tradier", "symbol": "AAPL"}),
|
||||
({"provider": "yfinance", "symbol": "AAPL"}),
|
||||
({"provider": "deribit", "symbol": "BTC"}),
|
||||
(
|
||||
{
|
||||
"provider": "tmx",
|
||||
|
||||
29
openbb_platform/poetry.lock
generated
vendored
29
openbb_platform/poetry.lock
generated
vendored
@@ -2192,6 +2192,23 @@ files = [
|
||||
[package.dependencies]
|
||||
openbb-core = ">=1.3.6,<2.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "openbb-deribit"
|
||||
version = "1.0.0b"
|
||||
description = "Deribit is a cryptocurrency exchange that offers futures and options trading."
|
||||
optional = true
|
||||
python-versions = "^3.9"
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
async-lru = "^2.0.4"
|
||||
openbb-core = "^1.3.7"
|
||||
|
||||
[package.source]
|
||||
type = "directory"
|
||||
url = "providers/deribit"
|
||||
|
||||
[[package]]
|
||||
name = "openbb-derivatives"
|
||||
version = "1.3.5"
|
||||
@@ -2991,13 +3008,13 @@ testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "poetry"
|
||||
version = "1.8.4"
|
||||
version = "1.8.5"
|
||||
description = "Python dependency management and packaging made easy."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8"
|
||||
files = [
|
||||
{file = "poetry-1.8.4-py3-none-any.whl", hash = "sha256:1223bb6dfdbdfbebc6790796b9b7a88ea1f1f4679e709594f698499010ffb129"},
|
||||
{file = "poetry-1.8.4.tar.gz", hash = "sha256:5490f8da66d17eecd660e091281f8aaa5554381644540291817c249872c99202"},
|
||||
{file = "poetry-1.8.5-py3-none-any.whl", hash = "sha256:5505fba69bf2a792b5d7402d21839c853644337392b745109b86a23010cce5f3"},
|
||||
{file = "poetry-1.8.5.tar.gz", hash = "sha256:eb2c88d224f58f36df8f7b36d6c380c07d1001bca28bde620f68fc086e881b70"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -3012,7 +3029,7 @@ installer = ">=0.7.0,<0.8.0"
|
||||
keyring = ">=24.0.0,<25.0.0"
|
||||
packaging = ">=23.1"
|
||||
pexpect = ">=4.7.0,<5.0.0"
|
||||
pkginfo = ">=1.10,<2.0"
|
||||
pkginfo = ">=1.12,<2.0"
|
||||
platformdirs = ">=3.0.0,<5"
|
||||
poetry-core = "1.9.1"
|
||||
poetry-plugin-export = ">=1.6.0,<2.0.0"
|
||||
@@ -4741,7 +4758,7 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
|
||||
type = ["pytest-mypy"]
|
||||
|
||||
[extras]
|
||||
all = ["openbb-alpha-vantage", "openbb-biztoc", "openbb-cboe", "openbb-charting", "openbb-ecb", "openbb-econometrics", "openbb-finra", "openbb-finviz", "openbb-government-us", "openbb-multpl", "openbb-nasdaq", "openbb-quantitative", "openbb-seeking-alpha", "openbb-stockgrid", "openbb-technical", "openbb-tmx", "openbb-tradier", "openbb-wsj"]
|
||||
all = ["openbb-alpha-vantage", "openbb-biztoc", "openbb-cboe", "openbb-charting", "openbb-deribit", "openbb-ecb", "openbb-econometrics", "openbb-finra", "openbb-finviz", "openbb-government-us", "openbb-multpl", "openbb-nasdaq", "openbb-quantitative", "openbb-seeking-alpha", "openbb-stockgrid", "openbb-technical", "openbb-tmx", "openbb-tradier", "openbb-wsj"]
|
||||
alpha-vantage = ["openbb-alpha-vantage"]
|
||||
biztoc = ["openbb-biztoc"]
|
||||
cboe = ["openbb-cboe"]
|
||||
@@ -4764,4 +4781,4 @@ wsj = ["openbb-wsj"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.13"
|
||||
content-hash = "a2901737d966bcf33f21094863132898f6ab2b3469e371bdd753f5651ff5a3cb"
|
||||
content-hash = "814de57cabbeaba8d3614703e3ac73d124aded9ff34970c06957fad994c6397f"
|
||||
|
||||
12
openbb_platform/providers/deribit/README.md
vendored
Normal file
12
openbb_platform/providers/deribit/README.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# OpenBB Deribit Provider Extension
|
||||
|
||||
## Coverage
|
||||
|
||||
- obb.derivatives.options.chains
|
||||
- Support for symbols:
|
||||
- BTC
|
||||
- ETH
|
||||
- XRP
|
||||
- SOL
|
||||
- BNB
|
||||
- PAXG
|
||||
1
openbb_platform/providers/deribit/__init__.py
Normal file
1
openbb_platform/providers/deribit/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""OpenBB Deribit Provider Module."""
|
||||
15
openbb_platform/providers/deribit/openbb_deribit/__init__.py
Normal file
15
openbb_platform/providers/deribit/openbb_deribit/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""OpenBB Deribit Provider Module."""
|
||||
|
||||
from openbb_core.provider.abstract.provider import Provider
|
||||
|
||||
from openbb_deribit.models.options_chains import DeribitOptionsChainsFetcher
|
||||
|
||||
deribit_provider = Provider(
|
||||
name="deribit",
|
||||
website="https://deribit.com/",
|
||||
description="""Unofficial Python client for public data published by Deribit.""",
|
||||
credentials=None,
|
||||
fetcher_dict={"OptionsChains": DeribitOptionsChainsFetcher},
|
||||
repr_name="Deribit Public Data",
|
||||
instructions="This provider does not require any credentials and is not meant for trading.",
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
"""Deribit Data Models."""
|
||||
@@ -0,0 +1,279 @@
|
||||
"""Deribit Options Chains Model."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from openbb_core.app.model.abstract.error import OpenBBError
|
||||
from openbb_core.provider.abstract.fetcher import Fetcher
|
||||
from openbb_core.provider.standard_models.options_chains import (
|
||||
OptionsChainsData,
|
||||
OptionsChainsQueryParams,
|
||||
)
|
||||
from openbb_core.provider.utils.errors import EmptyDataError
|
||||
from openbb_deribit.utils.helpers import DERIBIT_OPTIONS_SYMBOLS
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
|
||||
class DeribitOptionsChainsQueryParams(OptionsChainsQueryParams):
|
||||
"""Deribit Options Chains Query Parameters Model."""
|
||||
|
||||
__json_schema_extra__ = {
|
||||
"symbol": {
|
||||
"multiple_items_allowed": False,
|
||||
"choices": DERIBIT_OPTIONS_SYMBOLS,
|
||||
}
|
||||
}
|
||||
|
||||
@field_validator("symbol", mode="before", check_fields=False)
|
||||
@classmethod
|
||||
def _validate_symbol(cls, v):
|
||||
"""Validate the symbol."""
|
||||
if v.upper() not in DERIBIT_OPTIONS_SYMBOLS:
|
||||
raise ValueError(
|
||||
f"Invalid Deribit symbol. Supported symbols are: {', '.join(DERIBIT_OPTIONS_SYMBOLS)}",
|
||||
)
|
||||
return v
|
||||
|
||||
|
||||
class DeribitOptionsChainsData(OptionsChainsData):
|
||||
"""Deribit Options Chains Data Model."""
|
||||
|
||||
__alias_dict__ = {
|
||||
"contract_symbol": "instrument_name",
|
||||
"change_percent": "price_change",
|
||||
"underlying_symbol": "underlying_index",
|
||||
"underlying_spot_price": "index_price",
|
||||
"bid_size": "best_bid_amount",
|
||||
"ask_size": "best_ask_amount",
|
||||
"bid": "best_bid_price",
|
||||
"ask": "best_ask_price",
|
||||
"implied_volatility": "mark_iv",
|
||||
"mark": "mark_price",
|
||||
"last_trade_price": "last_price",
|
||||
"volume_notional": "volume_usd",
|
||||
}
|
||||
|
||||
__doc__ = OptionsChainsData.__doc__
|
||||
|
||||
bid_iv: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The implied volatility of the bid price.",
|
||||
json_schema_extra={"x-unit_measurement": "decimal"},
|
||||
)
|
||||
ask_iv: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The implied volatility of the ask price.",
|
||||
json_schema_extra={"x-unit_measurement": "decimal"},
|
||||
)
|
||||
interest_rate: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The interest rate used by Deribit to calculate greeks.",
|
||||
)
|
||||
underlying_spot_price: list[float] = Field(
|
||||
description="The spot price of the underlying asset."
|
||||
" The underlying asset is the specific future or index that the option is based on.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
settlement_price: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The settlement price of the contract.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
min_price: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The minimum price allowed.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
max_price: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The maximum price allowed.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
volume_notional: list[Union[float, None]] = Field(
|
||||
default_factory=list,
|
||||
description="The notional trading volume of the contract, as USD or USDC.",
|
||||
json_schema_extra={"x-unit_measurement": "currency"},
|
||||
)
|
||||
timestamp: list[datetime] = Field(
|
||||
description="The datetime of the data, as America/New_York time.",
|
||||
)
|
||||
|
||||
|
||||
class DeribitOptionsChainsFetcher(
|
||||
Fetcher[DeribitOptionsChainsQueryParams, DeribitOptionsChainsData]
|
||||
):
|
||||
"""Deribit Options Chains Fetcher."""
|
||||
|
||||
require_credentials = False
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: dict[str, Any]) -> DeribitOptionsChainsQueryParams:
|
||||
"""Transform the query parameters."""
|
||||
return DeribitOptionsChainsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
async def aextract_data(
|
||||
query: DeribitOptionsChainsQueryParams,
|
||||
credentials: Optional[dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> list[dict]:
|
||||
"""Extract the data."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
import asyncio # noqa
|
||||
import json
|
||||
import websockets
|
||||
from openbb_deribit.utils.helpers import get_options_symbols
|
||||
from pandas import to_datetime
|
||||
from warnings import warn
|
||||
|
||||
# We need to identify each option contract in order to fetch the chains data.
|
||||
symbols_dict: dict[str, str] = {}
|
||||
|
||||
try:
|
||||
symbols_dict = await get_options_symbols(query.symbol)
|
||||
except OpenBBError as e:
|
||||
raise OpenBBError(e) from e
|
||||
|
||||
# For each expiration, we need to create a websocket connection to fetch the data.
|
||||
# We subscribe to each contract symbol and break the connection when we have all the data for an expiry.
|
||||
# If it takes too long, we break the connection and return an error message.
|
||||
results: list = []
|
||||
messages: set = set()
|
||||
|
||||
async def call_api(expiration):
|
||||
"""Call the Deribit API."""
|
||||
symbols = symbols_dict[expiration]
|
||||
received_symbols: set = set()
|
||||
msg = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3600,
|
||||
"method": "public/subscribe",
|
||||
"params": {"channels": ["ticker." + d + ".100ms" for d in symbols]},
|
||||
}
|
||||
async with websockets.connect(
|
||||
"wss://www.deribit.com/ws/api/v2"
|
||||
) as websocket:
|
||||
await websocket.send(json.dumps(msg))
|
||||
try:
|
||||
await asyncio.wait_for(
|
||||
receive_data(websocket, symbols, received_symbols), timeout=2.0
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
messages.add(f"Timeout reached for {expiration}, data incomplete.")
|
||||
|
||||
async def receive_data(websocket, symbols, received_symbols):
|
||||
"""Receive the data from the websocket with a timeout."""
|
||||
while websocket.open:
|
||||
response = await websocket.recv()
|
||||
data = json.loads(response)
|
||||
|
||||
if "params" not in data:
|
||||
continue
|
||||
|
||||
if "error" in data and data.get("error"):
|
||||
messages.add(f"Error while receiving data -> {data['error']}")
|
||||
break
|
||||
|
||||
res = data.get("params", {}).get("data", {})
|
||||
symbol = res.get("instrument_name")
|
||||
|
||||
# While we are handling the data, we will parse the message.
|
||||
if symbol not in received_symbols:
|
||||
received_symbols.add(symbol)
|
||||
stats = res.pop("stats", {})
|
||||
greeks = res.pop("greeks", {})
|
||||
timestamp = res.pop("timestamp", None)
|
||||
underlying_symbol = res.get("underlying_index")
|
||||
|
||||
if underlying_symbol == "index_price":
|
||||
res["underlying_index"] = symbol.split("-")[0].replace("_", "-")
|
||||
|
||||
res["timestamp"] = to_datetime(
|
||||
timestamp, unit="ms", utc=True
|
||||
).tz_convert("America/New_York")
|
||||
|
||||
if res.get("estimated_delivery_price") == res.get("index_price"):
|
||||
_ = res.pop("estimated_delivery_price", None)
|
||||
|
||||
_ = res.pop("state", None)
|
||||
result = {
|
||||
"expiration": to_datetime(symbol.split("-")[1]).date(),
|
||||
"strike": (
|
||||
float(symbol.split("-")[2].replace("d", "."))
|
||||
if "d" in symbol.split("-")[2]
|
||||
else int(symbol.split("-")[2])
|
||||
),
|
||||
"option_type": (
|
||||
"call"
|
||||
if symbol.endswith("-C")
|
||||
else "put" if symbol.endswith("-P") else None
|
||||
),
|
||||
**res,
|
||||
**stats,
|
||||
**greeks,
|
||||
}
|
||||
result["dte"] = (
|
||||
result["expiration"] - to_datetime("today").date()
|
||||
).days
|
||||
results.append(result)
|
||||
|
||||
if len(received_symbols) == len(symbols):
|
||||
await websocket.close()
|
||||
break
|
||||
|
||||
tasks = [
|
||||
asyncio.create_task(call_api(expiration)) for expiration in symbols_dict
|
||||
]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
if messages and not results:
|
||||
raise OpenBBError(", ".join(messages))
|
||||
|
||||
if results and messages:
|
||||
for message in messages:
|
||||
warn(message)
|
||||
|
||||
if not results and not messages:
|
||||
raise EmptyDataError("All requests returned empty with no error messages.")
|
||||
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: DeribitOptionsChainsQueryParams,
|
||||
data: list[dict],
|
||||
**kwargs: Any,
|
||||
) -> DeribitOptionsChainsData:
|
||||
"""Transform the data."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from numpy import nan
|
||||
from pandas import DataFrame
|
||||
|
||||
df = DataFrame(data)
|
||||
|
||||
# For BTC and ETH options, we need to convert price units to USD.
|
||||
for col in df.columns:
|
||||
if col in [
|
||||
"last_price",
|
||||
"settlement_price",
|
||||
"mark_price",
|
||||
"min_price",
|
||||
"max_price",
|
||||
"best_ask_price",
|
||||
"best_bid_price",
|
||||
"high",
|
||||
"low",
|
||||
] and query.symbol.upper() in ["BTC", "ETH"]:
|
||||
df.loc[:, col] = df[col].astype(float).multiply(df.index_price).round(2)
|
||||
elif col in ["price_change", "mark_iv", "bid_iv", "ask_iv"]:
|
||||
df.loc[:, col] = df[col].astype(float).divide(100)
|
||||
|
||||
df = df.replace({nan: None})
|
||||
df = df.sort_values(["expiration", "strike", "option_type"])
|
||||
df = df.reset_index(drop=True)
|
||||
df.loc[:, "contract_size"] = 1
|
||||
results = df.to_dict(orient="list")
|
||||
|
||||
return DeribitOptionsChainsData.model_validate(results)
|
||||
@@ -0,0 +1 @@
|
||||
"""Deribit Utility Functions."""
|
||||
@@ -0,0 +1,111 @@
|
||||
"""Deribit Helpers Module."""
|
||||
|
||||
from typing import Literal, Optional
|
||||
|
||||
from async_lru import alru_cache
|
||||
from openbb_core.app.model.abstract.error import OpenBBError
|
||||
|
||||
DERIBIT_OPTIONS_SYMBOLS = ["BTC", "ETH", "SOL", "XRP", "BNB", "PAXG"]
|
||||
OptionsSymbols = Literal["BTC", "ETH", "SOL", "XRP", "BNB", "PAXG"]
|
||||
CURRENCIES = ["BTC", "ETH", "USDC", "USDT", "EURR", "all"]
|
||||
Currencies = Literal["BTC", "ETH", "USDC", "USDT", "EURR", "all"]
|
||||
DERIVATIVE_TYPES = ["future", "option", "spot", "future_combo", "option_combo"]
|
||||
DerivativeTypes = Literal["future", "option", "spot", "future_combo", "option_combo"]
|
||||
BASE_URL = "https://www.deribit.com"
|
||||
|
||||
|
||||
@alru_cache(maxsize=64)
|
||||
async def get_instruments(
|
||||
currency: Currencies = "BTC",
|
||||
derivative_type: Optional[DerivativeTypes] = None,
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Get Deribit instruments.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
currency : Currencies
|
||||
The currency to get instruments for. Default is "BTC".
|
||||
derivative_type : Optional[DerivativeTypes]
|
||||
The type of derivative to get instruments for. Default is None, which gets all types.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[dict]
|
||||
A list of instrument dictionaries.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_core.provider.utils.helpers import amake_request
|
||||
|
||||
if currency != "all" and currency.upper() not in CURRENCIES:
|
||||
raise ValueError(
|
||||
f"Currency {currency} not supported. Supported currencies are: {', '.join(CURRENCIES)}"
|
||||
)
|
||||
if derivative_type and derivative_type not in DERIVATIVE_TYPES:
|
||||
raise ValueError(
|
||||
f"Kind {derivative_type} not supported. Supported kinds are: {', '.join(DERIVATIVE_TYPES)}"
|
||||
)
|
||||
|
||||
url = f"{BASE_URL}/api/v2/public/get_instruments?currency={currency.upper() if currency != 'all' else 'any'}"
|
||||
|
||||
if derivative_type is not None:
|
||||
url += f"&kind={derivative_type}"
|
||||
|
||||
try:
|
||||
response = await amake_request(url)
|
||||
return response.get("result", []) # type: ignore
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
raise OpenBBError(
|
||||
f"Failed to get instruments -> {e.__class__.__name__}: {e}"
|
||||
) from e
|
||||
|
||||
|
||||
async def get_options_symbols(symbol: OptionsSymbols = "BTC") -> dict:
|
||||
"""
|
||||
Get a dictionary of contract symbols by expiry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : OptionsSymbols
|
||||
The underlying symbol to get options for. Default is "BTC".
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict[str, str]
|
||||
A dictionary of contract symbols by expiry date.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from pandas import to_datetime
|
||||
|
||||
if symbol.upper() not in DERIBIT_OPTIONS_SYMBOLS:
|
||||
raise ValueError(
|
||||
f"Invalid Deribit symbol. Supported symbols are: {', '.join(DERIBIT_OPTIONS_SYMBOLS)}",
|
||||
)
|
||||
|
||||
currency = (
|
||||
"USDC" if symbol.upper() in ["BNB", "PAXG", "SOL", "XRP"] else symbol.upper()
|
||||
)
|
||||
instruments = await get_instruments(currency, "option")
|
||||
expirations: dict = {}
|
||||
all_options = list(
|
||||
set(
|
||||
d.get("instrument_name")
|
||||
for d in instruments
|
||||
if d.get("instrument_name").startswith(symbol)
|
||||
and d.get("instrument_name").endswith(("-C", "-P"))
|
||||
)
|
||||
)
|
||||
for item in sorted(
|
||||
list(
|
||||
set(
|
||||
(
|
||||
to_datetime(d.split("-")[1]).date().strftime("%Y-%m-%d"),
|
||||
d.split("-")[1],
|
||||
)
|
||||
for d in all_options
|
||||
)
|
||||
)
|
||||
):
|
||||
expirations[item[0]] = item[1]
|
||||
|
||||
return {k: [d for d in all_options if v in d] for k, v in expirations.items()}
|
||||
1609
openbb_platform/providers/deribit/poetry.lock
generated
vendored
Normal file
1609
openbb_platform/providers/deribit/poetry.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
openbb_platform/providers/deribit/pyproject.toml
vendored
Normal file
20
openbb_platform/providers/deribit/pyproject.toml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
[tool.poetry]
|
||||
name = "openbb-deribit"
|
||||
version = "1.0.0b"
|
||||
description = "Deribit is a crypto-native derivatives exchange."
|
||||
authors = ["OpenBB Team <hello@openbb.co>"]
|
||||
license = "AGPL-3.0-only"
|
||||
readme = "README.md"
|
||||
packages = [{ include = "openbb_deribit" }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
openbb-core = "^1.3.7"
|
||||
async-lru = "^2.0.4"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
deribit = "openbb_deribit:deribit_provider"
|
||||
1
openbb_platform/providers/deribit/tests/__init__.py
Normal file
1
openbb_platform/providers/deribit/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""OpenBB Deribit Provider Tests."""
|
||||
@@ -0,0 +1,265 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://www.deribit.com/api/v2/public/get_instruments?currency=BTC&kind=option
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
eHz+ifEf/zcumxcqrf8IAA==
|
||||
headers:
|
||||
Access-Control-Allow-Headers:
|
||||
- Authorization,User-Agent,Range,X-Requested-With,Content-Type,Partner
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Length:
|
||||
- '12385'
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Sat, 07 Dec 2024 00:22:12 GMT
|
||||
Server:
|
||||
- nginx
|
||||
Strict-Transport-Security:
|
||||
- max-age=15768000
|
||||
Vary:
|
||||
- Origin,Authorization,Partner
|
||||
- accept-encoding
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -0,0 +1,265 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://www.deribit.com/api/v2/public/get_instruments?currency=BTC&kind=option
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
/BPjP/5vfg/xlq3/CAA=
|
||||
headers:
|
||||
Access-Control-Allow-Headers:
|
||||
- Authorization,User-Agent,Range,X-Requested-With,Content-Type,Partner
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, POST, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Length:
|
||||
- '12383'
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Sat, 07 Dec 2024 00:13:55 GMT
|
||||
Server:
|
||||
- nginx
|
||||
Strict-Transport-Security:
|
||||
- max-age=15768000
|
||||
Vary:
|
||||
- Origin,Authorization,Partner
|
||||
- accept-encoding
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -0,0 +1,99 @@
|
||||
"""Deribit Fetcher Tests."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from openbb_core.app.service.user_service import UserService
|
||||
from openbb_core.provider.utils.helpers import run_async
|
||||
from openbb_deribit.models.options_chains import (
|
||||
DeribitOptionsChainsData,
|
||||
DeribitOptionsChainsFetcher,
|
||||
)
|
||||
|
||||
test_credentials = UserService().default_user_settings.credentials.model_dump(
|
||||
mode="json"
|
||||
)
|
||||
|
||||
MOCK_OPTIONS_DATA = DeribitOptionsChainsData.model_validate(
|
||||
{
|
||||
"expiration": ["2024-12-07", "2024-12-07"],
|
||||
"strike": [84000.0, 84000.0],
|
||||
"option_type": ["call", "put"],
|
||||
"underlying_symbol": ["SYN.BTC-7DEC24", "SYN.BTC-7DEC24"],
|
||||
"underlying_price": [100671.2825, 100671.2825],
|
||||
"contract_symbol": ["BTC-7DEC24-84000-C", "BTC-7DEC24-84000-P"],
|
||||
"dte": [1, 1],
|
||||
"contract_size": [1, 1],
|
||||
"open_interest": [1.0, 124.8],
|
||||
"volume": [0.1, 151.9],
|
||||
"last_trade_price": [None, 20.13],
|
||||
"bid": [10.06, 0.05],
|
||||
"bid_size": [0.3, 0.0],
|
||||
"ask": [0.06, 10.06],
|
||||
"ask_size": [0.0, 0.2],
|
||||
"mark": [16666.69, 0.0],
|
||||
"high": [None, 442.83],
|
||||
"low": [None, 10.06],
|
||||
"change_percent": [0, -0.6],
|
||||
"implied_volatility": [1.3618999999999999, 1.3618999999999999],
|
||||
"delta": [0.99997, -3e-05],
|
||||
"gamma": [0.0, 0.0],
|
||||
"theta": [-0.24909, -0.0263],
|
||||
"vega": [0.00366, 0.00366],
|
||||
"rho": [0.91572, -3e-05],
|
||||
"underlying_spot_price": [100644.24, 100644.24],
|
||||
"settlement_price": [14590.44, 14.35],
|
||||
"timestamp": [
|
||||
"2024-12-06 17:26:36.234000-0500",
|
||||
"2024-12-06 17:26:36.234000-0500",
|
||||
],
|
||||
"min_price": [13184.4, 10.06],
|
||||
"max_price": [20078.53, 1509.66],
|
||||
"interest_rate": [0.0, 0.0],
|
||||
"bid_iv": [0.0, 0.0],
|
||||
"ask_iv": [0.0, 2.1254],
|
||||
"volume_notional": [0.0, 7083.24],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vcr_config():
|
||||
"""VCR configuration."""
|
||||
return {
|
||||
"filter_headers": [("User-Agent", None)],
|
||||
"filter_query_parameters": [
|
||||
None,
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_get_options_symbols():
|
||||
"""Test getting the list of options symbols."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_deribit.utils.helpers import get_options_symbols
|
||||
|
||||
params = {"symbol": "BTC"}
|
||||
|
||||
result = run_async(get_options_symbols, **params)
|
||||
assert result is not None
|
||||
assert isinstance(result, dict)
|
||||
assert len(result) > 0
|
||||
for key, value in result.items():
|
||||
assert isinstance(value, list)
|
||||
assert key.startswith("2")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_deribit_options_chains_fetcher(credentials=test_credentials):
|
||||
"""Test Deribit Options Chains Fetcher."""
|
||||
params = {"symbol": "BTC"}
|
||||
fetcher = DeribitOptionsChainsFetcher()
|
||||
|
||||
with patch(
|
||||
"openbb_deribit.models.options_chains.DeribitOptionsChainsFetcher.fetch_data",
|
||||
return_value=MagicMock(MOCK_OPTIONS_DATA),
|
||||
):
|
||||
result = await fetcher.fetch_data(params, {})
|
||||
assert isinstance(result, DeribitOptionsChainsData)
|
||||
2
openbb_platform/pyproject.toml
vendored
2
openbb_platform/pyproject.toml
vendored
@@ -45,6 +45,7 @@ openbb-regulators = "^1.3.5"
|
||||
openbb-alpha-vantage = { version = "^1.3.5", optional = true }
|
||||
openbb-biztoc = { version = "^1.3.5", optional = true }
|
||||
openbb-cboe = { version = "^1.3.5", optional = true }
|
||||
openbb-deribit = { path = "./providers/deribit", optional = true }
|
||||
openbb-ecb = { version = "^1.3.5", optional = true }
|
||||
openbb-finra = { version = "^1.3.5", optional = true }
|
||||
openbb-finviz = { version = "^1.2.5", optional = true }
|
||||
@@ -88,6 +89,7 @@ all = [
|
||||
"openbb-biztoc",
|
||||
"openbb-cboe",
|
||||
"openbb-charting",
|
||||
"openbb-deribit",
|
||||
"openbb-ecb",
|
||||
"openbb-econometrics",
|
||||
"openbb-finra",
|
||||
|
||||
Reference in New Issue
Block a user