When I first heard about Alpaca Markets, the pitch was "commission-free trading with an API designed for developers." I had been wrestling with Interactive Brokers' TWS gateway for months — the Java process that crashes every Tuesday, the binary socket protocol, the callback spaghetti. Alpaca promised a REST API, a Python SDK that installs with one command, and paper trading that does not require running a local gateway. I was skeptical. Broker APIs that are easy to use usually sacrifice something — instrument coverage, execution quality, market data depth. After building and running a small momentum strategy on Alpaca for six months, here is what I found.
Setting Up in Under Five Minutes
This is the part that genuinely impressed me. Open an account at alpaca.markets, generate API keys from the dashboard, and you are writing code in less time than it takes IBKR's account approval to clear:
from alpaca.trading.client import TradingClient
from alpaca.trading.requests import MarketOrderRequest
from alpaca.trading.enums import OrderSide, TimeInForce
import os
trading_client = TradingClient(
api_key=os.environ['ALPACA_API_KEY'],
secret_key=os.environ['ALPACA_SECRET_KEY'],
paper=True # Flip to False for live trading
)
account = trading_client.get_account()
print(f"Buying power: ${account.buying_power}")
print(f"Portfolio value: ${account.portfolio_value}")
The paper=True flag routes everything to Alpaca's paper trading environment. No separate credentials. No local gateway. The paper environment simulates fills with reasonable latency and includes all the same endpoints as live — orders, positions, account data. This is the first broker API I have used where paper trading actually felt like a first-class feature rather than an afterthought.
The SDK splits logically into three modules: alpaca.trading for orders and positions, alpaca.data for historical and real-time market data, and alpaca.broker for account management. You import only what you need. This is good API design.
Real-Time Data via WebSocket
Alpaca offers two data paths: a REST API for historical bars and a WebSocket stream for real-time quotes, trades, and bars. The WebSocket is where most algo trading strategies live:
from alpaca.data.live import StockDataStream
stream = StockDataStream(
api_key=os.environ['ALPACA_API_KEY'],
secret_key=os.environ['ALPACA_SECRET_KEY']
)
async def on_bar(data):
print(f"{data.symbol}: ${data.close} | VWAP ${data.vwap} | Vol {data.volume}")
stream.subscribe_bars(on_bar, 'AAPL', 'TSLA', 'SPY')
stream.run() # Blocks until interrupted
The WebSocket connection handles reconnection automatically, which is more than I can say for some paid data providers. The trade-off is data fidelity — Alpaca's free tier provides IEX-sourced data (typically 5-10% of consolidated volume), while the paid tier ($9/month at time of writing) provides SIP-sourced consolidated data. For strategies that trade on closing prices or daily signals, IEX is fine. For anything that needs tick-level precision or depends on volume analysis, the paid tier is necessary.
warning
The WebSocket will disconnect periodically — this is normal behavior, not a bug. Your stream handler must be idempotent. If a bar arrives twice because of a reconnect at the boundary, your strategy should not double-count it. Track bar timestamps and deduplicate on the
timestampfield.
Placing and Managing Orders
Alpaca's order model is clean: you create an order request object, submit it, and receive an order object back with a unique ID you can use to query status, cancel, or modify:
from alpaca.trading.requests import LimitOrderRequest, TakeProfitRequest, StopLossRequest
from alpaca.trading.enums import OrderSide, OrderClass, TimeInForce
# Bracket order: parent limit order + take profit + stop loss
order = LimitOrderRequest(
symbol='SPY',
qty=10,
side=OrderSide.BUY,
time_in_force=TimeInForce.DAY,
limit_price=440.50,
order_class=OrderClass.BRACKET,
take_profit=TakeProfitRequest(limit_price=445.00),
stop_loss=StopLossRequest(stop_price=435.00)
)
result = trading_client.submit_order(order)
print(f"Order ID: {result.id}")
Bracket orders are worth highlighting because they execute atomically — the take profit and stop loss are not separate API calls. If the parent fills, the brackets are immediately active. If the parent is cancelled, the brackets are cancelled automatically. This is the difference between a strategy that survives a network blip and one that leaves a naked position open overnight.
The one limitation I hit repeatedly: Alpaca supports equities and ETFs only. No options, no futures, no forex, no bonds. If your strategy requires anything beyond stocks, you will eventually outgrow Alpaca. I moved my options strategies back to IBKR and kept Alpaca for the equity momentum strategy that doesn't need derivatives.
Building a Simple Momentum Strategy
Here is a minimal example that actually runs — it buys the top-performing ETF from a basket based on trailing 20-day returns and rebalances weekly:
import pandas as pd
from alpaca.data.historical import StockHistoricalDataClient
from alpaca.data.requests import StockBarsRequest
from alpaca.data.timeframe import TimeFrame
data_client = StockHistoricalDataClient(api_key, secret_key)
symbols = ['SPY', 'QQQ', 'IWM', 'TLT', 'GLD']
def get_momentum_scores():
request = StockBarsRequest(
symbol_or_symbols=symbols,
timeframe=TimeFrame.Day,
start=(pd.Timestamp.now() - pd.Timedelta(days=30)).strftime('%Y-%m-%d'),
limit=25
)
bars = data_client.get_stock_bars(request).df
returns = bars.groupby('symbol')['close'].last() / \
bars.groupby('symbol')['close'].first() - 1
return returns.sort_values(ascending=False)
scores = get_momentum_scores()
print(f"Top performer: {scores.index[0]} ({scores.iloc[0]:.2%})")
This is not a profitable strategy. It is a template. Replace the ETF basket with your own universe, add a volatility filter, and test before live deployment. The point is that Alpaca's API surface is small enough that you can build an end-to-end strategy in under 100 lines of Python — from data fetch to order execution — without fighting infrastructure.
Alpaca vs. Interactive Brokers: When to Use Which
After using both APIs for real money, the decision framework is straightforward:
Use Alpaca if: you are building equity-only strategies, value clean APIs over instrument coverage, want to get from idea to paper trading in an afternoon, or are deploying on a cloud server and do not want to manage a local gateway process.
Use IBKR if: you need options, futures, forex, or international markets; your strategy depends on smart order routing across multiple exchanges; you require margin trading with programmatic margin requirement queries; or you are trading sizes where the $0.65 Alpaca charges on short sales adds up.
Alpaca is commission-free for stock and ETF trades. Short selling costs roughly $0.65 per trade at time of writing. IBKR's pricing is volume-tiered and can be lower for active traders but adds exchange fees and regulatory fees that Alpaca absorbs.
For my own workflow, I use Alpaca for the momentum rotation strategy (equities only, weekly rebalance, simple execution) and IBKR for anything involving options or margin. The API styles are different enough that context-switching between them is annoying, but the right tool for the job is usually determined by asset class, not API aesthetics.
Originally published at pickuma.com. Subscribe to the RSS or follow @pickuma.bsky.social for new reviews.
Top comments (0)