Alpaca Market Data API — Stocks (REST + WebSocket)
Real-time and historical US equity data. Unlike the Broker endpoints, market data lives on its own host with its own auth, and the real-time feed is WebSocket, not SSE.
Read alpaca-broker-integration first. Assets/clock/calendar live on the Trading API host; everything else here is the Market Data API host.
Reference
- Guides:
https://docs.alpaca.markets/docs/historical-stock-data, https://docs.alpaca.markets/docs/streaming-market-data
- Live schema:
alpaca-docs MCP → list-endpoints title "Market Data API"
0. Hosts & auth
| Surface |
Host |
| Market data REST |
https://data.alpaca.markets (sandbox data.sandbox.alpaca.markets) |
| Market data WebSocket |
wss://stream.data.alpaca.markets/{version}/{feed} |
| Assets / clock / calendar |
https://api.alpaca.markets (Trading API) — paper: paper-api.alpaca.markets |
Auth: headers APCA-API-KEY-ID / APCA-API-SECRET-KEY (Broker partners may use Broker Basic auth in broker context).
1. REST endpoints
| Path |
Purpose |
GET /v2/stocks/snapshots?symbols=… · GET /v2/stocks/{symbol}/snapshot |
Snapshot (latest trade/quote + bars) |
GET /v2/stocks/bars?symbols=… · GET /v2/stocks/{symbol}/bars |
Historical OHLCV bars |
GET /v2/stocks/bars/latest · …/{symbol}/bars/latest |
Latest bar(s) |
GET /v2/stocks/trades[/latest] · GET /v2/stocks/quotes[/latest] |
Historical / latest trades & quotes |
GET /v2/stocks/auctions |
Opening/closing auctions |
GET /v2/stocks/meta/conditions/{trade|quote} · /meta/exchanges |
Code lookups |
GET /v1beta1/news?symbols=… |
News (max limit 50) |
GET /v1beta1/screener/stocks/most-actives · /screener/{stocks|crypto}/movers |
Screeners |
GET /v2/assets (Trading API host) · GET /v1/assets (Broker API host) |
Asset master / tradability |
GET /v2/clock · GET /v2/calendar (Trading API host) |
Market hours |
Clock/calendar/assets paths are host-dependent — verified live against the sandbox:
| Path |
Trading API host (api.alpaca.markets) |
Broker API host (broker-api.*) |
/v1/clock |
— |
200 |
/v2/clock |
200 |
200 |
/v1/calendar |
— |
200 |
/v2/calendar |
200 |
404 |
/v1/assets |
— |
200 |
/v2/assets |
200 |
404 |
So: on the Trading/Market-Data API host use /v2/clock, /v2/calendar, /v2/assets. On the Broker API host use /v1/clock, /v1/calendar, /v1/assets (/v1/clock and /v2/clock both work there; /v2/calendar and /v2/assets 404). A Broker-API integration hitting /v1/clock is correct, not stale.
2. Bars — params
| Param |
Notes |
timeframe |
[1-59]Min/T, [1-23]Hour/H, 1Day/D, 1Week/W, [1,2,3,4,6,12]Month/M. Case-sensitive. e.g. 1Min, 5Min, 1Hour, 1Day |
start / end |
RFC3339 or YYYY-MM-DD, inclusive |
limit |
default 1000, max 10000 — counts data points across all symbols, not per symbol |
page_token |
pagination cursor (from next_page_token) |
adjustment |
raw (default), split, dividend, spin-off, all — comma-combinable |
feed |
see §3 |
sort |
asc (default) / desc |
asof |
YYYY-MM-DD for symbol/name-change mapping; - skips mapping |
Pagination lesson: results are sorted by symbol, then timestamp. A multi-symbol request that hits limit may return only the first symbol(s) — you must follow next_page_token until empty to get them all. Don't assume one page = all symbols.
3. Feeds (entitlement matters)
iex — single exchange (~2.5% of volume). The only feed available without a paid subscription. Good for dev/testing.
sip — consolidated, all exchanges (100% volume). Requires a paid data plan.
delayed_sip — SIP delayed 15 min (latest/snapshot endpoints).
otc, boats (Blue Ocean overnight ATS), overnight (Alpaca-derived, cheaper).
Lessons:
- Pick
iex explicitly if you're on the free tier — some endpoints default to sip, which then 403s without entitlement. (A common surprise: "why is my historical request failing?" → defaulted to SIP.)
- Without real-time access,
start/end windows withhold the most recent 15 minutes.
- Trade/quote sizes are in shares as of 2025-11-03 (were round lots before).
4. Object shapes (compact keys)
Snapshot per symbol: latestTrade, latestQuote, minuteBar, dailyBar, prevDailyBar. Multi-symbol response is a map { "AAPL": {…} }.
- Bar:
t time, o open, h high, l low, c close, v volume, n trade count, vw VWAP.
- Trade:
t time, p price, s size, x exchange, c conditions, z tape, i id.
- Quote:
bp/bs/bx bid price/size/exchange, ap/as/ax ask price/size/exchange, c conditions, z tape. (price 0 = no active bid/ask.)
5. WebSocket protocol
URL: wss://stream.data.alpaca.markets/{version}/{feed} — e.g. v2/iex, v2/sip, v2/delayed_sip, v1beta1/boats, v1beta1/overnight, or v2/test (always-on, use symbol FAKEPACA).
Connect flow:
- Connect →
[{"T":"success","msg":"connected"}]
- Auth within 10s:
{"action":"auth","key":"…","secret":"…"} → [{"T":"success","msg":"authenticated"}]
- Subscribe:
{"action":"subscribe","trades":["AAPL"],"quotes":["AMD"],"bars":["*"]} → server echoes full subscription state. * = all symbols. unsubscribe removes.
Message types (every message is a JSON array; T discriminates): t trade, q quote, b minute bar, d daily bar, u updated bar, s trading status (halt/resume), l LULD, c correction, x cancel/error, i imbalance; control: success, error, subscription. Subscribing to trades auto-adds corrections + cancelErrors.
WebSocket lessons:
- One concurrent connection per key on most plans — a 2nd connection →
{"code":406,"connection limit exceeded"}. Centralize the stream in one process and fan out to your own clients (don't open a socket per user).
- Authenticate within 10s or get dropped (
404).
- Other error codes:
401 not auth'd, 402 auth failed, 405 symbol limit, 407 slow client, 409 insufficient subscription (feed not entitled), 410 invalid action for feed.
- Messages are batched — always iterate the array; don't assume one frame = one event.
- Handle
u (updated bar) and c/x (corrections/cancels): a streamed bar/trade can be revised after the fact.
6. Assets, clock, calendar
Use the host-appropriate path (see the table in §1): /v2/... on the Trading API host, /v1/... on the Broker API host.
- Assets (
GET /v2/assets on Trading host · GET /v1/assets and /v1/assets/{symbol} on Broker host) — tradability metadata: tradable, fractionable, marginable, shortable, borrow_status (replaces deprecated easy_to_borrow), status (active/inactive), class (us_equity/us_option/crypto/ipo), exchange, attributes[] (e.g. has_options, overnight_tradable). Filter by status, asset_class, exchange. Cache this — it changes slowly; query it before trading to confirm tradable/fractionable (see alpaca-broker-trading-orders).
- Clock (
/v2/clock on Trading host · /v1/clock on Broker host) — is_open, next_open, next_close, timestamp. Use this to gate market-hours logic instead of hardcoding 9:30–16:00 ET.
- Calendar (
/v2/calendar on Trading host · /v1/calendar on Broker host — note there is no /v2/calendar on the Broker host) — per-day open/close (HH:MM), session_open/session_close (HHMM, extended hours), settlement_date. Use the calendar for holidays — a naive "weekdays only" check runs jobs on market holidays (harmless but wasteful) and miscomputes "previous trading day."
7. Caching strategy (cost & rate-limit lesson)
Market data is the highest-volume, highest-cost surface. Production lesson:
- Persist historical bars in your own store keyed by
(symbol, timeframe, timestamp) with upsert/skip-duplicate, and serve charts from there — only fetch the gap from Alpaca.
- Cache snapshots/quotes in a short-TTL cache (TTL tuned to market-open vs closed).
- Run one bulk backfill job for searchable symbols on a schedule rather than fetching per user request.
- Always follow
next_page_token and watch X-RateLimit-Remaining (see alpaca-broker-rate-limits-resilience).
Related skills: tradability before ordering → alpaca-broker-trading-orders; rate limits/pagination → alpaca-broker-rate-limits-resilience; the broker event stream (SSE, different from this WS) → alpaca-broker-sse-events.
1---2name: alpaca-broker-market-data3description: Pull and stream US stock market data from Alpaca — REST snapshots/bars/trades/quotes, historical bars with timeframes and feeds (IEX vs SIP), the assets master list, market clock & calendar, news, and the real-time WebSocket stream. Use when building charts, quotes, price feeds, or asset metadata on Alpaca in any language.4---56# Alpaca Market Data API — Stocks (REST + WebSocket)78Real-time and historical US equity data. Unlike the Broker endpoints, market data lives on **its own host with its own auth**, and the real-time feed is **WebSocket**, not SSE.910> Read `alpaca-broker-integration` first. Assets/clock/calendar live on the **Trading API** host; everything else here is the **Market Data API** host.1112## Reference13- Guides: `https://docs.alpaca.markets/docs/historical-stock-data`, `https://docs.alpaca.markets/docs/streaming-market-data`14- Live schema: `alpaca-docs` MCP → `list-endpoints` title `"Market Data API"`1516## 0. Hosts & auth1718| Surface | Host |19|---------|------|20| Market data REST | `https://data.alpaca.markets` (sandbox `data.sandbox.alpaca.markets`) |21| Market data WebSocket | `wss://stream.data.alpaca.markets/{version}/{feed}` |22| Assets / clock / calendar | `https://api.alpaca.markets` (Trading API) — paper: `paper-api.alpaca.markets` |2324**Auth:** headers `APCA-API-KEY-ID` / `APCA-API-SECRET-KEY` (Broker partners may use Broker Basic auth in broker context).2526## 1. REST endpoints2728| Path | Purpose |29|------|---------|30| `GET /v2/stocks/snapshots?symbols=…` · `GET /v2/stocks/{symbol}/snapshot` | Snapshot (latest trade/quote + bars) |31| `GET /v2/stocks/bars?symbols=…` · `GET /v2/stocks/{symbol}/bars` | Historical OHLCV bars |32| `GET /v2/stocks/bars/latest` · `…/{symbol}/bars/latest` | Latest bar(s) |33| `GET /v2/stocks/trades[/latest]` · `GET /v2/stocks/quotes[/latest]` | Historical / latest trades & quotes |34| `GET /v2/stocks/auctions` | Opening/closing auctions |35| `GET /v2/stocks/meta/conditions/{trade\|quote}` · `/meta/exchanges` | Code lookups |36| `GET /v1beta1/news?symbols=…` | News (max `limit` 50) |37| `GET /v1beta1/screener/stocks/most-actives` · `/screener/{stocks\|crypto}/movers` | Screeners |38| `GET /v2/assets` *(Trading API host)* · `GET /v1/assets` *(Broker API host)* | Asset master / tradability |39| `GET /v2/clock` · `GET /v2/calendar` *(Trading API host)* | Market hours |4041> **Clock/calendar/assets paths are host-dependent — verified live against the sandbox:**42>43> | Path | Trading API host (`api.alpaca.markets`) | Broker API host (`broker-api.*`) |44> |------|:--:|:--:|45> | `/v1/clock` | — | **200** |46> | `/v2/clock` | **200** | **200** |47> | `/v1/calendar` | — | **200** |48> | `/v2/calendar` | **200** | **404** |49> | `/v1/assets` | — | **200** |50> | `/v2/assets` | **200** | **404** |51>52> So: on the **Trading/Market-Data API host** use `/v2/clock`, `/v2/calendar`, `/v2/assets`. On the **Broker API host** use **`/v1/clock`**, **`/v1/calendar`**, **`/v1/assets`** (`/v1/clock` and `/v2/clock` both work there; `/v2/calendar` and `/v2/assets` 404). A Broker-API integration hitting `/v1/clock` is **correct**, not stale.5354## 2. Bars — params5556| Param | Notes |57|-------|-------|58| `timeframe` | `[1-59]Min`/`T`, `[1-23]Hour`/`H`, `1Day`/`D`, `1Week`/`W`, `[1,2,3,4,6,12]Month`/`M`. Case-sensitive. e.g. `1Min`, `5Min`, `1Hour`, `1Day` |59| `start` / `end` | RFC3339 or `YYYY-MM-DD`, inclusive |60| `limit` | default **1000**, max **10000** — counts data points **across all symbols**, not per symbol |61| `page_token` | pagination cursor (from `next_page_token`) |62| `adjustment` | `raw` (default), `split`, `dividend`, `spin-off`, `all` — comma-combinable |63| `feed` | see §3 |64| `sort` | `asc` (default) / `desc` |65| `asof` | `YYYY-MM-DD` for symbol/name-change mapping; `-` skips mapping |6667**Pagination lesson:** results are sorted by **symbol, then timestamp**. A multi-symbol request that hits `limit` may return only the first symbol(s) — you must follow `next_page_token` until empty to get them all. Don't assume one page = all symbols.6869## 3. Feeds (entitlement matters)7071- `iex` — single exchange (~2.5% of volume). **The only feed available without a paid subscription.** Good for dev/testing.72- `sip` — consolidated, all exchanges (100% volume). **Requires a paid data plan.**73- `delayed_sip` — SIP delayed 15 min (latest/snapshot endpoints).74- `otc`, `boats` (Blue Ocean overnight ATS), `overnight` (Alpaca-derived, cheaper).7576**Lessons:**77- **Pick `iex` explicitly** if you're on the free tier — some endpoints default to `sip`, which then 403s without entitlement. (A common surprise: "why is my historical request failing?" → defaulted to SIP.)78- Without real-time access, `start`/`end` windows **withhold the most recent 15 minutes**.79- Trade/quote **sizes are in shares** as of 2025-11-03 (were round lots before).8081## 4. Object shapes (compact keys)8283**Snapshot** per symbol: `latestTrade`, `latestQuote`, `minuteBar`, `dailyBar`, `prevDailyBar`. Multi-symbol response is a map `{ "AAPL": {…} }`.8485- **Bar:** `t` time, `o` open, `h` high, `l` low, `c` close, `v` volume, `n` trade count, `vw` VWAP.86- **Trade:** `t` time, `p` price, `s` size, `x` exchange, `c` conditions, `z` tape, `i` id.87- **Quote:** `bp`/`bs`/`bx` bid price/size/exchange, `ap`/`as`/`ax` ask price/size/exchange, `c` conditions, `z` tape. (price `0` = no active bid/ask.)8889## 5. WebSocket protocol9091**URL:** `wss://stream.data.alpaca.markets/{version}/{feed}` — e.g. `v2/iex`, `v2/sip`, `v2/delayed_sip`, `v1beta1/boats`, `v1beta1/overnight`, or `v2/test` (always-on, use symbol `FAKEPACA`).9293**Connect flow:**941. Connect → `[{"T":"success","msg":"connected"}]`952. **Auth within 10s:** `{"action":"auth","key":"…","secret":"…"}` → `[{"T":"success","msg":"authenticated"}]`963. Subscribe: `{"action":"subscribe","trades":["AAPL"],"quotes":["AMD"],"bars":["*"]}` → server echoes full subscription state. `*` = all symbols. `unsubscribe` removes.9798**Message types** (every message is a **JSON array**; `T` discriminates): `t` trade, `q` quote, `b` minute bar, `d` daily bar, `u` updated bar, `s` trading status (halt/resume), `l` LULD, `c` correction, `x` cancel/error, `i` imbalance; control: `success`, `error`, `subscription`. Subscribing to `trades` auto-adds `corrections` + `cancelErrors`.99100**WebSocket lessons:**101- **One concurrent connection per key** on most plans — a 2nd connection → `{"code":406,"connection limit exceeded"}`. Centralize the stream in **one process** and fan out to your own clients (don't open a socket per user).102- Authenticate within **10s** or get dropped (`404`).103- Other error codes: `401` not auth'd, `402` auth failed, `405` symbol limit, `407` slow client, `409` insufficient subscription (feed not entitled), `410` invalid action for feed.104- Messages are **batched** — always iterate the array; don't assume one frame = one event.105- Handle **`u` (updated bar)** and **`c`/`x` (corrections/cancels)**: a streamed bar/trade can be revised after the fact.106107## 6. Assets, clock, calendar108109Use the host-appropriate path (see the table in §1): `/v2/...` on the Trading API host, `/v1/...` on the Broker API host.110111- **Assets** (`GET /v2/assets` on Trading host · `GET /v1/assets` and `/v1/assets/{symbol}` on Broker host) — tradability metadata: `tradable`, `fractionable`, `marginable`, `shortable`, `borrow_status` (replaces deprecated `easy_to_borrow`), `status` (`active`/`inactive`), `class` (`us_equity`/`us_option`/`crypto`/`ipo`), `exchange`, `attributes[]` (e.g. `has_options`, `overnight_tradable`). Filter by `status`, `asset_class`, `exchange`. **Cache this** — it changes slowly; query it before trading to confirm `tradable`/`fractionable` (see `alpaca-broker-trading-orders`).112- **Clock** (`/v2/clock` on Trading host · `/v1/clock` on Broker host) — `is_open`, `next_open`, `next_close`, `timestamp`. Use this to gate market-hours logic instead of hardcoding 9:30–16:00 ET.113- **Calendar** (`/v2/calendar` on Trading host · `/v1/calendar` on Broker host — note there is no `/v2/calendar` on the Broker host) — per-day `open`/`close` (`HH:MM`), `session_open`/`session_close` (`HHMM`, extended hours), `settlement_date`. **Use the calendar for holidays** — a naive "weekdays only" check runs jobs on market holidays (harmless but wasteful) and miscomputes "previous trading day."114115## 7. Caching strategy (cost & rate-limit lesson)116117Market data is the highest-volume, highest-cost surface. Production lesson:1181. **Persist historical bars** in your own store keyed by `(symbol, timeframe, timestamp)` with upsert/skip-duplicate, and serve charts from there — only fetch the gap from Alpaca.1192. **Cache snapshots/quotes** in a short-TTL cache (TTL tuned to market-open vs closed).1203. **Run one bulk backfill job** for searchable symbols on a schedule rather than fetching per user request.1214. Always follow `next_page_token` and watch `X-RateLimit-Remaining` (see `alpaca-broker-rate-limits-resilience`).122123**Related skills:** tradability before ordering → `alpaca-broker-trading-orders`; rate limits/pagination → `alpaca-broker-rate-limits-resilience`; the *broker* event stream (SSE, different from this WS) → `alpaca-broker-sse-events`.