Crypto Bots

How to Use the Binance API: Complete Beginner Guide (2025)

Everything you need to start using the Binance API โ€” authentication, fetching prices, placing orders, websockets for live data, and rate limit handling. Python code throughout.

A
AI Agents Hubยท2026-03-10ยท8 min readยท1,555 words

Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.

The Binance API is the most-used exchange API in crypto. Over 1,000 different bots, tools, and platforms connect to it daily. This guide teaches you everything from your first API call to handling live price streams โ€” with working Python code.

Setting Up Binance API Access

1. Create Your API Keys

  1. Log in to binance.com
  2. Go to Profile โ†’ API Management
  3. Click Create API โ†’ System Generated
  4. Name it "My Trading Bot"
  5. Enable: Read Info, Enable Spot & Margin Trading
  6. Disable: Enable Withdrawals (NEVER enable this on a bot key)
  7. Restrict to your IP address if possible

2. Install the Library

pip install python-binance python-dotenv

3. Store Keys Securely

# .env file (never commit this!)
BINANCE_API_KEY=your_key_here
BINANCE_SECRET=your_secret_here
import os
from dotenv import load_dotenv
from binance.client import Client

load_dotenv()

client = Client(
    api_key=os.getenv("BINANCE_API_KEY"),
    api_secret=os.getenv("BINANCE_SECRET")
)

# Test connection
info = client.get_account()
print(f"Account type: {info['accountType']}")
print(f"Can trade: {info['canTrade']}")

Part 1: Getting Market Data

Current Price

# Single price
price = client.get_symbol_ticker(symbol="BTCUSDT")
print(f"BTC Price: ${float(price['price']):,.2f}")

# All prices
all_prices = client.get_all_tickers()
# Convert to dict for easy lookup
price_dict = {p['symbol']: float(p['price']) for p in all_prices}
print(f"ETH Price: ${price_dict['ETHUSDT']:,.2f}")

Order Book

order_book = client.get_order_book(symbol="BTCUSDT", limit=10)

print("Top 5 asks (sell orders):")
for price, qty in order_book['asks'][:5]:
    print(f"  ${float(price):>12,.2f}  |  {float(qty):.4f} BTC")

print("\nTop 5 bids (buy orders):")
for price, qty in order_book['bids'][:5]:
    print(f"  ${float(price):>12,.2f}  |  {float(qty):.4f} BTC")

# Bid-ask spread
best_bid = float(order_book['bids'][0][0])
best_ask = float(order_book['asks'][0][0])
spread = best_ask - best_bid
spread_pct = spread / best_bid * 100
print(f"\nSpread: ${spread:.2f} ({spread_pct:.4f}%)")

Candlestick Data (OHLCV)

import pandas as pd

def get_klines(symbol: str, interval: str = "1h", limit: int = 100) -> pd.DataFrame:
    """Fetch OHLCV data as a clean DataFrame."""
    klines = client.get_klines(symbol=symbol, interval=interval, limit=limit)
    
    df = pd.DataFrame(klines, columns=[
        'open_time', 'open', 'high', 'low', 'close', 'volume',
        'close_time', 'quote_volume', 'trades', 'taker_buy_base',
        'taker_buy_quote', 'ignore'
    ])
    
    # Convert types
    numeric_cols = ['open', 'high', 'low', 'close', 'volume']
    df[numeric_cols] = df[numeric_cols].astype(float)
    df['open_time'] = pd.to_datetime(df['open_time'], unit='ms')
    df.set_index('open_time', inplace=True)
    
    return df[['open', 'high', 'low', 'close', 'volume']]

# Get 100 hours of BTC data
btc = get_klines("BTCUSDT", "1h", 100)
print(btc.tail())
print(f"\nLatest close: ${btc['close'].iloc[-1]:,.2f}")
print(f"24h volume: {btc['volume'].iloc[-24:].sum():,.0f} BTC")

24-Hour Statistics

stats = client.get_ticker(symbol="ETHUSDT")

