diff --git a/freqtrade/plugins/pairlist/ProducerPairList.py b/freqtrade/plugins/pairlist/ProducerPairList.py index dc575f29b..fa351c9cc 100644 --- a/freqtrade/plugins/pairlist/ProducerPairList.py +++ b/freqtrade/plugins/pairlist/ProducerPairList.py @@ -6,6 +6,7 @@ Provides pair list from Leader data import logging from typing import Any, Dict, List, Optional +from freqtrade.exceptions import OperationalException from freqtrade.plugins.pairlist.IPairList import IPairList @@ -34,8 +35,9 @@ class ProducerPairList(IPairList): self._num_assets: int = self._pairlistconfig.get('number_assets', 0) self._producer_name = self._pairlistconfig.get('producer_name', 'default') - if config.get('external_message_consumer', {}).get('enabled') is False: - raise ValueError("ProducerPairList requires external_message_consumer to be enabled.") + if not config.get('external_message_consumer', {}).get('enabled'): + raise OperationalException( + "ProducerPairList requires external_message_consumer to be enabled.") @property def needstickers(self) -> bool: diff --git a/tests/conftest.py b/tests/conftest.py index 51b1b03e3..a9eeb481e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -200,6 +200,8 @@ def patch_freqtradebot(mocker, config) -> None: mocker.patch('freqtrade.freqtradebot.RPCManager._init', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager.send_msg', MagicMock()) patch_whitelist(mocker, config) + mocker.patch('freqtrade.freqtradebot.ExternalMessageConsumer') + mocker.patch('freqtrade.configuration.config_validation._validate_consumers') def get_patched_freqtradebot(mocker, config) -> FreqtradeBot: diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index 26b7ebbe2..a6b5813da 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -9,6 +9,7 @@ import pytest import time_machine from freqtrade.constants import AVAILABLE_PAIRLISTS +from freqtrade.data.dataprovider import DataProvider from freqtrade.enums import CandleType, RunMode from freqtrade.exceptions import OperationalException from freqtrade.persistence import Trade @@ -40,6 +41,12 @@ def whitelist_conf(default_conf): "sort_key": "quoteVolume", }, ] + default_conf.update({ + "external_message_consumer": { + "enabled": True, + "producers": [], + } + }) return default_conf @@ -1167,6 +1174,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo "[{'OffsetFilter': 'OffsetFilter - Taking 10 Pairs, starting from 5.'}]", None ), + ({"method": "ProducerPairList"}, + "[{'ProducerPairList': 'ProducerPairList - default'}]", + None + ), ]) def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, desc_expected, exception_expected): @@ -1341,3 +1352,64 @@ def test_expand_pairlist_keep_invalid(wildcardlist, pairs, expected): expand_pairlist(wildcardlist, pairs, keep_invalid=True) else: assert sorted(expand_pairlist(wildcardlist, pairs, keep_invalid=True)) == sorted(expected) + + +def test_ProducerPairlist_no_emc(mocker, whitelist_conf): + mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) + + whitelist_conf['pairlists'] = [ + { + "method": "ProducerPairList", + "number_assets": 10, + "producer_name": "hello_world", + } + ] + del whitelist_conf['external_message_consumer'] + + with pytest.raises(OperationalException, + match=r"ProducerPairList requires external_message_consumer to be enabled."): + get_patched_freqtradebot(mocker, whitelist_conf) + + +def test_ProducerPairlist(mocker, whitelist_conf, markets): + mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) + mocker.patch.multiple('freqtrade.exchange.Exchange', + markets=PropertyMock(return_value=markets), + exchange_has=MagicMock(return_value=True), + ) + whitelist_conf['pairlists'] = [ + { + "method": "ProducerPairList", + "number_assets": 2, + "producer_name": "hello_world", + } + ] + whitelist_conf.update({ + "external_message_consumer": { + "enabled": True, + "producers": [ + { + "name": "hello_world", + "host": "null", + "port": 9891, + "ws_token": "dummy", + } + ] + } + }) + + exchange = get_patched_exchange(mocker, whitelist_conf) + dp = DataProvider(whitelist_conf, exchange, None) + pairs = ['ETH/BTC', 'LTC/BTC', 'XRP/BTC'] + # different producer + dp._set_producer_pairs(pairs + ['MEEP/USDT'], 'default') + pm = PairListManager(exchange, whitelist_conf, dp) + pm.refresh_pairlist() + assert pm.whitelist == [] + # proper producer + dp._set_producer_pairs(pairs, 'hello_world') + pm.refresh_pairlist() + + # Pairlist reduced to 2 + assert pm.whitelist == pairs[:2] + assert len(pm.whitelist) == 2