⬡ TECHNICAL TUTORIAL · WITH CODE · 14 MIN READ

Python trading bot with the Binance API.

From setting up the environment to your first computed signal, with real, safe code. We will connect, pull candles, structure the strategy and — most importantly — test on the testnet before a single real cent.

By the RoboTraderIA Team· updated May 2026· intermediate level

Binance has one of the most complete and best documented APIs in crypto, and Python is the ideal language to explore it. In this tutorial you will build the foundation of a real trading bot — not a toy. We will prioritize three things that separate hobby code from serious code: key security, separation of concerns and testing before going live.

First of all — about risk: a crypto bot trades in an extremely volatile market, 24/7, with no circuit breaker. A bug in your code can empty the account while you sleep. Everything here must be tested exhaustively on the testnet. Never run it with money you cannot afford to lose, and never enable withdrawal permission on your API keys.

01Setting up the environment

Python 3.11+, virtualenv and the library. There are two main choices: python-binance (specific, more direct for Binance) and ccxt (generic, works on dozens of exchanges). To start focused, we will go with python-binance.

# Create the project and an isolated environment
mkdir bot-binance && cd bot-binance
python -m venv venv
source venv/bin/activate  # Linux/Mac (Windows: venv\Scripts\activate)

pip install python-binance pandas python-dotenv

02Generating API keys (securely)

In your Binance account, go to API Management and create a key. The golden rules of security:

  • Minimum permissions: enable only "Read" and "Spot Trading". NEVER enable "Withdrawals".
  • Restrict by IP if you are going to run it on a VPS with a fixed IP.
  • Save the Secret Key right away — it is shown only once.

Put the keys in a file named .env (and add .env to your .gitignore):

# .env — NEVER commit this file
BINANCE_API_KEY=sua_chave_aqui
BINANCE_API_SECRET=seu_secret_aqui

The mistake that costs you dearly: pasting the key straight into your code and pushing it to GitHub. Bots scan GitHub within seconds looking for exposed keys and drain accounts. Always use .env + .gitignore.

03Connecting and pulling candles

First contact — connect to the testnet (test environment with a fake balance) and pull data:

# conectar.py
import os
from binance.client import Client
from dotenv import load_dotenv
import pandas as pd

load_dotenv()
# testnet=True usa o ambiente de teste — comece SEMPRE aqui
client = Client(os.getenv("BINANCE_API_KEY"),
                os.getenv("BINANCE_API_SECRET"),
                testnet=True)

def get_candles(symbol="BTCUSDT", interval="15m", limit=100):
    raw = client.get_klines(symbol=symbol, interval=interval, limit=limit)
    df = pd.DataFrame(raw, columns=[
        "open_time","open","high","low","close","volume",
        "close_time","qav","trades","tbav","tqav","ignore"])
    df["close"] = df["close"].astype(float)
    return df

df = get_candles()
print(df[["close"]].tail())

04Computing the signal (strategy as a pure function)

Here is the principle that sets professional code apart: the strategy is a pure function — it takes data in, returns a signal, with no side effects. That makes it testable in isolation, without connecting to anything. Example with a moving average crossover + RSI:

# strategy.py
import pandas as pd

def calcular_rsi(series, periodo=14):
    delta = series.diff()
    ganho = delta.clip(lower=0).rolling(periodo).mean()
    perda = -delta.clip(upper=0).rolling(periodo).mean()
    rs = ganho / perda
    return 100 - (100 / (1 + rs))

def calcular_sinal(df: pd.DataFrame) -> str:
    df["ma_rapida"] = df["close"].rolling(9).mean()
    df["ma_lenta"]  = df["close"].rolling(21).mean()
    df["rsi"] = calcular_rsi(df["close"])

    u = df.iloc[-1]
    # Buy: uptrend + RSI not overbought
    if u["ma_rapida"] > u["ma_lenta"] and u["rsi"] < 70:
        return "COMPRA"
    if u["ma_rapida"] < u["ma_lenta"] and u["rsi"] > 30:
        return "VENDA"
    return "AGUARDA"

