from __future__ import annotations import pytest import app.core.pricing.black_scholes as black_scholes from app.core.pricing.black_scholes import BlackScholesInputs @pytest.mark.parametrize( "params, expected_price", [ ( BlackScholesInputs( spot=460.0, strike=460.0, time_to_expiry=1.0, risk_free_rate=0.045, volatility=0.16, option_type="put", dividend_yield=0.0, ), 19.68944358516964, ) ], ) def test_put_price_calculation( monkeypatch: pytest.MonkeyPatch, params: BlackScholesInputs, expected_price: float, ) -> None: """European put price from the research-paper ATM example.""" monkeypatch.setattr(black_scholes, "ql", None) result = black_scholes.black_scholes_price_and_greeks(params) assert result.price == pytest.approx(expected_price, rel=1e-9) def test_greeks_values(monkeypatch: pytest.MonkeyPatch) -> None: """Validate Black-Scholes Greeks against research-paper baseline inputs.""" monkeypatch.setattr(black_scholes, "ql", None) result = black_scholes.black_scholes_price_and_greeks( BlackScholesInputs( spot=460.0, strike=460.0, time_to_expiry=1.0, risk_free_rate=0.045, volatility=0.16, option_type="put", dividend_yield=0.0, ) ) assert result.delta == pytest.approx(-0.35895628379355216, rel=1e-9) assert result.gamma == pytest.approx(0.005078017547110844, rel=1e-9) assert result.theta == pytest.approx(-5.4372889301396174, rel=1e-9) assert result.vega == pytest.approx(171.92136207498476, rel=1e-9) assert result.rho == pytest.approx(-184.80933413020364, rel=1e-9) def test_margin_call_price_calculation() -> None: """Margin-call trigger from research defaults: 460 spot, 1,000,000 collateral, 600,000 loan.""" threshold = black_scholes.margin_call_threshold_price( portfolio_value=1_000_000.0, loan_amount=600_000.0, current_price=460.0, margin_call_ltv=0.75, ) assert threshold == pytest.approx(368.0, rel=1e-12)