feat: route trades to Alpaca (paper-default) instead of the mock store #13

Merged
pregno merged 19 commits from feat/alpaca-trading-integration into main 2026-06-13 17:34:20 +02:00
Owner

Summary

Replaces the simulated, spot-priced position store with real Alpaca orders (paper by default). Alpaca is now the source of truth for orders/fills/positions; the SQLite positions table is a thin mirror reconciled on a 30s timer + at startup.

  • Sizing: fixed notional USD per trade (ALPACA_NOTIONAL_USD, default 1000), via Alpaca notional market orders.
  • Gating: missing Alpaca keys ⇒ trading disabled, system still runs (mirrors the old priceSource gate); POST /api/positions returns 503, GET still serves with null marks. A startup log announces trading: ENABLED env=… notional=$… / DISABLED.
  • Paper/live: ALPACA_ENV=paper|live (default paper); only an exact live reaches the live endpoint.
  • Lifecycle: pending → open → closing → closed | rejected, one active position per symbol (partial unique index). Optimistic record + Reconciler resolves fills/rejections/drift.
  • Classes: equity/equity_etf → stock orders (day); cryptoBASE/USD orders (gtc); commodity/null skipped; crypto shorts refused.
  • REVERSE closes the open leg and defers the opposite-leg open to the reconciler once the close fills (avoids racing an open against an unsettled close).
  • priceSource (Binance/Yahoo) retained only for the OutcomeTracker — trading no longer depends on it.

New: AlpacaBroker (+ Broker seam), alpaca-symbols, Reconciler, create-broker, migration 0010. Spec & plan under docs/superpowers/.

Test Plan

  • pnpm typecheck clean (shared + server + web)
  • pnpm test — 408 passing across 71 files (broker guards, symbol mapping, position-service, auto-trader mode gating + deferred REVERSE, reconciler transitions/drift, API marks + 503 gating, config)
  • pnpm --filter @pmsd/server build succeeds
  • Manual paper-account smoke: POST a position during the US session → appears pending then open with a live mark within ~30s; confirm order in the Alpaca paper dashboard

Follow-ups (deliberately out of scope)

  • No upper bound on notional / no secondary confirmation for live mode (only the ALPACA_ENV switch + startup log)
  • GET /api/positions fetches Alpaca's full position list once per distinct symbol rather than once per request (perf nicety)
## Summary Replaces the simulated, spot-priced position store with real **Alpaca** orders (paper by default). Alpaca is now the source of truth for orders/fills/positions; the SQLite `positions` table is a thin mirror reconciled on a 30s timer + at startup. - **Sizing:** fixed notional USD per trade (`ALPACA_NOTIONAL_USD`, default 1000), via Alpaca notional market orders. - **Gating:** missing Alpaca keys ⇒ trading disabled, system still runs (mirrors the old `priceSource` gate); `POST /api/positions` returns 503, `GET` still serves with null marks. A startup log announces `trading: ENABLED env=… notional=$…` / `DISABLED`. - **Paper/live:** `ALPACA_ENV=paper|live` (default `paper`); only an exact `live` reaches the live endpoint. - **Lifecycle:** `pending → open → closing → closed | rejected`, one active position per symbol (partial unique index). Optimistic record + `Reconciler` resolves fills/rejections/drift. - **Classes:** `equity`/`equity_etf` → stock orders (`day`); `crypto` → `BASE/USD` orders (`gtc`); `commodity`/`null` skipped; crypto shorts refused. - **REVERSE** closes the open leg and defers the opposite-leg open to the reconciler once the close fills (avoids racing an open against an unsettled close). - `priceSource` (Binance/Yahoo) retained only for the OutcomeTracker — trading no longer depends on it. New: `AlpacaBroker` (+ `Broker` seam), `alpaca-symbols`, `Reconciler`, `create-broker`, migration `0010`. Spec & plan under `docs/superpowers/`. ## Test Plan - [x] `pnpm typecheck` clean (shared + server + web) - [x] `pnpm test` — 408 passing across 71 files (broker guards, symbol mapping, position-service, auto-trader mode gating + deferred REVERSE, reconciler transitions/drift, API marks + 503 gating, config) - [x] `pnpm --filter @pmsd/server build` succeeds - [ ] Manual paper-account smoke: POST a position during the US session → appears `pending` then `open` with a live mark within ~30s; confirm order in the Alpaca paper dashboard ## Follow-ups (deliberately out of scope) - No upper bound on notional / no secondary confirmation for live mode (only the `ALPACA_ENV` switch + startup log) - `GET /api/positions` fetches Alpaca's full position list once per distinct symbol rather than once per request (perf nicety)
pregno merged commit 8f37a5141c into main 2026-06-13 17:34:20 +02:00
pregno deleted branch feat/alpaca-trading-integration 2026-06-13 17:34:20 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pregno/polymarket-screener!13
No description provided.