How to set up Alpaca paper trading with Python

How to set up Alpaca paper trading with Python
Alpaca paper trading lets you test automated trading ideas with fake money against live market conditions. If you're building a Python-based trading system, Alpaca's paper environment uses the same API (a way for your code to talk directly to the brokerage) as live trading. Your code won't need to change when you switch to real money.
This article walks through the whole process. You'll open an Alpaca paper trading account, connect to it with Python, place test orders, inspect your holdings, and run a simple automated script. If you want to compare other simulators for testing trading ideas, we've covered those separately.
What Alpaca Paper Trading Is
Alpaca is a commission-free brokerage designed around its API. Most brokers focus on web dashboards and mobile apps. Alpaca is built for people who want to send orders from Python scripts, not from a point-and-click interface.
Paper trading is Alpaca's simulated environment. You get a fake account loaded with $100,000 in pretend cash. Every order you submit goes through logic similar to a real order, but no actual money moves. Alpaca uses live market data for pricing, so results are closer to real trading than a historical test, but the fills are still simulated and won't perfectly match live execution.
A historical test (often called a backtest, meaning testing trading rules on past prices) shows what your rules would have done previously, but it can't show how orders behave in a live market. Paper trading lets you see delays, pending orders, and partial fills (where only some of your shares get bought) without risking cash.
How Alpaca Paper Trading Differs From Backtesting
When you backtest a trading idea, you assume your orders would have filled at the prices in the dataset. That assumption is often wrong. Your order might move the price, or the stock might not have enough buyers or sellers at the price you wanted.
Paper trading runs your script forward in time against live data. You submit an order, and Alpaca's matching engine simulates whether and how it would fill.
The tradeoff is speed. A backtest can simulate years of trading in seconds. Paper trading runs in real time. Most traders use both methods. Backtest first to filter out bad ideas quickly, then paper trade the survivors to catch problems that historical tests miss.
Setting Up Your Alpaca Paper Trading Account
Go to alpaca.markets and sign up. Once you're in the dashboard, switch to the "Paper Trading" view (there's a toggle in the sidebar). Then generate your API keys. You'll get an API Key ID and a Secret Key. Save both somewhere safe.
Install the Alpaca Python SDK:
pip install alpaca-trade-api
Alpaca has released newer SDK versions over time, and method names can change between releases. If an import fails or a method doesn't exist, check Alpaca's official documentation for the current recommended package.
Store your credentials as environment variables so they don't end up in your code. Create a file called .env in your project folder:
# .env
ALPACA_API_KEY=your-api-key-id
ALPACA_SECRET_KEY=your-secret-key
ALPACA_BASE_URL=https://paper-api.alpaca.markets
Then load them in Python with python-dotenv:
pip install python-dotenv
# config.py
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("ALPACA_API_KEY")
SECRET_KEY = os.getenv("ALPACA_SECRET_KEY")
BASE_URL = os.getenv("ALPACA_BASE_URL")
The BASE_URL tells the SDK to use the paper trading environment. When you're ready to trade with real money, you change this URL. Everything else stays the same.
Alpaca Paper Trading Example in Python
We'll write one script that connects to Alpaca, reads your account balance, pulls recent prices, places a test order, and inspects the position.
Connecting and Checking Your Account
import alpaca_trade_api as tradeapi
from config import API_KEY, SECRET_KEY, BASE_URL
# Create a connection to the Alpaca paper trading API
api = tradeapi.REST(API_KEY, SECRET_KEY, BASE_URL, api_version="v2")
# Get account information
account = api.get_account()
print(f"Account status: {account.status}")
print(f"Cash available: ${float(account.cash):,.2f}")
print(f"Portfolio value: ${float(account.portfolio_value):,.2f}")
print(f"Buying power: ${float(account.buying_power):,.2f}")
You should see your paper account with $100,000 in cash (or whatever remains from earlier tests). The buying_power field is the amount Alpaca will currently let you spend on new trades.
Fetching Price Data
from alpaca_trade_api.rest import TimeFrame
# Get the last 10 daily bars for Apple
bars = api.get_bars("AAPL", TimeFrame.Day, limit=10).df
# The result is a pandas DataFrame
print(bars[["open", "high", "low", "close", "volume"]])
This returns a pandas DataFrame (a table-like structure in Python) with open, high, low, close prices and volume for each trading day. The TimeFrame parameter also accepts Minute and Hour if you need finer detail. If this returns an error, check your Alpaca dashboard for data permissions before you debug anything else.
Placing an Order
Important: if the US stock market is closed (9:30 AM to 4:00 PM Eastern, Monday through Friday), market orders will queue and execute at the next open, possibly at a very different price.
# Place a market order to buy 10 shares of Apple
market_order = api.submit_order(
symbol="AAPL",
qty=10,
side="buy",
type="market",
time_in_force="day" # Cancel if not filled by end of trading day
)
print(f"Order submitted: {market_order.id}")
print(f"Order status: {market_order.status}")
The time_in_force setting tells Alpaca when to cancel the order if it doesn't fill. "day" cancels at market close. "gtc" means good till canceled. "ioc" means immediate or cancel, so Alpaca fills whatever it can right away and cancels the rest.
For a limit order, you specify the maximum price you're willing to pay.
# Place a limit order to buy 5 shares of Microsoft at $400 or less
limit_order = api.submit_order(
symbol="MSFT",
qty=5,
side="buy",
type="limit",
time_in_force="gtc",
limit_price=400.00
)
print(f"Limit order submitted: {limit_order.id}")
print(f"Limit price: ${limit_order.limit_price}")
Checking Order Status After Submission
When you submit an order, the initial status is usually submitted or accepted. That does not mean the order has filled. You need to check again after a short wait.
import time
# Wait a few seconds for the order to process
time.sleep(3)
# Fetch the order again by its ID
updated_order = api.get_order(market_order.id)
print(f"Updated status: {updated_order.status}")
print(f"Filled quantity: {updated_order.filled_qty}")
print(f"Filled average price: {updated_order.filled_avg_price}")
Checking Your Positions and Orders
# Check all current positions (your holdings)
positions = api.list_positions()
print(f"\nCurrent positions: {len(positions)}")
for pos in positions:
print(f" {pos.symbol}: {pos.qty} shares")
print(f" Average entry price: ${float(pos.avg_entry_price):,.2f}")
print(f" Current price: ${float(pos.current_price):,.2f}")
print(f" Unrealized P/L: ${float(pos.unrealized_pl):,.2f}")
The unrealized_pl field shows how much money you'd make or lose if you sold right now. "Unrealized" means you haven't sold yet, so the gain or loss exists only on paper.
Selling and Canceling
# Sell all 10 shares of Apple
sell_order = api.submit_order(
symbol="AAPL",
qty=10,
side="sell",
type="market",
time_in_force="day"
)
print(f"Sell order submitted: {sell_order.id}")
You can also close all positions at once or cancel all open orders, which is useful when you want to reset your paper account.
api.close_all_positions()
print("All positions closed")
api.cancel_all_orders()
print("All open orders canceled")
A Simple Automated Alpaca Paper Trading Script
Paper trading becomes more useful when you let a script make the same decision each time. Here's a minimal example that checks whether a stock's latest closing price is above the average of its previous 20 closing prices, and buys if it is.
import alpaca_trade_api as tradeapi
from alpaca_trade_api.rest import TimeFrame
from config import API_KEY, SECRET_KEY, BASE_URL
api = tradeapi.REST(API_KEY, SECRET_KEY, BASE_URL, api_version="v2")
def should_buy(symbol):
"""Check if the latest close is above the average of the previous 20 closes."""
bars = api.get_bars(symbol, TimeFrame.Day, limit=21).df
if len(bars) < 21:
return False
current_price = float(bars["close"].iloc[-1])
moving_avg = float(bars["close"].iloc[-21:-1].mean())
print(f"{symbol} current price: ${current_price:,.2f}")
print(f"{symbol} 20-day average (previous closes): ${moving_avg:,.2f}")
return current_price > moving_avg
def run_strategy(symbol, qty):
"""Buy if price is above the moving average, sell if below."""
# Note: this broad except clause is a tutorial shortcut.
# In production code, catch the specific API exception for "no position found."
try:
position = api.get_position(symbol)
has_position = True
current_qty = int(position.qty)
except Exception:
has_position = False
current_qty = 0
if should_buy(symbol):
if not has_position:
print(f"Buying {qty} shares of {symbol}")
api.submit_order(
symbol=symbol,
qty=qty,
side="buy",
type="market",
time_in_force="day"
)
else:
print(f"Already holding {current_qty} shares of {symbol}")
else:
if has_position:
print(f"Selling {current_qty} shares of {symbol}")
api.submit_order(
symbol=symbol,
qty=current_qty,
side="sell",
type="market",
time_in_force="day"
)
else:
print(f"No position in {symbol}, staying out")
# Run for Apple
run_strategy("AAPL", 10)
This script runs once and makes a single decision. To automate it, schedule it with cron on Linux or run it in a loop that sleeps between checks. If you want to explore how to automate trading with other brokers' APIs, the concepts are similar but the connection details differ.
Common Mistakes With Alpaca Paper Trading
The paper account doesn't reset between sessions. If you bought 500 shares of Tesla last week, those shares are still there. Always check your positions before you run a new test.
Submitting orders when the market is closed is another frequent problem. A market order sent at 8 PM will queue and execute at the next open, possibly at a very different price.
clock = api.get_clock()
print(f"Market is {'open' if clock.is_open else 'closed'}")
print(f"Next open: {clock.next_open}")
print(f"Next close: {clock.next_close}")
Paper results also don't guarantee live results. In real trading, your orders can move the price, especially for stocks that don't trade much. If you later trade options (contracts tied to a stock's price), a paper account helps you test the order flow before you risk money.
Troubleshooting
If authentication fails, make sure your API keys belong to the paper environment, not the live account. The paper keys and live keys are different, and mixing them up is the most common setup error.
If get_bars returns an empty DataFrame or an error, double-check the stock symbol for typos and confirm in your Alpaca dashboard that your account has market data access enabled.
If your order stays in accepted status and never fills, the market is probably closed. Wait until 9:30 AM Eastern on a weekday and try again.
What to Do Next
Start with one stock and run the script for a few days. Once you're comfortable, try adding a stop-loss rule (an automatic sell if the price drops below a threshold you set). You could also log each order to a CSV file so you can review your decisions later.
The free Algorithmic Trading With Python guides show how to write trading rules in Python, test them on past data, and run them on a schedule.