Building a crypto trading bot in Python is one of the most practical automation projects a developer can do. In this guide, you'll go from zero to a fully working bot that:
- Fetches live prices from Binance via the
ccxtlibrary - Calculates a simple RSI-based buy/sell signal
- Sends a Telegram alert when a signal fires
- Runs every 15 minutes automatically — no server needed
Prerequisites
You need basic Python knowledge and a Binance or any other exchange account. We'll use the ccxt library which supports 100+ exchanges with a unified API.
pip install ccxt pandas requests
Step 1: Fetch Live OHLCV Data with ccxt
The ccxt library gives you a consistent interface across virtually every major exchange. Here's how to pull the last 100 candles for BTC/USDT from Binance:
import ccxt
import pandas as pd
def fetch_ohlcv(symbol="BTC/USDT", timeframe="15m", limit=100):
exchange = ccxt.binance({
"enableRateLimit": True,
})
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
df = pd.DataFrame(ohlcv, columns=["timestamp", "open", "high", "low", "close", "volume"])
df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
df.set_index("timestamp", inplace=True)
return df
This returns a clean DataFrame you can use for any technical analysis.
Step 2: Generate a Simple RSI Signal
The Relative Strength Index (RSI) is a momentum oscillator. When RSI falls below 30, the asset is considered oversold (buy signal). When it rises above 70, it's overbought (sell signal).
def calculate_rsi(df, period=14):
delta = df["close"].diff()
gain = delta.clip(lower=0).rolling(window=period).mean()
loss = (-delta.clip(upper=0)).rolling(window=period).mean()
rs = gain / loss
df["rsi"] = 100 - (100 / (1 + rs))
return df
def get_signal(df):
latest_rsi = df["rsi"].iloc[-1]
latest_close = df["close"].iloc[-1]
if latest_rsi < 30:
return "BUY", latest_close, latest_rsi
elif latest_rsi > 70:
return "SELL", latest_close, latest_rsi
else:
return "HOLD", latest_close, latest_rsi
Step 3: Send a Telegram Alert
When a signal fires, you want to know immediately. This function sends a formatted Telegram message using a bot token:
import requests
import os
def send_telegram_alert(signal, price, rsi):
token = os.environ.get("TELEGRAM_BOT_TOKEN")
chat_id = os.environ.get("TELEGRAM_CHAT_ID")
emoji = "🟢" if signal == "BUY" else "🔴" if signal == "SELL" else "⚪"
message = (
f"{emoji} *BTC/USDT Signal: {signal}*\n\n"
f"💰 Price: `${price:,.2f}`\n"
f"📊 RSI (14): `{rsi:.2f}`\n"
f"⏰ Timeframe: 15m\n"
)
url = f"https://api.telegram.org/bot{token}/sendMessage"
requests.post(url, json={
"chat_id": chat_id,
"text": message,
"parse_mode": "Markdown"
})
Step 4: Wire It All Together as a Handler
def handler(event, context):
"""
LiteLambda entry point.
Runs every 15 minutes via cron schedule: */15 * * * *
"""
symbol = "BTC/USDT"
# 1. Fetch data
df = fetch_ohlcv(symbol, timeframe="15m", limit=100)
# 2. Calculate RSI
df = calculate_rsi(df)
# 3. Get signal
signal, price, rsi = get_signal(df)
print(f"Signal: {signal} | Price: ${price:,.2f} | RSI: {rsi:.2f}")
# 4. Only alert on actionable signals
if signal in ("BUY", "SELL"):
send_telegram_alert(signal, price, rsi)
print("Telegram alert sent!")
return {
"signal": signal,
"price": price,
"rsi": round(rsi, 2)
}
Step 5: Add Your pip Packages
In your LiteLambda cron job configuration, add the following to the Pip Packages field:
ccxt==4.3.89
pandas==2.2.2
requests==2.32.3
LiteLambda will automatically build an isolated Docker container with these exact versions. No requirements.txt fighting, no pip install errors.
Step 6: Set Your Environment Variables
In the Environment Variables section, add:
TELEGRAM_BOT_TOKEN=your_bot_token_from_botfather
TELEGRAM_CHAT_ID=your_personal_or_group_chat_id
These are injected securely at runtime via os.environ. Never hardcode secrets.
Step 7: Set the Cron Schedule
Set your schedule to */15 * * * * to run every 15 minutes. If you want hourly analysis, use 0 * * * *.
Going Further: Real Order Execution
Once you're confident in your signal quality, you can add real order execution. Important: Only do this with money you can afford to lose.
def place_order(signal, exchange, symbol="BTC/USDT", usdt_amount=50):
# Load API keys from env
exchange.apiKey = os.environ.get("BINANCE_API_KEY")
exchange.secret = os.environ.get("BINANCE_SECRET")
price = exchange.fetch_ticker(symbol)["last"]
quantity = usdt_amount / price
quantity = exchange.amount_to_precision(symbol, quantity)
side = "buy" if signal == "BUY" else "sell"
order = exchange.create_market_order(symbol, side, quantity)
return order
Common Pitfalls
- Rate limits: ccxt has built-in rate limiting when you set
enableRateLimit: True. Always use it. - Exchange downtime: Wrap your
fetch_ohlcvin a try/except. LiteLambda's retry logic can handle transient failures. - Over-optimisation: RSI alone is not a complete strategy. Combine it with volume, trend filters, or a stop-loss before risking real money.
- Timezone issues: All cron schedules run in UTC on LiteLambda.
Why Host on LiteLambda Instead of a VPS?
Running a trading bot on a $5/month VPS sounds simple until you have to deal with SSH access, keeping Python updated, restarting the process if it crashes, and managing logs. LiteLambda handles all of that:
| LiteLambda | Bare VPS | |
|---|---|---|
| Setup time | 2 minutes | 30–60 minutes |
| Process management | Automatic | Manual (systemd/supervisor) |
| Execution logs | Built-in dashboard | You manage log files |
| Crash alerts | Built-in email/Telegram | DIY |
| Cost for 15-min cron | Free tier | ~$5/month always-on |
The bot above uses about 3 credits per run at default settings. At 96 runs/day (every 15 minutes), you'd use ~288 credits/day. The free tier gives you 100 credits to start, and the Starter plan gives you 5,000/month — more than enough for a 24/7 trading bot.