print(f"ETH 24h Stats:")
print(f"  Open:        ${float(stats['openPrice']):,.2f}")
print(f"  High:        ${float(stats['highPrice']):,.2f}")
print(f"  Low:         ${float(stats['lowPrice']):,.2f}")
print(f"  Close:       ${float(stats['lastPrice']):,.2f}")
print(f"  Change:      {float(stats['priceChangePercent']):+.2f}%")
print(f"  Volume:      {float(stats['volume']):,.0f} ETH")
print(f"  Quote Volume:${float(stats['quoteVolume']):,.0f}")

Part 2: Account and Orders

Check Your Balances

def get_balances(min_value_usd=1.0) -> dict:
    """Get all non-zero balances with USD value."""
    account = client.get_account()
    balances = {}
    
    prices = {p['symbol']: float(p['price']) for p in client.get_all_tickers()}
    
    for asset in account['balances']:
        total = float(asset['free']) + float(asset['locked'])
        if total < 0.00001:
            continue
        
        symbol = asset['asset'] + 'USDT'
        usd_price = prices.get(symbol, 1.0 if asset['asset'] == 'USDT' else 0)
        usd_value = total * usd_price
        
        if usd_value >= min_value_usd:
            balances[asset['asset']] = {
                'free': float(asset['free']),
                'locked': float(asset['locked']),
                'total': total,
                'usd_value': usd_value,
            }
    
    return dict(sorted(balances.items(), key=lambda x: x[1]['usd_value'], reverse=True))

balances = get_balances()
total_usd = sum(b['usd_value'] for b in balances.values())

print(f"Portfolio (Total: ${total_usd:,.2f})")
for asset, data in balances.items():
    print(f"  {asset:<8} {data['total']:>12.4f}  =  ${data['usd_value']:>10,.2f}")

Placing Orders

from binance.enums import *

# Market buy (execute immediately at current price)
def market_buy(symbol: str, quote_amount: float):
    """Buy using a specific USDT amount."""
    order = client.order_market_buy(
        symbol=symbol,
        quoteOrderQty=quote_amount  # Spend exactly this much USDT
    )
    print(f"Market BUY: {order['executedQty']} {symbol.replace('USDT','')} @ avg ${float(order['cummulativeQuoteQty'])/float(order['executedQty']):,.2f}")
    return order

# Market sell
def market_sell(symbol: str, base_amount: float):
    """Sell a specific amount of the base asset."""
    order = client.order_market_sell(
        symbol=symbol,
        quantity=base_amount
    )
    print(f"Market SELL: {base_amount} {symbol.replace('USDT','')} @ avg ${float(order['cummulativeQuoteQty'])/float(order['executedQty']):,.2f}")
    return order

# Limit buy
def limit_buy(symbol: str, quantity: float, price: float):
    """Buy at a specific price (passive order)."""
    order = client.order_limit_buy(
        symbol=symbol,
        quantity=client.round_quantity(symbol, quantity),
        price=client.round_price(symbol, price),
        timeInForce=TIME_IN_FORCE_GTC,  # Good Till Cancelled
    )
    print(f"Limit BUY placed: {quantity} {symbol.replace('USDT','')} @ ${price:,.2f}")
    return order

# Stop-loss order
def stop_loss_sell(symbol: str, quantity: float, stop_price: float):
    """Sell when price drops to stop_price."""
    order = client.create_order(
        symbol=symbol,
        side=SIDE_SELL,
        type=ORDER_TYPE_STOP_LOSS_LIMIT,
        quantity=client.round_quantity(symbol, quantity),
        stopPrice=client.round_price(symbol, stop_price),
        price=client.round_price(symbol, stop_price * 0.999),  # Limit slightly below stop
        timeInForce=TIME_IN_FORCE_GTC,
    )
    print(f"Stop-loss SET: {quantity} {symbol.replace('USDT','')} at ${stop_price:,.2f}")
    return order

Order Management

# Check all open orders
open_orders = client.get_open_orders(symbol="BTCUSDT")
print(f"Open orders: {len(open_orders)}")
for order in open_orders:
    print(f"  {order['side']} {order['origQty']} @ ${float(order['price']):,.2f} ({order['status']})")

# Cancel specific order
# client.cancel_order(symbol="BTCUSDT", orderId=12345678)

