How to Build a
Trading Bot in Python
A complete, step-by-step tutorial for building a Python trading bot that fetches real-time stock and crypto prices, generates trading signals using moving averages and RSI, and runs on autopilot. Everything uses the free MarketLens API (500 calls/day, no credit card).
Need an API key to follow along?
Sign up for free -- 500 calls/day, 719+ endpoints, no credit card required.
Get Your Free API Key
Get 500 free API calls/day. No credit card required.
Join 15,000+ developers. No spam.
What You'll Build
By the end of this tutorial, you'll have a fully functional trading bot that:
- Fetches real-time stock quotes and crypto prices from the MarketLens API
- Calculates SMA crossover and RSI signals for buy/sell decisions
- Uses ML-powered market predictions for smarter entries
- Implements risk management with stop-loss and position sizing
- Backtests your strategy against historical data
- Runs on autopilot with a scheduler and logging
Prerequisites
Required
- Python 3.10 or newer
- Basic Python knowledge
- A free MarketLens API key
Libraries We'll Use
requests-- HTTP clientpandas-- data analysisschedule-- task schedulerpython-dotenv-- env vars
Project Setup
Create your project directory and install dependencies:
mkdir trading-bot && cd trading-bot
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install requests pandas schedule python-dotenv
Create a .env file with your API key:
MARKETLENS_API_KEY=your_api_key_here
Don't have an API key yet? Sign up free -- takes 30 seconds, no credit card needed.
Fetch Real-Time Market Data
Let's start by creating a MarketLens API client that fetches stock quotes and historical data. Create market_data.py:
import os
import requests
import pandas as pd
from dotenv import load_dotenv
load_dotenv()
# MarketLens API configuration
BASE_URL = "https://marketlens.dev/api/v1"
API_KEY = os.getenv("MARKETLENS_API_KEY")
HEADERS = {"X-API-Key": API_KEY}
def get_stock_quote(symbol: str) -> dict:
"""Fetch a real-time stock quote from MarketLens."""
url = f"{BASE_URL}/stocks/{symbol}"
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
return response.json()
def get_historical_data(symbol: str, days: int = 90) -> pd.DataFrame:
"""Fetch historical price data and return as a DataFrame."""
url = f"{BASE_URL}/stocks/{symbol}/history?days={days}"
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
data = response.json()
df = pd.DataFrame(data["prices"])
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values("date").reset_index(drop=True)
return df
# Quick test
if __name__ == "__main__":
quote = get_stock_quote("AAPL")
print(f"AAPL: ${quote['price']} ({quote['change_percent']}%)")
history = get_historical_data("AAPL", days=30)
print(f"\nLast 5 days:")
print(history.tail())
Run it to verify your API key works:
AAPL: $198.45 (+1.23%)
Last 5 days:
date open high low close volume
25 2026-03-07 195.20 196.80 194.50 196.10 48523100
26 2026-03-08 196.30 197.90 195.80 197.45 51234500
27 2026-03-10 197.50 198.20 196.10 196.80 44892300
28 2026-03-11 196.90 199.10 196.40 198.70 55123400
29 2026-03-12 198.80 199.50 197.90 198.45 47891200
Build Trading Signal Logic
Now let's implement two classic trading strategies: SMA crossover (when the fast moving average crosses the slow moving average) and RSI (Relative Strength Index for overbought/oversold detection). Create signals.py:
import pandas as pd
from market_data import get_historical_data
def calculate_sma_crossover(df: pd.DataFrame,
fast: int = 10,
slow: int = 30) -> str:
"""
Simple Moving Average crossover strategy.
Returns: 'BUY', 'SELL', or 'HOLD'
"""
df["sma_fast"] = df["close"].rolling(window=fast).mean()
df["sma_slow"] = df["close"].rolling(window=slow).mean()
# Check the last two rows for a crossover
if len(df) < slow + 1:
return "HOLD"
prev = df.iloc[-2]
curr = df.iloc[-1]
# Bullish crossover: fast crosses above slow
if prev["sma_fast"] <= prev["sma_slow"] and curr["sma_fast"] > curr["sma_slow"]:
return "BUY"
# Bearish crossover: fast crosses below slow
if prev["sma_fast"] >= prev["sma_slow"] and curr["sma_fast"] < curr["sma_slow"]:
return "SELL"
return "HOLD"
def calculate_rsi(df: pd.DataFrame, period: int = 14) -> float:
"""
Calculate the Relative Strength Index.
RSI > 70 = overbought (consider selling)
RSI < 30 = oversold (consider buying)
"""
delta = df["close"].diff()
gain = delta.where(delta > 0, 0).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return round(rsi.iloc[-1], 2)
def get_combined_signal(symbol: str) -> dict:
"""Combine SMA crossover + RSI for a stronger signal."""
df = get_historical_data(symbol, days=90)
sma_signal = calculate_sma_crossover(df)
rsi = calculate_rsi(df)
# Combined logic
if sma_signal == "BUY" and rsi < 40:
signal = "STRONG BUY"
elif sma_signal == "BUY":
signal = "BUY"
elif sma_signal == "SELL" and rsi > 60:
signal = "STRONG SELL"
elif sma_signal == "SELL":
signal = "SELL"
elif rsi > 70:
signal = "OVERBOUGHT"
elif rsi < 30:
signal = "OVERSOLD"
else:
signal = "HOLD"
return {
"symbol": symbol,
"signal": signal,
"rsi": rsi,
"sma_signal": sma_signal,
"price": df.iloc[-1]["close"],
}
Add Crypto Trading Support
MarketLens supports 50+ cryptocurrencies. Let's extend our bot to trade crypto too. Add this to market_data.py:
def get_crypto_price(symbol: str) -> dict:
"""Fetch real-time crypto price from MarketLens."""
url = f"{BASE_URL}/crypto/{symbol}"
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
return response.json()
def get_crypto_history(symbol: str, days: int = 90) -> pd.DataFrame:
"""Fetch crypto historical data as a DataFrame."""
url = f"{BASE_URL}/crypto/{symbol}/history?days={days}"
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
data = response.json()
df = pd.DataFrame(data["prices"])
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values("date").reset_index(drop=True)
return df
# Usage
btc = get_crypto_price("BTC")
print(f"Bitcoin: ${btc['price']:,.2f}")
# Bitcoin: $87,432.15
eth = get_crypto_price("ETH")
print(f"Ethereum: ${eth['price']:,.2f}")
# Ethereum: $3,215.80
Crypto markets trade 24/7, so your bot can monitor them around the clock -- unlike stocks, which are limited to market hours.
Use ML-Powered Market Predictions
MarketLens provides machine learning-powered predictions with confidence scores. Let's integrate these into our trading signals for smarter entries:
def get_prediction(symbol: str) -> dict:
"""Get ML-powered market prediction from MarketLens."""
url = f"{BASE_URL}/predictions/{symbol}"
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
return response.json()
# Example response:
# {
# "symbol": "AAPL",
# "prediction": "bullish",
# "confidence": 0.78,
# "target_price": 205.50,
# "timeframe": "7d",
# "factors": ["strong_earnings", "sector_momentum", "technical_breakout"]
# }
def get_enhanced_signal(symbol: str) -> dict:
"""Combine technical signals with ML prediction."""
# Get technical signal
technical = get_combined_signal(symbol)
# Get ML prediction
prediction = get_prediction(symbol)
# Boost confidence when technical + ML agree
ml_bullish = prediction["prediction"] == "bullish"
ml_confidence = prediction["confidence"]
if technical["signal"] in ("BUY", "STRONG BUY") and ml_bullish and ml_confidence > 0.7:
final_signal = "STRONG BUY"
confidence = "HIGH"
elif technical["signal"] in ("SELL", "STRONG SELL") and not ml_bullish and ml_confidence > 0.7:
final_signal = "STRONG SELL"
confidence = "HIGH"
else:
final_signal = technical["signal"]
confidence = "MEDIUM" if ml_confidence > 0.5 else "LOW"
return {
**technical,
"final_signal": final_signal,
"ml_prediction": prediction["prediction"],
"ml_confidence": ml_confidence,
"target_price": prediction["target_price"],
"confidence": confidence,
}
Add Risk Management
No trading bot is complete without risk management. Create risk.py:
from dataclasses import dataclass
@dataclass
class RiskParams:
"""Risk management parameters."""
max_position_pct: float = 0.05 # Max 5% of portfolio per trade
stop_loss_pct: float = 0.03 # 3% stop-loss
take_profit_pct: float = 0.08 # 8% take-profit
max_daily_trades: int = 5 # Max trades per day
min_confidence: str = "MEDIUM" # Minimum signal confidence
def calculate_position_size(
portfolio_value: float,
price: float,
risk: RiskParams = RiskParams()
) -> int:
"""Calculate how many shares to buy based on risk parameters."""
max_spend = portfolio_value * risk.max_position_pct
shares = int(max_spend // price)
return max(shares, 0)
def check_stop_loss(entry_price: float, current_price: float,
risk: RiskParams = RiskParams()) -> bool:
"""Check if stop-loss has been triggered."""
loss_pct = (entry_price - current_price) / entry_price
return loss_pct >= risk.stop_loss_pct
def check_take_profit(entry_price: float, current_price: float,
risk: RiskParams = RiskParams()) -> bool:
"""Check if take-profit has been triggered."""
gain_pct = (current_price - entry_price) / entry_price
return gain_pct >= risk.take_profit_pct
# Example
risk = RiskParams()
shares = calculate_position_size(portfolio_value=10_000, price=198.45, risk=risk)
print(f"Buy {shares} shares of AAPL (${shares * 198.45:,.2f})")
# Buy 2 shares of AAPL ($396.90)
Follow Along with Your Own API Key
Get real market data while you build. 500 free API calls/day -- enough to test everything in this tutorial.
Backtest Your Strategy
Before running your bot with real money, always backtest against historical data. MarketLens provides up to 5 years of historical price data on paid plans (90 days on free). Create backtest.py:
from market_data import get_historical_data
from signals import calculate_sma_crossover, calculate_rsi
def backtest(symbol: str, days: int = 90,
initial_cash: float = 10_000) -> dict:
"""Backtest the SMA crossover + RSI strategy."""
df = get_historical_data(symbol, days=days)
cash = initial_cash
shares = 0
trades = []
for i in range(30, len(df)):
window = df.iloc[:i + 1].copy()
signal = calculate_sma_crossover(window)
rsi = calculate_rsi(window)
price = df.iloc[i]["close"]
date = df.iloc[i]["date"]
if signal == "BUY" and rsi < 40 and cash >= price:
# Buy as many shares as we can (max 5% of portfolio)
portfolio_val = cash + shares * price
max_spend = portfolio_val * 0.05
buy_shares = int(max_spend // price)
if buy_shares > 0:
cost = buy_shares * price
cash -= cost
shares += buy_shares
trades.append({"date": date, "action": "BUY",
"shares": buy_shares, "price": price})
elif signal == "SELL" and rsi > 60 and shares > 0:
# Sell all shares
revenue = shares * price
cash += revenue
trades.append({"date": date, "action": "SELL",
"shares": shares, "price": price})
shares = 0
# Final portfolio value
final_price = df.iloc[-1]["close"]
final_value = cash + shares * final_price
profit = final_value - initial_cash
return_pct = (profit / initial_cash) * 100
return {
"symbol": symbol,
"period_days": days,
"initial_cash": initial_cash,
"final_value": round(final_value, 2),
"profit": round(profit, 2),
"return_pct": round(return_pct, 2),
"total_trades": len(trades),
"trades": trades,
}
# Run backtest
result = backtest("AAPL", days=90)
print(f"Symbol: {result['symbol']}")
print(f"Period: {result['period_days']} days")
print(f"Initial: ${result['initial_cash']:,.2f}")
print(f"Final: ${result['final_value']:,.2f}")
print(f"Return: {result['return_pct']}%")
print(f"Trades: {result['total_trades']}")
Automate with a Scheduler
Now let's tie it all together into a bot that runs automatically. Create bot.py:
import time
import logging
import schedule
from datetime import datetime
from market_data import get_stock_quote, get_crypto_price
from signals import get_combined_signal
from risk import RiskParams, calculate_position_size
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("trading_bot.log"),
logging.StreamHandler(),
],
)
log = logging.getLogger(__name__)
# Configuration
WATCHLIST_STOCKS = ["AAPL", "MSFT", "GOOGL", "NVDA", "TSLA"]
WATCHLIST_CRYPTO = ["BTC", "ETH", "SOL"]
PORTFOLIO_VALUE = 10_000
RISK = RiskParams()
def scan_markets():
"""Scan watchlist and generate trading signals."""
log.info("=== Market Scan Started ===")
for symbol in WATCHLIST_STOCKS:
try:
signal = get_combined_signal(symbol)
quote = get_stock_quote(symbol)
log.info(
f"{symbol}: ${quote['price']} | "
f"Signal: {signal['signal']} | RSI: {signal['rsi']}"
)
if signal["signal"] in ("BUY", "STRONG BUY"):
shares = calculate_position_size(
PORTFOLIO_VALUE, quote["price"], RISK
)
log.info(
f" >>> BUY SIGNAL: {shares} shares of {symbol} "
f"@ ${quote['price']}"
)
elif signal["signal"] in ("SELL", "STRONG SELL"):
log.info(f" >>> SELL SIGNAL: {symbol}")
except Exception as e:
log.error(f"Error scanning {symbol}: {e}")
# Scan crypto (24/7)
for symbol in WATCHLIST_CRYPTO:
try:
crypto = get_crypto_price(symbol)
log.info(
f"{symbol}: ${crypto['price']:,.2f} | "
f"24h: {crypto['change_24h']}%"
)
except Exception as e:
log.error(f"Error scanning {symbol}: {e}")
log.info("=== Market Scan Complete ===")
# Schedule: scan every 5 minutes during market hours
schedule.every(5).minutes.do(scan_markets)
if __name__ == "__main__":
log.info("Trading bot started!")
scan_markets() # Run immediately
while True:
schedule.run_pending()
time.sleep(1)
Run the bot:
python bot.py
2026-03-13 09:30:15 [INFO] Trading bot started!
2026-03-13 09:30:15 [INFO] === Market Scan Started ===
2026-03-13 09:30:16 [INFO] AAPL: $198.45 | Signal: HOLD | RSI: 52.3
2026-03-13 09:30:16 [INFO] MSFT: $425.10 | Signal: BUY | RSI: 35.8
2026-03-13 09:30:16 [INFO] >>> BUY SIGNAL: 1 shares of MSFT @ $425.10
2026-03-13 09:30:17 [INFO] GOOGL: $175.20 | Signal: HOLD | RSI: 48.1
2026-03-13 09:30:17 [INFO] NVDA: $890.50 | Signal: STRONG BUY | RSI: 28.4
2026-03-13 09:30:17 [INFO] >>> BUY SIGNAL: 0 shares of NVDA @ $890.50
2026-03-13 09:30:18 [INFO] TSLA: $178.30 | Signal: SELL | RSI: 72.1
2026-03-13 09:30:18 [INFO] >>> SELL SIGNAL: TSLA
2026-03-13 09:30:18 [INFO] BTC: $87,432.15 | 24h: +2.3%
2026-03-13 09:30:19 [INFO] ETH: $3,215.80 | 24h: +1.8%
2026-03-13 09:30:19 [INFO] SOL: $142.50 | 24h: -0.5%
2026-03-13 09:30:19 [INFO] === Market Scan Complete ===
Complete Project Structure
Here's the full file layout of your trading bot:
trading-bot/
.env # Your MarketLens API key
market_data.py # API client (stocks + crypto)
signals.py # SMA crossover + RSI signals
risk.py # Position sizing, stop-loss, take-profit
backtest.py # Historical strategy testing
bot.py # Main bot with scheduler
trading_bot.log # Generated at runtime
requirements.txt # requests, pandas, schedule, python-dotenv
Next Steps
Connect a Broker
Integrate with Alpaca or Interactive Brokers API to execute real trades automatically.
Add Notifications
Send Telegram or Discord alerts when buy/sell signals fire. Use the MarketLens webhook endpoint for push alerts.
Upgrade to Pro
Need more than 500 calls/day? Pro plans start at $29/mo with 10,000 calls/day and 5 years of historical data.
Use the Python SDK
Install pip install marketlens for a cleaner interface. See the SDK docs.
Build Your Trading Bot Today
Get your free API key -- 500 calls/day, all 719+ endpoints, no credit card required.
Frequently Asked Questions
Yes. The free tier gives you 500 API calls per day, which is enough to run a trading bot that checks prices every 5 minutes for 20+ symbols throughout the trading day. No credit card required. Sign up here.
Yes. MarketLens provides real-time crypto prices for Bitcoin, Ethereum, and 50+ other cryptocurrencies. The API covers prices, market cap, 24h volume, and historical data. Crypto markets trade 24/7, so you can run your bot around the clock.
Basic Python knowledge is sufficient. You should be comfortable with pip install, making HTTP requests, and working with dictionaries/lists. This tutorial covers everything else step by step.
Yes. Algorithmic trading is legal in most jurisdictions including the US, EU, and UK. However, always comply with your broker's terms of service and local securities regulations. This tutorial covers signal generation -- you'll need a broker API (like Alpaca or Interactive Brokers) for actual order execution.
MarketLens provides ML-powered market predictions with confidence scores. These are probabilistic forecasts, not guarantees. Always use predictions as one signal among many in your trading strategy, and never risk more than you can afford to lose.
Ready to Start Building?
Get 500 free API calls/day. No credit card required.
Join 15,000+ developers. No spam.
Related Articles
Stock Market API in Python
Free tutorial with complete code examples for quotes, charts, and screeners.
TutorialBuild a Stock Dashboard with Python
Flask + Chart.js real-time stock dashboard in under 100 lines.
ComparisonBest Crypto APIs in 2026
Compare real-time pricing, WebSocket support, and free tier limits.
ComparisonBest Free Real-Time Stock APIs
Compare 5 free stock APIs with pricing tables and code examples.