From e040c518cac73e6ee1ad551757eef93407fc6fdc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jun 2020 16:18:39 +0200 Subject: [PATCH] Dynamic backoff on DDos errors --- freqtrade/exchange/common.py | 11 +++++++++-- tests/exchange/test_exchange.py | 14 +++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index d931e1789..b0f6b14e3 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -91,6 +91,13 @@ MAP_EXCHANGE_CHILDCLASS = { } +def calculate_backoff(retry, max_retries): + """ + Calculate backoff + """ + return retry ** 2 + 1 + + def retrier_async(f): async def wrapper(*args, **kwargs): count = kwargs.pop('count', API_RETRY_COUNT) @@ -125,13 +132,13 @@ def retrier(_func=None, retries=API_RETRY_COUNT): kwargs.update({'count': count}) logger.warning('retrying %s() still for %s times', f.__name__, count) if isinstance(ex, DDosProtection): - time.sleep(1) + time.sleep(calculate_backoff(count, retries)) return wrapper(*args, **kwargs) else: logger.warning('Giving up retrying: %s()', f.__name__) raise ex return wrapper - # Support both @retrier and @retrier() syntax + # Support both @retrier and @retrier(retries=2) syntax if _func is None: return decorator else: diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 64ea317aa..358452caf 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -14,7 +14,7 @@ from pandas import DataFrame from freqtrade.exceptions import (DependencyException, InvalidOrderException, DDosProtection, OperationalException, TemporaryError) from freqtrade.exchange import Binance, Exchange, Kraken -from freqtrade.exchange.common import API_RETRY_COUNT +from freqtrade.exchange.common import API_RETRY_COUNT, calculate_backoff from freqtrade.exchange.exchange import (market_is_active, symbol_is_pair, timeframe_to_minutes, timeframe_to_msecs, @@ -2296,3 +2296,15 @@ def test_calculate_fee_rate(mocker, default_conf, order, expected) -> None: ex = get_patched_exchange(mocker, default_conf) assert ex.calculate_fee_rate(order) == expected + + +@pytest.mark.parametrize('retry,max_retries,expected', [ + (0, 3, 1), + (1, 3, 2), + (2, 3, 5), + (3, 3, 10), + (0, 1, 1), + (1, 1, 2), +]) +def test_calculate_backoff(retry, max_retries, expected): + assert calculate_backoff(retry, max_retries) == expected