diff --git a/Makefile b/Makefile index d1a2ed2..a128ff0 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ test: ## run tests quickly with the default Python py.test test-all: ## run tests on every Python version with tox - tox + tox $(PY_VERSION) coverage: ## check code coverage quickly with the default Python coverage run --source libcryptomarket -m pytest diff --git a/libcryptomarket/api/cryptocompare_api.py b/libcryptomarket/api/cryptocompare_api.py index 295a21a..524e241 100644 --- a/libcryptomarket/api/cryptocompare_api.py +++ b/libcryptomarket/api/cryptocompare_api.py @@ -3,6 +3,7 @@ import requests from datetime import datetime API_URL = "https://min-api.cryptocompare.com/data/" +MAX_QUERY_LIMIT = 2000 class CryptocompareCoinlist: diff --git a/libcryptomarket/historical.py b/libcryptomarket/historical.py index b0a6424..df25247 100644 --- a/libcryptomarket/historical.py +++ b/libcryptomarket/historical.py @@ -35,6 +35,10 @@ def get_historical_prices(source='cryptocompare', symbol=None, exchange=None, raise ValueError("Only accept input parameter limit, or from_time" " and to_time pair.") + if (from_time is None) ^ (to_time is None): + raise ValueError("Cannot accept either from_time or to_time is " + "None") + # Parse from (first 3) and to (last 3) symbol from the parameter # symbol. from_sym = symbol[:3] @@ -45,6 +49,7 @@ def get_historical_prices(source='cryptocompare', symbol=None, exchange=None, data = [] if limit > 0: + # Get the data by limit of records to_time = 0 while limit > 0: @@ -55,20 +60,40 @@ def get_historical_prices(source='cryptocompare', symbol=None, exchange=None, if len(response) == 0: # Terminate if no further response - limit = 0 + break else: data += response limit -= len(response) to_time = response[0]['time'] - 1 + elif from_time is not None and to_time is not None: + # Get the data by time range + from libcryptomarket.api.cryptocompare_api import MAX_QUERY_LIMIT + from_time_ts = int(from_time.timestamp()) + to_time_ts = int(to_time.timestamp()) + + while from_time_ts < to_time_ts: + response = func(limit=MAX_QUERY_LIMIT, + toTs=to_time_ts)['Data'] + + if len(response) == 0: + # Terminate if no further response + break + else: + data += response + to_time_ts = response[0]['time'] - 1 - elif from_time is not None or to_time is not None: - raise NotImplementedError() else: data += func()['Data'] data = pd.DataFrame([CryptocompareHisto(**e).__dict__ for e in data]) + # Filter only valid time range + if from_time is not None and to_time is not None: + data = data[(data['r_time'] >= from_time) & + (data['r_time'] <= to_time)] + data = data.set_index(['r_time']) data.index.name = 'datetime' + return data else: raise ValueError("No source is called {0}".format(source)) diff --git a/tests/test_cryptocompare_api.py b/tests/test_cryptocompare_api.py index dd74cdd..fb7a0eb 100644 --- a/tests/test_cryptocompare_api.py +++ b/tests/test_cryptocompare_api.py @@ -127,7 +127,7 @@ def test_get_historical_prices_cryptocompare(monkeypatch): 'volumeto': 0.2586 }] - } + } return MockReturnClass() @@ -139,7 +139,6 @@ def test_get_historical_prices_cryptocompare(monkeypatch): exchange='Poloniex', symbol='LTCBTC') - expected_result = pd.DataFrame([ { 'r_close': 0.007707, @@ -162,4 +161,4 @@ def test_get_historical_prices_cryptocompare(monkeypatch): }]).set_index(['r_time']) expected_result.index.name = 'datetime' - assert_frame_equal(result, expected_result) \ No newline at end of file + assert_frame_equal(result, expected_result)