Skip to content

Instantly share code, notes, and snippets.

@moondancecrypto
Created August 23, 2020 14:15
Show Gist options
  • Save moondancecrypto/78f5137146f5f48f0119f0d89530f9e2 to your computer and use it in GitHub Desktop.
Save moondancecrypto/78f5137146f5f48f0119f0d89530f9e2 to your computer and use it in GitHub Desktop.
A script to fetch OHLCV data from Binance.
import sys
import time
import dateparser
import pytz
import json
import csv
from datetime import datetime
from binance.client import Client
def date_to_milliseconds(date_str):
"""Convert UTC date to milliseconds
If using offset strings add "UTC" to date string e.g. "now UTC", "11 hours ago UTC"
See dateparse docs for formats http://dateparser.readthedocs.io/en/latest/
:param date_str: date in readable format, i.e. "January 01, 2018", "11 hours ago UTC", "now UTC"
:type date_str: str
"""
# get epoch value in UTC
epoch = datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
# parse our date string
d = dateparser.parse(date_str)
# if the date is not timezone aware apply UTC timezone
if d.tzinfo is None or d.tzinfo.utcoffset(d) is None:
d = d.replace(tzinfo=pytz.utc)
# return the difference in time
return int((d - epoch).total_seconds() * 1000.0)
def interval_to_milliseconds(interval):
"""Convert a Binance interval string to milliseconds
:param interval: Binance interval string 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w
:type interval: str
:return:
None if unit not one of m, h, d or w
None if string not in correct format
int value of interval in milliseconds
"""
ms = None
seconds_per_unit = {
"m": 60,
"h": 60 * 60,
"d": 24 * 60 * 60,
"w": 7 * 24 * 60 * 60
}
unit = interval[-1]
if unit in seconds_per_unit:
try:
ms = int(interval[:-1]) * seconds_per_unit[unit] * 1000
except ValueError:
pass
return ms
def get_historical_klines(symbol, interval, start_str, end_str=None):
"""Get Historical Klines from Binance
See dateparse docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/
If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC"
:param symbol: Name of symbol pair e.g BNBBTC
:type symbol: str
:param interval: Biannce Kline interval
:type interval: str
:param start_str: Start date string in UTC format
:type start_str: str
:param end_str: optional - end date string in UTC format
:type end_str: str
:return: list of OHLCV values
"""
# create the Binance client, no need for api key
client = Client("", "")
# init our list
output_data = []
# setup the max limit
limit = 500
# convert interval to useful value in seconds
timeframe = interval_to_milliseconds(interval)
# convert our date strings to milliseconds
start_ts = date_to_milliseconds(start_str)
# if an end time was passed convert it
end_ts = None
if end_str:
end_ts = date_to_milliseconds(end_str)
idx = 0
# it can be difficult to know when a symbol was listed on Binance so allow start time to be before list date
symbol_existed = False
while True:
# fetch the klines from start_ts up to max 500 entries or the end_ts if set
temp_data = client.get_klines(
symbol=symbol,
interval=interval,
limit=limit,
startTime=start_ts,
endTime=end_ts
)
# handle the case where our start date is before the symbol pair listed on Binance
if not symbol_existed and len(temp_data):
symbol_existed = True
if symbol_existed:
# append this loops data to our output data
output_data += temp_data
# update our start timestamp using the last value in the array and add the interval timeframe
start_ts = temp_data[len(temp_data) - 1][0] + timeframe
else:
# it wasn't listed yet, increment our start date
start_ts += timeframe
idx += 1
# check if we received less than the required limit and exit the loop
if len(temp_data) < limit:
# exit the while loop
break
# sleep after every 3rd call to be kind to the API
if idx % 3 == 0:
time.sleep(1)
return output_data
#
# Fetch OHLCV data and save in each CSV file
#
start = "1 Jan, 2017"
end = "now"
symbol = "LINKUSDT"
interval = "5m"
symbol = sys.argv[1]
interval = sys.argv[2]
print(symbol)
# fetch data
klines = get_historical_klines(symbol, interval, start, end)
# format date and time
#start_date=datetime.fromtimestamp(date_to_milliseconds(start)/1000.0).strftime('%Y%m%d-%H%M%S')
end_date=datetime.fromtimestamp(date_to_milliseconds(end)/1000.0).strftime('%Y%m%d-%H%M%S')
# save data in CSV
f = open("data/Binance_{}_{}_all.csv".format(symbol,interval), 'w')
writer = csv.writer(f, lineterminator='\n')
writer.writerow(['Date', 'Timestamp', 'Open', 'High', 'Low', 'Close', 'Volume', 'Close time', 'Quote asset volume', 'Number of trades', 'Taker buy base asset volume', 'Taker buy quote asset volume', 'Can be ignored'])
for candle in klines:
candle_date=datetime.fromtimestamp(candle[0]/1000.0).strftime('%Y-%m-%d %H:%M:%S.%d')[:-3]
outlist = [candle_date] + candle
writer.writerow(outlist)
f.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment