feat: add portfolio snapshot read layer
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
"""Snapshot scheduler tests (REQ-030 AC-1)."""
|
||||
from __future__ import annotations
|
||||
|
||||
from trex_core.adapters.broker.paper import PaperBroker
|
||||
from trex_core.adapters.portfolio.stub_read import StubPortfolioRead
|
||||
from trex_core.application.portfolio import PortfolioItem, SnapshotStore
|
||||
from trex_core.application.snapshot_scheduler import SnapshotScheduler
|
||||
|
||||
|
||||
def test_run_once_fetches_universe_and_swaps_store():
|
||||
read = StubPortfolioRead(daemon_id="d-1", items=[
|
||||
PortfolioItem(portfolio_id="pf-X", symbol="X",
|
||||
cash_balance=100, asset_quantity=0),
|
||||
])
|
||||
store = SnapshotStore()
|
||||
sched = SnapshotScheduler(read_port=read, store=store, broker=PaperBroker())
|
||||
assert sched.run_once() is True
|
||||
pids = {a.item.portfolio_id for a in store.list_assets()}
|
||||
assert pids == {"pf-X"}
|
||||
# universe membership + strategy params come from fetch (baseline)
|
||||
# cash/quantity are baseline values (option D will overwrite later)
|
||||
a = store.get("pf-X")
|
||||
assert a.item.cash_balance == 100
|
||||
assert a.warning is False
|
||||
|
||||
|
||||
def test_run_once_failure_sets_degraded_signal():
|
||||
class BadRead:
|
||||
def whoami(self): return "d-2"
|
||||
def get_portfolios(self, daemon_id):
|
||||
from trex_core.application.portfolio import PortfolioHubUnavailableError
|
||||
raise PortfolioHubUnavailableError("simulated")
|
||||
store = SnapshotStore()
|
||||
sched = SnapshotScheduler(read_port=BadRead(), store=store, broker=PaperBroker())
|
||||
assert sched.run_once() is False
|
||||
reason, msg = store.degraded_state()
|
||||
assert reason is not None and reason.value == "portfolio_hub_unavailable"
|
||||
|
||||
|
||||
def test_swap_preserves_warning_for_carried_over_portfolio():
|
||||
store = SnapshotStore()
|
||||
store.swap([PortfolioItem(portfolio_id="pf-X", symbol="X",
|
||||
cash_balance=100, asset_quantity=0)])
|
||||
store.set_warning("pf-X", True)
|
||||
# second swap includes the same portfolio with refreshed cash
|
||||
store.swap([PortfolioItem(portfolio_id="pf-X", symbol="X",
|
||||
cash_balance=200, asset_quantity=0)])
|
||||
a = store.get("pf-X")
|
||||
assert a.warning is True
|
||||
assert a.item.cash_balance == 200
|
||||
|
||||
|
||||
def test_option_d_update_cash_position_overrides_baseline():
|
||||
"""REQ-030 wiring — when *_after lands we update the authoritative values."""
|
||||
store = SnapshotStore()
|
||||
store.swap([PortfolioItem(portfolio_id="pf-X", symbol="X",
|
||||
cash_balance=100, asset_quantity=0)])
|
||||
store.update_cash_position("pf-X", cash_balance=92.5, asset_quantity=1)
|
||||
a = store.get("pf-X")
|
||||
assert a.item.cash_balance == 92.5
|
||||
assert a.item.asset_quantity == 1
|
||||
Reference in New Issue
Block a user