Why the pure function matters: you can run calcular_sinal() over 5 years of historical data in seconds, without connecting to the API. That is the basis of backtesting. Strategy logic mixed in with execution code is impossible to test properly.

05Executing an order (on the testnet first!)

With the signal computed, the execution layer sends the order. Note that this runs on the testnet — fake balance:

# executor.py
from binance.enums import *

def executar_ordem(client, symbol, sinal, quantidade):
    if sinal == "COMPRA":
        ordem = client.create_order(
            symbol=symbol, side=SIDE_BUY,
            type=ORDER_TYPE_MARKET, quantity=quantidade)
        return ordem
    if sinal == "VENDA":
        ordem = client.create_order(
            symbol=symbol, side=SIDE_SELL,
            type=ORDER_TYPE_MARKET, quantity=quantidade)
        return ordem
    return None  # WAIT: do nothing

Want the complete project, assembled and commented?

Download our open source example bot — clean structure, tests and risk management included.

Download the free bot →

06Architecture of a bot that will not blow up your account

Put the pieces together with clear separation. A serious bot has independent layers:

# recommended structure
# ├── client.py     # Binance connection + reconnect
# ├── strategy.py   # pure functions: data → signal (testable)
# ├── risk.py       # position size, stop, take, limits
# ├── executor.py   # sends orders, tracks state
# ├── logger.py     # logs everything (auditing is vital)
# └── main.py       # main loop, glues it all together

# main.py — loop básico
import time

while True:
    try:
        df = get_candles()
        sinal = calcular_sinal(df)
        qtd = calcular_tamanho_posicao(saldo, risco_pct=1)  # from risk.py
        if sinal != "AGUARDA":
            executar_ordem(client, "BTCUSDT", sinal, qtd)
            log(sinal, qtd)
        time.sleep(60)  # checks every minute
    except Exception as e:
        log_erro(e)
        time.sleep(30)  # never let the loop die silently

07Risk management in the code

The strategy defines when to enter; risk management defines how much. Without the second, the first does not matter. Your risk.py module must contain, at a minimum:

  • Position sizing based on a % of the account balance (e.g. risking 1% per trade).
  • Stop loss automatic on every position — never go without one.
  • Daily loss limit that shuts the bot down when it is hit.
  • Maximum simultaneous positions so risk does not concentrate.

08Testnet and backtest before going live

Mandatory sequence before any real money: (1) backtest of the strategy function over historical data, (2) testnet on Binance for weeks with a fake balance under real market conditions, (3) only then live with the minimum amount. Skipping any step is like driving with your eyes closed.

The natural next step: once you master the Binance API, the pattern carries over almost identically to other exchanges through ccxt, and the same architecture (pure strategy + executor + risk) applies to bots on MT5. See our general guide to building trading bots.

09Frequently asked questions

python-binance or ccxt?

python-binance is specific and more direct if you want to start focused on Binance. ccxt is generic and works on dozens of exchanges with the same syntax — better if you plan to trade on several. To learn, start with python-binance.

Do I need money to test?

No. Binance has a free testnet with a fake balance, under real market conditions. Use testnet=True in the client. Test for weeks before anything real.

Is it safe to keep the API key in the code?

Never. Use environment variables (.env), restrict the key's permissions to the minimum (read + spot, never withdrawal), and add .env to .gitignore. Bots scan GitHub looking for exposed keys.

Can the bot trade on its own 24 hours a day?

Yes, but it has to run on a machine that is always on — ideally a VPS. Crypto trades 24/7, so a bot on your personal PC stops the moment you shut the machine down.

Can I use this on Brazil's B3?

The Binance API is for crypto. For Brazil's B3 exchange (mini index, mini dollar futures), the route is MT5 through Python's MetaTrader5 library, or your broker's API. The architecture (pure strategy + executor) is the same.

Related reading

🎁 Get the free trading bot (with the Quotex, Deriv and IQ Option APIs)

Open source bot + ready-made API code. You edit it by chatting with ChatGPT/Claude — no programming. Free, no spam.

👉 Want the ready-made bot instead? Go to botbinaryoptions.com →