- FastAPI + NiceGUI web application - QuantLib-based Black-Scholes pricing with Greeks - Protective put, laddered, and LEAPS strategies - Real-time WebSocket updates - TradingView-style charts via Lightweight-Charts - Docker containerization - GitLab CI/CD pipeline for VPS deployment - VPN-only access configuration
68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
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)
|