cryptocurrency

Binance Api Historical Data: Endpoints, Limits, And Python Code

Accessing clean market history is the foundation of any robust quantitative trading strategy, backtest, or crypto data pipeline. Querying past market behavior via the Binance API requires navigating s

Binance Api Historical Data: Endpoints, Limits, And Python Code
In this story

Accessing clean market history is the foundation of any robust quantitative trading strategy, backtest, or crypto data pipeline. Querying past market behavior via the Binance API requires navigating strict rate limits, pagination rules, and specialized endpoints that change depending on whether you need candlestick data, raw trade ticks, or account-level fills.

This guide breaks down the exact endpoints, parameters, and code patterns needed to extract historical data from Binance efficiently without running into IP bans or corrupted datasets.

Understanding Binance Data Types and Endpoints

Before writing code, you must select the correct endpoint for your target dataset. Binance separates its public market data into distinct categories, each managed by specific REST paths and weight limits.

  • Kline/Candlestick Data (/api/v3/klines): The standard format for price history. It supplies open, high, low, close, and volume (OHLCV) metrics across timeframes ranging from 1 second to 1 month.
  • Aggregated Trades (/api/v3/aggTrades): Trades that occurred at the exact same price within a tiny window are compressed into single records. This cuts down data volume while preserving granular price action.
  • Historical Trades (/api/v3/historicalTrades): Used to query older raw trades past the real-time cache limit. This endpoint requires an API key with appropriate permissions.
  • Futures Data Endpoints (/fapi/v1/...): Derivative markets use separate base URLs and handle funding rates, mark prices, and open interest history via dedicated routes.

Each endpoint enforces strict pagination caps. For instance, the klines endpoint returns a maximum of 1,000 candles per request. Asking for a 1-minute chart spanning two years in a single call will fail. You must loop through requests using timestamp markers. Similar analysis on this trend has been provided by BBC.

Fetching Historical Klines with Python and Pagination

To build a continuous historical dataset, write a pagination loop that shifts the startTime parameter based on the last received candle timestamp. The following Python script uses the official requests library to pull hourly BTC/USDT spot data cleanly.

import time
import requests
import pandas as pd

def fetch_binance_klines(symbol, interval, start_str, end_str=None):
    url = "https://api.binance.com/api/v3/klines"
    
    # Convert human dates to milliseconds timestamp
    start_ts = int(pd.Timestamp(start_str).timestamp() * 1000)
    end_ts = int(pd.Timestamp(end_str).timestamp() * 1000) if end_str else int(time.time() * 1000)
    
    all_data = []
    
    while start_ts < end_ts:
        params = {
            "symbol": symbol,
            "interval": interval,
            "startTime": start_ts,
            "endTime": end_ts,
            "limit": 1000
        }
        
        response = requests.get(url, params=params)
        if response.status_code != 200:
            print(f"Error {response.status_code}: {response.text}")
            time.sleep(5)
            continue
            
        data = response.json()
        if not data:
            break
            
        all_data.extend(data)
        # Move start timestamp to the close time of the last candle plus one millisecond
        start_ts = data[-1][6] + 1
        
        # Respect Binance rate limits
        time.sleep(0.2)
        
    df = pd.DataFrame(all_data, columns=[
        "open_time", "open", "high", "low", "close", "volume",
        "close_time", "quote_asset_volume", "number_of_trades",
        "taker_buy_base_volume", "taker_buy_quote_volume", "ignore"
    ])
    
    # Format columns
    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

# Example usage: fetch 1-hour BTC data for January 2026
btc_df = fetch_binance_klines("BTCUSDT", "1h", "2026-01-01", "2026-02-01")
print(btc_df.head())

Managing Rate Limits and Weight Management

Binance tracks usage via a Request Weight system rather than a simple call count. Every endpoint carries a specific weight cost that accumulates per minute against your IP address or API key.

  • IP Limits: Standard rate limits cap requests at 6,000 weight units per minute. Exceeding this triggers an HTTP 429 error, followed by temporary IP bans (HTTP 418).
  • Weight Headers: Check the response headers (X-MBX-USED-WEIGHT-1M) during runtime to monitor current consumption.
  • Backoff Logic: Implement exponential backoff when a 429 or 418 status code appears. Pause execution for 60 seconds before resuming requests.

Alternative Approach: Using CCXT for Multi-Exchange Compatibility

If you plan to scale your infrastructure across multiple exchanges beyond Binance, writing custom request logic for each platform becomes tedious. Using the CCXT library simplifies historical extraction while handling pagination automatically under the hood.

import ccxt
import pandas as pd

exchange = ccxt.binance()

def fetch_via_ccxt(symbol, timeframe, since_date):
    since_ts = exchange.parse8601(since_date)
    all_ohlcv = []
    
    while True:
        ohlcv = exchange.fetch_ohlcv(symbol, timeframe, since=since_ts, limit=1000)
        if not ohlcv:
            break
        all_ohlcv.extend(ohlcv)
        since_ts = ohlcv[-1][0] + 1
        
        if len(ohlcv) < 1000:
            break
            
    df = pd.DataFrame(all_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

Common Mistakes When Pulling Historical Data

Developers frequently run into data integrity issues due to edge cases in exchange structures. Avoid these common pitfalls during pipeline construction:

  • Ignoring Gaps in Data: If an asset experiences low liquidity or trading halts, Binance omits kline timestamps for those intervals. Always reindex your final pandas DataFrame to a continuous time grid and fill missing volume with zeros or forward-fill prices.
  • Confusing Spot and Futures Timestamps: Spot klines use open time as the primary index reference, whereas certain derivative analytics endpoints use close times. Verify timestamp anchors before merging multi-source datasets.
  • Hardcoding Sleep Timers: Fixed time.sleep(1) calls either waste time or fail during network slowdowns. Dynamic throttling tied to response weight headers keeps data ingestion fast and safe.

Frequently Asked Questions

How far back does Binance historical data go?

Spot market kline data on Binance typically extends back to the inception of the trading pair, often around July 2017 for major assets like BTC and ETH. High-resolution tick data or raw trades are pruned more frequently from active REST endpoints, requiring bulk data archives for multi-year tick backtests.

Can I download bulk historical files instead of using the API?

Yes. Binance maintains an official data archive repository containing daily and monthly CSV dumps of klines, trades, and order books for spot and futures markets. This method is significantly faster for initial backtesting setups because it bypasses API rate limits entirely.

Why do my historical requests return empty lists?

An empty list usually means the requested startTime predates the creation date of the trading pair, or the interval format is malformed. Verify your symbol formatting (e.g., BTCUSDT for spot vs BTC/USDT depending on the wrapper library).

How do I handle account trade history older than six months?

Standard user trade endpoints restrict real-time queries to recent activity. For older personal audits or tax reports, you must use the asynchronous export features on the Binance web portal or generate statement files via the restricted institutional APIs.

IC

Written by

Isabella Carter

As a veteran correspondent, Isabella Carter has reported from across the globe, bringing firsthand perspectives to international stories and local issues.

More from cryptocurrency