feat: use broker-authoritative qty in slots RPC holdings

Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-08-24 14:15:43 +00:00
committed by GitHub
co-authored by genichin
parent 832dcb5fbb
commit 30bcbe1d12
11 changed files with 303 additions and 15 deletions
+38 -1
View File
@@ -9,10 +9,12 @@ from __future__ import annotations
import logging
from datetime import date as date_cls
from datetime import datetime, timezone
from typing import Optional
from typing import Optional, Protocol
from uuid import UUID
from trex_core.application.intents import BuyIntent, IntentService, SellIntent
from trex_core.application.account_snapshot import AccountSnapshotUnavailable
from trex_core.application.broker_port import BalanceItem
from trex_core.application.messaging import RpcRequest, RpcResponse
from trex_core.application.portfolio import (
PauseStore,
@@ -185,6 +187,10 @@ _FILTER_STATUS: dict[str, set[str]] = {
}
class SlotsBrokerQuantityReader(Protocol):
def holdings_for_slots_rpc(self) -> tuple[list[BalanceItem], datetime]: ...
def make_slots_rpc_handler(
slot_repo: SlotRepository,
*,
@@ -197,6 +203,7 @@ def make_slots_rpc_handler(
ledger_outbox=None,
max_active_slots: Optional[int] = None,
strategy_state_store=None,
broker_quantity_reader: Optional[SlotsBrokerQuantityReader] = None,
):
"""Build the RPC handler for `trex.slots.req` (REQ-073/074/116).
@@ -252,6 +259,36 @@ def make_slots_rpc_handler(
for s in slots
]
broker_qty_by_symbol: dict[str, int] = {}
broker_qty_available = False
broker_qty_captured_at: Optional[datetime] = None
if broker_quantity_reader is not None:
try:
holdings, broker_qty_captured_at = broker_quantity_reader.holdings_for_slots_rpc()
broker_qty_by_symbol = {
str(item.symbol): int(item.hldg_qty)
for item in holdings
}
broker_qty_available = True
except AccountSnapshotUnavailable:
broker_qty_available = False
for row, slot in zip(slot_rows, slots):
row["slot_quantity"] = row.get("qty")
if slot.status.value != "holding":
continue
row["broker_quantity_available"] = broker_qty_available
row["broker_quantity_captured_at"] = (
broker_qty_captured_at.isoformat() if broker_qty_captured_at is not None else None
)
if broker_qty_available:
broker_qty = int(broker_qty_by_symbol.get(str(slot.symbol), 0))
row["qty"] = float(broker_qty)
row["qty_source"] = "broker"
else:
row["qty"] = None
row["qty_source"] = "unavailable"
# dcy-028 / REQ-073/074·079 (C-1): attach opaque strategy_state map per
# row via one batched store read (read piggyback — no extra round trip).
# Only entries matching the slot's current occupancy_seq are surfaced.