feat(PORT-001A): add collateral entry basis settings
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user