Implement DDos backoff (1s)
This commit is contained in:
parent
baaf7f1c54
commit
2c45114a64
@ -45,6 +45,13 @@ class TemporaryError(FreqtradeException):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DDosProtection(TemporaryError):
|
||||||
|
"""
|
||||||
|
Temporary error caused by DDOS protection.
|
||||||
|
Bot will wait for a second and then retry.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class StrategyError(FreqtradeException):
|
class StrategyError(FreqtradeException):
|
||||||
"""
|
"""
|
||||||
Errors with custom user-code deteced.
|
Errors with custom user-code deteced.
|
||||||
|
@ -4,8 +4,9 @@ from typing import Dict
|
|||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
|
|
||||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
from freqtrade.exceptions import (DDosProtection, DependencyException,
|
||||||
OperationalException, TemporaryError)
|
InvalidOrderException, OperationalException,
|
||||||
|
TemporaryError)
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -88,6 +89,8 @@ class Binance(Exchange):
|
|||||||
f'Could not create {ordertype} sell order on market {pair}. '
|
f'Could not create {ordertype} sell order on market {pair}. '
|
||||||
f'Tried to sell amount {amount} at rate {rate}. '
|
f'Tried to sell amount {amount} at rate {rate}. '
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
from freqtrade.exceptions import TemporaryError
|
from freqtrade.exceptions import DDosProtection, TemporaryError
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -99,6 +101,8 @@ def retrier_async(f):
|
|||||||
count -= 1
|
count -= 1
|
||||||
kwargs.update({'count': count})
|
kwargs.update({'count': count})
|
||||||
logger.warning('retrying %s() still for %s times', f.__name__, count)
|
logger.warning('retrying %s() still for %s times', f.__name__, count)
|
||||||
|
if isinstance(ex, DDosProtection):
|
||||||
|
await asyncio.sleep(1)
|
||||||
return await wrapper(*args, **kwargs)
|
return await wrapper(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
logger.warning('Giving up retrying: %s()', f.__name__)
|
logger.warning('Giving up retrying: %s()', f.__name__)
|
||||||
@ -117,6 +121,8 @@ def retrier(f):
|
|||||||
count -= 1
|
count -= 1
|
||||||
kwargs.update({'count': count})
|
kwargs.update({'count': count})
|
||||||
logger.warning('retrying %s() still for %s times', f.__name__, count)
|
logger.warning('retrying %s() still for %s times', f.__name__, count)
|
||||||
|
if isinstance(ex, DDosProtection):
|
||||||
|
time.sleep(1)
|
||||||
return wrapper(*args, **kwargs)
|
return wrapper(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
logger.warning('Giving up retrying: %s()', f.__name__)
|
logger.warning('Giving up retrying: %s()', f.__name__)
|
||||||
|
@ -18,12 +18,13 @@ from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE,
|
|||||||
TRUNCATE, decimal_to_precision)
|
TRUNCATE, decimal_to_precision)
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
from freqtrade.constants import ListPairsWithTimeframes
|
||||||
from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list
|
from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list
|
||||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
from freqtrade.exceptions import (DDosProtection, DependencyException,
|
||||||
OperationalException, TemporaryError)
|
InvalidOrderException, OperationalException,
|
||||||
|
TemporaryError)
|
||||||
from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async
|
from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async
|
||||||
from freqtrade.misc import deep_merge_dicts, safe_value_fallback
|
from freqtrade.misc import deep_merge_dicts, safe_value_fallback
|
||||||
from freqtrade.constants import ListPairsWithTimeframes
|
|
||||||
|
|
||||||
CcxtModuleType = Any
|
CcxtModuleType = Any
|
||||||
|
|
||||||
@ -527,6 +528,8 @@ class Exchange:
|
|||||||
f'Could not create {ordertype} {side} order on market {pair}.'
|
f'Could not create {ordertype} {side} order on market {pair}.'
|
||||||
f'Tried to {side} amount {amount} at rate {rate}.'
|
f'Tried to {side} amount {amount} at rate {rate}.'
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not place {side} order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not place {side} order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -606,6 +609,8 @@ class Exchange:
|
|||||||
balances.pop("used", None)
|
balances.pop("used", None)
|
||||||
|
|
||||||
return balances
|
return balances
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get balance due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get balance due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -620,6 +625,8 @@ class Exchange:
|
|||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f'Exchange {self._api.name} does not support fetching tickers in batch. '
|
f'Exchange {self._api.name} does not support fetching tickers in batch. '
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not load tickers due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not load tickers due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -633,6 +640,8 @@ class Exchange:
|
|||||||
raise DependencyException(f"Pair {pair} not available")
|
raise DependencyException(f"Pair {pair} not available")
|
||||||
data = self._api.fetch_ticker(pair)
|
data = self._api.fetch_ticker(pair)
|
||||||
return data
|
return data
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not load ticker due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not load ticker due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -766,6 +775,8 @@ class Exchange:
|
|||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f'Exchange {self._api.name} does not support fetching historical '
|
f'Exchange {self._api.name} does not support fetching historical '
|
||||||
f'candle (OHLCV) data. Message: {e}') from e
|
f'candle (OHLCV) data. Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(f'Could not fetch historical candle (OHLCV) data '
|
raise TemporaryError(f'Could not fetch historical candle (OHLCV) data '
|
||||||
f'for pair {pair} due to {e.__class__.__name__}. '
|
f'for pair {pair} due to {e.__class__.__name__}. '
|
||||||
@ -802,6 +813,8 @@ class Exchange:
|
|||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f'Exchange {self._api.name} does not support fetching historical trade data.'
|
f'Exchange {self._api.name} does not support fetching historical trade data.'
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(f'Could not load trade history due to {e.__class__.__name__}. '
|
raise TemporaryError(f'Could not load trade history due to {e.__class__.__name__}. '
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
@ -948,6 +961,8 @@ class Exchange:
|
|||||||
except ccxt.InvalidOrder as e:
|
except ccxt.InvalidOrder as e:
|
||||||
raise InvalidOrderException(
|
raise InvalidOrderException(
|
||||||
f'Could not cancel order. Message: {e}') from e
|
f'Could not cancel order. Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not cancel order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not cancel order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -1003,6 +1018,8 @@ class Exchange:
|
|||||||
except ccxt.InvalidOrder as e:
|
except ccxt.InvalidOrder as e:
|
||||||
raise InvalidOrderException(
|
raise InvalidOrderException(
|
||||||
f'Tried to get an invalid order (id: {order_id}). Message: {e}') from e
|
f'Tried to get an invalid order (id: {order_id}). Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -1027,6 +1044,8 @@ class Exchange:
|
|||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f'Exchange {self._api.name} does not support fetching order book.'
|
f'Exchange {self._api.name} does not support fetching order book.'
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get order book due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get order book due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -1063,7 +1082,8 @@ class Exchange:
|
|||||||
matched_trades = [trade for trade in my_trades if trade['order'] == order_id]
|
matched_trades = [trade for trade in my_trades if trade['order'] == order_id]
|
||||||
|
|
||||||
return matched_trades
|
return matched_trades
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get trades due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get trades due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -1080,6 +1100,8 @@ class Exchange:
|
|||||||
|
|
||||||
return self._api.calculate_fee(symbol=symbol, type=type, side=side, amount=amount,
|
return self._api.calculate_fee(symbol=symbol, type=type, side=side, amount=amount,
|
||||||
price=price, takerOrMaker=taker_or_maker)['rate']
|
price=price, takerOrMaker=taker_or_maker)['rate']
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get fee info due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get fee info due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
|
@ -4,8 +4,9 @@ from typing import Dict
|
|||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
|
|
||||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
from freqtrade.exceptions import (DDosProtection, DependencyException,
|
||||||
OperationalException, TemporaryError)
|
InvalidOrderException, OperationalException,
|
||||||
|
TemporaryError)
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
from freqtrade.exchange.common import retrier
|
from freqtrade.exchange.common import retrier
|
||||||
|
|
||||||
@ -68,6 +69,8 @@ class Ftx(Exchange):
|
|||||||
f'Could not create {ordertype} sell order on market {pair}. '
|
f'Could not create {ordertype} sell order on market {pair}. '
|
||||||
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
|
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -96,6 +99,8 @@ class Ftx(Exchange):
|
|||||||
except ccxt.InvalidOrder as e:
|
except ccxt.InvalidOrder as e:
|
||||||
raise InvalidOrderException(
|
raise InvalidOrderException(
|
||||||
f'Tried to get an invalid order (id: {order_id}). Message: {e}') from e
|
f'Tried to get an invalid order (id: {order_id}). Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -111,6 +116,8 @@ class Ftx(Exchange):
|
|||||||
except ccxt.InvalidOrder as e:
|
except ccxt.InvalidOrder as e:
|
||||||
raise InvalidOrderException(
|
raise InvalidOrderException(
|
||||||
f'Could not cancel order. Message: {e}') from e
|
f'Could not cancel order. Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not cancel order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not cancel order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
|
@ -4,7 +4,7 @@ from typing import Dict
|
|||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
|
|
||||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
from freqtrade.exceptions import (DependencyException, InvalidOrderException, DDosProtection,
|
||||||
OperationalException, TemporaryError)
|
OperationalException, TemporaryError)
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
from freqtrade.exchange.common import retrier
|
from freqtrade.exchange.common import retrier
|
||||||
@ -45,6 +45,8 @@ class Kraken(Exchange):
|
|||||||
balances[bal]['free'] = balances[bal]['total'] - balances[bal]['used']
|
balances[bal]['free'] = balances[bal]['total'] - balances[bal]['used']
|
||||||
|
|
||||||
return balances
|
return balances
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not get balance due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not get balance due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
@ -93,6 +95,8 @@ class Kraken(Exchange):
|
|||||||
f'Could not create {ordertype} sell order on market {pair}. '
|
f'Could not create {ordertype} sell order on market {pair}. '
|
||||||
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
|
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
|
||||||
f'Message: {e}') from e
|
f'Message: {e}') from e
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
raise TemporaryError(
|
raise TemporaryError(
|
||||||
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
||||||
|
@ -4,14 +4,14 @@ import copy
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from random import randint
|
from random import randint
|
||||||
from unittest.mock import MagicMock, Mock, PropertyMock
|
from unittest.mock import MagicMock, Mock, PropertyMock, patch
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import ccxt
|
import ccxt
|
||||||
import pytest
|
import pytest
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
from freqtrade.exceptions import (DependencyException, InvalidOrderException, DDosProtection,
|
||||||
OperationalException, TemporaryError)
|
OperationalException, TemporaryError)
|
||||||
from freqtrade.exchange import Binance, Exchange, Kraken
|
from freqtrade.exchange import Binance, Exchange, Kraken
|
||||||
from freqtrade.exchange.common import API_RETRY_COUNT
|
from freqtrade.exchange.common import API_RETRY_COUNT
|
||||||
@ -38,6 +38,14 @@ def get_mock_coro(return_value):
|
|||||||
|
|
||||||
def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
||||||
fun, mock_ccxt_fun, **kwargs):
|
fun, mock_ccxt_fun, **kwargs):
|
||||||
|
|
||||||
|
with patch('freqtrade.exchange.common.time.sleep'):
|
||||||
|
with pytest.raises(DDosProtection):
|
||||||
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.DDoSProtection("DDos"))
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
|
getattr(exchange, fun)(**kwargs)
|
||||||
|
assert api_mock.__dict__[mock_ccxt_fun].call_count == API_RETRY_COUNT + 1
|
||||||
|
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeaDBeef"))
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeaDBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
@ -52,6 +60,13 @@ def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
|||||||
|
|
||||||
|
|
||||||
async def async_ccxt_exception(mocker, default_conf, api_mock, fun, mock_ccxt_fun, **kwargs):
|
async def async_ccxt_exception(mocker, default_conf, api_mock, fun, mock_ccxt_fun, **kwargs):
|
||||||
|
|
||||||
|
with patch('freqtrade.exchange.common.asyncio.sleep'):
|
||||||
|
with pytest.raises(DDosProtection):
|
||||||
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.DDoSProtection("DeadBeef"))
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
|
await getattr(exchange, fun)(**kwargs)
|
||||||
|
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
|
Loading…
Reference in New Issue
Block a user