feat(slots): additive strategy fields + filter (REQ-116, BAT-055)
trex.slots.req wire 계약 additive 확장 — 기존 소비자(orb/tsl) backward compatible. - PortfolioItem: strategy_name(Optional[str]) + markets(list) 필드 추가 - hub_read.py: get_portfolios()에서 strategy_name/markets 파싱 추가 (safe default) - slot_to_dict(): strategy_name/strategy_params/markets 3필드 row에 추가 (SnapshotStore→PortfolioItem 경유) - make_slots_rpc_handler(): strategy 요청 파라미터 → Python 레벨 후처리 필터 (available_slots 계산 이후, REQ-073 AC-6 불변) - 테스트: AC-1~8 전수 + hub_read 파싱 + 회귀 갱신 (777 passed, 47 skipped) - docs/interface-contract.md: 요청 파라미터·응답 행 스키마·소스 테이블·REQ-074 AC-5 주석 갱신 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
@@ -30,6 +30,9 @@ class PortfolioItem:
|
||||
|
||||
Mirrors portfolio-hub's `list_portfolios_v1` PortfolioItem with **no price
|
||||
field** — pricing is the strategy module's concern, not core's.
|
||||
|
||||
REQ-116 (BAT-055): strategy_name and markets added additively.
|
||||
strategy_params already existed; now surfaced in slot_to_dict output.
|
||||
"""
|
||||
portfolio_id: str # == asset_id, dcy-004 OQ-1
|
||||
symbol: str
|
||||
@@ -37,6 +40,9 @@ class PortfolioItem:
|
||||
asset_quantity: float # integer shares semantically; float for tolerance
|
||||
active_strategy_id: Optional[str] = None
|
||||
strategy_params: dict = field(default_factory=dict) # opaque, pass-through
|
||||
# REQ-116 additive fields (BAT-055) — safe defaults for legacy hub responses
|
||||
strategy_name: Optional[str] = None # portfolio-hub strategy_name; None if absent
|
||||
markets: list = field(default_factory=list) # portfolio-hub markets list; [] if absent
|
||||
|
||||
|
||||
class PortfolioHubReadError(Exception):
|
||||
@@ -461,13 +467,21 @@ def slot_to_dict(
|
||||
}
|
||||
|
||||
# hub authority: asset_quantity (hub primary) + cash_balance
|
||||
# REQ-116: strategy_name / strategy_params / markets also from PortfolioItem
|
||||
asset_qty: Optional[float] = None
|
||||
cash_balance: Optional[float] = None
|
||||
strategy_name_val: Optional[str] = None
|
||||
strategy_params_val: dict = {}
|
||||
markets_val: list = []
|
||||
if snapshot_store is not None and s.portfolio_id:
|
||||
snap = snapshot_store.get(s.portfolio_id)
|
||||
if snap is not None:
|
||||
asset_qty = float(snap.item.asset_quantity)
|
||||
cash_balance = float(snap.item.cash_balance)
|
||||
# REQ-116 (BAT-055): strategy fields from PortfolioItem (hub authority)
|
||||
strategy_name_val = snap.item.strategy_name
|
||||
strategy_params_val = dict(snap.item.strategy_params)
|
||||
markets_val = list(snap.item.markets)
|
||||
|
||||
# qty (slot mirror) vs asset_quantity (hub): divergence → warned=True
|
||||
slot_qty = float(s.qty) if s.qty is not None else None
|
||||
@@ -477,6 +491,10 @@ def slot_to_dict(
|
||||
d["cash_balance"] = cash_balance
|
||||
d["cash_estimated"] = False # handler overlays ledger_outbox estimate if available
|
||||
d["warned"] = warned
|
||||
# REQ-116 (BAT-055): strategy fields — additive, safe default when hub absent
|
||||
d["strategy_name"] = strategy_name_val
|
||||
d["strategy_params"] = strategy_params_val
|
||||
d["markets"] = markets_val
|
||||
|
||||
# watchdog nested object (WatchdogStore)
|
||||
if watchdog_store is not None:
|
||||
|
||||
Reference in New Issue
Block a user