Alpaca¶
kind = "alpaca" trades US-listed stocks and ETFs through Alpaca's Trading API, with market data from Alpaca's free IEX stream (Trade US stocks on Alpaca).
| Markets | US stocks and ETFs |
| Order entry | REST |
| Environments | paper (default), live |
| Keys | key id and secret key |
| Replace | PATCH, a new order at the venue |
| Dead man's switch | none |
| Example config | configs/alpaca-paper.toml |
testnet = true, the default, refuses the live trading host api.alpaca.markets.
Connections¶
| channel | endpoint | purpose |
|---|---|---|
| md | ws_url (wss://stream.data.alpaca.markets/v2/iex) |
quotes, trades; v2/test streams the symbol FAKEPACA at any hour |
| trade | ws_private_url (wss://paper-api.alpaca.markets/stream) |
trade_updates: order states and executions, in binary frames |
| rest | rest_url (https://paper-api.alpaca.markets) |
the requests below |
| request | use |
|---|---|
GET /v2/clock, GET /v2/assets/<symbol> |
clock offset, reference data |
POST /v2/orders |
new order |
PATCH /v2/orders/<id> |
replace |
DELETE /v2/orders/<id> |
cancel, kill switch, trading-stream loss |
GET /v2/orders?status=open&symbols= |
reconciliation, kill switch |
GET /v2/positions |
reconciliation |
GET /v2/account/activities/FILL |
fill replay, newest first, paged by page_token |
GET /v2/orders/<id> |
the client id of an order a replayed fill names |
Keys¶
Every REST request carries APCA-API-KEY-ID and APCA-API-SECRET-KEY. Both WebSockets send {"action":"auth","key":..,"secret":..} first. A refused key on the trading stream is fatal for the venue. The market-data stream needs the keys too, so a dry run keeps them and sends no order.
Reference data¶
| FastMM | value |
|---|---|
| tick | $0.01 (Rule 612 at or above $1.00) |
| lot | 1 share; a fractional configured lot if the asset is fractionable |
| asset class | equity |
An asset that is not active and tradable is disabled.
Market data¶
Every IEX quote is a one-level book snapshot of IEX's own top of book. It is often wider than the national best bid and offer that paper fills use. Sizes are as the feed sends them, and trades carry no aggressor.
The stream sends nothing on subscribing and nothing for a symbol outside IEX's hours, so a book exists from the symbol's first quote. The free plan allows one market-data connection per account; a second is refused with error 406. Client pings every 5 s keep a quiet connection from going Stale.
Orders¶
client_order_id is FastMM's client order id. Alpaca has no post-only order.
| FastMM | Alpaca |
|---|---|
PostOnly |
plain limit |
Gtc, Day |
time_in_force; day by default |
| IOC, FOK | ioc, fok |
| market | day |
extended_hours = true |
"extended_hours":true on resting limit orders |
A replace is PATCH with the new price, quantity and client id. Alpaca makes a new order with a new id, which the reply acknowledges, and ends the old one with the event replaced. A cancel names the venue's order id; one sent before the id is known waits for it. DELETE answers 204 also for an order that is over.
Trade updates¶
Orders with other client ids are ignored.
| event | engine event |
|---|---|
new |
ack |
fill, partial_fill |
fill: this execution's price and quantity; filled_qty is the cumulative quantity |
canceled |
cancel ack |
expired, done_for_day |
expiry |
rejected |
reject |
Fills carry no fee and no maker or taker flag. Alpaca charges no commission; regulatory fees are summed per day and posted after the close.
Reconciliation and fills¶
A reconciliation first replays the account's FILL activities since the watermark (Execution replay). An activity's id is <New York time>::<execution_id>; the part after :: is the execution id the stream reported, so a fill is booked once whichever brings it.
Then come the open orders of the subscribed symbols and the position of every subscribed symbol from GET /v2/positions, zero when flat. A restarted session therefore trades from the broker's position.
On trading-stream loss the connector cancels the symbols' open orders (cancel_on_order_channel_loss). It reconciles when the stream is back.
Kill switch and dead man's switch¶
The kill switch lists the open orders of the subscribed symbols and cancels each over its own blocking connection. It repeats until the list is empty, at most 3 rounds.
Alpaca has no dead man's switch. Orders a process left resting stay until the next session's start-up sweep cancels them or the day ends, for day orders.
Rate limits¶
Alpaca allows 200 requests a minute per account. The connector caps new orders and replaces at 80 % of requests_per_minute; a 429 pauses order entry for 10 s.
Venue rules¶
A strategy meets these Alpaca rules as rejects:
| order | reject reason |
|---|---|
| a buy at or above the account's open sell in the symbol, or a sell at or below its open buy (potential wash trade) | SelfTradePrevention |
| a short sale while a buy of the symbol is open | SelfTradePrevention |
| a sell larger than the long position not held by other sell orders | InsufficientBalance |
From a flat position the account therefore quotes one side at a time. With a long position of at least the ask size, it quotes both.
Not handled¶
| what | effect |
|---|---|
| sessions and halts | the engine does not know market hours; a quote outside them waits, or trades in the extended session with extended_hours |
| LULD bands, short-sale restrictions, buying power | not checked by the connector |
| sub-dollar ticks, the SIP feed | not supported |
| options and crypto on Alpaca | not supported |
Sources (read 2026-10-27): the Alpaca API reference and its streaming pages.