diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 90a33a226..e0e4d7723 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -556,12 +556,17 @@ class Exchange(object): tickers = await asyncio.gather(*input_coroutines, return_exceptions=True) # handle caching - for pair, ticks in tickers: + for res in tickers: + if isinstance(res, Exception): + logger.warning("Async code raised an exception: %s", res.__class__.__name__) + continue + pair = res[0] + ticks = res[1] # keeping last candle time as last refreshed time of the pair if ticks: self._pairs_last_refresh_time[pair] = ticks[-1][0] // 1000 - # keeping parsed dataframe in cache - self._klines[pair] = parse_ticker_dataframe(ticks, tick_interval, fill_missing=True) + # keeping parsed dataframe in cache + self._klines[pair] = parse_ticker_dataframe(ticks, tick_interval, fill_missing=True) return tickers @retrier_async @@ -578,9 +583,12 @@ class Exchange(object): # Ex: Bittrex returns a list of tickers ASC (oldest first, newest last) # when GDAX returns a list of tickers DESC (newest first, oldest last) # Only sort if necessary to save computing time - if data and data[0][0] > data[-1][0]: - data = sorted(data, key=lambda x: x[0]) - + try: + if data and data[0][0] > data[-1][0]: + data = sorted(data, key=lambda x: x[0]) + except IndexError: + logger.exception("Error loading %s. Result was %s.", pair, data) + return pair, [] logger.debug("done fetching %s ...", pair) return pair, data diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 29154bc39..26808e78a 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -923,6 +923,30 @@ async def test_async_get_candles_history(default_conf, mocker): assert exchange._async_get_candle_history.call_count == 2 +@pytest.mark.asyncio +async def test_async_get_candles_history_inv_result(default_conf, mocker, caplog): + + async def mock_get_candle_hist(pair, *args, **kwargs): + if pair == 'ETH/BTC': + return [[]] + else: + raise TypeError() + + exchange = get_patched_exchange(mocker, default_conf) + + # Monkey-patch async function with empty result + exchange._api_async.fetch_ohlcv = MagicMock(side_effect=mock_get_candle_hist) + + pairs = ['ETH/BTC', 'XRP/BTC'] + res = await exchange.async_get_candles_history(pairs, "5m") + assert type(res) is list + assert len(res) == 2 + assert type(res[0]) is tuple + assert type(res[1]) is TypeError + assert log_has("Error loading ETH/BTC. Result was [[]].", caplog.record_tuples) + assert log_has("Async code raised an exception: TypeError", caplog.record_tuples) + + def test_get_order_book(default_conf, mocker, order_book_l2): default_conf['exchange']['name'] = 'binance' api_mock = MagicMock()