# Cancel all open orders for a symbol
def cancel_all(symbol: str):
    orders = client.get_open_orders(symbol=symbol)
    for order in orders:
        client.cancel_order(symbol=symbol, orderId=order['orderId'])
    print(f"Cancelled {len(orders)} orders for {symbol}")

# Get trade history
trades = client.get_my_trades(symbol="BTCUSDT", limit=10)
for trade in trades:
    side = "BUY" if trade['isBuyer'] else "SELL"
    print(f"{side} {trade['qty']} BTC @ ${float(trade['price']):,.2f} (fee: {trade['commission']} {trade['commissionAsset']})")

Part 3: WebSockets for Live Data

REST API is for historical data. For live prices, use WebSockets:

from binance import ThreadedWebsocketManager
import time

# Real-time price ticker
def handle_ticker(msg):
    if msg['e'] == 'error':
        print(f"Error: {msg['m']}")
        return
    
    symbol = msg['s']
    price = float(msg['c'])
    change = float(msg['P'])
    print(f"{symbol}: ${price:,.2f} ({change:+.2f}%)")

twm = ThreadedWebsocketManager()
twm.start()

# Subscribe to BTC and ETH tickers
twm.start_symbol_ticker_socket(callback=handle_ticker, symbol='BTCUSDT')
twm.start_symbol_ticker_socket(callback=handle_ticker, symbol='ETHUSDT')

time.sleep(10)  # Run for 10 seconds
twm.stop()

Live Candlestick Data

def handle_kline(msg):
    """Process live kline/candlestick data."""
    if msg['e'] == 'error':
        return
    
    k = msg['k']
    
    # k['x'] is True when the candle is closed (complete)
    is_closed = k['x']
    symbol = k['s']
    interval = k['i']
    open_price = float(k['o'])
    close_price = float(k['c'])
    high = float(k['h'])
    low = float(k['l'])
    volume = float(k['v'])
    
    status = "CLOSED" if is_closed else "OPEN"
    print(f"[{status}] {symbol} {interval}: O={open_price:.2f} H={high:.2f} L={low:.2f} C={close_price:.2f} V={volume:.2f}")
    
    # Only act on closed candles
    if is_closed:
        process_closed_candle(symbol, interval, open_price, high, low, close_price, volume)

def process_closed_candle(symbol, interval, o, h, l, c, v):
    """Your strategy logic goes here."""
    # Check your signals on the newly completed candle
    pass

twm = ThreadedWebsocketManager()
twm.start()
twm.start_kline_socket(callback=handle_kline, symbol='BTCUSDT', interval='1m')

Part 4: Rate Limits and Error Handling

Binance has strict rate limits. Violate them and you get banned.

Limits:

  • 1200 requests/minute for REST
  • 10 orders/second per symbol
  • 100,000 orders/day per account
import time
from binance.exceptions import BinanceAPIException, BinanceRequestException

def safe_api_call(func, *args, max_retries=3, **kwargs):
    """Wrap any Binance API call with retry logic."""
    for attempt in range(max_retries):
        try:
            return func(*args, **kwargs)
        
        except BinanceAPIException as e:
            if e.code == -1003:  # TOO_MANY_REQUESTS
                wait_time = 60 if attempt == 0 else 300
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
            elif e.code == -2010:  # INSUFFICIENT_BALANCE
                print(f"Insufficient balance: {e.message}")
                return None
            elif e.code == -1013:  # MIN_NOTIONAL
                print(f"Order too small (below minimum notional)")
                return None
            else:
                print(f"Binance API Error [{e.code}]: {e.message}")
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)  # Exponential backoff
                else:
                    raise
        
        except BinanceRequestException as e:
            print(f"Network error: {e}")
            time.sleep(5)
    
    return None

# Usage
order = safe_api_call(client.order_market_buy, symbol="BTCUSDT", quoteOrderQty=100)

Part 5: Exchange Filters

Every trading pair has filters that your orders must respect. Ignore them and your orders will be rejected.

