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:
- Minimum interval: 1 minute (
1m) - Maximum data points per request: 1000
- Daily data requirement: 1440 minutes (24 hours × 60 minutes)
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.
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 urljoinBase 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:
- Open time (timestamp)
- Open, High, Low, Close prices
- Volume
- Close time
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:
BTCUSDT_2025-04-05.jsonBTCUSDT_2025-04-05.csv
Perfect for offline analysis in Pandas, Excel, or machine learning pipelines.
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:
- Binance API
- Historical crypto data
- Download candlestick data
- Python cryptocurrency API
- Binance kline Python
- Fetch 1-minute crypto data
- Binance historical prices
- REST API Python tutorial
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.