Binance API: Download Daily Historical Data Using Python

·

Accessing historical cryptocurrency market data is essential for traders, developers, and analysts who want to perform backtesting, build trading algorithms, or conduct in-depth market analysis. The Binance API provides a powerful and free way to retrieve high-resolution price data—down to one-minute intervals—for thousands of trading pairs. This guide walks you through how to download daily historical candlestick data using Python, with clear code examples and best practices.

Whether you're analyzing Bitcoin (BTCUSDT), Ethereum, or any other major trading pair, this method ensures you get complete 24-hour data by working around Binance's 1000-point limit per API call.


Understanding Binance Kline/Candlestick Data

The Binance REST API endpoint /api/v1/klines returns kline (candlestick) data, which includes open, high, low, close prices, volume, and timestamps for a given symbol and time interval.

Key Features:

Since one day contains more minutes than the maximum allowed per request (1000), we need to split the daily fetch into two 12-hour segments and merge them.

👉 Generate highly click-attractive anchor text here based on article context and anchor link characteristics; no brand names other than 'OKX' may appear here.


Step-by-Step: Fetching Full-Day 1-Minute Data

We’ll use Python’s requests library to interact with the Binance API. No third-party wrappers like python-binance are required—this keeps things lightweight and transparent.

Required Libraries

import datetime
import requests
import json
from urllib.parse import urljoin

Base Configuration

class BinanceClient:
    BASE_URL = "https://api.binance.com"
    
    def __init__(self, api_key=None):
        self.API_KEY = api_key

    def download_historical_data(self, symbol: str, date: str):
        """Download full day of 1-minute klines for a given symbol and date."""
        # Parse input date
        start_date = datetime.datetime.strptime(date, "%Y-%m-%d")
        
        # First 12 hours: 00:00 - 11:59
        data = self._download_12h_klines(start_date, start_date + datetime.timedelta(hours=12))
        
        # Second 12 hours: 12:00 - 23:59
        next_start = start_date + datetime.timedelta(hours=12)
        next_end = next_start + datetime.timedelta(hours=12)
        data.extend(self._download_12h_klines(next_start, next_end))

        # Save as JSON and CSV
        filename = f"{symbol}_{date}"
        self._save_json(data, f"{filename}.json")
        self._save_csv(data, f"{filename}.csv")
        
        print(f"✅ Data saved: {filename}.json and {filename}.csv")

    def _download_12h_klines(self, start_dt: datetime.datetime, end_dt: datetime.datetime):
        """Fetch up to 720 minutes (12h) of 1-minute klines."""
        start_time = int(start_dt.timestamp() * 1000)
        end_time = int(end_dt.timestamp() * 1000)

        params = {
            'symbol': symbol.upper(),
            'interval': '1m',
            'limit': 720,  # Safe under 1000 limit
            'startTime': start_time,
            'endTime': end_time
        }

        headers = {'X-MBX-APIKEY': self.API_KEY} if self.API_KEY else {}
        url = urljoin(self.BASE_URL, '/api/v1/klines')

        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            return response.json()
        else:
            raise BinanceException(response.status_code, response.json() if response.headers.get('Content-Type') == 'application/json' else None)

Handling Errors Gracefully

It's crucial to handle API errors properly. Here's a clean exception class:

class BinanceException(Exception):
    def __init__(self, status_code: int, data: dict = None):
        self.status_code = status_code
        if data:
            self.code = data.get('code')
            self.msg = data.get('msg')
            message = f"{status_code} [{self.code}] {self.msg}"
        else:
            self.code = self.msg = None
            message = f"HTTP {status_code}"
        super().__init__(message)

This helps identify rate limits, invalid symbols, or malformed requests without crashing your script.


Saving Output: JSON & CSV

After fetching the data, save it in both structured formats:

def _save_json(self, data, filename):
    with open(filename, 'w') as f:
        json.dump(data, f, indent=2)

def _save_csv(self, data, filename):
    with open(filename, 'w') as f:
        # CSV header
        f.write("open_time,open,high,low,close,volume,close_time\n")
        for k in data:
            f.write(f"{k[0]},{k[1]},{k[2]},{k[3]},{k[4]},{k[5]},{k[6]}\n")

Each row contains:

You can extend this to include number of trades or quote asset volume if needed.


Example Usage

client = BinanceClient(api_key="your_api_key_here")  # Optional for public data
client.download_historical_data('BTCUSDT', '2025-04-05')

This will generate:

Perfect for offline analysis in Pandas, Excel, or machine learning pipelines.

👉 Generate highly click-attractive anchor text here based on article context and anchor link characteristics; no brand names other than 'OKX' may appear here.


Frequently Asked Questions (FAQ)

Q: Do I need an API key to download historical data?

A: No. Public endpoints like /api/v1/klines do not require authentication. However, including an API key helps identify your requests and may improve rate limit handling.

Q: Can I fetch data older than a year?

A: Yes. Binance retains several years of historical kline data. Just ensure your timestamp logic is correct and respect rate limits (e.g., no more than 1200 requests per minute).

Q: What intervals are supported?

A: Supported intervals include 1m, 3m, 5m, 15m, 30m, 1h, 4h, 1d, etc. For daily summaries, use 1d. For granular analysis, stick with 1m.

Q: Why split into two 12-hour calls?

A: Because each API call returns a maximum of 1000 data points, but a full day at 1-minute resolution requires 1440 points. Two calls of ~720 each ensure full coverage without hitting limits.

Q: How can I automate daily downloads?

A: Use cron jobs (Linux/macOS) or Task Scheduler (Windows) to run the script daily at midnight UTC. Combine with cloud storage (e.g., AWS S3 or Google Drive) for long-term archiving.

Q: Is there a way to get tick-level data?

A: The kline endpoint doesn’t provide tick data. For ultra-fine-grained trades, consider using the /api/v1/trades or WebSocket streams—but those come with higher bandwidth and processing demands.


Core Keywords for SEO

To align with search intent and improve visibility:

These terms naturally appear throughout the article while maintaining readability and technical depth.


With this approach, you now have a reliable system to download complete daily cryptocurrency price data from Binance using simple Python scripts—ideal for research, modeling, or integration into larger financial systems.

Whether you're building a personal analytics dashboard or training an AI model on market behavior, mastering the Binance API is a foundational skill in today’s digital asset landscape.

👉 Generate highly click-attractive anchor text here based on article context and anchor link characteristics; no brand names other than 'OKX' may appear here.