def get_symbol_filters(symbol: str) -> dict:
    """Get all trading filters for a symbol."""
    info = client.get_symbol_info(symbol)
    
    filters = {}
    for f in info['filters']:
        if f['filterType'] == 'LOT_SIZE':
            filters['min_qty'] = float(f['minQty'])
            filters['max_qty'] = float(f['maxQty'])
            filters['step_size'] = float(f['stepSize'])
        elif f['filterType'] == 'PRICE_FILTER':
            filters['min_price'] = float(f['minPrice'])
            filters['tick_size'] = float(f['tickSize'])
        elif f['filterType'] == 'MIN_NOTIONAL':
            filters['min_notional'] = float(f['minNotional'])  # Min order value in USDT
    
    return filters

btc_filters = get_symbol_filters("BTCUSDT")
print(f"BTC/USDT filters: {btc_filters}")
# Output: {'min_qty': 0.00001, 'step_size': 0.00001, 'min_notional': 5.0, ...}

def round_qty(symbol: str, qty: float) -> float:
    """Round quantity to exchange's step size."""
    f = get_symbol_filters(symbol)
    step = f['step_size']
    return round(qty - (qty % step), 8)

Complete Trading Bot Template

Putting it all together:

import time
import os
import logging
import pandas as pd
from binance.client import Client
from binance.exceptions import BinanceAPIException
from dotenv import load_dotenv

load_dotenv()
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
log = logging.getLogger(__name__)

client = Client(os.getenv("BINANCE_API_KEY"), os.getenv("BINANCE_SECRET"))

def get_signal(symbol: str, fast: int = 9, slow: int = 21) -> int:
    """Return 1 (buy), -1 (sell), 0 (hold)."""
    klines = client.get_klines(symbol=symbol, interval='1h', limit=slow + 5)
    closes = [float(k[4]) for k in klines]
    
    def ema(data, period):
        if len(data) < period:
            return sum(data) / len(data)
        k = 2 / (period + 1)
        ema_val = data[0]
        for price in data[1:]:
            ema_val = price * k + ema_val * (1 - k)
        return ema_val
    
    fast_ema = ema(closes, fast)
    slow_ema = ema(closes, slow)
    
    if fast_ema > slow_ema * 1.001:  # 0.1% buffer
        return 1
    elif fast_ema < slow_ema * 0.999:
        return -1
    return 0

def run_bot(symbol='BTCUSDT', size_usdt=100):
    log.info(f"Bot starting: {symbol}, size=${size_usdt}")
    last_signal = 0
    
    while True:
        try:
            signal = get_signal(symbol)
            balance = client.get_asset_balance(asset='USDT')
            btc_balance = client.get_asset_balance(asset='BTC')
            
            usdt = float(balance['free'])
            btc = float(btc_balance['free'])
            price = float(client.get_symbol_ticker(symbol=symbol)['price'])
            
            log.info(f"{symbol}: ${price:,.2f} | Signal:{signal} | USDT:{usdt:.2f} | BTC:{btc:.5f}")
            
            if signal == 1 and last_signal != 1 and usdt >= size_usdt:
                order = client.order_market_buy(symbol=symbol, quoteOrderQty=size_usdt)
                log.info(f"BUY executed: {order['executedQty']} BTC")
                
            elif signal == -1 and last_signal != -1 and btc > 0.0001:
                order = client.order_market_sell(symbol=symbol, quantity=round(btc - btc % 0.00001, 5))
                log.info(f"SELL executed: {order['executedQty']} BTC")
            
            last_signal = signal
            
        except BinanceAPIException as e:
            log.error(f"API error: {e}")
        except Exception as e:
            log.error(f"Unexpected error: {e}")
        
        time.sleep(60)

if __name__ == '__main__':
    run_bot()

Next Steps

Now that you can connect to Binance and trade:

  1. Add technical indicators (pandas-ta library makes this easy)
  2. Add Telegram notifications for order fills
  3. Deploy to a VPS for 24/7 operation
  4. Read about backtesting your strategy before going live with real money
  5. Consider multiple exchange arbitrage for market-neutral strategies

The Binance API is powerful and well-documented. The official docs are comprehensive โ€” bookmark them.

Related Articles