Automated Trading with Alpaca API: Free Paper Trading and Live Stock Bot Setup
Alpaca offers a free commission-free trading API for stocks and crypto. This guide shows how to build an AI trading bot using Alpaca's paper trading environment before going live.
Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.
Why Alpaca for Trading Bots?
Most trading tutorials focus on crypto exchanges. But Alpaca offers something unique: a completely free, commission-free brokerage API for US equities AND crypto โ with paper trading that uses real market data.
This makes Alpaca the best place to develop and test trading bots before risking real money:
- Paper trading with live market data (no fake prices)
- Commission-free live trading for US stocks
- WebSocket streaming for real-time price feeds
- REST API for orders, account management, and history
- Crypto support (BTC, ETH, and others)
Setting Up Alpaca
pip install alpaca-trade-api alpaca-py
Get API keys from alpaca.markets (both paper and live trading require different keys).
from alpaca.trading.client import TradingClient
from alpaca.data.historical import StockHistoricalDataClient
from alpaca.trading.requests import MarketOrderRequest
from alpaca.trading.enums import OrderSide, TimeInForce
# Paper trading (safe for testing)
ALPACA_KEY = "YOUR_PAPER_KEY"
ALPACA_SECRET = "YOUR_PAPER_SECRET"
BASE_URL = "https://paper-api.alpaca.markets"
trading_client = TradingClient(ALPACA_KEY, ALPACA_SECRET, paper=True)
data_client = StockHistoricalDataClient(ALPACA_KEY, ALPACA_SECRET)
# Check account
account = trading_client.get_account()
print(f"Portfolio value: ${float(account.portfolio_value):,.2f}")
print(f"Buying power: ${float(account.buying_power):,.2f}")
Building a Moving Average Crossover Bot
import pandas as pd
from alpaca.data.requests import StockBarsRequest
from alpaca.data.timeframe import TimeFrame
from datetime import datetime, timedelta
def get_stock_data(symbol: str, days: int = 100) -> pd.DataFrame:
request = StockBarsRequest(
symbol_or_symbols=symbol,
timeframe=TimeFrame.Day,
start=datetime.now() - timedelta(days=days),
end=datetime.now()
)
bars = data_client.get_stock_bars(request)
df = bars.df.reset_index()
df.set_index('timestamp', inplace=True)
return df
def calculate_signals(df: pd.DataFrame, short_window=20, long_window=50) -> pd.DataFrame:
df['sma_short'] = df['close'].rolling(short_window).mean()
df['sma_long'] = df['close'].rolling(long_window).mean()
df['signal'] = 0
df.loc[df['sma_short'] > df['sma_long'], 'signal'] = 1 # Bullish
df.loc[df['sma_short'] < df['sma_long'], 'signal'] = -1 # Bearish
# Crossover events (signal changed)
df['crossover'] = df['signal'].diff()
return df
def execute_signal(symbol: str, signal: int, allocation_pct: float = 0.10):
"""Execute buy/sell based on signal"""
account = trading_client.get_account()
portfolio_value = float(account.portfolio_value)
current_price = get_latest_price(symbol)
# Check current position
try:
position = trading_client.get_open_position(symbol)
has_position = True
position_qty = float(position.qty)
except Exception:
has_position = False
position_qty = 0
if signal == 1 and not has_position:
# Buy: allocate 10% of portfolio
dollars_to_invest = portfolio_value * allocation_pct
qty = int(dollars_to_invest / current_price)
if qty > 0:
order = trading_client.submit_order(
MarketOrderRequest(
symbol=symbol,
qty=qty,
side=OrderSide.BUY,
time_in_force=TimeInForce.DAY
)
)
print(f"โ
BUY {qty} shares of {symbol} @ ~${current_price:.2f}")
elif signal == -1 and has_position:
# Sell entire position
order = trading_client.submit_order(
MarketOrderRequest(
symbol=symbol,
qty=position_qty,
side=OrderSide.SELL,
time_in_force=TimeInForce.DAY
)
)
print(f"โ
SELL {position_qty} shares of {symbol}")
# Main strategy loop
WATCHLIST = ['AAPL', 'MSFT', 'NVDA', 'TSLA', 'GOOGL']
def run_strategy():
for symbol in WATCHLIST:
df = get_stock_data(symbol)
df = calculate_signals(df)
latest = df.iloc[-1]
if latest['crossover'] == 2: # Bullish crossover
execute_signal(symbol, 1)
elif latest['crossover'] == -2: # Bearish crossover
execute_signal(symbol, -1)
AI-Enhanced Alpaca Bot with News Sentiment
from openai import OpenAI
import requests
openai_client = OpenAI()
def get_news_sentiment(symbol: str) -> float:
"""Return sentiment score from -1 (bearish) to +1 (bullish)"""
# Alpaca has a built-in news API
news_url = f"https://data.alpaca.markets/v1beta1/news?symbols={symbol}&limit=10"
headers = {'APCA-API-KEY-ID': ALPACA_KEY, 'APCA-API-SECRET-KEY': ALPACA_SECRET}
news = requests.get(news_url, headers=headers).json()
headlines = [article['headline'] for article in news.get('news', [])]
if not headlines:
return 0.0
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": f"""Rate the overall sentiment of these news headlines about {symbol}
from -1.0 (very bearish) to +1.0 (very bullish).
Headlines: {headlines}
Reply with just a number between -1.0 and 1.0."""
}]
)
try:
return float(response.choices[0].message.content.strip())
except:
return 0.0
def combined_signal(symbol: str) -> str:
"""Combine technical + sentiment for final signal"""
df = get_stock_data(symbol)
df = calculate_signals(df)
tech_signal = df.iloc[-1]['signal']
sentiment = get_news_sentiment(symbol)
# Combined score: 60% technical, 40% sentiment
combined = 0.6 * tech_signal + 0.4 * sentiment
if combined > 0.3:
return 'BUY'
elif combined < -0.3:
return 'SELL'
else:
return 'HOLD'
WebSocket for Real-Time Trading
from alpaca.data.live import StockDataStream
stream = StockDataStream(ALPACA_KEY, ALPACA_SECRET)
async def handle_trade(data):
"""Called on every trade update for subscribed symbols"""
symbol = data.symbol
price = data.price
# Simple momentum: if price spikes 1% in 1 minute, buy
if price_change_1min(symbol) > 0.01:
execute_signal(symbol, 1, allocation_pct=0.05)
stream.subscribe_trades(handle_trade, 'AAPL', 'NVDA', 'MSFT')
stream.run()
Paper Trading Strategy
Step 1: Run on paper for 1 month
Step 2: Review win rate and Sharpe ratio
Step 3: If profitable with >1.0 Sharpe, go live with 25% of intended capital
Step 4: Scale up over 3 months if live results match paper results
The paper-to-live transition is where most bots fail. Slippage, partial fills, and market impact are all different in live trading. Start small and scale responsibly.
Tagged in
Related Articles
Paper Trading vs Live Trading: When to Make the Switch
4 min read
Crypto BotsCrypto Bot Risk Management: The 10 Rules That Separate Winners From Losers
7 min read
Crypto BotsHow to Build a Self-Healing Trading Bot That Fixes Its Own Errors
5 min read
Crypto BotsPump.fun and Solana Meme Coin Bots: How to Automate the Hottest Trend
5 min read