Building a crypto trading bot with AI is genuinely easy today: a coding agent such as Claude Code or Codex can write a Python bot that connects to an exchange through ccxt, runs a simple strategy and places orders. The real work is everything around the code: testing on a testnet and in backtests, limiting the API key to trading only, and moving to real money with tiny amounts.
This guide goes step by step from an empty folder to a bot that runs 24/7 on a server and sends you Telegram alerts. First, though, the part I have to be straight about.
Risk first: this is not financial advice
This is a software tutorial, not investment advice. A few facts up front:
- Most trading bots lose money. Especially the simple strategies you find online, once fees, slippage and sudden moves are counted.
- A strategy that looks great in a backtest often fails live. Strategies tuned to past data (overfitting) fall apart quickly.
- AI-written code can contain costly bugs. A wrong amount unit, a flipped buy/sell condition or a retry loop that keeps placing orders can drain an account in minutes.
- Only give a bot money you can afford to lose. Start on testnet, then go live with the smallest amount the exchange allows.
The strategy in this post is a code example. I’m not presenting it as a way to make money.
Which stack to pick
When you’re vibe coding a bot, choose the stack the agent knows best. My pick:
- Python 3.11+: the most mature ecosystem for data (pandas), backtesting and exchange libraries, and the language agents have seen most examples in.
- ccxt: an open-source library that talks to many exchanges through one interface. Code written for one exchange usually moves to another with a few lines changed, and it supports the testnet/sandbox mode of many exchanges.
- pandas: to work with candle (OHLCV) data as a table.
- python-dotenv: to keep API keys in a
.envfile, out of the code. - SQLite: to record open positions and orders without running a database server.
Setup:
mkdir crypto-bot && cd crypto-bot
git init
python3 -m venv .venv && source .venv/bin/activate
pip install ccxt pandas python-dotenv requests
echo ".env" >> .gitignore
echo ".venv/" >> .gitignore
Add those .gitignore lines in the first minute. An API key pushed to GitHub by accident is the most common and most expensive mistake in this whole area.
Step 1: a testnet account and a properly scoped API key
Many large exchanges offer a test environment (testnet or sandbox) where no real money moves. Search the exchange’s developer docs for “testnet” or “sandbox” and create a separate test account and test API key there. If there’s no testnet, or your pair isn’t on it, we’ll have the agent build a paper-trading mode that reads real prices but only records orders locally.
When you eventually create a key on the real account:
- Enable read and trade only. Never enable withdrawals. If the key leaks, nobody can send your funds elsewhere.
- Use IP whitelisting. If the exchange supports it, lock the key to your VPS’s static IP.
- Keep futures and margin disabled. Start with spot.
- Create one key per bot, so you can revoke just that one if something goes wrong.
A .env file looks like this:
EXCHANGE=binance
API_KEY=your-test-key
API_SECRET=your-test-secret
USE_TESTNET=true
TELEGRAM_TOKEN=
TELEGRAM_CHAT_ID=
Don’t paste these values into the chat with the agent. The agent needs to know .env exists, not what’s in it.
Step 2: the first prompt
Open the agent in the project folder (claude or codex) and ask for the bot in layers, not all at once. A first prompt you can copy:
Set up a skeleton for a simple spot trading bot in Python 3.11 with ccxt.
Rules:
- Read settings from .env with python-dotenv. Never open or print .env.
- If USE_TESTNET=true, enable ccxt sandbox mode; otherwise print a
"LIVE MODE" warning on start and wait 10 seconds.
- Modules: config.py, exchange.py (connection, balance, candles, orders),
strategy.py (returns a signal, never places orders), risk.py (position
size, daily loss limit), bot.py (main loop), storage.py (SQLite log).
- Every order must pass risk.py first. Max 2% of balance per order;
stop the bot if the daily loss exceeds 5%.
- With DRY_RUN=true, never place orders, only log them.
- Use Python logging to logs/bot.log and the console.
- No strategy yet: strategy.py should always return "hold".
When done, summarize the file layout and how to run it.
Why a skeleton first? Keeping strategy, order placement and risk rules in separate files makes the code easier to review and bugs easier to catch. If the strategy can’t place orders, a bug there produces a wrong signal at worst, and the risk layer caps the damage.
Step 3: an example strategy (moving average crossover)
Again: this is an example, not advice. A moving average crossover is one of the clearest strategies for showing the structure. When the fast average crosses above the slow one it signals “buy”; when it crosses below, “sell”.
# strategy.py — example only, not financial advice
import pandas as pd
def signal(ohlcv: list, fast: int = 20, slow: int = 50) -> str:
df = pd.DataFrame(ohlcv, columns=["ts", "open", "high", "low", "close", "volume"])
if len(df) < slow + 2:
return "hold"
df["fast"] = df["close"].rolling(fast).mean()
df["slow"] = df["close"].rolling(slow).mean()
prev, last = df.iloc[-3], df.iloc[-2] # the last candle is still open, skip it
if prev.fast <= prev.slow and last.fast > last.slow:
return "buy"
if prev.fast >= prev.slow and last.fast < last.slow:
return "sell"
return "hold"
One detail worth noticing: the signal is computed from the last closed candle, because the newest one is still moving. Agents often miss this, and the bot ends up flipping in and out within one candle.
Prompt to add it:
Add a 20/50 moving average crossover to strategy.py. Compute signals from
closed candles only. Write pytest tests for the signal function: cross up,
cross down, not enough data and a flat market. Run the tests and show me
the output.
Step 4: backtesting
Before going live, run the strategy on historical data. You can have the agent fetch candles with ccxt and write a simple backtest loop. For anything more serious, look at backtesting.py, vectorbt or Freqtrade; Freqtrade is a mature open-source bot framework that already includes backtesting, dry-run and Telegram control.
A prompt:
Write backtest.py. Fetch the last year of BTC/USDT 1h candles with ccxt,
paginating, and save them as CSV under data/. Apply strategy.signal candle
by candle without looking ahead. Deduct 0.1% fee and 0.05% slippage per
trade. Report total return, number of trades, win rate, max drawdown and
buy-and-hold return over the same period.
When you read the results:
- Always include fees and slippage. Without them almost any strategy looks good.
- Compare with buy-and-hold. If the bot does worse than simply holding, it isn’t worth the effort.
- Check for look-ahead bias yourself. Read the loop and make sure it never uses data that didn’t exist yet.
- Don’t tweak parameters until the curve looks nice. If 17/43 beats 20/50, that’s most likely chance.
Step 5: testnet and paper trading
After the backtest, run the bot on testnet for at least a few days:
DRY_RUN=false USE_TESTNET=true python bot.py
At this stage you’re checking behavior, not profit. Do orders go out with the right amount? Does the bot remember an open position after a restart? When the exchange returns an error, does it crash or back off and retry? Does the daily loss limit actually kick in?
Trigger a failure on purpose, for example an order bigger than your balance, and watch the bot log it cleanly and stop.
Step 6: rate limits, error handling and logging
Exchanges limit API requests. A bot that exceeds them gets errors first and may be temporarily blocked if it keeps going. ccxt’s enableRateLimit option spaces requests out automatically; have the agent confirm it’s on.
Review exchange.py:
- Make sure ccxt enableRateLimit is on.
- On NetworkError and RateLimitExceeded, retry up to 5 times with
increasing backoff. On InsufficientFunds and InvalidOrder, do not retry;
log it and send a Telegram alert.
- Log the request, exchange response and order id for every order.
- Prevent a second order for the same signal (idempotency).
A good log line answers “why did the bot do that?” later: time, signal, price, computed amount, risk check result, order id. Never log API keys or secrets.
Step 7: Telegram alerts
The bot should tell you what it’s doing. The simplest way is a plain HTTP call to the Telegram Bot API:
# notify.py
import os, requests
def send(text: str) -> None:
token, chat = os.getenv("TELEGRAM_TOKEN"), os.getenv("TELEGRAM_CHAT_ID")
if not token or not chat:
return
try:
requests.post(f"https://api.telegram.org/bot{token}/sendMessage",
json={"chat_id": chat, "text": text}, timeout=10)
except requests.RequestException:
pass # a failed alert must not stop the bot
You get the token from Telegram’s official bot creation flow. Events worth an alert: bot started/stopped, order placed, error, daily loss limit reached. My guide to building a Telegram bot with AI covers adding commands, such as stopping the bot remotely.
Step 8: running 24/7 on a VPS
When your laptop sleeps, so does the bot. A small Linux VPS is enough; a static IP matters for the IP whitelist.
With systemd
# /etc/systemd/system/crypto-bot.service
[Unit]
Description=Crypto bot
After=network-online.target
[Service]
User=bot
WorkingDirectory=/home/bot/crypto-bot
EnvironmentFile=/home/bot/crypto-bot/.env
ExecStart=/home/bot/crypto-bot/.venv/bin/python bot.py
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now crypto-bot
journalctl -u crypto-bot -f
Run the bot as its own user, not root, and lock down the env file with chmod 600 .env.
With Docker
If you prefer Docker, have the agent write a Dockerfile and docker-compose.yml with restart: unless-stopped, env_file for .env, and volumes for logs/ and the SQLite file, so the bot and its records survive a server reboot.
Common mistakes: what the AI tends to get wrong
- Amounts and precision. Exchanges enforce a minimum amount and decimal precision per pair. Agents skip this and get rejected orders, or round the wrong way. Have it use ccxt’s
amount_to_precisionand market limits. - Using the open candle. Signals from a candle that’s still moving are noise.
- Testnet flag left on in production, or off in testing. Log the mode loudly on start.
- Losing state on restart. If the bot forgets an open position, it may buy again. Persist state in SQLite and reconcile it with the exchange on start.
- Orders in a retry loop. If retry logic wraps order placement, the same order can go out many times.
- Swallowed errors.
except: passeverywhere makes a bot that looks alive and does nothing. - Trusting “tests passed”. Look at the output yourself.
Security checklist
- API keys live only in
.env, and.envis in.gitignore. - Never paste keys into the agent, a chat or a screenshot.
- Withdrawals off, IP whitelist on, margin off.
- Read the commands the agent wants to run before approving, especially anything that reads
.env, uploads files or makes network calls. - If you suspect a key leaked, revoke it on the exchange right away and create a new one.
- Turn on two-factor authentication on the exchange account.
- Install dependencies you recognize; check any package name the agent suggests that you’ve never heard of.
Doing it with AgentVera
On projects like this I run more than one agent side by side. In an AgentVera grid you can have Claude Code work on the strategy and backtest in one worktree while Codex builds the Telegram alerts and Docker files in another, without touching each other’s files. After each turn, automatic code review has a second model read what the agent wrote, which is a useful second pair of eyes on amount math and buy/sell conditions. You review the diff in the Git panel before merging and see token usage per agent. When the bot is ready, SSH and SFTP gets the files onto the VPS, and the Docker manager shows the container locally.
None of this is required; two terminals and git work too. If the parallel setup interests you, see parallel coding agents.
Wrapping up
The coding side of building a crypto trading bot with AI is a few hours: Python, ccxt, clearly separated modules, a risk layer and good logs. The part that takes time and actually matters is testing: backtest, testnet, paper trading, and only then a tiny live amount. Scope the API key to trading, turn withdrawals off and read every order line the agent writes. And remember that most bots lose money; build this one to learn, not to get rich.