feat(kevin): reconcile Alpaca bracket auto-closes + order status

Bracket stop-loss/take-profit legs fill at Alpaca without passing through the executor, so those closes (and their P&L) were invisible locally.

- broker: add get_order(nested) + list_orders to BaseBroker/AlpacaBroker (+ SimulatedBroker); BrokerOrder carries child legs

- Trade gains broker_order_id (migration f6a7b8c9d0e1); executor stamps the entry order id

- new api_gateway trade-reconcile loop: books a closing SELL + realized P&L when a bracket leg fills (idempotent on the leg order id), syncs PENDING->terminal status, logs drift; runs alongside portfolio_sync

[ci skip]

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-06-04 22:31:24 +00:00
parent 52b3c76482
commit 82dc622544
13 changed files with 1049 additions and 8 deletions

View file

@ -93,6 +93,7 @@ class Trade(TimestampMixin, Base):
)
status: Mapped[TradeStatus] = mapped_column(nullable=False, default=TradeStatus.PENDING)
pnl: Mapped[float | None] = mapped_column(Float, nullable=True)
broker_order_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
# Relationships
strategy: Mapped[Strategy | None] = relationship(back_populates="trades")