Getting Binance Historical Data For Specific TimeZone

Guy picture Guy · Mar 12, 2020 · Viewed 7.2k times · Source

I found this python script on the web, it gets OHLCV historical data from Binance api by wanted dates, assets and time intervals. The script currently returns the data for UTC time.

I want to modify it so it will return the data (daily/hourly) according to a specified timezone. I guess it takes only to change one function or add an argument but I can't manage to do it correctly.

How can I change it so it will return data for UTC+2 (or any other time zone)?

Thanks! Guy

import time
import dateparser
import pytz
import os
from datetime import datetime
import binance
print(binance.__file__)
from binance.client import Client
import time
import pandas as pd


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 GetUpdateData(kline):
     Time = time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime(kline[0]/1000))
     Open = kline[1]
     High = kline[2]
     Low = kline[3]
     Close = kline[4]
     Volume = kline[5]
     Close_time = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(kline[6]/1000))
     Quote_asset_volume = kline[7]
     Number_of_trades = kline[8]  
     Taker_buy_base_asset_volume = kline[9] 
     Taker_buy_quote_asset_volume = kline[10] 
     return Time,Open,High,Low,Close,Volume,Close_time,Quote_asset_volume,Number_of_trades,Taker_buy_base_asset_volume,Taker_buy_quote_asset_volume
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

start = "01 January, 2017"
end = "01 February, 2017"
symbols = ['ETHBTC']
interval = '1d'#Client.KLINE_INTERVAL_15MIN
for symbol in symbols:
    klines = get_historical_klines(symbol, interval, start, end)

    times = []
    Opens = []
    Highs = []
    Lows  = []
    Closes = [] 
    Volumes = []
    Close_times = []
    Quote_asset_volumes = []
    Number_of_tradess = []
    Taker_buy_base_asset_volumes = []
    Taker_buy_quote_asset_volumes = []
    for k in klines:
        Time,Open,High,Low,Close,Volume,Close_time,Quote_asset_volume,Number_of_trades,Taker_buy_base_asset_volume,Taker_buy_quote_asset_volume = GetUpdateData(k)
        times.append(Time)
        Opens.append(Open)
        Highs.append(High)
        Lows.append(Low)
        Closes.append(Close)
        Volumes.append(Volume)
        Close_times.append(Close_time)
        Quote_asset_volumes.append(Quote_asset_volume)
        Number_of_tradess.append(Number_of_trades)
        Taker_buy_base_asset_volumes.append(Taker_buy_base_asset_volume)
        Taker_buy_quote_asset_volumes.append(Taker_buy_quote_asset_volume)


    DataStruct = pd.DataFrame()
    DataStruct['time'] = times
    DataStruct['Open'] = Opens
    DataStruct['High'] = Highs
    DataStruct['Low'] = Lows
    DataStruct['Close'] = Closes
    DataStruct['Volume'] = Volumes
    DataStruct['Close_time'] = Close_times
    DataStruct['Quote_asset_volume'] = Quote_asset_volumes
    DataStruct['Number_of_trades'] = Number_of_tradess
    DataStruct['Taker_buy_base_asset_volume'] = Taker_buy_base_asset_volumes
    DataStruct['Taker_buy_quote_asset_volume'] = Taker_buy_quote_asset_volumes

    FileName = symbol+ '_' + start+ '_' + end + ' .csv'
    FileName = FileName.replace(' ','_')
    FileName = FileName.replace(',','')
    Path2Save = os.path.normpath(r'')
    SaveStrFile = os.path.normpath(Path2Save+ '\\' +FileName)
    #save FeatureWeights to CSV file
    D_S_header = ['time','Open','High','Low','Close','Volume','Close_time','Quote_asset_volume','Number_of_trades','Taker_buy_base_asset_volume','Taker_buy_quote_asset_volume']
    DataStruct.to_csv(path_or_buf = SaveStrFile, header = D_S_header )

Answer

jorijnsmit picture jorijnsmit · Apr 3, 2020

In these lines you see the timezone being defined:

# get epoch value in UTC
epoch = datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)

Just redefine the timezone there. For a list of timezones supported by pytz you can get a list using pytz.all_timezones.