Initial commit: Add project files
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user