feat(DATA-003): calculate live option greeks

This commit is contained in:
Bu5hm4nn
2026-03-23 23:46:40 +01:00
parent 46ce81d2d6
commit de03bd0064
5 changed files with 218 additions and 37 deletions

View File

@@ -0,0 +1,97 @@
from __future__ import annotations
from datetime import datetime
import pandas as pd
import pytest
from app.core.calculations import option_row_greeks
from app.core.pricing.black_scholes import (
DEFAULT_RISK_FREE_RATE,
DEFAULT_VOLATILITY,
BlackScholesInputs,
black_scholes_price_and_greeks,
)
from app.services.cache import CacheService
from app.services.data_service import DataService
@pytest.mark.parametrize(
"row, expected_volatility",
[
(
{
"strike": 460.0,
"expiry": "2026-06-19",
"type": "put",
"impliedVolatility": 0.24,
},
0.24,
),
(
{
"strike": 460.0,
"expiry": "2026-06-19",
"type": "put",
"impliedVolatility": 0.0,
},
DEFAULT_VOLATILITY,
),
],
)
def test_option_row_greeks_uses_live_iv_or_falls_back(row: dict[str, object], expected_volatility: float) -> None:
valuation_date = datetime(2026, 3, 23).date()
greeks = option_row_greeks(row, underlying_price=460.0, valuation_date=valuation_date)
expected = black_scholes_price_and_greeks(
BlackScholesInputs(
spot=460.0,
strike=460.0,
time_to_expiry=(datetime(2026, 6, 19).date() - valuation_date).days / 365.0,
risk_free_rate=DEFAULT_RISK_FREE_RATE,
volatility=expected_volatility,
option_type="put",
valuation_date=valuation_date,
)
)
assert greeks["delta"] == pytest.approx(expected.delta, rel=1e-9)
assert greeks["gamma"] == pytest.approx(expected.gamma, rel=1e-9)
assert greeks["theta"] == pytest.approx(expected.theta, rel=1e-9)
assert greeks["vega"] == pytest.approx(expected.vega, rel=1e-9)
def test_option_row_greeks_handles_invalid_input_gracefully() -> None:
greeks = option_row_greeks(
{"strike": 0.0, "expiry": "not-a-date", "type": "call", "impliedVolatility": -1.0},
underlying_price=0.0,
)
assert greeks == {"delta": 0.0, "gamma": 0.0, "theta": 0.0, "vega": 0.0, "rho": 0.0}
def test_normalize_option_rows_populates_greeks() -> None:
frame = pd.DataFrame(
[
{
"contractSymbol": "GLD260619P00460000",
"strike": 460.0,
"bid": 18.5,
"ask": 19.5,
"lastPrice": 19.0,
"impliedVolatility": 0.22,
"openInterest": 100,
"volume": 50,
}
]
)
service = DataService(CacheService(None))
rows = service._normalize_option_rows(frame, "GLD", "2026-06-19", "put", 460.0)
assert len(rows) == 1
assert rows[0]["symbol"] == "GLD260619P00460000"
assert rows[0]["delta"] < 0.0
assert rows[0]["gamma"] > 0.0
assert rows[0]["theta"] < 0.0
assert rows[0]["vega"] > 0.0