Alpaca integration — scoped to market data + optional live-broker handoff
Status: Draft (reframed)
Owner:software-architectLast updated: 2026-04-22
Parent epic: #183
Supersedes: prior version of this doc (PR #184). Prior version's premise — per-user Alpaca OAuth for everything — has been replaced by the MBT-native paper engine. See mbt-paper-trading-engine.md for the replacement.
Related ADRs:0002, 0013, 0014, 0008(Superseded), 0009(Superseded), 0010(Superseded), 0011(Superseded)
1. Context + the reframe
The prior version of this doc (committed in PR #184 on the design/multi-tenant-alpaca branch) pointed every user at Alpaca OAuth for both paper and live trading. That premise is now obsolete: Raxx runs its own paper-trading engine (MBT). Alpaca's role in the architecture narrows to two deliberate surfaces:
Market Data API — one server-side Alpaca account, one key, shared across all users. Source of quotes, bars, options chains, and end-of-day settles for MBT.
Live-broker handoff — per-user Alpaca OAuth, only when a Pro+ user graduates from paper and explicitly connects a live broker. Minority of users; many will never touch it.
Everything else the old doc specified — per-user OAuth, per-user trade-update streams, mass-revocation as a headline invariant — applies only to the live-handoff subset. The "no stored credentials" invariant is restored for the majority of users (free + most Pro), because without a live broker connection there is no broker token to store.
This doc is now short by design. MBT is the big story (mbt-paper-trading-engine.md). This doc only covers how Alpaca slots in around it.
2. Invariants that apply
Unchanged from docs/architecture/auth.md §2. Specific to this surface:
No stored credentials for users without a live-broker handoff. The ADR 0009 exception — OAuth access tokens at rest — no longer applies globally. It applies only to the live-handoff subset and is re-scoped in ADR 0014.
Paper-first gating. Live-handoff is gated by paper-profitable-for-N-cycles on MBT, not on Alpaca paper. Enforcement stays server-side.
Credentials into infra. The Market Data API key lives in the secret store; so does the OAuth client secret for live-broker registration.
Audit. Every live-handoff authorization, refresh, use, and revocation writes an audit_log row. Market-data key use is logged at the hub level, not per-user.
3. Market Data API (shared, server-side)
Shape
One Alpaca account owned by Raxx (paid tier determined by product economics — see ADR 0015 or §5 open questions).
API key + secret in the secret store as ALPACA_MARKET_DATA_KEY / ALPACA_MARKET_DATA_SECRET. 90-day rotation. Rotatable without redeploy.
Single long-lived REST + WebSocket client in MarketDataHub (new service in backend_v2/api/services/). Fans out to in-process pub/sub in v1; Redis pub/sub when we horizontally scale.
Consumers
MBT order matching — reads NBBO ticks to simulate fills.
Charts and chains in Antlers — via SSE on /api/market-data/stream?symbols=....
Pro+: real-time + historical chains archive + full depth where available.
Enforcement is at the MarketDataHub service boundary, not Antlers. A Free user who calls the raw API gets the delayed path.
Cost + capacity flags
Alpaca caps WebSocket connections per account (typically 1 concurrent on most tiers). At scale this is a single-point-of-saturation; second key or an account upgrade mitigates.
Market-data entitlement (SIP vs IEX) drives cost + what "real-time" actually means. Product decision pending; flagged in open questions.
4. Live-broker handoff (Pro+ opt-in)
This is the only surface where per-user Alpaca OAuth still exists. Full treatment in ADR 0014.
Who + when
Available to Pro+ users only (per pricing matrix: "All supported brokers"). Pro users get "Alpaca live + 1 other"; same handoff pattern.
Gated by: (a) paper-profitable-for-N-cycles on MBT, or (b) explicit audited override requiring step-up WebAuthn.
Opt-in. A Pro+ user who stays in paper never enrolls, has no Alpaca token stored, stays under invariant #1 strictly.
Flow
User clicks "Connect live Alpaca" in Antlers → Alpaca OAuth auth-code flow → Raxx receives access token + (if issued) refresh token.
Token stored per ADR 0014 (narrower re-statement of ADR 0009's envelope-encryption pattern, applied only to the live-handoff subset).
MBT remains the primary simulator. Orders can be routed to live Alpaca via an explicit "submit to live broker" action per trade (not a global mirror). Every live submission is a separate audited event.
Step-up WebAuthn on every live submit in v1. (Later: session-level "live-mode window" with a shorter TTL, behind its own ADR.)
Not included
Mirror-all-paper-to-live automation. Not in v1. Copy-trading-like behavior hits regulatory questions (§6) that require counsel before product design.
MQ-A scheduled execution against live broker. Deferred. Hosted strategy execution against user's Alpaca live account crosses into adviser territory — flagged for counsel.
5. What changed from PR #184
For reviewers familiar with the prior version:
Concern
PR #184 approach
New approach
Where paper trading runs
Alpaca paper (per-user OAuth)
MBT (our simulator)
OAuth tokens stored
For every user
Only for Pro+ users who enroll live-handoff
Invariant #1 compliance
Documented exception for all users (ADR 0009)
Restored for most users; exception narrows to live-handoff subset (ADR 0014)
Market data
Per-user OAuth (+ shared hub sketched for scale)
One shared server-side key; no user OAuth for data
Premium tier compute
Fargate + Firecracker per strategy against user's live Alpaca (ADR 0011)
Deferred; re-scoped as "dedicated compute running MQ-A strategies against MBT + shared market data" — not against user's broker. New ADR when premium-tier spec is written.
Retention of paper history
Alpaca's retention policy
Our policy — per tier, our DB (Free 90d / Pro 3yr / Pro+ unlimited)
Regulatory posture
Flagged Advisers Act + BD-via-Broker-API
Same flags; MBT stays in user-directed-simulation lane more cleanly
ADRs 0008, 0009, 0010, 0011 are being marked Superseded by ADRs 0013 + 0014 (see each ADR's updated Status header).
PR #184 will be closed with a redirect to the new PR (design/mbt-paper-trading-engine).
6. Regulatory posture (unchanged from prior, reframed lane)
Flags for securities counsel; do not assume any of these are resolved. The MBT reframe makes the safest-lane story cleaner:
MBT as education + user-directed simulation → safest. User authors or selects rules; MBT simulates. Not adviser activity.
Live-broker handoff on user initiation → low risk. User-directed execution; Raxx is not making the trading decision.
MBT + Raxx-authored strategies the user subscribes to and runs on paper → borderline under Investment Advisers Act §202(a)(11). Even on paper, if the publication is individualized, it can trigger adviser-like obligations. Needs counsel.
Copy-trading via live-handoff (user's real Alpaca account mirrors Kris's trades) → likely RIA registration required. SEC has been explicit on this. Flagged; no product design against it until counsel engaged.
Broker API path (Alpaca as clearing) — no longer on our roadmap under the reframe. Removing this line item removes a whole class of regulatory exposure.
v1 stays in the safest lane deliberately. Flags for counsel remain:
Market data key in secret store, 90-day rotation, scoped to a single read-only data account. Compromise → rotate; upstream impact is "our account is blocked for N minutes."
OAuth client secret (Raxx's, for the live-handoff) in the secret store, 90-day rotation, separate per env (paper — though we won't use Alpaca paper going forward, keep the registration for disaster fallback — vs live).
Live-handoff tokens encrypted per ADR 0014 (envelope encryption, KMS-backed, rotatable without re-enrolling users). Same pattern as old ADR 0009 but scoped to far fewer rows.
Kill switches:ALPACA_MARKET_DATA_DISABLED=1 falls MBT back to last-known-good market-data cache + user banner. ALPACA_LIVE_HANDOFF_DISABLED=1 blocks new live authorizations + blocks live order submissions (existing positions untouched).
Audit rows for every live-handoff connection lifecycle event, every live order submit. Market-data use logged at hub level, not per-request (too noisy; aggregated metrics are sufficient).
8. Open questions
Market-data tier. SIP vs IEX? Drives cost + user expectation. Product + finance call.
Account capacity ceiling. At what user count does one Alpaca data account become insufficient (WebSocket concurrency, entitlement counts)? Alpaca-partnerships inquiry.
Handoff broker beyond Alpaca. Pro tier promises "Alpaca live + 1 other." Which broker (IBKR? tastytrade?), and does that broker's OAuth posture match Alpaca's? Flag for follow-up ADR.
Options chain archive source for Pro+ historical chains — Alpaca's options history is thin. ORATS / Polygon / CBOE DataShop candidates. Blocks Pro+ GA, not MBT v1.
Backup paper account. Do we keep an Alpaca paper registration alive as a disaster-recovery path (e.g. if MBT's simulator has a bug, route users temporarily back to Alpaca paper)? Operational judgment call.
End of doc. See mbt-paper-trading-engine.md for the primary engine design, ADR 0013 for the reframe decision, and ADR 0014 for the re-scoped Alpaca posture.