prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [Kucoin] {"code":"429000","msg":"Too Many Requests"}. Able to ignore this error and prevent DDOS protection?
  <!-- 
  Have you searched for similar issues before posting it?
  
  If you have discovered a bug in the bot, please [search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue). 
  If it hasn't been reported, please create a new issue.
  
  Please do not use bug reports to request new features.
  -->
  
  ## Describe your environment
  
    * Operating system: Canonical Ubuntu
    * Python Version: 
    * CCXT version: 1.56.86
    * Freqtrade Version: 
    
  Note: All issues other than enhancement requests will be closed without further comment if the above template is deleted or not filled out.
  
  ## Describe the problem:
  
  {"code":"429000","msg":"Too Many Requests"} error triggering DDOS protection delay. 
  
  ### Steps to reproduce:
  Randomly effect pairs on Kucoin
  
  ### Observed Results:
  
  DDOS protection triggering when it doesn't need to which may cause unintended and financially ruinous behavior in the bot. 
  
  Admin on telegram says we can retry the request instantly without fear of DDOS protection triggering. 
  
  ![image](https://user-images.githubusercontent.com/15849763/136735376-37c1bcb2-d49a-4ca5-b314-1d4a1f2a9eed.png)
  
  
  
  
  ### Relevant code exceptions or logs
  
  freqtrade    | 2021-10-11 04:55:04,274 - freqtrade.exchange.common - WARNING - _async_get_candle_history() returned exception: "kucoin GET https://openapi-v2.kucoin.com/api/v1/market/candles?symbol=DYDX-USDT&type=5min&startAt=1633778101&endAt=1633928101 429 Too Many Requests {"code":"429000","msg":"Too Many Requests"}"
  freqtrade    | 2021-10-11 04:55:04,275 - freqtrade.exchange.common - WARNING - retrying _async_get_candle_history() still for 4 times
  freqtrade    | 2021-10-11 04:55:04,275 - freqtrade.exchange.common - INFO - Applying DDosProtection backoff delay: 1
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `freqtrade/exchange/common.py`
  Content:
  ```
  1 import asyncio
  2 import logging
  3 import time
  4 from functools import wraps
  5 
  6 from freqtrade.exceptions import DDosProtection, RetryableOrderError, TemporaryError
  7 
  8 
  9 logger = logging.getLogger(__name__)
  10 
  11 
  12 # Maximum default retry count.
  13 # Functions are always called RETRY_COUNT + 1 times (for the original call)
  14 API_RETRY_COUNT = 4
  15 API_FETCH_ORDER_RETRY_COUNT = 5
  16 
  17 BAD_EXCHANGES = {
  18     "bitmex": "Various reasons.",
  19     "phemex": "Does not provide history. ",
  20     "poloniex": "Does not provide fetch_order endpoint to fetch both open and closed orders.",
  21 }
  22 
  23 MAP_EXCHANGE_CHILDCLASS = {
  24     'binanceus': 'binance',
  25     'binanceje': 'binance',
  26 }
  27 
  28 
  29 EXCHANGE_HAS_REQUIRED = [
  30     # Required / private
  31     'fetchOrder',
  32     'cancelOrder',
  33     'createOrder',
  34     # 'createLimitOrder', 'createMarketOrder',
  35     'fetchBalance',
  36 
  37     # Public endpoints
  38     'loadMarkets',
  39     'fetchOHLCV',
  40 ]
  41 
  42 EXCHANGE_HAS_OPTIONAL = [
  43     # Private
  44     'fetchMyTrades',  # Trades for order - fee detection
  45     # Public
  46     'fetchOrderBook', 'fetchL2OrderBook', 'fetchTicker',  # OR for pricing
  47     'fetchTickers',  # For volumepairlist?
  48     'fetchTrades',  # Downloading trades data
  49 ]
  50 
  51 
  52 def remove_credentials(config) -> None:
  53     """
  54     Removes exchange keys from the configuration and specifies dry-run
  55     Used for backtesting / hyperopt / edge and utils.
  56     Modifies the input dict!
  57     """
  58     if config.get('dry_run', False):
  59         config['exchange']['key'] = ''
  60         config['exchange']['secret'] = ''
  61         config['exchange']['password'] = ''
  62         config['exchange']['uid'] = ''
  63 
  64 
  65 def calculate_backoff(retrycount, max_retries):
  66     """
  67     Calculate backoff
  68     """
  69     return (max_retries - retrycount) ** 2 + 1
  70 
  71 
  72 def retrier_async(f):
  73     async def wrapper(*args, **kwargs):
  74         count = kwargs.pop('count', API_RETRY_COUNT)
  75         try:
  76             return await f(*args, **kwargs)
  77         except TemporaryError as ex:
  78             logger.warning('%s() returned exception: "%s"', f.__name__, ex)
  79             if count > 0:
  80                 logger.warning('retrying %s() still for %s times', f.__name__, count)
  81                 count -= 1
  82                 kwargs.update({'count': count})
  83                 if isinstance(ex, DDosProtection):
  84                     backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)
  85                     logger.info(f"Applying DDosProtection backoff delay: {backoff_delay}")
  86                     await asyncio.sleep(backoff_delay)
  87                 return await wrapper(*args, **kwargs)
  88             else:
  89                 logger.warning('Giving up retrying: %s()', f.__name__)
  90                 raise ex
  91     return wrapper
  92 
  93 
  94 def retrier(_func=None, retries=API_RETRY_COUNT):
  95     def decorator(f):
  96         @wraps(f)
  97         def wrapper(*args, **kwargs):
  98             count = kwargs.pop('count', retries)
  99             try:
  100                 return f(*args, **kwargs)
  101             except (TemporaryError, RetryableOrderError) as ex:
  102                 logger.warning('%s() returned exception: "%s"', f.__name__, ex)
  103                 if count > 0:
  104                     logger.warning('retrying %s() still for %s times', f.__name__, count)
  105                     count -= 1
  106                     kwargs.update({'count': count})
  107                     if isinstance(ex, (DDosProtection, RetryableOrderError)):
  108                         # increasing backoff
  109                         backoff_delay = calculate_backoff(count + 1, retries)
  110                         logger.info(f"Applying DDosProtection backoff delay: {backoff_delay}")
  111                         time.sleep(backoff_delay)
  112                     return wrapper(*args, **kwargs)
  113                 else:
  114                     logger.warning('Giving up retrying: %s()', f.__name__)
  115                     raise ex
  116         return wrapper
  117     # Support both @retrier and @retrier(retries=2) syntax
  118     if _func is None:
  119         return decorator
  120     else:
  121         return decorator(_func)
  122
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py
  --- a/freqtrade/exchange/common.py
  +++ b/freqtrade/exchange/common.py
  @@ -81,9 +81,16 @@
                   count -= 1
                   kwargs.update({'count': count})
                   if isinstance(ex, DDosProtection):
  -                    backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)
  -                    logger.info(f"Applying DDosProtection backoff delay: {backoff_delay}")
  -                    await asyncio.sleep(backoff_delay)
  +                    if "kucoin" in str(ex) and "429000" in str(ex):
  +                        # Temporary fix for 429000 error on kucoin
  +                        # see https://github.com/freqtrade/freqtrade/issues/5700 for details.
  +                        logger.warning(
  +                            f"Kucoin 429 error, avoid triggering DDosProtection backoff delay. "
  +                            f"{count} tries left before giving up")
  +                    else:
  +                        backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)
  +                        logger.info(f"Applying DDosProtection backoff delay: {backoff_delay}")
  +                        await asyncio.sleep(backoff_delay)
                   return await wrapper(*args, **kwargs)
               else:
                   logger.warning('Giving up retrying: %s()', f.__name__)
  
verification_info: {"golden_diff": "diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py\n--- a/freqtrade/exchange/common.py\n+++ b/freqtrade/exchange/common.py\n@@ -81,9 +81,16 @@\n                 count -= 1\n                 kwargs.update({'count': count})\n                 if isinstance(ex, DDosProtection):\n-                    backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)\n-                    logger.info(f\"Applying DDosProtection backoff delay: {backoff_delay}\")\n-                    await asyncio.sleep(backoff_delay)\n+                    if \"kucoin\" in str(ex) and \"429000\" in str(ex):\n+                        # Temporary fix for 429000 error on kucoin\n+                        # see https://github.com/freqtrade/freqtrade/issues/5700 for details.\n+                        logger.warning(\n+                            f\"Kucoin 429 error, avoid triggering DDosProtection backoff delay. \"\n+                            f\"{count} tries left before giving up\")\n+                    else:\n+                        backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)\n+                        logger.info(f\"Applying DDosProtection backoff delay: {backoff_delay}\")\n+                        await asyncio.sleep(backoff_delay)\n                 return await wrapper(*args, **kwargs)\n             else:\n                 logger.warning('Giving up retrying: %s()', f.__name__)\n", "issue": "[Kucoin] {\"code\":\"429000\",\"msg\":\"Too Many Requests\"}. Able to ignore this error and prevent DDOS protection?\n<!-- \r\nHave you searched for similar issues before posting it?\r\n\r\nIf you have discovered a bug in the bot, please [search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue). \r\nIf it hasn't been reported, please create a new issue.\r\n\r\nPlease do not use bug reports to request new features.\r\n-->\r\n\r\n## Describe your environment\r\n\r\n  * Operating system: Canonical Ubuntu\r\n  * Python Version: \r\n  * CCXT version: 1.56.86\r\n  * Freqtrade Version: \r\n  \r\nNote: All issues other than enhancement requests will be closed without further comment if the above template is deleted or not filled out.\r\n\r\n## Describe the problem:\r\n\r\n{\"code\":\"429000\",\"msg\":\"Too Many Requests\"} error triggering DDOS protection delay. \r\n\r\n### Steps to reproduce:\r\nRandomly effect pairs on Kucoin\r\n\r\n### Observed Results:\r\n\r\nDDOS protection triggering when it doesn't need to which may cause unintended and financially ruinous behavior in the bot. \r\n\r\nAdmin on telegram says we can retry the request instantly without fear of DDOS protection triggering. \r\n\r\n![image](https://user-images.githubusercontent.com/15849763/136735376-37c1bcb2-d49a-4ca5-b314-1d4a1f2a9eed.png)\r\n\r\n\r\n\r\n\r\n### Relevant code exceptions or logs\r\n\r\nfreqtrade    | 2021-10-11 04:55:04,274 - freqtrade.exchange.common - WARNING - _async_get_candle_history() returned exception: \"kucoin GET https://openapi-v2.kucoin.com/api/v1/market/candles?symbol=DYDX-USDT&type=5min&startAt=1633778101&endAt=1633928101 429 Too Many Requests {\"code\":\"429000\",\"msg\":\"Too Many Requests\"}\"\r\nfreqtrade    | 2021-10-11 04:55:04,275 - freqtrade.exchange.common - WARNING - retrying _async_get_candle_history() still for 4 times\r\nfreqtrade    | 2021-10-11 04:55:04,275 - freqtrade.exchange.common - INFO - Applying DDosProtection backoff delay: 1\r\n\n", "before_files": [{"content": "import asyncio\nimport logging\nimport time\nfrom functools import wraps\n\nfrom freqtrade.exceptions import DDosProtection, RetryableOrderError, TemporaryError\n\n\nlogger = logging.getLogger(__name__)\n\n\n# Maximum default retry count.\n# Functions are always called RETRY_COUNT + 1 times (for the original call)\nAPI_RETRY_COUNT = 4\nAPI_FETCH_ORDER_RETRY_COUNT = 5\n\nBAD_EXCHANGES = {\n    \"bitmex\": \"Various reasons.\",\n    \"phemex\": \"Does not provide history. \",\n    \"poloniex\": \"Does not provide fetch_order endpoint to fetch both open and closed orders.\",\n}\n\nMAP_EXCHANGE_CHILDCLASS = {\n    'binanceus': 'binance',\n    'binanceje': 'binance',\n}\n\n\nEXCHANGE_HAS_REQUIRED = [\n    # Required / private\n    'fetchOrder',\n    'cancelOrder',\n    'createOrder',\n    # 'createLimitOrder', 'createMarketOrder',\n    'fetchBalance',\n\n    # Public endpoints\n    'loadMarkets',\n    'fetchOHLCV',\n]\n\nEXCHANGE_HAS_OPTIONAL = [\n    # Private\n    'fetchMyTrades',  # Trades for order - fee detection\n    # Public\n    'fetchOrderBook', 'fetchL2OrderBook', 'fetchTicker',  # OR for pricing\n    'fetchTickers',  # For volumepairlist?\n    'fetchTrades',  # Downloading trades data\n]\n\n\ndef remove_credentials(config) -> None:\n    \"\"\"\n    Removes exchange keys from the configuration and specifies dry-run\n    Used for backtesting / hyperopt / edge and utils.\n    Modifies the input dict!\n    \"\"\"\n    if config.get('dry_run', False):\n        config['exchange']['key'] = ''\n        config['exchange']['secret'] = ''\n        config['exchange']['password'] = ''\n        config['exchange']['uid'] = ''\n\n\ndef calculate_backoff(retrycount, max_retries):\n    \"\"\"\n    Calculate backoff\n    \"\"\"\n    return (max_retries - retrycount) ** 2 + 1\n\n\ndef retrier_async(f):\n    async def wrapper(*args, **kwargs):\n        count = kwargs.pop('count', API_RETRY_COUNT)\n        try:\n            return await f(*args, **kwargs)\n        except TemporaryError as ex:\n            logger.warning('%s() returned exception: \"%s\"', f.__name__, ex)\n            if count > 0:\n                logger.warning('retrying %s() still for %s times', f.__name__, count)\n                count -= 1\n                kwargs.update({'count': count})\n                if isinstance(ex, DDosProtection):\n                    backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)\n                    logger.info(f\"Applying DDosProtection backoff delay: {backoff_delay}\")\n                    await asyncio.sleep(backoff_delay)\n                return await wrapper(*args, **kwargs)\n            else:\n                logger.warning('Giving up retrying: %s()', f.__name__)\n                raise ex\n    return wrapper\n\n\ndef retrier(_func=None, retries=API_RETRY_COUNT):\n    def decorator(f):\n        @wraps(f)\n        def wrapper(*args, **kwargs):\n            count = kwargs.pop('count', retries)\n            try:\n                return f(*args, **kwargs)\n            except (TemporaryError, RetryableOrderError) as ex:\n                logger.warning('%s() returned exception: \"%s\"', f.__name__, ex)\n                if count > 0:\n                    logger.warning('retrying %s() still for %s times', f.__name__, count)\n                    count -= 1\n                    kwargs.update({'count': count})\n                    if isinstance(ex, (DDosProtection, RetryableOrderError)):\n                        # increasing backoff\n                        backoff_delay = calculate_backoff(count + 1, retries)\n                        logger.info(f\"Applying DDosProtection backoff delay: {backoff_delay}\")\n                        time.sleep(backoff_delay)\n                    return wrapper(*args, **kwargs)\n                else:\n                    logger.warning('Giving up retrying: %s()', f.__name__)\n                    raise ex\n        return wrapper\n    # Support both @retrier and @retrier(retries=2) syntax\n    if _func is None:\n        return decorator\n    else:\n        return decorator(_func)\n", "path": "freqtrade/exchange/common.py"}], "after_files": [{"content": "import asyncio\nimport logging\nimport time\nfrom functools import wraps\n\nfrom freqtrade.exceptions import DDosProtection, RetryableOrderError, TemporaryError\n\n\nlogger = logging.getLogger(__name__)\n\n\n# Maximum default retry count.\n# Functions are always called RETRY_COUNT + 1 times (for the original call)\nAPI_RETRY_COUNT = 4\nAPI_FETCH_ORDER_RETRY_COUNT = 5\n\nBAD_EXCHANGES = {\n    \"bitmex\": \"Various reasons.\",\n    \"phemex\": \"Does not provide history. \",\n    \"poloniex\": \"Does not provide fetch_order endpoint to fetch both open and closed orders.\",\n}\n\nMAP_EXCHANGE_CHILDCLASS = {\n    'binanceus': 'binance',\n    'binanceje': 'binance',\n}\n\n\nEXCHANGE_HAS_REQUIRED = [\n    # Required / private\n    'fetchOrder',\n    'cancelOrder',\n    'createOrder',\n    # 'createLimitOrder', 'createMarketOrder',\n    'fetchBalance',\n\n    # Public endpoints\n    'loadMarkets',\n    'fetchOHLCV',\n]\n\nEXCHANGE_HAS_OPTIONAL = [\n    # Private\n    'fetchMyTrades',  # Trades for order - fee detection\n    # Public\n    'fetchOrderBook', 'fetchL2OrderBook', 'fetchTicker',  # OR for pricing\n    'fetchTickers',  # For volumepairlist?\n    'fetchTrades',  # Downloading trades data\n]\n\n\ndef remove_credentials(config) -> None:\n    \"\"\"\n    Removes exchange keys from the configuration and specifies dry-run\n    Used for backtesting / hyperopt / edge and utils.\n    Modifies the input dict!\n    \"\"\"\n    if config.get('dry_run', False):\n        config['exchange']['key'] = ''\n        config['exchange']['secret'] = ''\n        config['exchange']['password'] = ''\n        config['exchange']['uid'] = ''\n\n\ndef calculate_backoff(retrycount, max_retries):\n    \"\"\"\n    Calculate backoff\n    \"\"\"\n    return (max_retries - retrycount) ** 2 + 1\n\n\ndef retrier_async(f):\n    async def wrapper(*args, **kwargs):\n        count = kwargs.pop('count', API_RETRY_COUNT)\n        try:\n            return await f(*args, **kwargs)\n        except TemporaryError as ex:\n            logger.warning('%s() returned exception: \"%s\"', f.__name__, ex)\n            if count > 0:\n                logger.warning('retrying %s() still for %s times', f.__name__, count)\n                count -= 1\n                kwargs.update({'count': count})\n                if isinstance(ex, DDosProtection):\n                    if \"kucoin\" in str(ex) and \"429000\" in str(ex):\n                        # Temporary fix for 429000 error on kucoin\n                        # see https://github.com/freqtrade/freqtrade/issues/5700 for details.\n                        logger.warning(\n                            f\"Kucoin 429 error, avoid triggering DDosProtection backoff delay. \"\n                            f\"{count} tries left before giving up\")\n                    else:\n                        backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)\n                        logger.info(f\"Applying DDosProtection backoff delay: {backoff_delay}\")\n                        await asyncio.sleep(backoff_delay)\n                return await wrapper(*args, **kwargs)\n            else:\n                logger.warning('Giving up retrying: %s()', f.__name__)\n                raise ex\n    return wrapper\n\n\ndef retrier(_func=None, retries=API_RETRY_COUNT):\n    def decorator(f):\n        @wraps(f)\n        def wrapper(*args, **kwargs):\n            count = kwargs.pop('count', retries)\n            try:\n                return f(*args, **kwargs)\n            except (TemporaryError, RetryableOrderError) as ex:\n                logger.warning('%s() returned exception: \"%s\"', f.__name__, ex)\n                if count > 0:\n                    logger.warning('retrying %s() still for %s times', f.__name__, count)\n                    count -= 1\n                    kwargs.update({'count': count})\n                    if isinstance(ex, (DDosProtection, RetryableOrderError)):\n                        # increasing backoff\n                        backoff_delay = calculate_backoff(count + 1, retries)\n                        logger.info(f\"Applying DDosProtection backoff delay: {backoff_delay}\")\n                        time.sleep(backoff_delay)\n                    return wrapper(*args, **kwargs)\n                else:\n                    logger.warning('Giving up retrying: %s()', f.__name__)\n                    raise ex\n        return wrapper\n    # Support both @retrier and @retrier(retries=2) syntax\n    if _func is None:\n        return decorator\n    else:\n        return decorator(_func)\n", "path": "freqtrade/exchange/common.py"}]}