The gist
Claude Code can manage a trading account, analyze the market and build strategies through Alpaca's official MCP server and API. This is not "AI predicts prices" (nobody can do that reliably). It's "AI automates carrying out a strategy, keeping track of a portfolio and managing risk." Start with paper trading, using virtual money, until you trust your strategy. This lesson teaches you to work with the tools. It does not promise income and is not investment advice.
⚠️ Required disclaimer
This is an educational lesson. It is not financial advice and not an investment recommendation. Algorithmic trading carries a real risk of losing money, and results on a virtual account don't guarantee results on a real one. A large share of retail traders lose money: some regulators require brokers to publish the percentage of losing accounts, so look for that number at your broker. Always start with paper trading. Real money only after a long test on a virtual account, after you understand every line of the code, and after talking to a licensed professional.
Key concepts
- Alpaca: a broker with an API (application programming interface, a way for programs to talk to each other) built for algorithmic trading (US stocks, crypto)
- Alpaca MCP: Alpaca's official MCP server for Claude Code
- Paper trading: trading with virtual money (free, you only need to sign up on the broker's site)
- Position limit: the maximum size of one position (5% in this lesson, as a teaching example)
- Stop-loss: automatically closing a position when it loses a set amount (-8% in this lesson, as a teaching example)
- Backtesting: testing a strategy on historical data
Theory
Alpaca: an API-first broker
Alpaca is a US broker built specifically for algorithmic trading. Unlike retail brokers with a polished app, Alpaca's main product is its API.
Features (the broker's terms change, so check its website):
| Feature | Alpaca |
|---|---|
| US stocks | ✅ (NYSE, NASDAQ) |
| Fractional shares | ✅ (minimum amount: on Alpaca's site) |
| Crypto | ✅ (BTC, ETH and others) |
| Paper trading | ✅ Free, sign-up required |
| Live account | ✅ Terms and fees: on Alpaca's site |
| Minimum deposit | None for paper; for a live account: on Alpaca's site |
| API cost | Basic access is free; extended market data may cost extra |
| WebSocket streams | ✅ Real-time data |
| Countries where you can open an account | ⚠️ The list changes: check whether Alpaca accepts residents of your country |
Signing up for paper trading:
- alpaca.markets → Sign Up
- Create an account → you get a paper trading account and keys
- Paper trading comes with a virtual balance (the starting amount is listed on Alpaca's site)
- Your keys are in your dashboard → API Keys
Alpaca MCP: connecting it to Claude Code
Alpaca has an official MCP server (the alpacahq/alpaca-mcp-server repository). It runs through uvx (a Python package runner):
# Connect with one command
claude mcp add alpaca --scope user --transport stdio uvx alpaca-mcp-serverOr through a .mcp.json file in your project folder:
{
"mcpServers": {
"alpaca": {
"command": "uvx",
"args": ["alpaca-mcp-server"],
"env": {
"ALPACA_API_KEY": "your_key_id",
"ALPACA_SECRET_KEY": "your_secret_key",
"ALPACA_PAPER_TRADE": "true"
}
}
}
}To check that the server connected, run the /mcp command.
ALPACA_PAPER_TRADE=true: virtual money (this is the default) ALPACA_PAPER_TRADE=false with live keys: real money. Don't switch until you've passed every check in this lesson.
Don't paste your keys directly into a file that will end up in git: keep them in environment variables or a password manager (more on this in the lesson Security in Claude Code).
What Claude Code can do through Alpaca MCP
Once it's connected, you ask Claude Code:
"Show my current balance and open positions" "Buy 10 shares of AAPL at market price" "Sell 5 shares of MSFT with a $420 limit" "Show my trade history for the past week" "Close all open positions" "What's my P&L for today?"
Claude Code turns these requests into API calls to Alpaca and returns the results.
Python + Alpaca API: full control
For more complex strategies, use Python code directly.
Important: the example below uses the
alpaca-trade-apilibrary. Its repository was archived (June 2026), and for new code Alpaca recommends its official SDK,alpaca-py. The logic of the checks (position size, stop-loss, daily limit) doesn't depend on the library: when you move toalpaca-py, only the API calls change.
pip install alpaca-trade-api pandas numpyimport alpaca_trade_api as tradeapi
import pandas as pd
import os
# Connect to paper trading
api = tradeapi.REST(
os.environ['ALPACA_API_KEY'],
os.environ['ALPACA_SECRET_KEY'],
'https://paper-api.alpaca.markets',
api_version='v2'
)
def check_account():
"""Check the account status"""
account = api.get_account()
print(f"Balance: ${float(account.equity):.2f}")
print(f"Buying power: ${float(account.buying_power):.2f}")
print(f"Status: {account.status}")
def get_positions():
"""Current positions"""
positions = api.list_positions()
for pos in positions:
pnl = float(pos.unrealized_pl)
pnl_pct = float(pos.unrealized_plpc) * 100
print(f"{pos.symbol}: {pos.qty} shares | P&L: ${pnl:.2f} ({pnl_pct:.1f}%)")
def safe_market_order(symbol: str, qty: float, side: str,
max_position_pct: float = 0.05):
"""
Safe market order with a position size check.
max_position_pct = no more than 5% of capital in one position.
"""
account = api.get_account()
equity = float(account.equity)
# Get the price
last_trade = api.get_latest_trade(symbol)
price = float(last_trade.price)
# Check the position size
position_value = qty * price
position_pct = position_value / equity
if position_pct > max_position_pct:
max_qty = int((equity * max_position_pct) / price)
print(f"⚠️ Reducing size: {qty} → {max_qty} (5% portfolio limit)")
qty = max_qty
if qty <= 0:
print("❌ Position size is too small")
return None
# Place the order
order = api.submit_order(
symbol=symbol,
qty=qty,
side=side, # 'buy' or 'sell'
type='market',
time_in_force='gtc'
)
print(f"✅ Order placed: {side.upper()} {qty}x {symbol} (~${position_value:.2f})")
return order
def set_stop_loss(symbol: str, stop_loss_pct: float = 0.08):
"""
Sets a stop-loss on an existing position.
stop_loss_pct = 0.08 → close if the loss reaches 8%
"""
try:
position = api.get_position(symbol)
current_price = float(position.current_price)
stop_price = current_price * (1 - stop_loss_pct)
qty = abs(int(float(position.qty)))
# Stop-loss order
order = api.submit_order(
symbol=symbol,
qty=qty,
side='sell',
type='stop',
stop_price=round(stop_price, 2),
time_in_force='gtc'
)
print(f"🛡️ Stop-loss set: {symbol} @ ${stop_price:.2f} ({stop_loss_pct*100}%)")
return order
except Exception as e:
print(f"❌ No position in {symbol}: {e}")
# Example usage
if __name__ == "__main__":
check_account()
print("\nCurrent positions:")
get_positions()
# Buy AAPL (no more than 5% of the portfolio)
safe_market_order("AAPL", 5, "buy")
# Set a -8% stop-loss
set_stop_loss("AAPL", 0.08)A simple strategy: moving averages
def simple_ma_strategy(symbol: str, short_window: int = 7, long_window: int = 21):
"""
Moving average crossover strategy.
FOR LEARNING ONLY. Not financial advice!
"""
import datetime
# Get historical data
end = datetime.datetime.now()
start = end - datetime.timedelta(days=60)
bars = api.get_bars(
symbol,
tradeapi.TimeFrame.Day,
start.strftime('%Y-%m-%d'),
end.strftime('%Y-%m-%d')
).df
# Calculate the moving averages
bars['SMA_short'] = bars['close'].rolling(window=short_window).mean()
bars['SMA_long'] = bars['close'].rolling(window=long_window).mean()
# Signals
bars['signal'] = 0
bars.loc[bars['SMA_short'] > bars['SMA_long'], 'signal'] = 1 # Long
bars.loc[bars['SMA_short'] < bars['SMA_long'], 'signal'] = -1 # Short/Flat
# Latest signal
last_signal = bars['signal'].iloc[-1]
last_price = bars['close'].iloc[-1]
print(f"\n{symbol} @ ${last_price:.2f}")
print(f"SMA{short_window}: ${bars['SMA_short'].iloc[-1]:.2f}")
print(f"SMA{long_window}: ${bars['SMA_long'].iloc[-1]:.2f}")
if last_signal == 1:
print("📈 Signal: BUY (SMA_short > SMA_long)")
elif last_signal == -1:
print("📉 Signal: SELL (SMA_short < SMA_long)")
else:
print("⏸️ Signal: NEUTRAL")
return last_signal, last_price
# Analyze several symbols
watchlist = ["AAPL", "MSFT", "NVDA", "AMZN"]
for ticker in watchlist:
signal, price = simple_ma_strategy(ticker)Risk management: required rules
5 basic rules (a teaching example, pick your own numbers):
RISK_RULES = {
# Rule 1: No more than 5% of capital in one position
"max_position_pct": 0.05,
# Rule 2: A stop-loss on every position
"stop_loss_pct": 0.08,
# Rule 3: No more than 20% in one sector
"max_sector_pct": 0.20,
# Rule 4: Daily loss limit
"max_daily_loss_pct": 0.03, # Stop trading at -3% for the day
# Rule 5: A check before every trade
"pre_trade_checks": True,
}
def check_daily_loss_limit():
"""Stop trading if the daily loss is > 3%"""
account = api.get_account()
# Compare with the start of the day
daily_pnl_pct = float(account.equity) / float(account.last_equity) - 1
if daily_pnl_pct < -RISK_RULES["max_daily_loss_pct"]:
print(f"🚨 DAILY LIMIT: loss {daily_pnl_pct*100:.1f}%. Stopping trading.")
return False
return TrueBinance Futures through MCP (advanced)
For crypto trading, MCP catalogs list MCP servers for Binance futures. They're written by third-party authors, so before you connect one, check the author, the code and the repository history. You connect them the same way as any MCP server (claude mcp add or a .mcp.json file).
{
"mcpServers": {
"binance-futures": {
"command": "uvx",
"args": ["binance-futures-mcp"],
"env": {
"BINANCE_API_KEY": "your_key",
"BINANCE_SECRET_KEY": "your_secret",
"TESTNET": "true" // ALWAYS start with testnet!
}
}
}
}Important: Binance Futures are leveraged derivatives. The risks are far higher than buying stocks without leverage. Start only on Testnet, and only if you fully understand how futures work. Availability depends on your country: check whether the exchange serves residents of your country.
What paper trading teaches you and what it doesn't
Developers regularly post experiments with a virtual account run through Claude Code and the Alpaca API. You can't verify the numbers in those posts, and you shouldn't treat them as a benchmark: they depend on the time period, the stocks chosen, and what the author shared or left out. The learning value of such an experiment is something else: you check that your code places orders, respects the limits and keeps a log.
What's important to understand: paper trading doesn't account for slippage (the difference between the price when the signal fires and the price you actually get), the market impact of large orders, or the psychology of real money. Real results are usually worse than virtual ones, and past results guarantee nothing about the future.
Practice
- Sign up at alpaca.markets → get paper trading API keys
- Set up Alpaca MCP in Claude Code (paper trading URL!)
- Ask Claude: "show my balance and open positions"
- Run the Python script → buy 1 share of AAPL (paper trading)
- Set a stop-loss on the position you bought
- Check your P&L after 24 hours and write down what needs fixing in the code
Tools and resources
- Alpaca Markets: sign-up + documentation
- Alpaca MCP: the official MCP server
- alpaca-py: the current official Python SDK (the older alpaca-trade-api library is archived)
- Backtrader: a Python framework for backtesting
- MCPMarket: a catalog of MCP servers (servers for exchanges are written by third-party authors, so check their code)
Key takeaways
Alpaca MCP is the official way to manage a trading account through Claude Code. Always start with paper trading. Real money only after a long test on a virtual account, and even that doesn't guarantee results.
Teaching risk rules: 5% maximum per position, an 8% stop-loss on each one, a -3% daily loss limit. Without risk rules it's not trading, it's gambling. Choose your actual numbers yourself, together with a licensed professional.
Claude Code doesn't "predict" the market. Nobody can. It automates carrying out a strategy, monitoring risk and keeping logs. The strategy is your responsibility. This is not investment advice.
Next lesson
→ Social media automation: Instagram, messaging apps, content on autopilot
The mark stays in this browser only and is never sent anywhere. My progress