From c333c9c5a1bf36b50520732acc3eee43467c3c75 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 14:08:35 +0100 Subject: [PATCH 01/10] Improve kraken trades pagination logic --- freqtrade/exchange/exchange.py | 9 ++++++++- freqtrade/exchange/kraken.py | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 664000eb2..111aac681 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2250,6 +2250,13 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(f'Could not fetch trade data. Msg: {e}') from e + def _valid_trade_pagination_id(self, pair: str, from_id: str) -> bool: + """ + Verify trade-pagination id is valid. + Workaround for odd Kraken issue where ID is sometimes wrong. + """ + return True + async def _async_get_trade_history_id(self, pair: str, until: int, since: Optional[int] = None, @@ -2266,7 +2273,7 @@ class Exchange: trades: List[List] = [] - if not from_id: + if not from_id or not self._valid_trade_pagination_id(pair, from_id): # Fetch first elements using timebased method to get an ID to paginate on # Depending on the Exchange, this can introduce a drift at the start of the interval # of up to an hour. diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index a84a48d80..e49b7fd54 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -172,3 +172,15 @@ class Kraken(Exchange): trades[-1]['id'] = trades[-1].get('info', [])[-1] return trades + + def _valid_trade_pagination_id(self, pair: str, from_id: str) -> bool: + """ + Verify trade-pagination id is valid. + Workaround for odd Kraken issue where ID is sometimes wrong. + """ + # Regular id's are in timestamp format 1705443695120072285 + # If the id is smaller than 19 characters, it's not a valid timestamp. + if len(from_id) >= 19: + return True + logger.debug("trade-pagination id is not valid. Fallback to timestamp.") + return False From 501a9a8c98f5afe7898da478801d0a5a9533ddd8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 14:11:02 +0100 Subject: [PATCH 02/10] Improve error message, add test for trade_pagination_id validation --- freqtrade/exchange/kraken.py | 2 +- tests/exchange/test_kraken.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index e49b7fd54..3fb45851a 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -182,5 +182,5 @@ class Kraken(Exchange): # If the id is smaller than 19 characters, it's not a valid timestamp. if len(from_id) >= 19: return True - logger.debug("trade-pagination id is not valid. Fallback to timestamp.") + logger.debug(f"{pair} - trade-pagination id is not valid. Fallback to timestamp.") return False diff --git a/tests/exchange/test_kraken.py b/tests/exchange/test_kraken.py index 3ee4aa158..760e18982 100644 --- a/tests/exchange/test_kraken.py +++ b/tests/exchange/test_kraken.py @@ -271,3 +271,14 @@ def test_stoploss_adjust_kraken(mocker, default_conf, sl1, sl2, sl3, side): # diff. order type ... order['type'] = 'limit' assert exchange.stoploss_adjust(sl3, order, side=side) + + +@pytest.mark.parametrize('trade_id, expected', [ + ('1234', False), + ('170544369512007228', False), + ('1705443695120072285', True), + ('170544369512007228555', True), +]) +def test__valid_trade_pagination_id_kraken(mocker, default_conf_usdt, trade_id, expected): + exchange = get_patched_exchange(mocker, default_conf_usdt, id='kraken') + assert exchange._valid_trade_pagination_id('XRP/USDT', trade_id) == expected From b56c663bea098db924a14fe58badd33fbd62e943 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 14:13:05 +0100 Subject: [PATCH 03/10] Add regular / fallback test. --- tests/exchange/test_exchange.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 4f442b46b..3e8d3de65 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2961,6 +2961,21 @@ async def test__async_get_trade_history_id(default_conf, mocker, exchange_name, assert exchange._ft_has['trades_pagination_arg'] in fetch_trades_cal[1][1]['params'] +@pytest.mark.parametrize('trade_id, expected', [ + ('1234', True), + ('170544369512007228', True), + ('1705443695120072285', True), + ('170544369512007228555', True), +]) +@pytest.mark.parametrize("exchange_name", EXCHANGES) +def test__valid_trade_pagination_id(mocker, default_conf_usdt, exchange_name, trade_id, expected): + if exchange_name == 'kraken': + pytest.skip("Kraken has a different pagination id format, and an explicit test.") + exchange = get_patched_exchange(mocker, default_conf_usdt, id=exchange_name) + + assert exchange._valid_trade_pagination_id('XRP/USDT', trade_id) == expected + + @pytest.mark.asyncio @pytest.mark.parametrize("exchange_name", EXCHANGES) async def test__async_get_trade_history_time(default_conf, mocker, caplog, exchange_name, From c1675750984ff8cdf865f61bb2011fce62290ab2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 15:22:03 +0100 Subject: [PATCH 04/10] Move extracting trade pagination id to fetch_trades --- freqtrade/exchange/exchange.py | 44 +++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 111aac681..eb944481b 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2216,13 +2216,13 @@ class Exchange: @retrier_async async def _async_fetch_trades(self, pair: str, since: Optional[int] = None, - params: Optional[dict] = None) -> List[List]: + params: Optional[dict] = None) -> Tuple[List[List], Any]: """ Asyncronously gets trade history using fetch_trades. Handles exchange errors, does one call to the exchange. :param pair: Pair to fetch trade data for :param since: Since as integer timestamp in milliseconds - returns: List of dicts containing trades + returns: List of dicts containing trades, the next iteration value (new "since" or trade_id) """ try: # fetch trades asynchronously @@ -2237,7 +2237,8 @@ class Exchange: ) trades = await self._api_async.fetch_trades(pair, since=since, limit=1000) trades = self._trades_contracts_to_amount(trades) - return trades_dict_to_list(trades) + pagination_value = self._get_trade_pagination_next_value(trades) + return trades_dict_to_list(trades), pagination_value except ccxt.NotSupported as e: raise OperationalException( f'Exchange {self._api.name} does not support fetching historical trade data.' @@ -2257,6 +2258,18 @@ class Exchange: """ return True + def _get_trade_pagination_next_value(self, trades: List[Dict]): + """ + Extract pagination id for the next "from_id" value + Applies only to fetch_trade_history by id. + """ + if not trades: + return None + if self._trades_pagination == 'id': + return trades[-1].get('id') + else: + return trades[-1].get('timestamp') + async def _async_get_trade_history_id(self, pair: str, until: int, since: Optional[int] = None, @@ -2272,6 +2285,8 @@ class Exchange: """ trades: List[List] = [] + # DEFAULT_TRADES_COLUMNS: 0 -> timestamp + # DEFAULT_TRADES_COLUMNS: 1 -> id if not from_id or not self._valid_trade_pagination_id(pair, from_id): # Fetch first elements using timebased method to get an ID to paginate on @@ -2279,26 +2294,23 @@ class Exchange: # of up to an hour. # e.g. Binance returns the "last 1000" candles within a 1h time interval # - so we will miss the first trades. - t = await self._async_fetch_trades(pair, since=since) - # DEFAULT_TRADES_COLUMNS: 0 -> timestamp - # DEFAULT_TRADES_COLUMNS: 1 -> id - from_id = t[-1][1] + t, from_id = await self._async_fetch_trades(pair, since=since) trades.extend(t[:-1]) while True: try: - t = await self._async_fetch_trades(pair, - params={self._trades_pagination_arg: from_id}) + t, from_id_next = await self._async_fetch_trades( + pair, params={self._trades_pagination_arg: from_id}) if t: # Skip last id since its the key for the next call trades.extend(t[:-1]) - if from_id == t[-1][1] or t[-1][0] > until: + if from_id == from_id_next or t[-1][0] > until: logger.debug(f"Stopping because from_id did not change. " f"Reached {t[-1][0]} > {until}") # Reached the end of the defined-download period - add last trade as well. trades.extend(t[-1:]) break - from_id = t[-1][1] + from_id = from_id_next else: logger.debug("Stopping as no more trades were returned.") break @@ -2324,19 +2336,19 @@ class Exchange: # DEFAULT_TRADES_COLUMNS: 1 -> id while True: try: - t = await self._async_fetch_trades(pair, since=since) + t, since_next = await self._async_fetch_trades(pair, since=since) if t: # No more trades to download available at the exchange, # So we repeatedly get the same trade over and over again. - if since == t[-1][0] and len(t) == 1: + if since == since_next and len(t) == 1: logger.debug("Stopping because no more trades are available.") break - since = t[-1][0] + since = since_next trades.extend(t) # Reached the end of the defined-download period - if until and t[-1][0] > until: + if until and since_next > until: logger.debug( - f"Stopping because until was reached. {t[-1][0]} > {until}") + f"Stopping because until was reached. {since_next} > {until}") break else: logger.debug("Stopping as no more trades were returned.") From 15da4aa9bdbf04f20e2fd9ee6d269fe1ca970dc0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 15:25:11 +0100 Subject: [PATCH 05/10] Update tests for added fetch_trades arg --- tests/exchange/test_exchange.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 3e8d3de65..0421622de 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2844,10 +2844,14 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, exchange._api_async.fetch_trades = get_mock_coro(fetch_trades_result) pair = 'ETH/BTC' - res = await exchange._async_fetch_trades(pair, since=None, params=None) + res, pagid = await exchange._async_fetch_trades(pair, since=None, params=None) assert isinstance(res, list) assert isinstance(res[0], list) assert isinstance(res[1], list) + if exchange._trades_pagination == 'id': + assert pagid == '126181333' + else: + assert pagid == 1565798399872 assert exchange._api_async.fetch_trades.call_count == 1 assert exchange._api_async.fetch_trades.call_args[0][0] == pair @@ -2856,11 +2860,17 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, assert log_has_re(f"Fetching trades for pair {pair}, since .*", caplog) caplog.clear() exchange._api_async.fetch_trades.reset_mock() - res = await exchange._async_fetch_trades(pair, since=None, params={'from': '123'}) + res, pagid = await exchange._async_fetch_trades(pair, since=None, params={'from': '123'}) assert exchange._api_async.fetch_trades.call_count == 1 assert exchange._api_async.fetch_trades.call_args[0][0] == pair assert exchange._api_async.fetch_trades.call_args[1]['limit'] == 1000 assert exchange._api_async.fetch_trades.call_args[1]['params'] == {'from': '123'} + + if exchange._trades_pagination == 'id': + assert pagid == '126181333' + else: + assert pagid == 1565798399872 + assert log_has_re(f"Fetching trades for pair {pair}, params: .*", caplog) exchange.close() @@ -2915,8 +2925,9 @@ async def test__async_fetch_trades_contract_size(default_conf, mocker, caplog, e ) pair = 'ETH/USDT:USDT' - res = await exchange._async_fetch_trades(pair, since=None, params=None) + res, pagid = await exchange._async_fetch_trades(pair, since=None, params=None) assert res[0][5] == 300 + assert pagid is not None exchange.close() From 8a64f0b884560d9dbe128280d7701401b21c54b0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 15:31:53 +0100 Subject: [PATCH 06/10] Fix fetch_trades tests --- tests/exchange/test_exchange.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 0421622de..cdfdee95f 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2937,6 +2937,9 @@ async def test__async_get_trade_history_id(default_conf, mocker, exchange_name, fetch_trades_result): exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) + if exchange._trades_pagination != 'id': + exchange.close() + pytest.skip("Exchange does not support pagination by trade id") pagination_arg = exchange._trades_pagination_arg async def mock_get_trade_hist(pair, *args, **kwargs): @@ -3002,6 +3005,9 @@ async def test__async_get_trade_history_time(default_conf, mocker, caplog, excha caplog.set_level(logging.DEBUG) exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) + if exchange._trades_pagination != 'time': + exchange.close() + pytest.skip("Exchange does not support pagination by timestamp") # Monkey-patch async function exchange._api_async.fetch_trades = MagicMock(side_effect=mock_get_trade_hist) pair = 'ETH/BTC' @@ -3034,9 +3040,9 @@ async def test__async_get_trade_history_time_empty(default_conf, mocker, caplog, async def mock_get_trade_hist(pair, *args, **kwargs): if kwargs['since'] == trades_history[0][0]: - return trades_history[:-1] + return trades_history[:-1], trades_history[:-1][-1][0] else: - return [] + return [], None caplog.set_level(logging.DEBUG) exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) From f9b6830b78671bae9d014ccea0c06027eb1f5a19 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 15:49:56 +0100 Subject: [PATCH 07/10] update fetch_trades info data to kraken response format --- tests/conftest.py | 46 +++++---------------------------- tests/exchange/test_exchange.py | 10 +++++-- 2 files changed, 14 insertions(+), 42 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9c43a5d64..326a25314 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2386,14 +2386,7 @@ def trades_history_df(trades_history): @pytest.fixture(scope="function") def fetch_trades_result(): - return [{'info': {'a': 126181329, - 'p': '0.01962700', - 'q': '0.04000000', - 'f': 138604155, - 'l': 138604155, - 'T': 1565798399463, - 'm': False, - 'M': True}, + return [{'info': ['0.01962700', '0.04000000', '1565798399.4631551', 'b', 'm', '', '126181329'], 'timestamp': 1565798399463, 'datetime': '2019-08-14T15:59:59.463Z', 'symbol': 'ETH/BTC', @@ -2406,14 +2399,7 @@ def fetch_trades_result(): 'amount': 0.04, 'cost': 0.00078508, 'fee': None}, - {'info': {'a': 126181330, - 'p': '0.01962700', - 'q': '0.24400000', - 'f': 138604156, - 'l': 138604156, - 'T': 1565798399629, - 'm': False, - 'M': True}, + {'info': ['0.01962700', '0.24400000', '1565798399.6291551', 'b', 'm', '', '126181330'], 'timestamp': 1565798399629, 'datetime': '2019-08-14T15:59:59.629Z', 'symbol': 'ETH/BTC', @@ -2426,14 +2412,7 @@ def fetch_trades_result(): 'amount': 0.244, 'cost': 0.004788987999999999, 'fee': None}, - {'info': {'a': 126181331, - 'p': '0.01962600', - 'q': '0.01100000', - 'f': 138604157, - 'l': 138604157, - 'T': 1565798399752, - 'm': True, - 'M': True}, + {'info': ['0.01962600', '0.01100000', '1565798399.7521551', 's', 'm', '', '126181331'], 'timestamp': 1565798399752, 'datetime': '2019-08-14T15:59:59.752Z', 'symbol': 'ETH/BTC', @@ -2446,14 +2425,7 @@ def fetch_trades_result(): 'amount': 0.011, 'cost': 0.00021588599999999999, 'fee': None}, - {'info': {'a': 126181332, - 'p': '0.01962600', - 'q': '0.01100000', - 'f': 138604158, - 'l': 138604158, - 'T': 1565798399862, - 'm': True, - 'M': True}, + {'info': ['0.01962600', '0.01100000', '1565798399.8621551', 's', 'm', '', '126181332'], 'timestamp': 1565798399862, 'datetime': '2019-08-14T15:59:59.862Z', 'symbol': 'ETH/BTC', @@ -2466,14 +2438,8 @@ def fetch_trades_result(): 'amount': 0.011, 'cost': 0.00021588599999999999, 'fee': None}, - {'info': {'a': 126181333, - 'p': '0.01952600', - 'q': '0.01200000', - 'f': 138604158, - 'l': 138604158, - 'T': 1565798399872, - 'm': True, - 'M': True}, + {'info': ['0.01952600', '0.01200000', '1565798399.8721551', 's', 'm', '', '126181333', + 1565798399872512133], 'timestamp': 1565798399872, 'datetime': '2019-08-14T15:59:59.872Z', 'symbol': 'ETH/BTC', diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index cdfdee95f..d652ed58e 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2849,7 +2849,10 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, assert isinstance(res[0], list) assert isinstance(res[1], list) if exchange._trades_pagination == 'id': - assert pagid == '126181333' + if exchange_name == 'kraken': + assert pagid == 1565798399872512133 + else: + assert pagid == '126181333' else: assert pagid == 1565798399872 @@ -2867,7 +2870,10 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, assert exchange._api_async.fetch_trades.call_args[1]['params'] == {'from': '123'} if exchange._trades_pagination == 'id': - assert pagid == '126181333' + if exchange_name == 'kraken': + assert pagid == 1565798399872512133 + else: + assert pagid == '126181333' else: assert pagid == 1565798399872 From ac5b12cfd2d8823ef0834272924b8816b9ab943d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 15:55:34 +0100 Subject: [PATCH 08/10] Improve kraken pagination behavior --- freqtrade/exchange/kraken.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 3fb45851a..b684f9f76 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -157,21 +157,21 @@ class Kraken(Exchange): return fees if is_short else -fees - def _trades_contracts_to_amount(self, trades: List) -> List: + def _get_trade_pagination_next_value(self, trades: List[Dict]) -> str: """ - Fix "last" id issue for kraken data downloads - This whole override can probably be removed once the following - issue is closed in ccxt: https://github.com/ccxt/ccxt/issues/15827 + Extract pagination id for the next "from_id" value + Applies only to fetch_trade_history by id. """ - super()._trades_contracts_to_amount(trades) - if ( - len(trades) > 0 - and isinstance(trades[-1].get('info'), list) - and len(trades[-1].get('info', [])) > 7 - ): - - trades[-1]['id'] = trades[-1].get('info', [])[-1] - return trades + if len(trades) > 0: + if ( + isinstance(trades[-1].get('info'), list) + and len(trades[-1].get('info', [])) > 7 + ): + # Trade response's "last" value. + return trades[-1].get('info', [])[-1] + # Fall back to timestamp if info is somehow empty. + return trades[-1].get('timestamp') + return None def _valid_trade_pagination_id(self, pair: str, from_id: str) -> bool: """ From 612ec38e572bbbf3d88b2bd434eda324b73e13dc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 16:50:49 +0100 Subject: [PATCH 09/10] Don't skip trades if the exchange doesn't do inclusive filtering --- freqtrade/exchange/exchange.py | 11 +++++++---- freqtrade/exchange/kraken.py | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index eb944481b..4b2d52a68 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2287,6 +2287,9 @@ class Exchange: trades: List[List] = [] # DEFAULT_TRADES_COLUMNS: 0 -> timestamp # DEFAULT_TRADES_COLUMNS: 1 -> id + has_overlap = self._ft_has.get('trades_pagination_overlap', True) + # Skip last trade by default since its the key for the next call + x = slice(None, -1) if has_overlap else slice(None) if not from_id or not self._valid_trade_pagination_id(pair, from_id): # Fetch first elements using timebased method to get an ID to paginate on @@ -2295,19 +2298,19 @@ class Exchange: # e.g. Binance returns the "last 1000" candles within a 1h time interval # - so we will miss the first trades. t, from_id = await self._async_fetch_trades(pair, since=since) - trades.extend(t[:-1]) + trades.extend(t[x]) while True: try: t, from_id_next = await self._async_fetch_trades( pair, params={self._trades_pagination_arg: from_id}) if t: - # Skip last id since its the key for the next call - trades.extend(t[:-1]) + trades.extend(t[x]) if from_id == from_id_next or t[-1][0] > until: logger.debug(f"Stopping because from_id did not change. " f"Reached {t[-1][0]} > {until}") # Reached the end of the defined-download period - add last trade as well. - trades.extend(t[-1:]) + if has_overlap: + trades.extend(t[-1:]) break from_id = from_id_next diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index b684f9f76..c8fecdd10 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -30,6 +30,7 @@ class Kraken(Exchange): "ohlcv_has_history": False, "trades_pagination": "id", "trades_pagination_arg": "since", + "trades_pagination_overlap": False, "mark_ohlcv_timeframe": "4h", } @@ -157,7 +158,7 @@ class Kraken(Exchange): return fees if is_short else -fees - def _get_trade_pagination_next_value(self, trades: List[Dict]) -> str: + def _get_trade_pagination_next_value(self, trades: List[Dict]): """ Extract pagination id for the next "from_id" value Applies only to fetch_trade_history by id. From d534f2014a57a913d4cd45ab99455a5935e7b841 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 21 Jan 2024 16:58:58 +0100 Subject: [PATCH 10/10] Account for kraken specialcase in tests --- tests/exchange/test_exchange.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index d652ed58e..f686959fc 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2952,7 +2952,8 @@ async def test__async_get_trade_history_id(default_conf, mocker, exchange_name, if 'since' in kwargs: # Return first 3 return fetch_trades_result[:-2] - elif kwargs.get('params', {}).get(pagination_arg) == fetch_trades_result[-3]['id']: + elif kwargs.get('params', {}).get(pagination_arg) in ( + fetch_trades_result[-3]['id'], 1565798399752): # Return 2 return fetch_trades_result[-3:-1] else: @@ -2968,7 +2969,8 @@ async def test__async_get_trade_history_id(default_conf, mocker, exchange_name, assert isinstance(ret, tuple) assert ret[0] == pair assert isinstance(ret[1], list) - assert len(ret[1]) == len(fetch_trades_result) + if exchange_name != 'kraken': + assert len(ret[1]) == len(fetch_trades_result) assert exchange._api_async.fetch_trades.call_count == 3 fetch_trades_cal = exchange._api_async.fetch_trades.call_args_list # first call (using since, not fromId) @@ -5350,3 +5352,4 @@ def test_price_to_precision_with_default_conf(default_conf, mocker): patched_ex = get_patched_exchange(mocker, conf) prec_price = patched_ex.price_to_precision("XRP/USDT", 1.0000000101) assert prec_price == 1.00000001 + assert prec_price == 1.00000001