diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 19a22b87d..17b818b27 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -112,7 +112,7 @@ class FreqtradeBot(object): }) logger.info('Changing state to: %s', state.name) if state == State.RUNNING: - self.rpc.startup_messages(self.config) + self.rpc.startup_messages(self.config, self.pairlists) if state == State.STOPPED: time.sleep(1) diff --git a/freqtrade/pairlist/StaticPairList.py b/freqtrade/pairlist/StaticPairList.py index 24ad30deb..5b0e37357 100644 --- a/freqtrade/pairlist/StaticPairList.py +++ b/freqtrade/pairlist/StaticPairList.py @@ -19,15 +19,37 @@ class StaticPairList(object): self._blacklist = self._config['exchange'].get('pair_blacklist', []) # self.refresh_whitelist() + @property + def name(self) -> str: + """ + Gets name of the class + -> no need to overwrite in subclasses + """ + return self.__class__.__name__ + @property def whitelist(self) -> List[str]: - """ Contains the current whitelist """ + """ + Has the current whitelist + -> no need to overwrite in subclasses + """ return self._whitelist @property def blacklist(self) -> List[str]: + """ + Has the current blacklist + -> no need to overwrite in subclasses + """ return self._blacklist + def short_desc(self) -> str: + """ + Short whitelist method description - used for startup-messages + -> Please overwrite in subclasses + """ + return f"{self.name}: {self.whitelist}" + def refresh_whitelist(self) -> None: """ Refreshes whitelist and assigns it to self._whitelist diff --git a/freqtrade/pairlist/VolumePairList.py b/freqtrade/pairlist/VolumePairList.py index 41f9943a1..f45c57676 100644 --- a/freqtrade/pairlist/VolumePairList.py +++ b/freqtrade/pairlist/VolumePairList.py @@ -21,7 +21,7 @@ class VolumePairList(StaticPairList): self._whitelistconf = self._config.get('whitelist', {}).get('config') self._whitelist = self._config['exchange']['pair_whitelist'] self._blacklist = self._config['exchange'].get('pair_blacklist', []) - self._number_pairs = self._whitelistconf.get('number_assets') + self._number_pairs = self._whitelistconf['number_assets'] if not self._freqtrade.exchange.exchange_has('fetchTickers'): raise OperationalException( 'Exchange does not support dynamic whitelist.' @@ -29,14 +29,12 @@ class VolumePairList(StaticPairList): ) # self.refresh_whitelist() - @property - def whitelist(self) -> List[str]: - """ Contains the current whitelist """ - return self._whitelist - - @property - def blacklist(self) -> List[str]: - return self._blacklist + def short_desc(self) -> str: + """ + Short whitelist method description - used for startup-messages + -> Please overwrite in subclasses + """ + return f"{self.name} - top {self._whitelistconf['number_assets']} volume pairs." def refresh_whitelist(self) -> None: """ diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 50cbd27ef..6ca32e4be 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -446,7 +446,8 @@ class RPC(object): def _rpc_whitelist(self) -> Dict: """ Returns the currently active whitelist""" - res = {'method': self._freqtrade.config.get('dynamic_whitelist', 0) or 'static', + res = {'method': self._freqtrade.pairlists.name, + 'length': len(self._freqtrade.pairlists.whitelist), 'whitelist': self._freqtrade.active_pair_whitelist } return res diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index 74a4e3bdc..de861677d 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -52,7 +52,7 @@ class RPCManager(object): logger.debug('Forwarding message to rpc.%s', mod.name) mod.send_msg(msg) - def startup_messages(self, config) -> None: + def startup_messages(self, config, pairlist) -> None: if config.get('dry_run', False): self.send_msg({ 'type': RPCMessageType.WARNING_NOTIFICATION, @@ -72,14 +72,8 @@ class RPCManager(object): f'*Ticker Interval:* `{ticker_interval}`\n' f'*Strategy:* `{strategy_name}`' }) - if config.get('dynamic_whitelist', False): - top_pairs = 'top volume ' + str(config.get('dynamic_whitelist', 20)) - specific_pairs = '' - else: - top_pairs = 'whitelisted' - specific_pairs = '\n' + ', '.join(config['exchange'].get('pair_whitelist', '')) self.send_msg({ 'type': RPCMessageType.STATUS_NOTIFICATION, - 'status': f'Searching for {top_pairs} {stake_currency} pairs to buy and sell...' - f'{specific_pairs}' + 'status': f'Searching for {stake_currency} pairs to buy and sell ' + f'based on {pairlist.short_desc()}' }) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 55c5abef2..9a3abaea4 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -447,10 +447,8 @@ class Telegram(RPC): """ try: whitelist = self._rpc_whitelist() - if whitelist['method'] == 'static': - message = f"Using static whitelist with `{len(whitelist['whitelist'])}` pairs \n" - else: - message = f"Dynamic whitelist with `{whitelist['method']}` pairs\n" + + message = f"Using whitelist `{whitelist['method']}` with {whitelist['length']} pairs\n" message += f"`{', '.join(whitelist['whitelist'])}`" logger.debug(message) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index b0b598654..54bb45cd4 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -662,12 +662,15 @@ def test_rpc_whitelist(mocker, default_conf) -> None: def test_rpc_whitelist_dynamic(mocker, default_conf) -> None: patch_coinmarketcap(mocker) patch_exchange(mocker) - default_conf['dynamic_whitelist'] = 4 + default_conf['whitelist'] = {'method': 'VolumePairList', + 'config': {'number_assets': 4} + } mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) freqtradebot = FreqtradeBot(default_conf) rpc = RPC(freqtradebot) ret = rpc._rpc_whitelist() - assert ret['method'] == 4 + assert ret['method'] == 'VolumePairList' + assert ret['length'] == 4 assert ret['whitelist'] == default_conf['exchange']['pair_whitelist'] diff --git a/freqtrade/tests/rpc/test_rpc_manager.py b/freqtrade/tests/rpc/test_rpc_manager.py index cbb858522..9359fc927 100644 --- a/freqtrade/tests/rpc/test_rpc_manager.py +++ b/freqtrade/tests/rpc/test_rpc_manager.py @@ -128,7 +128,9 @@ def test_startupmessages_telegram_enabled(mocker, default_conf, caplog) -> None: telegram_mock.reset_mock() default_conf['dry_run'] = True - default_conf['dynamic_whitelist'] = 20 + default_conf['whitelist'] = {'method': 'VolumePairList', + 'config': {'number_assets': 20} + } rpc_manager.startup_messages(default_conf) assert telegram_mock.call_count == 3 diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 4f29c5a03..8a97abf58 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1034,7 +1034,9 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None: _send_msg=msg_mock ) mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) - default_conf['dynamic_whitelist'] = 4 + default_conf['whitelist'] = {'method': 'VolumePairList', + 'config': {'number_assets': 4} + } freqtradebot = get_patched_freqtradebot(mocker, default_conf) telegram = Telegram(freqtradebot) diff --git a/freqtrade/tests/test_acl_pair.py b/freqtrade/tests/test_acl_pair.py index a12de9a81..5acd9abda 100644 --- a/freqtrade/tests/test_acl_pair.py +++ b/freqtrade/tests/test_acl_pair.py @@ -54,14 +54,16 @@ def test_refresh_pairlists(mocker, markets, whitelist_conf): def test_refresh_whitelist_dynamic(mocker, markets, tickers, whitelist_conf): - whitelist_conf['dynamic_whitelist'] = 5 - freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) + whitelist_conf['whitelist'] = {'method': 'VolumePairList', + 'config': {'number_assets': 5} + } mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_markets=markets, get_tickers=tickers, exchange_has=MagicMock(return_value=True) ) + freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) # argument: use the whitelist dynamically by exchange-volume whitelist = ['ETH/BTC', 'TKN/BTC'] diff --git a/freqtrade/tests/test_arguments.py b/freqtrade/tests/test_arguments.py index e09aeb1df..d28ab30af 100644 --- a/freqtrade/tests/test_arguments.py +++ b/freqtrade/tests/test_arguments.py @@ -17,7 +17,8 @@ def test_parse_args_none() -> None: def test_parse_args_defaults() -> None: args = Arguments([], '').get_parsed_arg() assert args.config == 'config.json' - assert args.dynamic_whitelist is None + assert args.strategy_path is None + assert args.datadir is None assert args.loglevel == 0 diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index 951d831b2..5eda9d871 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -102,7 +102,7 @@ def test_load_config(default_conf, mocker) -> None: assert validated_conf.get('strategy') == 'DefaultStrategy' assert validated_conf.get('strategy_path') is None - assert 'dynamic_whitelist' not in validated_conf + assert 'edge' not in validated_conf def test_load_config_with_params(default_conf, mocker) -> None: @@ -133,7 +133,6 @@ def test_load_config_with_params(default_conf, mocker) -> None: )) arglist = [ - '--dynamic-whitelist', '10', '--strategy', 'TestStrategy', '--strategy-path', '/some/path' ] @@ -152,7 +151,6 @@ def test_load_config_with_params(default_conf, mocker) -> None: )) arglist = [ - '--dynamic-whitelist', '10', '--strategy', 'TestStrategy', '--strategy-path', '/some/path' ] diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index ca604340b..0cdc9b0e6 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -2532,7 +2532,9 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order def test_startup_messages(default_conf, mocker): - default_conf['dynamic_whitelist'] = 20 + default_conf['whitelist'] = {'method': 'VolumePairList', + 'config': {'number_assets': 20} + } mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) freqtrade = get_patched_freqtradebot(mocker, default_conf) assert freqtrade.state is State.RUNNING