63 lines
2.2 KiB
Python
63 lines
2.2 KiB
Python
from datetime import datetime, timezone
|
|
from decimal import Decimal
|
|
import unittest
|
|
|
|
from kartsell_policy_contract import SellAction, SellInput, default_chain
|
|
|
|
|
|
def base_input(**changes):
|
|
values = dict(
|
|
position_lot_id="lot-1",
|
|
cycle_id="cycle-1",
|
|
evidence_id="evidence-1",
|
|
dataset_id="dataset-1",
|
|
model_version="model-1",
|
|
config_version="config-1",
|
|
code_sha="sha-1",
|
|
as_of=datetime(2026, 8, 1, 7, tzinfo=timezone.utc),
|
|
published_at_cutoff=datetime(2026, 8, 1, 6, tzinfo=timezone.utc),
|
|
current_portfolio_weight=Decimal("0.60"),
|
|
strategic_core_floor_weight=Decimal("0.30"),
|
|
)
|
|
values.update(changes)
|
|
return SellInput(**values)
|
|
|
|
|
|
class PolicyContractTests(unittest.TestCase):
|
|
def test_hard_impairment_wins(self):
|
|
result = default_chain().evaluate(base_input(
|
|
hard_impairment_approved=True,
|
|
capital_floor_breached=True,
|
|
survival_sell_ratio_of_lot=Decimal("0.5"),
|
|
gap_below_floor_atr=Decimal("2"),
|
|
))
|
|
self.assertEqual("ALG-SELL-001", result.policy_id)
|
|
self.assertEqual(SellAction.FULL_SELL, result.action)
|
|
self.assertFalse(result.reentry_eligible)
|
|
|
|
def test_gap_preserves_absolute_core_weight(self):
|
|
result = default_chain().evaluate(base_input(
|
|
strategic_core_floor_weight=Decimal("0.50"),
|
|
gap_below_floor_atr=Decimal("2"),
|
|
))
|
|
self.assertEqual("ALG-SELL-002", result.policy_id)
|
|
self.assertEqual(Decimal("0.50000000"), result.target_portfolio_weight_after)
|
|
|
|
def test_survival_can_cross_core(self):
|
|
result = default_chain().evaluate(base_input(
|
|
capital_floor_breached=True,
|
|
survival_sell_ratio_of_lot=Decimal("0.50"),
|
|
))
|
|
self.assertEqual("ALG-SELL-PORT-001", result.policy_id)
|
|
self.assertEqual(Decimal("0.30000000"), result.target_portfolio_weight_after)
|
|
|
|
def test_future_published_at_is_rejected(self):
|
|
with self.assertRaises(ValueError):
|
|
default_chain().evaluate(base_input(
|
|
published_at_cutoff=datetime(2026, 8, 1, 8, tzinfo=timezone.utc)
|
|
))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|