feat(PORT-001A): add collateral entry basis settings

This commit is contained in:
Bu5hm4nn
2026-03-24 00:38:13 +01:00
parent 140a21c0b6
commit 56e84680e8
6 changed files with 349 additions and 134 deletions

View File

@@ -2,6 +2,8 @@ from __future__ import annotations
import pytest
from app.models.portfolio import PortfolioConfig
def test_ltv_calculation(sample_portfolio) -> None:
assert sample_portfolio.current_ltv == pytest.approx(0.60, rel=1e-12)
@@ -20,3 +22,57 @@ def test_net_equity_calculation(sample_portfolio) -> None:
def test_margin_call_threshold(sample_portfolio) -> None:
assert sample_portfolio.margin_call_price() == pytest.approx(368.0, rel=1e-12)
assert sample_portfolio.ltv_at_price(sample_portfolio.margin_call_price()) == pytest.approx(0.75, rel=1e-12)
def test_portfolio_config_derives_gold_weight_from_start_value_and_entry_price() -> None:
config = PortfolioConfig(
gold_value=215_000.0,
entry_price=215.0,
entry_basis_mode="value_price",
)
assert config.gold_ounces == pytest.approx(1_000.0, rel=1e-12)
assert config.gold_value == pytest.approx(215_000.0, rel=1e-12)
assert config.entry_basis_mode == "value_price"
def test_portfolio_config_derives_start_value_from_gold_weight_and_entry_price() -> None:
config = PortfolioConfig(
gold_ounces=1_000.0,
entry_price=215.0,
entry_basis_mode="weight",
)
assert config.gold_value == pytest.approx(215_000.0, rel=1e-12)
assert config.gold_ounces == pytest.approx(1_000.0, rel=1e-12)
assert config.entry_basis_mode == "weight"
def test_portfolio_config_serializes_canonical_entry_basis_fields() -> None:
config = PortfolioConfig(gold_value=215_000.0, entry_price=215.0)
data = config.to_dict()
assert data["gold_value"] == pytest.approx(215_000.0, rel=1e-12)
assert data["gold_ounces"] == pytest.approx(1_000.0, rel=1e-12)
assert data["entry_price"] == pytest.approx(215.0, rel=1e-12)
assert PortfolioConfig.from_dict(data).gold_ounces == pytest.approx(1_000.0, rel=1e-12)
def test_portfolio_config_keeps_legacy_gold_value_payloads_compatible() -> None:
config = PortfolioConfig.from_dict({"gold_value": 215_000.0, "loan_amount": 145_000.0})
assert config.gold_value == pytest.approx(215_000.0, rel=1e-12)
assert config.entry_price == pytest.approx(215.0, rel=1e-12)
assert config.gold_ounces == pytest.approx(1_000.0, rel=1e-12)
def test_portfolio_config_rejects_invalid_entry_basis_values() -> None:
with pytest.raises(ValueError, match="Entry price must be positive"):
PortfolioConfig(entry_price=0.0)
with pytest.raises(ValueError, match="Gold weight must be positive"):
PortfolioConfig(gold_ounces=-1.0, entry_price=215.0, entry_basis_mode="weight")
with pytest.raises(ValueError, match="Gold value and weight contradict each other"):
PortfolioConfig(gold_value=215_000.0, gold_ounces=900.0, entry_price=215.0)