diff --git a/freqtrade/plugins/pairlist/MarketCapPairList.py b/freqtrade/plugins/pairlist/MarketCapPairList.py index afe47bdce..a618f72d2 100644 --- a/freqtrade/plugins/pairlist/MarketCapPairList.py +++ b/freqtrade/plugins/pairlist/MarketCapPairList.py @@ -18,9 +18,6 @@ from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter logger = logging.getLogger(__name__) -MODE_VALUES = ['top_rank', 'total_assets'] - - class MarketCapPairList(IPairList): is_pairlist_generator = True @@ -36,22 +33,18 @@ class MarketCapPairList(IPairList): 'for "pairlist.config.number_assets"') self._stake_currency = config['stake_currency'] - self._mode = self._pairlistconfig.get('mode', 'top_rank') self._number_assets = self._pairlistconfig['number_assets'] + self._max_rank = self._pairlistconfig.get('max_rank', 30) self._refresh_period = self._pairlistconfig.get('refresh_period', 86400) self._marketcap_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period) self._def_candletype = self._config['candle_type_def'] self._coingekko: CoinGeckoAPI = CoinGeckoAPI() - if self._number_assets > 250: + if self._max_rank > 250: raise OperationalException( - "This filter only support number_assets value up to 250." + "This filter only support marketcap rank up to 250." ) - if not self._validate_keys(self._mode): - raise OperationalException( - f'key {self._mode} not in {MODE_VALUES}') - @property def needstickers(self) -> bool: """ @@ -61,17 +54,13 @@ class MarketCapPairList(IPairList): """ return False - def _validate_keys(self, key): - return key in MODE_VALUES - def short_desc(self) -> str: """ Short whitelist method description - used for startup-messages """ - num = self._pairlistconfig['number_assets'] - msg = f"{self.name} - Only include pairs ranked within top {num} market cap." - if self._mode == "total_assets": - msg = f"{self.name} - top {num} pairs sorted by market cap." + num = self._number_assets + rank = self._max_rank + msg = f"{self.name} - {num} pairs placed within top {rank} market cap." return msg @staticmethod @@ -84,15 +73,14 @@ class MarketCapPairList(IPairList): "number_assets": { "type": "number", "default": 30, - "description": "Max market cap rank", - "help": "Only use assets with high market cap rank", + "description": "Number of assets", + "help": "Number of assets to use from the pairlist", }, - "mode": { - "type": "option", - "default": "top_rank", - "options": MODE_VALUES, - "description": "Mode of number", - "help": "How to interpret the number", + "max_rank": { + "type": "number", + "default": 30, + "description": "Max rank of assets", + "help": "Maximum rank of assets to use from the pairlist", }, "refresh_period": { "type": "number", @@ -149,28 +137,19 @@ class MarketCapPairList(IPairList): if marketcap_list: filtered_pairlist = [] - if self._mode == 'top_rank': - top_marketcap = marketcap_list[:self._number_assets:] + market = self._config['trading_mode'] + pair_format = f"{self._stake_currency.upper()}" + if (market == 'futures'): + pair_format += f":{self._stake_currency.upper()}" - for pair in pairlist: - base = self._exchange.get_pair_base_currency(pair) - if base.lower() in top_marketcap: - filtered_pairlist.append(pair) - else: - self.log_once(f"Remove {pair} from whitelist because it's not ranked " - f"within top {self._number_assets} market cap", logger.info) + top_marketcap = marketcap_list[:self._max_rank:] - else: - market = self._config['trading_mode'] - pair_format = f"{self._stake_currency.upper()}" - if (market == 'futures'): - pair_format += f":{self._stake_currency.upper()}" - for mc_pair in marketcap_list: - test_pair = f"{mc_pair.upper()}/{pair_format}" - if test_pair in pairlist: - filtered_pairlist.append(test_pair) - if len(filtered_pairlist) == self._number_assets: - break + for mc_pair in top_marketcap: + test_pair = f"{mc_pair.upper()}/{pair_format}" + if test_pair in pairlist: + filtered_pairlist.append(test_pair) + if len(filtered_pairlist) == self._number_assets: + break if len(filtered_pairlist) > 0: return filtered_pairlist diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index 3d26979e1..72fce666d 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -1517,29 +1517,29 @@ def test_FullTradesFilter(mocker, default_conf_usdt, fee, caplog) -> None: @pytest.mark.parametrize('pairlists,result', [ ([ - # Test top 2 mc + # Get 2 pairs {"method": "StaticPairList", "allow_inactive": True}, - {"method": "MarketCapPairList", "mode": "top_rank", "number_assets": 2} - ], ['ETH/USDT', 'BTC/USDT']), - ([ - # Test top 6 mc - {"method": "StaticPairList", "allow_inactive": True}, - {"method": "MarketCapPairList", "mode": "top_rank", "number_assets": 6} - ], ['ETH/USDT', 'XRP/USDT', 'BTC/USDT']), - ([ - # Test total assets mode, 2 assets - {"method": "StaticPairList", "allow_inactive": True}, - {"method": "MarketCapPairList", "mode": "total_assets", "number_assets": 2} + {"method": "MarketCapPairList", "number_assets": 2} ], ['BTC/USDT', 'ETH/USDT']), + ([ + # Get 6 pairs + {"method": "StaticPairList", "allow_inactive": True}, + {"method": "MarketCapPairList", "number_assets": 6} + ], ['BTC/USDT', 'ETH/USDT', 'XRP/USDT', 'ADA/USDT']), + ([ + # Get 3 pairs within top 6 ranks + {"method": "StaticPairList", "allow_inactive": True}, + {"method": "MarketCapPairList", "max_rank": 6, "number_assets": 3} + ], ['BTC/USDT', 'ETH/USDT', 'XRP/USDT']), ([ - # Test total assets mode, 5 assets + # Get 4 pairs within top 8 ranks {"method": "StaticPairList", "allow_inactive": True}, - {"method": "MarketCapPairList", "mode": "total_assets", "number_assets": 5} + {"method": "MarketCapPairList", "max_rank": 8, "number_assets": 4} ], ['BTC/USDT', 'ETH/USDT', 'XRP/USDT']), ([ # MarketCapPairList as generator - {"method": "MarketCapPairList", "mode": "total_assets", "number_assets": 5} + {"method": "MarketCapPairList", "number_assets": 5} ], ['BTC/USDT', 'ETH/USDT', 'XRP/USDT']) ]) def test_MarketCapPairList_filter(mocker, default_conf_usdt, markets, pairlists, result): @@ -1576,7 +1576,7 @@ def test_MarketCapPairList_filter(mocker, default_conf_usdt, markets, pairlists, } ] - default_conf_usdt['exchange']['pair_whitelist'].extend(['BTC/USDT', 'ETC/USDT']) + default_conf_usdt['exchange']['pair_whitelist'].extend(['BTC/USDT', 'ETC/USDT', 'ADA/USDT']) default_conf_usdt['trading_mode'] = 'spot' default_conf_usdt['pairlists'] = pairlists mocker.patch.multiple(EXMS,