Tutorial Python Updated March 2026

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).

By MarketLens Team | 45 min read | March 13, 2026

Need an API key to follow along?

Sign up for free -- 500 calls/day, 719+ endpoints, no credit card required.

Get Free API Key

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
Disclaimer: This tutorial is for educational purposes. Algorithmic trading involves substantial risk of financial loss. Never trade with money you cannot afford to lose. Past performance does not guarantee future results.

Prerequisites

Required

Libraries We'll Use

  • requests -- HTTP client
  • pandas -- data analysis
  • schedule -- task scheduler
  • python-dotenv -- env vars
1

Project Setup

Create your project directory and install dependencies:

bash
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:

.env
MARKETLENS_API_KEY=your_api_key_here

Don't have an API key yet? Sign up free -- takes 30 seconds, no credit card needed.

2

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:

python
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:

output
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
3

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:

python
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"],
    }
4

Add Crypto Trading Support

MarketLens supports 50+ cryptocurrencies. Let's extend our bot to trade crypto too. Add this to market_data.py:

python
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.

5

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:

python
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,
    }
6

Add Risk Management

No trading bot is complete without risk management. Create risk.py:

python
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.

7

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:

python
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']}")
8

Automate with a Scheduler

Now let's tie it all together into a bot that runs automatically. Create bot.py:

python
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:

bash
python bot.py
output
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:

Project Structure
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