pickuma.
Finance

Alpaca Markets Trading API Review: Commission-Free Algo Trading for Developers

A developer's hands-on review of Alpaca's trading API — paper trading setup, Python SDK, real-time websocket streams, order execution, and how it compares to IBKR for retail algo trading.

7 min read

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.

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.

FAQ

Is Alpaca's paper trading realistic enough to test strategies?
Reasonably, with one caveat: fills in paper trading are optimistic. Your limit order at the bid will fill immediately in paper mode, but in live trading it may sit in the queue behind orders that arrived milliseconds earlier. For strategies on daily timeframes, this difference is negligible. For intraday scalping, you will see a performance gap between paper and live results, and you should account for partial fills and queue position in your expectations.
Does Alpaca support short selling?
Yes, but only for stocks designated as easy-to-borrow (ETB). You can check borrow availability programmatically via the `GET /v2/assets/{symbol}` endpoint. Alpaca charges a short-sale fee of roughly $0.65 per trade plus any borrow fees on hard-to-borrow names. If your strategy is short-biased, verify borrow availability before submitting sell orders — attempting to short a non-borrowable stock will reject the order.
Can I run multiple strategies on the same Alpaca account?
Technically yes, but Alpaca's position accounting is account-level, not strategy-level. If strategy A is long 100 shares of AAPL and strategy B shorts 50, you are net long 50 in your account. You need to implement your own bookkeeping layer to track which strategy owns which position. A common pattern is to use multiple paper accounts for strategy isolation during testing.
How does Alpaca handle corporate actions (dividends, splits, mergers)?
Alpaca processes splits automatically and adjusts your position quantities. Dividends are credited to your account on the pay date. Mergers and acquisitions are handled on a case-by-case basis — you will receive an email notification if a position in your account is affected. For algo strategies, subscribe to Alpaca's corporate actions webhook or poll the announcements endpoint.
What happens if the WebSocket disconnects mid-trade?
Your orders remain active on Alpaca's servers regardless of your WebSocket connection status. The WebSocket is for data streaming only — order management goes through REST endpoints. The real risk is not a lost order but a missed data point. If your strategy depends on real-time bar data and the stream drops for 30 seconds, you may miss a signal. Implement a heartbeat check: if no message arrives for 60 seconds, reconnect and query the REST historical endpoint back to the last recorded timestamp to fill the gap.

Related reading

See all Finance articles →

Get the best tools, weekly

One email every Friday. No spam, unsubscribe anytime.