diff --git a/freqtrade/pairlist/IPairList.py b/freqtrade/pairlist/IPairList.py index 845c5d01f..366a49bae 100644 --- a/freqtrade/pairlist/IPairList.py +++ b/freqtrade/pairlist/IPairList.py @@ -5,7 +5,7 @@ Provides lists as configured in config.json """ import logging -from abc import ABC, abstractmethod +from abc import ABC, abstractmethod, abstractproperty from typing import Dict, List from freqtrade.exchange import market_is_active @@ -28,6 +28,14 @@ class IPairList(ABC): """ return self.__class__.__name__ + @abstractproperty + def needstickers(self) -> bool: + """ + Boolean property defining if tickers are necessary. + If no Pairlist requries tickers, an empty List is passed + as tickers argument to filter_pairlist + """ + @abstractmethod def short_desc(self) -> str: """ diff --git a/freqtrade/pairlist/LowPriceFilter.py b/freqtrade/pairlist/LowPriceFilter.py index 2f4a3be75..4d4a92676 100644 --- a/freqtrade/pairlist/LowPriceFilter.py +++ b/freqtrade/pairlist/LowPriceFilter.py @@ -14,6 +14,15 @@ class LowPriceFilter(IPairList): self._low_price_percent = pairlistconfig.get('low_price_percent', 0) + @property + def needstickers(self) -> bool: + """ + Boolean property defining if tickers are necessary. + If no Pairlist requries tickers, an empty List is passed + as tickers argument to filter_pairlist + """ + return True + def short_desc(self) -> str: """ Short whitelist method description - used for startup-messages diff --git a/freqtrade/pairlist/PrecisionFilter.py b/freqtrade/pairlist/PrecisionFilter.py index 0a590bec6..3e68ec607 100644 --- a/freqtrade/pairlist/PrecisionFilter.py +++ b/freqtrade/pairlist/PrecisionFilter.py @@ -9,6 +9,15 @@ logger = logging.getLogger(__name__) class PrecisionFilter(IPairList): + @property + def needstickers(self) -> bool: + """ + Boolean property defining if tickers are necessary. + If no Pairlist requries tickers, an empty List is passed + as tickers argument to filter_pairlist + """ + return True + def short_desc(self) -> str: """ Short whitelist method description - used for startup-messages diff --git a/freqtrade/pairlist/StaticPairList.py b/freqtrade/pairlist/StaticPairList.py index c10dde5a6..54cd21d13 100644 --- a/freqtrade/pairlist/StaticPairList.py +++ b/freqtrade/pairlist/StaticPairList.py @@ -17,6 +17,15 @@ class StaticPairList(IPairList): def __init__(self, exchange, config, pairlistconfig: dict) -> None: super().__init__(exchange, config, pairlistconfig) + @property + def needstickers(self) -> bool: + """ + Boolean property defining if tickers are necessary. + If no Pairlist requries tickers, an empty List is passed + as tickers argument to filter_pairlist + """ + return False + def short_desc(self) -> str: """ Short whitelist method description - used for startup-messages @@ -32,4 +41,4 @@ class StaticPairList(IPairList): :param tickers: Tickers (from exchange.get_tickers()). May be cached. :return: new whitelist """ - return self.validate_whitelist(self._config['exchange']['pair_whitelist']) + return self._config['exchange']['pair_whitelist'] diff --git a/freqtrade/pairlist/VolumePairList.py b/freqtrade/pairlist/VolumePairList.py index ff601bc44..27b99ade8 100644 --- a/freqtrade/pairlist/VolumePairList.py +++ b/freqtrade/pairlist/VolumePairList.py @@ -38,6 +38,15 @@ class VolumePairList(IPairList): raise OperationalException( f'key {self._sort_key} not in {SORT_VALUES}') + @property + def needstickers(self) -> bool: + """ + Boolean property defining if tickers are necessary. + If no Pairlist requries tickers, an empty List is passed + as tickers argument to filter_pairlist + """ + return True + def _validate_keys(self, key): return key in SORT_VALUES diff --git a/freqtrade/pairlist/pairlistmanager.py b/freqtrade/pairlist/pairlistmanager.py index 9e92fdb6a..d3532ee54 100644 --- a/freqtrade/pairlist/pairlistmanager.py +++ b/freqtrade/pairlist/pairlistmanager.py @@ -22,11 +22,12 @@ class PairListManager(): self._whitelist = self._config['exchange'].get('pair_whitelist') self._blacklist = self._config['exchange'].get('pair_blacklist', []) self._pairlists: List[IPairList] = [] - + self._tickers_needed = False for pl in self._config.get('pairlists', [{'method': "StaticPairList"}]): pairl = PairListResolver(pl.get('method'), exchange, config, pl.get('config')).pairlist + self._tickers_needed = pairl.needstickers or self._tickers_needed self._pairlists.append(pairl) @property @@ -52,17 +53,22 @@ class PairListManager(): pairlist = self._whitelist.copy() # tickers should be cached to avoid calling the exchange on each call. - tickers = self._exchange.get_tickers() + tickers = [] + if self._tickers_needed: + tickers = self._exchange.get_tickers() + for pl in self._pairlists: pl.filter_pairlist(pairlist, tickers) - pairlist = self._verify_blacklist(pairlist) + # Validation against blacklist happens after the pairlists to ensure blacklist is respected. + pairlist = self.verify_blacklist(pairlist, self.blacklist) self._whitelist = pairlist - def _verify_blacklist(self, pairlist: List[str]) -> List[str]: + @staticmethod + def verify_blacklist(pairlist: List[str], blacklist: List[str]) -> List[str]: for pair in deepcopy(pairlist): - if pair in self.blacklist: + if pair in blacklist: logger.warning(f"Pair {pair} in your blacklist. Removing it from whitelist...") pairlist.remove(pair) return pairlist