diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 8ae027fa2..001b7f02d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -60,7 +60,7 @@ class FreqtradeBot: # Check config consistency here since strategies can set certain options validate_config_consistency(config) - self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange + self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) persistence.init(self.config.get('db_url', None), clean_open_orders=self.config.get('dry_run', False)) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 726257cdd..bab997cb1 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -60,7 +60,7 @@ class Backtesting: # Reset keys for backtesting remove_credentials(self.config) self.strategylist: List[IStrategy] = [] - self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange + self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) if config.get('fee'): self.fee = config['fee'] diff --git a/freqtrade/resolvers/exchange_resolver.py b/freqtrade/resolvers/exchange_resolver.py index 60f37b1c9..e28a5cf80 100644 --- a/freqtrade/resolvers/exchange_resolver.py +++ b/freqtrade/resolvers/exchange_resolver.py @@ -15,9 +15,8 @@ class ExchangeResolver(IResolver): This class contains all the logic to load a custom exchange class """ - __slots__ = ['exchange'] - - def __init__(self, exchange_name: str, config: dict, validate: bool = True) -> None: + @staticmethod + def load_exchange(exchange_name: str, config: dict, validate: bool = True) -> Exchange: """ Load the custom class from config parameter :param config: configuration dictionary @@ -25,17 +24,20 @@ class ExchangeResolver(IResolver): # Map exchange name to avoid duplicate classes for identical exchanges exchange_name = MAP_EXCHANGE_CHILDCLASS.get(exchange_name, exchange_name) exchange_name = exchange_name.title() + exchange = None try: - self.exchange = self._load_exchange(exchange_name, kwargs={'config': config, - 'validate': validate}) + exchange = ExchangeResolver._load_exchange(exchange_name, + kwargs={'config': config, + 'validate': validate}) except ImportError: logger.info( f"No {exchange_name} specific subclass found. Using the generic class instead.") - if not hasattr(self, "exchange"): - self.exchange = Exchange(config, validate=validate) + if not exchange: + exchange = Exchange(config, validate=validate) + return exchange - def _load_exchange( - self, exchange_name: str, kwargs: dict) -> Exchange: + @staticmethod + def _load_exchange(exchange_name: str, kwargs: dict) -> Exchange: """ Loads the specified exchange. Only checks for exchanges exported in freqtrade.exchanges diff --git a/freqtrade/resolvers/pairlist_resolver.py b/freqtrade/resolvers/pairlist_resolver.py index 5b5bcee3a..611660ff4 100644 --- a/freqtrade/resolvers/pairlist_resolver.py +++ b/freqtrade/resolvers/pairlist_resolver.py @@ -18,8 +18,6 @@ class PairListResolver(IResolver): This class contains all the logic to load custom PairList class """ - __slots__ = [] - @staticmethod def load_pairlist(pairlist_name: str, exchange, pairlistmanager, config: dict, pairlistconfig: dict, pairlist_pos: int) -> IPairList: @@ -41,7 +39,6 @@ class PairListResolver(IResolver): 'pairlistconfig': pairlistconfig, 'pairlist_pos': pairlist_pos}) - @staticmethod def _load_pairlist(pairlist_name: str, config: dict, kwargs: dict) -> IPairList: """ diff --git a/freqtrade/utils.py b/freqtrade/utils.py index 9e01c7ea6..18966c574 100644 --- a/freqtrade/utils.py +++ b/freqtrade/utils.py @@ -198,7 +198,7 @@ def start_download_data(args: Dict[str, Any]) -> None: pairs_not_available: List[str] = [] # Init exchange - exchange = ExchangeResolver(config['exchange']['name'], config).exchange + exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config) try: if config.get('download_trades'): @@ -233,7 +233,7 @@ def start_list_timeframes(args: Dict[str, Any]) -> None: config['ticker_interval'] = None # Init exchange - exchange = ExchangeResolver(config['exchange']['name'], config, validate=False).exchange + exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) if args['print_one_column']: print('\n'.join(exchange.timeframes)) @@ -252,7 +252,7 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None: config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) # Init exchange - exchange = ExchangeResolver(config['exchange']['name'], config, validate=False).exchange + exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) # By default only active pairs/markets are to be shown active_only = not args.get('list_pairs_all', False) @@ -333,7 +333,7 @@ def start_test_pairlist(args: Dict[str, Any]) -> None: from freqtrade.pairlist.pairlistmanager import PairListManager config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) - exchange = ExchangeResolver(config['exchange']['name'], config, validate=False).exchange + exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) quote_currencies = args.get('quote_currencies') if not quote_currencies: diff --git a/tests/conftest.py b/tests/conftest.py index 82111528e..501f89fff 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -77,7 +77,7 @@ def get_patched_exchange(mocker, config, api_mock=None, id='bittrex', patch_exchange(mocker, api_mock, id, mock_markets) config["exchange"]["name"] = id try: - exchange = ExchangeResolver(id, config).exchange + exchange = ExchangeResolver.load_exchange(id, config) except ImportError: exchange = Exchange(config) return exchange diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 629f99aa2..dccf7d74f 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -124,19 +124,19 @@ def test_exchange_resolver(default_conf, mocker, caplog): mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) - exchange = ExchangeResolver('Bittrex', default_conf).exchange + exchange = ExchangeResolver.load_exchange('Bittrex', default_conf) assert isinstance(exchange, Exchange) assert log_has_re(r"No .* specific subclass found. Using the generic class instead.", caplog) caplog.clear() - exchange = ExchangeResolver('kraken', default_conf).exchange + exchange = ExchangeResolver.load_exchange('kraken', default_conf) assert isinstance(exchange, Exchange) assert isinstance(exchange, Kraken) assert not isinstance(exchange, Binance) assert not log_has_re(r"No .* specific subclass found. Using the generic class instead.", caplog) - exchange = ExchangeResolver('binance', default_conf).exchange + exchange = ExchangeResolver.load_exchange('binance', default_conf) assert isinstance(exchange, Exchange) assert isinstance(exchange, Binance) assert not isinstance(exchange, Kraken) @@ -145,7 +145,7 @@ def test_exchange_resolver(default_conf, mocker, caplog): caplog) # Test mapping - exchange = ExchangeResolver('binanceus', default_conf).exchange + exchange = ExchangeResolver.load_exchange('binanceus', default_conf) assert isinstance(exchange, Exchange) assert isinstance(exchange, Binance) assert not isinstance(exchange, Kraken) diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index e7f098777..21929de2b 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -53,7 +53,8 @@ def test_load_pairlist_noexist(mocker, markets, default_conf): with pytest.raises(OperationalException, match=r"Impossible to load Pairlist 'NonexistingPairList'. " r"This class does not exist or contains Python code errors."): - PairListResolver.load_pairlist('NonexistingPairList', bot.exchange, plm, default_conf, {}, 1) + PairListResolver.load_pairlist('NonexistingPairList', bot.exchange, plm, + default_conf, {}, 1) def test_refresh_market_pair_not_in_whitelist(mocker, markets, static_pl_conf):