Alpaca Markets is a commission-free stock trading API. Horizon supports Alpaca as a first-class exchange for equity trading, stock/ETF hedging, and multi-asset strategies.
Quick Setup
hz.run(
name="stock_hedge",
exchange=hz.Alpaca(api_key="...", api_secret="..."),
mode="live",
...
)
Standalone Equity Trading
import horizon as hz
from horizon import Side, OrderSide, OrderRequest
hz.run(
name="equity_strategy",
exchange=hz.Alpaca(paper=True),
markets=[hz.Market(id="AAPL", exchange="alpaca", ticker="AAPL", asset_class="equity")],
feeds={"aapl": hz.AlpacaFeed(symbols=["AAPL"])},
pipeline=[my_strategy],
risk=hz.Risk.equity(max_position=100, max_notional=50000),
)
Credentials
Explicit
Environment variables
hz.Alpaca(api_key="PKXXXXXX", api_secret="XXXXXX")
export ALPACA_API_KEY="PKXXXXXX"
export ALPACA_API_SECRET="XXXXXXXX"
# or use Alpaca's native env var names:
export APCA_API_KEY_ID="PKXXXXXX"
export APCA_API_SECRET_KEY="XXXXXXXX"
hz.Alpaca() # reads from env
Paper vs Live
# Paper trading (default)
hz.Alpaca(paper=True) # https://paper-api.alpaca.markets
# Live trading
hz.Alpaca(paper=False) # https://api.alpaca.markets
Test with paper=True before switching to live. Paper mode uses the same API with simulated fills, so your strategy logic runs the same way.
Alpaca Configuration
@dataclass
class Alpaca:
api_key: str | None = None
api_secret: str | None = None
paper: bool = True
api_url: str | None = None
data_source: str = "iex"
| Field | Default | Description |
|---|
api_key | None | Alpaca API key ID (env: ALPACA_API_KEY or APCA_API_KEY_ID) |
api_secret | None | Alpaca API secret key (env: ALPACA_API_SECRET or APCA_API_SECRET_KEY) |
paper | True | Use paper trading URL |
api_url | Auto | Override API URL (set automatically from paper flag) |
data_source | "iex" | Market data source: "iex" (free) or "sip" (paid, full NBBO) |
Authentication
Alpaca uses header-based auth. No token refresh needed.
APCA-API-KEY-ID: {api_key}
APCA-API-SECRET-KEY: {api_secret}
Both headers are sent on every request.
Market Data Feed
Stock quotes via WebSocket:
hz.run(
feeds={
"spy": hz.AlpacaFeed(symbols=["SPY"]),
"tlt": hz.AlpacaFeed(symbols=["TLT"]),
},
...
)
The feed connects to wss://stream.data.alpaca.markets/v2/{source} and subscribes to both trades and quotes for each symbol.
Each symbol gets its own snapshot entry keyed by {feed_name}:{SYMBOL} (e.g., tlt:TLT), plus a feed-level entry under the feed name with the last update across all symbols.
| Field | Type | Default | Description |
|---|
symbols | list[str] | required | Stock/ETF tickers to subscribe (e.g., ["TLT", "SPY"]) |
api_key | str | None | Override API key (defaults to env vars) |
api_secret | str | None | Override API secret (defaults to env vars) |
data_source | str | "iex" | "iex" (free, 15-min delayed for some symbols) or "sip" (paid, real-time NBBO) |
Symbol Mapping
Alpaca uses standard stock tickers. No token ID resolution needed:
# Market ID maps directly to the Alpaca symbol
market = hz.Market(id="TLT", name="iShares 20+ Year Treasury Bond ETF")
| Horizon Field | Alpaca Field | Notes |
|---|
OrderRequest.market_id | symbol | Standard ticker (e.g., “AAPL”, “SPY”, “TLT”) |
OrderRequest.order_side | side | "buy" or "sell" |
OrderRequest.price | limit_price | Limit order price |
OrderRequest.size | qty | Supports fractional shares |
Alpaca uses Side.Long for all positions. Prediction market concepts like Side.Yes / Side.No do not apply to stock orders.
Fill Polling
Alpaca fills are polled from the GET /v2/orders?status=filled endpoint. Each cycle:
- Queries recently filled orders
- Deduplicates against previously seen fill IDs (FIFO eviction at 10k)
- Maps Alpaca’s response to Horizon
Fill objects with exchange-assigned timestamps
Multi-Exchange Hedging
Use Alpaca alongside Polymarket or Kalshi for hedged strategies:
hz.run(
name="hedged_fed_rate",
exchange=[
hz.Polymarket(), # prediction market
hz.Alpaca(paper=True), # stock hedge
],
feeds={
"fed_rate": hz.PolymarketBook("will-fed-cut-rates"),
"tlt": hz.AlpacaFeed(symbols=["TLT"]),
},
pipeline=[
hz.stock_hedge(hz.HedgeConfig(
prediction_feed="fed_rate",
stock_feed="tlt",
stock_symbol="TLT",
auto_rebalance=True,
)),
my_strategy,
],
)
The first exchange (Polymarket) becomes the primary. Orders are routed based on market.exchange.
Feature Support Matrix
| Feature | Polymarket | Kalshi | Alpaca |
|---|
| Trading (orders/fills) | Yes | Yes | Yes |
| Orderbook feed | Yes (WS) | Yes (REST) | Yes (WS) |
| Market discovery | Yes | Yes | Yes |
| Hedge pipeline | No | No | Yes |
| Paper trading | No | Yes (demo) | Yes |
| Fractional shares | No | No | Yes |
| LLM forecasting | Yes | Yes | No |
| Resolution analysis | Yes | Yes | No |
Getting API Keys
- Sign up at alpaca.markets
- Go to Paper Trading > API Keys
- Generate a new key pair
- For live trading, switch to Live Trading and generate live keys
See Stock Market Hedging for the full hedging guide and Stock Hedge Strategy for a complete worked example.