mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-05 17:01:58 +00:00
* merge branch develop with main * bump desktop version * fix the merge * sync Cargo.lock to desktop 2.0.0 * fix cli conftest.py --------- Co-authored-by: deeleeramone <>
161 lines
4.9 KiB
Python
161 lines
4.9 KiB
Python
"""Shared fixtures for the openbb_deribit test suite."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
DATA_DIR = Path(__file__).parent / "data"
|
|
|
|
|
|
def payload(name: str):
|
|
"""Return one captured Deribit payload."""
|
|
return json.loads((DATA_DIR / f"{name}.json").read_text(encoding="utf-8"))
|
|
|
|
|
|
@pytest.fixture
|
|
def load():
|
|
"""Return the loader for a captured Deribit payload."""
|
|
return payload
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _no_network(request, monkeypatch):
|
|
"""Fail loudly rather than reaching the exchange from a unit test.
|
|
|
|
A test marked ``uses_session`` builds its own sessions and is left alone;
|
|
a session is only a connection pool until something asks it for a URL.
|
|
"""
|
|
if request.node.get_closest_marker("uses_session"):
|
|
return
|
|
|
|
async def _forbidden(*args, **kwargs):
|
|
raise AssertionError(
|
|
"A unit test opened a session. Patch the client or the session."
|
|
)
|
|
|
|
monkeypatch.setattr("openbb_deribit.utils.session.get_session", _forbidden)
|
|
monkeypatch.setattr("openbb_deribit.utils.session.get_cached_session", _forbidden)
|
|
|
|
|
|
@pytest.fixture
|
|
def responder(monkeypatch):
|
|
"""Answer client calls from a mapping of method name to payload."""
|
|
|
|
def install(mapping: dict):
|
|
async def _request(method, params=None, use_cache=True):
|
|
if method not in mapping:
|
|
raise AssertionError(f"No fixture registered for public/{method}.")
|
|
|
|
answer = mapping[method]
|
|
|
|
return answer(params) if callable(answer) else answer
|
|
|
|
async def _gather(calls, use_cache=True):
|
|
return [await _request(method, params) for method, params in calls]
|
|
|
|
monkeypatch.setattr("openbb_deribit.utils.client.request", _request)
|
|
monkeypatch.setattr("openbb_deribit.utils.client.gather", _gather)
|
|
|
|
return mapping
|
|
|
|
return install
|
|
|
|
|
|
def _chain_rows(inverse: bool, spot: float, size: float):
|
|
"""Build a small, well-formed chain around a spot price."""
|
|
from datetime import date, timedelta
|
|
|
|
today = date.today()
|
|
rows = []
|
|
|
|
for days in (1, 30):
|
|
expiration = today + timedelta(days=days)
|
|
|
|
for step in range(-4, 5):
|
|
strike = round(spot * (1 + step * 0.02), 4)
|
|
|
|
for option_type in ("call", "put"):
|
|
moneyness = (
|
|
max(0.0, spot - strike)
|
|
if option_type == "call"
|
|
else max(0.0, strike - spot)
|
|
)
|
|
extrinsic = spot * 0.01 * (days / 30) ** 0.5
|
|
mark = moneyness + extrinsic
|
|
rows.append(
|
|
{
|
|
"contract_symbol": (
|
|
f"TEST-{days}-{strike:g}-{option_type[0].upper()}"
|
|
),
|
|
"expiration": expiration,
|
|
"dte": days,
|
|
"strike": float(strike),
|
|
"option_type": option_type,
|
|
"contract_size": size,
|
|
"tick_size": 0.0001,
|
|
"is_inverse": inverse,
|
|
"mark": mark,
|
|
"bid": mark * 0.98,
|
|
"ask": mark * 1.02,
|
|
"last": mark,
|
|
"implied_volatility": 50.0 + abs(step) * 2,
|
|
"open_interest": 10.0 + step,
|
|
"volume": 5.0,
|
|
"underlying_price": spot,
|
|
"underlying_spot_price": spot,
|
|
"delta": 0.5,
|
|
"gamma": 0.001,
|
|
"theta": -1.0,
|
|
"vega": 10.0,
|
|
"rho": 1.0,
|
|
}
|
|
)
|
|
|
|
return rows
|
|
|
|
|
|
@pytest.fixture
|
|
def chain_frame():
|
|
"""Return a builder for a synthetic option chain."""
|
|
from pandas import DataFrame
|
|
|
|
def build(inverse: bool = True, spot: float = 100.0, size: float = 1.0):
|
|
return DataFrame(_chain_rows(inverse, spot, size))
|
|
|
|
return build
|
|
|
|
|
|
@pytest.fixture
|
|
def options_chain(chain_frame):
|
|
"""Return a synthetic chain as the model the options charts draw from."""
|
|
from openbb_deribit.utils.options.data_handler import to_chain
|
|
|
|
return to_chain(chain_frame(), "BTC")
|
|
|
|
|
|
@pytest.fixture
|
|
def loaded_chain(monkeypatch, chain_frame):
|
|
"""Serve a synthetic chain wherever a chain would be loaded."""
|
|
|
|
def install(
|
|
inverse: bool = True,
|
|
spot: float = 100.0,
|
|
size: float = 1.0,
|
|
books: list | None = None,
|
|
):
|
|
frame = chain_frame(inverse, spot, size)
|
|
|
|
async def _load(symbol, use_cache=True):
|
|
return frame.copy()
|
|
|
|
async def _combos(symbol, use_cache=True):
|
|
return list(books or [])
|
|
|
|
monkeypatch.setattr("openbb_deribit.utils.options.chain.load_chain", _load)
|
|
monkeypatch.setattr("openbb_deribit.utils.options.chain.load_combos", _combos)
|
|
|
|
return frame
|
|
|
|
return install
|