Alpaca CLOB Example
File: python/websocketmanager/alpaca_clob_example.py
Streams BTC/USD order book from Alpaca crypto WebSocket with API key authentication.
API Details
| Property | Value |
|---|---|
| WebSocket URL | wss://stream.data.alpaca.markets/v1beta3/crypto/us |
| Authentication | Message-based: {"action":"auth","key":"...","secret":"..."} |
| Subscribe | {"action":"subscribe","orderbooks":["BTC/USD"]} |
| Order book type | L3 (full depth) |
| Keys | Paper-trading keys work on the market-data stream |
Authentication Flow
Unlike Binance where the stream is public, Alpaca expects a login on every new socket,
within 10 seconds. The example connects with a handshake (WebSocketManager 0.7.0+): on
every socket open (the first connect, every auto_reconnect, every actor handoff to
another pod) the WebSocketManager asks the example for the messages to send, by
request-reply on x.examples.alpaca-clob.handshake. The example is the handler:
def handshake_reply(request: dict) -> dict:
symbols = request.get("config", {}).get("symbols", SYMBOL).split(",")
return {"messages": [
# wait for Alpaca's confirmation; any Alpaca error fails the handshake (and is retried)
{"text": json.dumps(login_message()), "expect": '"msg":"authenticated"', "fail": '"T":"error"'},
# nothing to wait for: the full book (r=true) that follows is published
{"text": json.dumps({"action": "subscribe", "orderbooks": symbols})},
]}
conn = await api.gateway.websocketmanager.Connect({
"url": ALPACA_WS_URL,
"auto_reconnect": True,
"publish_topic": DEPTH_TOPIC,
"handshake": {"topic": HANDSHAKE_TOPIC, "config": {"symbols": SYMBOL}},
})
login_message() is computed on every request, so a credential that depends on the time
(a Broker API access token, which expires) is fresh on every open. With Trading API keys it
is the plain {"action":"auth","key":…,"secret":…}.
The connection re-authenticates only while the example runs: the handler lives in it. For a
feed that outlives the example, deploy the
AlpacaHandshake worker on the
handshake topic instead: it builds the same reply and gets the key as worker secrets
(CreateWorkerRequest.secrets, references into the cluster's worker Secret; WorkManager 0.21+).
The Alpaca notebook shows it with UseWorkerHandler = true. Either way, the
reply carries the login over the platform's pub/sub (to the WebSocketManager instance's
reply topic), so anyone who can subscribe there can read it: use paper-trading keys on a
shared cluster.
Getting Alpaca API Keys
- Login to Alpaca Dashboard
- Navigate to Settings → API Keys
- Generate new key pair
- Set in
.env:ALPACA_API_KEYandALPACA_API_SECRET
What It Does
- Starts the handshake handler (subscribed to
x.examples.alpaca-clob.handshake) and a listener onx.examples.alpaca-clob.orderbook, before connecting: pub/sub starts at the topic's tail - Connects to Alpaca's crypto stream through WebSocketManager with
auto_reconnect, the handshake andpublish_topic;Connectreturns once Alpaca confirmed the login - Applies the full book and each update to a local order book
- Saves the top 20 levels and spread to State (
statestore/x.examples.alpaca-clob.orderbook.BTC_USD) every 10 s - Disconnects on exit
For a worker that maintains the books on the platform, with a live depth chart, see the
alpaca-order-book-live.verso notebook (AlpacaOrderBook worker).
Running
source .env # Must have ALPACA_API_KEY and ALPACA_API_SECRET
cd python
uv run python websocketmanager/alpaca_clob_example.py