Fix bug when fetching orders fails

This commit is contained in:
Matthias 2020-06-28 19:45:42 +02:00
parent 6362bfc36e
commit c6124180fe
5 changed files with 32 additions and 8 deletions

View File

@ -37,6 +37,13 @@ class InvalidOrderException(FreqtradeException):
"""
class RetryableOrderError(InvalidOrderException):
"""
This is returned when the order is not found.
This Error will be repeated with increasing backof (in line with DDosError).
"""
class ExchangeError(DependencyException):
"""
Error raised out of the exchange.

View File

@ -3,7 +3,8 @@ import logging
import time
from functools import wraps
from freqtrade.exceptions import DDosProtection, TemporaryError
from freqtrade.exceptions import (DDosProtection, RetryableOrderError,
TemporaryError)
logger = logging.getLogger(__name__)
@ -109,8 +110,8 @@ def retrier_async(f):
count -= 1
kwargs.update({'count': count})
logger.warning('retrying %s() still for %s times', f.__name__, count)
if isinstance(ex, DDosProtection):
await asyncio.sleep(1)
if isinstance(ex, DDosProtection) or isinstance(ex, RetryableOrderError):
await asyncio.sleep(calculate_backoff(count + 1, API_RETRY_COUNT))
return await wrapper(*args, **kwargs)
else:
logger.warning('Giving up retrying: %s()', f.__name__)
@ -125,14 +126,15 @@ def retrier(_func=None, retries=API_RETRY_COUNT):
count = kwargs.pop('count', retries)
try:
return f(*args, **kwargs)
except TemporaryError as ex:
except (TemporaryError, RetryableOrderError) as ex:
logger.warning('%s() returned exception: "%s"', f.__name__, ex)
if count > 0:
count -= 1
kwargs.update({'count': count})
logger.warning('retrying %s() still for %s times', f.__name__, count)
if isinstance(ex, DDosProtection):
time.sleep(calculate_backoff(count, retries))
if isinstance(ex, DDosProtection) or isinstance(ex, RetryableOrderError):
# increasing backoff
time.sleep(calculate_backoff(count + 1, retries))
return wrapper(*args, **kwargs)
else:
logger.warning('Giving up retrying: %s()', f.__name__)

View File

@ -22,7 +22,7 @@ from freqtrade.constants import ListPairsWithTimeframes
from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list
from freqtrade.exceptions import (DDosProtection, ExchangeError,
InvalidOrderException, OperationalException,
TemporaryError)
RetryableOrderError, TemporaryError)
from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async
from freqtrade.misc import deep_merge_dicts, safe_value_fallback
@ -1015,6 +1015,9 @@ class Exchange:
f'Tried to get an invalid dry-run-order (id: {order_id}). Message: {e}') from e
try:
return self._api.fetch_order(order_id, pair)
except ccxt.OrderNotFound as e:
raise RetryableOrderError(
f'Order not found (id: {order_id}). Message: {e}') from e
except ccxt.InvalidOrder as e:
raise InvalidOrderException(
f'Tried to get an invalid order (id: {order_id}). Message: {e}') from e

View File

@ -1888,6 +1888,18 @@ def test_fetch_order(default_conf, mocker, exchange_name):
exchange.fetch_order(order_id='_', pair='TKN/BTC')
assert api_mock.fetch_order.call_count == 1
api_mock.fetch_order = MagicMock(side_effect=ccxt.OrderNotFound("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
with patch('freqtrade.exchange.common.time.sleep') as tm:
with pytest.raises(InvalidOrderException):
exchange.fetch_order(order_id='_', pair='TKN/BTC')
# Ensure backoff is called
assert tm.call_args_list[0][0][0] == 1
assert tm.call_args_list[1][0][0] == 2
assert tm.call_args_list[2][0][0] == 5
assert tm.call_args_list[3][0][0] == 10
assert api_mock.fetch_order.call_count == API_RETRY_COUNT + 1
ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
'fetch_order', 'fetch_order',
order_id='_', pair='TKN/BTC')

View File

@ -2078,7 +2078,7 @@ def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_ord
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
fetch_ticker=ticker,
fetch_order=MagicMock(side_effect=DependencyException),
fetch_order=MagicMock(side_effect=ExchangeError),
cancel_order=cancel_order_mock,
get_fee=fee
)