172 lines
6.0 KiB
Python
172 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
|
|
import pytest
|
|
|
|
from app.services.event_comparison_ui import EventComparisonFixtureHistoricalPriceSource, EventComparisonPageService
|
|
|
|
|
|
def test_event_comparison_page_service_runs_seeded_gld_preset_deterministically() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
report = service.run_read_only_comparison(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=("protective-put-atm-12m", "protective-put-95pct-12m"),
|
|
underlying_units=1000.0,
|
|
loan_amount=68000.0,
|
|
margin_call_ltv=0.75,
|
|
)
|
|
|
|
assert report.event_preset.slug == "gld-jan-2024-selloff"
|
|
assert report.scenario.start_date.isoformat() == "2024-01-02"
|
|
assert report.scenario.end_date.isoformat() == "2024-01-08"
|
|
assert [item.template_slug for item in report.rankings] == [
|
|
"protective-put-atm-12m",
|
|
"protective-put-95pct-12m",
|
|
]
|
|
assert report.rankings[0].rank == 1
|
|
assert (
|
|
report.rankings[0].result.daily_path[-1].net_portfolio_value
|
|
> report.rankings[-1].result.daily_path[-1].net_portfolio_value
|
|
)
|
|
|
|
|
|
def test_event_comparison_page_service_uses_preset_default_templates_when_none_selected() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
report = service.run_read_only_comparison(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=(),
|
|
underlying_units=1000.0,
|
|
loan_amount=68000.0,
|
|
margin_call_ltv=0.75,
|
|
)
|
|
|
|
assert [item.template_slug for item in report.rankings] == [
|
|
"protective-put-atm-12m",
|
|
"ladder-50-50-atm-95pct-12m",
|
|
"protective-put-95pct-12m",
|
|
"protective-put-90pct-12m",
|
|
]
|
|
|
|
|
|
def test_event_comparison_page_service_exposes_seeded_preset_options() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
options = service.preset_options("GLD")
|
|
|
|
assert options[0]["slug"] == "gld-jan-2024-selloff"
|
|
assert options[0]["label"] == "GLD January 2024 Selloff"
|
|
assert tuple(options[0]["default_template_slugs"]) == (
|
|
"protective-put-atm-12m",
|
|
"protective-put-95pct-12m",
|
|
"protective-put-90pct-12m",
|
|
"ladder-50-50-atm-95pct-12m",
|
|
)
|
|
|
|
|
|
def test_event_comparison_page_service_keeps_fixture_window_while_using_caller_portfolio_inputs() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
report = service.run_read_only_comparison(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=("protective-put-atm-12m",),
|
|
underlying_units=9680.0,
|
|
loan_amount=222000.0,
|
|
margin_call_ltv=0.80,
|
|
)
|
|
|
|
assert report.scenario.start_date.isoformat() == "2024-01-02"
|
|
assert report.scenario.end_date.isoformat() == "2024-01-08"
|
|
assert report.scenario.initial_portfolio.entry_spot == 100.0
|
|
assert report.scenario.initial_portfolio.underlying_units == 9680.0
|
|
assert report.scenario.initial_portfolio.loan_amount == 222000.0
|
|
assert report.scenario.initial_portfolio.margin_call_ltv == 0.80
|
|
|
|
|
|
def test_event_comparison_page_service_resets_template_selection_to_preset_defaults() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
assert service.default_template_selection("gld-jan-2024-selloff") == (
|
|
"protective-put-atm-12m",
|
|
"protective-put-95pct-12m",
|
|
"protective-put-90pct-12m",
|
|
"ladder-50-50-atm-95pct-12m",
|
|
)
|
|
assert service.default_template_selection("gld-jan-2024-drawdown") == (
|
|
"protective-put-atm-12m",
|
|
"ladder-50-50-atm-95pct-12m",
|
|
"ladder-33-33-33-atm-95pct-90pct-12m",
|
|
)
|
|
|
|
|
|
def test_event_comparison_page_service_preview_uses_same_materialization_path() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
scenario = service.preview_scenario(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=("protective-put-atm-12m",),
|
|
underlying_units=1000.0,
|
|
loan_amount=68000.0,
|
|
margin_call_ltv=0.75,
|
|
)
|
|
|
|
assert scenario.start_date.isoformat() == "2024-01-02"
|
|
assert scenario.end_date.isoformat() == "2024-01-08"
|
|
assert scenario.initial_portfolio.entry_spot == 100.0
|
|
assert [ref.slug for ref in scenario.template_refs] == ["protective-put-atm-12m"]
|
|
|
|
|
|
def test_event_comparison_page_service_rejects_undercollateralized_historical_start() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
with pytest.raises(ValueError, match="Historical scenario starts undercollateralized"):
|
|
service.preview_scenario(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=("protective-put-atm-12m",),
|
|
underlying_units=1000.0,
|
|
loan_amount=145000.0,
|
|
margin_call_ltv=0.75,
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="Historical scenario starts undercollateralized"):
|
|
service.run_read_only_comparison(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=("protective-put-atm-12m",),
|
|
underlying_units=1000.0,
|
|
loan_amount=145000.0,
|
|
margin_call_ltv=0.75,
|
|
)
|
|
|
|
|
|
def test_event_comparison_fixture_fails_closed_for_unsupported_range() -> None:
|
|
source = EventComparisonFixtureHistoricalPriceSource()
|
|
|
|
with pytest.raises(ValueError, match="seeded 2024-01-02 through 2024-01-08"):
|
|
source.load_daily_closes("GLD", date(2024, 1, 1), date(2024, 1, 8))
|
|
|
|
|
|
def test_event_comparison_page_service_builds_chart_model_with_unhedged_reference() -> None:
|
|
service = EventComparisonPageService()
|
|
|
|
report = service.run_read_only_comparison(
|
|
preset_slug="gld-jan-2024-selloff",
|
|
template_slugs=("protective-put-atm-12m", "protective-put-95pct-12m"),
|
|
underlying_units=1000.0,
|
|
loan_amount=68000.0,
|
|
margin_call_ltv=0.75,
|
|
)
|
|
chart_model = service.chart_model(report)
|
|
|
|
assert chart_model.dates == (
|
|
"2024-01-02",
|
|
"2024-01-03",
|
|
"2024-01-04",
|
|
"2024-01-05",
|
|
"2024-01-08",
|
|
)
|
|
assert chart_model.series[0].name == "Unhedged collateral baseline"
|
|
assert chart_model.series[1].name == "Protective Put ATM"
|
|
assert len(chart_model.series[0].values) == len(chart_model.dates)
|