Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #722

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions binance/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import requests
import time
from operator import itemgetter
from .helpers import date_to_milliseconds, interval_to_milliseconds
from .helpers import date_to_milliseconds, interval_to_milliseconds, increment_month
from .exceptions import BinanceAPIException, BinanceRequestException, BinanceWithdrawException


Expand Down Expand Up @@ -831,7 +831,14 @@ def get_historical_klines(self, symbol, interval, start_str, end_str=None,
break

# increment next call by our timeframe
start_ts += timeframe
if interval == self.KLINE_INTERVAL_1MONTH:
start_ts = increment_month(start_ts)
else:
start_ts += timeframe

# check if end_ts is reached
if end_ts is not None and start_ts >= end_ts:
break

# sleep after every 3rd call to be kind to the API
if idx % 3 == 0:
Expand Down Expand Up @@ -912,7 +919,14 @@ def get_historical_klines_generator(self, symbol, interval, start_str, end_str=N
break

# increment next call by our timeframe
start_ts += timeframe
if interval == self.KLINE_INTERVAL_1MONTH:
start_ts = increment_month(start_ts)
else:
start_ts += timeframe

# check if end_ts is reached
if end_ts is not None and start_ts >= end_ts:
break

# sleep after every 3rd call to be kind to the API
if idx % 3 == 0:
Expand Down
18 changes: 18 additions & 0 deletions binance/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytz

from datetime import datetime
from dateutil.relativedelta import relativedelta


def date_to_milliseconds(date_str):
Expand Down Expand Up @@ -50,3 +51,20 @@ def interval_to_milliseconds(interval):
return int(interval[:-1]) * seconds_per_unit[interval[-1]] * 1000
except (ValueError, KeyError):
return None


def increment_month(origin_ts):
"""Increment a given timestamp by one month

:param origin_ts: original timestamp, e.g.: 1501545600000, 1504224000000, ...
:type origin_ts: int

:return:
Timestamp incremented by one month from a given timestamp
"""
d = datetime.fromtimestamp(origin_ts/1000) + relativedelta(months=1)
# 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 int(datetime.timestamp(d))
2 changes: 1 addition & 1 deletion docs/helpers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ Helper Functions
================

.. autoclass:: binance.helpers
:members: date_to_milliseconds, interval_to_milliseconds
:members: date_to_milliseconds, interval_to_milliseconds, increment_month
:noindex:
29 changes: 27 additions & 2 deletions examples/save_historical_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import json

from datetime import datetime

from dateutil.relativedelta import relativedelta
from binance.client import Client


Expand Down Expand Up @@ -57,6 +59,23 @@ def interval_to_milliseconds(interval):
return ms


def increment_month(origin_ts):
"""Increment a given timestamp by one month

:param origin_ts: original timestamp, e.g.: 1501545600000, 1504224000000, ...
:type origin_ts: int

:return:
Timestamp incremented by one month from a given timestamp
"""
d = datetime.fromtimestamp(origin_ts/1000) + relativedelta(months=1)
# 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 int(datetime.timestamp(d))


def get_historical_klines(symbol, interval, start_str, end_str=None):
"""Get Historical Klines from Binance

Expand Down Expand Up @@ -118,10 +137,16 @@ def get_historical_klines(symbol, interval, start_str, end_str=None):
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
if interval == Client.KLINE_INTERVAL_1MONTH:
start_ts = increment_month(temp_data[len(temp_data) - 1][0])
else:
start_ts = temp_data[len(temp_data) - 1][0] + timeframe
else:
# it wasn't listed yet, increment our start date
start_ts += timeframe
if interval == Client.KLINE_INTERVAL_1MONTH:
start_ts = increment_month(start_ts)
else:
start_ts += timeframe

idx += 1
# check if we received less than the required limit and exit the loop
Expand Down
117 changes: 117 additions & 0 deletions tests/test_historical_klines.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,120 @@ def test_historical_kline_generator_empty_response():

with pytest.raises(StopIteration):
next(klines)


def test_historical_kline_with_month_interval():
"""Test historical klines with one month interval"""

first_available_res = [
[
1498867200000,
"0.00005000",
"0.00005480",
"0.00001000",
"0.00003654",
"61059068.00000000",
1501545599999,
"2572.23205388",
33297,
"33906053.00000000",
"1442.17447471",
"100206524.84393587"
]
]
first_res = []
row = [
1519862400000,
"0.00101270",
"0.00167650",
"0.00083250",
"0.00159650",
"122814213.69000000",
1522540799999,
"142681.39725065",
3242765,
"68994444.35000000",
"79545.22096745",
"0"
]

for i in range(0, 8):
first_res.append(row)

with requests_mock.mock() as m:
m.get(
"https://api.binance.com/api/v1/klines?interval=1M&limit=1&startTime=0&symbol=BNBBTC",
json=first_available_res,
)
m.get(
"https://api.binance.com/api/v1/klines?interval=1M&limit=500&startTime=1519862400000&endTime=1539234000000&symbol=BNBBTC",
json=first_res,
)
klines = client.get_historical_klines(
symbol="BNBBTC",
interval=Client.KLINE_INTERVAL_1MONTH,
start_str="1st March 2018",
end_str="11st Oct 2018 05:00:00",
)
assert len(klines) == 8


def test_historical_kline_generator_with_month_interval():
"""Test historical klines generator with one month interval"""

first_available_res = [
[
1498867200000,
"0.00005000",
"0.00005480",
"0.00001000",
"0.00003654",
"61059068.00000000",
1501545599999,
"2572.23205388",
33297,
"33906053.00000000",
"1442.17447471",
"100206524.84393587"
]
]
first_res = []
row = [
1519862400000,
"0.00101270",
"0.00167650",
"0.00083250",
"0.00159650",
"122814213.69000000",
1522540799999,
"142681.39725065",
3242765,
"68994444.35000000",
"79545.22096745",
"0"
]

for i in range(0, 8):
first_res.append(row)

with requests_mock.mock() as m:
m.get(
"https://api.binance.com/api/v1/klines?interval=1M&limit=1&startTime=0&symbol=BNBBTC",
json=first_available_res,
)
m.get(
"https://api.binance.com/api/v1/klines?interval=1M&limit=500&startTime=1519862400000&endTime=1539234000000&symbol=BNBBTC",
json=first_res,
)
klines = client.get_historical_klines_generator(
symbol="BNBBTC",
interval=Client.KLINE_INTERVAL_1MONTH,
start_str=1519862400000,
end_str=1539234000000,
)

for i in range(8):
assert len(next(klines)) > 0

with pytest.raises(StopIteration):
next(klines)