Skip to content

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

  1. Login to Alpaca Dashboard
  2. Navigate to Settings → API Keys
  3. Generate a new key pair (paper keys work for testing)
  4. Set in .env: ALPACA_API_KEY and ALPACA_API_SECRET

What It Does

  1. Calls WebSocketManager.Connect to open an Alpaca WebSocket connection
  2. Sends SendRaw (auth), SendRaw (subscribe), StartPublish (set output topic) — same pattern the Binance example uses, with Alpaca's wire format on top
  3. Subscribes to the output topic and prints one line per frame, with T (kind), S (symbol), and either p/s (trade) or b/a (orderbook) fields
  4. Lists active connections via WebSocketManager.List
  5. 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