Alpaca Market Data Worker
File: scripts/run_alpaca_market_data_example.py
Streams crypto market data from Alpaca's v1beta3 WebSocket feed directly via WebSocketManager's own gRPC API — no worker involved. Mirrors the Binance CLOB example flow but with Alpaca's inline-key auth handshake and additive subscribe format.
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) for orderbooks channel |
Frame T types |
o=orderbook, d=trade, subscription, success |
| Environment | Paper keys from app.alpaca.markets work on the real feed |
Authentication Flow
Unlike Binance where the stream is public, Alpaca requires API key
authentication over the WebSocket itself. The example calls
WebSocketManager's gRPC API directly — Connect, then SendRaw twice
to forward the auth and subscribe messages verbatim:
# Step 1: Connect
websocketmanager.Connect(url="wss://stream.data.alpaca.markets/v1beta3/crypto/us", auto_reconnect=True)
# → returns {"id": "<conn_id>"}
# Step 2: Authenticate (SendRaw — message is base64-encoded, a protobuf bytes field)
websocketmanager.SendRaw(id="<conn_id>", message="<base64 of {\"action\":\"auth\",...}>", content_type="application/json")
# Step 3: Subscribe to symbols (additive — the server's set is the union)
websocketmanager.SendRaw(id="<conn_id>", message="<base64 of {\"action\":\"subscribe\",\"orderbooks\":[...]}>", content_type="application/json")
# Step 4: Stream frames to a Dapr topic
websocketmanager.StartPublish(id="<conn_id>", topic="x.examples.alpaca-ticks")
The Dapr topic (x.examples.alpaca-ticks by default) carries one message per server
frame, with the frame's T field identifying the message kind.
Getting Alpaca API Keys
- Login to Alpaca Dashboard
- Navigate to Settings → API Keys
- Generate a new key pair (paper keys work for testing)
- Set in
.env:ALPACA_API_KEYandALPACA_API_SECRET
What It Does
- Calls
WebSocketManager.Connectto open an Alpaca WebSocket connection - Sends
SendRaw(auth),SendRaw(subscribe),StartPublish(set output topic) — same pattern the Binance example uses, with Alpaca's wire format on top - Subscribes to the output topic and prints one line per frame, with
T(kind),S(symbol), and eitherp/s(trade) orb/a(orderbook) fields - Lists active connections via
WebSocketManager.List - Cleanup: sends
Disconnect
Settings
The script reads from scripts/settings.alpaca.json:
{
"url": "wss://stream.data.alpaca.markets/v1beta3/crypto/us",
"channel": "orderbooks",
"symbols": ["BTC/USD", "ETH/USD", "SOL/USD", "DOGE/USD", "AVAX/USD"],
"topic": "x.examples.alpaca-ticks"
}
Five symbols is enough to demonstrate per-symbol parsing. Change
channel to trades to subscribe to L1 trade prints instead of L3
orderbook updates.
Running
source .env # Must have ALPACA_API_KEY and ALPACA_API_SECRET
cd virtufin-examples
python scripts/run_alpaca_market_data_example.py
Ctrl+C to stop. On exit the script disconnects the WebSocket.
Differences from the Binance C# Example
| Aspect | Binance | Alpaca |
|---|---|---|
| Auth | None (public) | Inline {"action":"auth",...} message |
| Subscribe format | {"method":"SUBSCRIBE","params":[...]} |
{"action":"subscribe","<channel>":[...]} |
| Frame format | {"stream":"...","data":{...}} |
Array of {"T":"o/d/subscription",...} |
| Connections | 1 (all pairs on one connection) | 1 (all symbols on one connection) |
| Output topic | x.examples.binance-clob.depth |
x.examples.alpaca-ticks (single topic, script filters by S) |
| Reconnect | auto_reconnect flag on Connect |
Same — auto_reconnect flag on Connect |