feat(EXEC-001): add hedge strategy builder

This commit is contained in:
Bu5hm4nn
2026-03-27 22:33:20 +01:00
parent 554a41a060
commit 4620234967
9 changed files with 429 additions and 37 deletions

View File

@@ -125,8 +125,10 @@ def test_strategy_selection_engine_uses_named_templates(monkeypatch: pytest.Monk
]
def test_strategy_template_service_catalog_reads_named_templates() -> None:
catalog = StrategyTemplateService().catalog_items()
def test_strategy_template_service_catalog_reads_named_templates(tmp_path: Path) -> None:
catalog = StrategyTemplateService(
repository=FileStrategyTemplateRepository(tmp_path / "strategy_templates.json")
).catalog_items()
assert [item["label"] for item in catalog] == [
"Protective Put ATM",
@@ -142,3 +144,77 @@ def test_strategy_template_service_catalog_reads_named_templates() -> None:
"laddered_put_50_50_atm_otm95",
"laddered_put_33_33_33_atm_otm95_otm90",
]
def test_strategy_template_service_creates_and_persists_custom_protective_template(tmp_path: Path) -> None:
repository = FileStrategyTemplateRepository(tmp_path / "strategy_templates.json")
service = StrategyTemplateService(repository=repository)
template = service.create_custom_template(
display_name="Crash Guard 97%",
template_kind="protective_put",
target_expiry_days=180,
strike_pcts=(0.97,),
)
assert template.display_name == "Crash Guard 97%"
assert template.slug == "crash-guard-97"
assert template.target_expiry_days == 180
assert template.legs[0].strike_rule.value == 0.97
assert template.tags == ("custom", "protective_put")
assert service.get_template("crash-guard-97").display_name == "Crash Guard 97%"
def test_strategy_template_service_rejects_duplicate_custom_template_name(tmp_path: Path) -> None:
repository = FileStrategyTemplateRepository(tmp_path / "strategy_templates.json")
service = StrategyTemplateService(repository=repository)
service.create_custom_template(
display_name="Crash Guard 97%",
template_kind="protective_put",
target_expiry_days=180,
strike_pcts=(0.97,),
)
with pytest.raises(ValueError, match="Template name already exists"):
service.create_custom_template(
display_name="Crash Guard 97%",
template_kind="protective_put",
target_expiry_days=90,
strike_pcts=(0.92,),
)
def test_strategy_template_service_catalog_includes_custom_ladder_template(tmp_path: Path) -> None:
repository = FileStrategyTemplateRepository(tmp_path / "strategy_templates.json")
service = StrategyTemplateService(repository=repository)
service.create_custom_template(
display_name="Crash Ladder 98/92",
template_kind="laddered_put",
target_expiry_days=270,
strike_pcts=(0.98, 0.92),
weights=(0.5, 0.5),
)
custom_item = next(item for item in service.catalog_items() if item["label"] == "Crash Ladder 98/92")
assert custom_item["coverage"] == "Layered"
assert custom_item["estimated_cost"] > 0
assert custom_item["downside_put_legs"] == [
{"allocation_weight": 0.5, "strike_pct": 0.98},
{"allocation_weight": 0.5, "strike_pct": 0.92},
]
def test_strategy_template_service_catalog_custom_cost_reflects_expiry_days(tmp_path: Path) -> None:
repository = FileStrategyTemplateRepository(tmp_path / "strategy_templates.json")
service = StrategyTemplateService(repository=repository)
service.create_custom_template(
display_name="Crash Guard 95 180d",
template_kind="protective_put",
target_expiry_days=180,
strike_pcts=(0.95,),
)
custom_item = next(item for item in service.catalog_items() if item["label"] == "Crash Guard 95 180d")
assert custom_item["estimated_cost"] == 3.49