Context (verified)
- The
Broker port defines get_balances() (packages/keel-broker-api/keel_broker_api/port.py:158); the Alpaca adapter implements it fully — USD cash row with available clamped at settled cash (surfacing T+1) plus one row per long position (keel_broker_alpaca/adapter.py:442-482).
- Balances are never persisted or exposed — no endpoint, no view.
- Paper cash lives in
agent_state["paper_cash_usdc"] (keel/strategy/paper.py:214), shown on Status only in paper mode (keel/commands/status.py:367-368).
Alpaca's Balances page (stat tiles + per-asset breakdown + "as of" stamps) separates what you have from what you did — worth taking. Its "buying power" framing is refused.
Scope
GET /api/balances — live adapter read (paper: paper cash + agent MTM), every figure a Field; as-of stamp mandatory on every tile (freshness is a claim, state it).
- Balances view (Portfolio section):
- settled vs total cash distinction preserved where the venue reports it (the T+1 clamp the Alpaca adapter already applies)
- per-asset rows with qty + marked value
- paper mode: paper cash + unrealized MTM alongside, clearly labeled
equity_state_mode
- Long-tail: adapters without balance support (honest stubs) render an explicit capability-gap row, never zeros.
Refusals
- No "buying power" framing, no leverage invitation, no CTA of any kind on this page. Cash is a fact, not an affordance.
Acceptance
- Works against paper mode and the Alpaca paper endpoint; as-of always visible; capability gaps honest.
- No monetary JSON numbers;
state field carries warn on stale reads.
Depends on #698 and the Orders/Positions payload patterns (Sprint 1, fourth).
Context (verified)
Brokerport definesget_balances()(packages/keel-broker-api/keel_broker_api/port.py:158); the Alpaca adapter implements it fully — USD cash row withavailableclamped at settled cash (surfacing T+1) plus one row per long position (keel_broker_alpaca/adapter.py:442-482).agent_state["paper_cash_usdc"](keel/strategy/paper.py:214), shown on Status only in paper mode (keel/commands/status.py:367-368).Alpaca's Balances page (stat tiles + per-asset breakdown + "as of" stamps) separates what you have from what you did — worth taking. Its "buying power" framing is refused.
Scope
GET /api/balances— live adapter read (paper: paper cash + agent MTM), every figure aField; as-of stamp mandatory on every tile (freshness is a claim, state it).equity_state_modeRefusals
Acceptance
statefield carries warn on stale reads.Depends on #698 and the Orders/Positions payload patterns (Sprint 1, fourth).