stable/freqtrade/pairlist/IPairList.py

130 lines
4.8 KiB
Python
Raw Normal View History

2018-12-05 19:44:56 +00:00
"""
2020-05-19 00:35:01 +00:00
PairList Handler base class
2020-05-17 11:13:26 +00:00
"""
2018-12-05 19:44:56 +00:00
import logging
from abc import ABC, abstractmethod, abstractproperty
2020-02-02 04:00:40 +00:00
from typing import Any, Dict, List
2018-12-05 19:44:56 +00:00
from cachetools import TTLCache, cached
from freqtrade.exchange import market_is_active
2020-05-17 11:13:26 +00:00
2018-12-05 19:44:56 +00:00
logger = logging.getLogger(__name__)
class IPairList(ABC):
2020-02-02 04:00:40 +00:00
def __init__(self, exchange, pairlistmanager,
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
pairlist_pos: int) -> None:
"""
:param exchange: Exchange instance
2020-05-19 00:35:01 +00:00
:param pairlistmanager: Instantiated Pairlist manager
:param config: Global bot configuration
2020-05-19 00:35:01 +00:00
:param pairlistconfig: Configuration for this Pairlist Handler - can be empty.
:param pairlist_pos: Position of the Pairlist Handler in the chain
"""
2019-11-09 05:55:16 +00:00
self._exchange = exchange
self._pairlistmanager = pairlistmanager
2018-12-05 19:44:56 +00:00
self._config = config
2019-11-09 05:55:16 +00:00
self._pairlistconfig = pairlistconfig
self._pairlist_pos = pairlist_pos
self.refresh_period = self._pairlistconfig.get('refresh_period', 1800)
self._last_refresh = 0
self._log_cache = TTLCache(maxsize=1024, ttl=self.refresh_period)
2018-12-05 19:44:56 +00:00
@property
def name(self) -> str:
"""
Gets name of the class
-> no need to overwrite in subclasses
"""
return self.__class__.__name__
def log_on_refresh(self, logmethod, message: str) -> None:
"""
Logs message - not more often than "refresh_period" to avoid log spamming
Logs the log-message as debug as well to simplify debugging.
:param logmethod: Function that'll be called. Most likely `logger.info`.
:param message: String containing the message to be sent to the function.
:return: None.
"""
@cached(cache=self._log_cache)
def _log_on_refresh(message: str):
logmethod(message)
# Log as debug first
logger.debug(message)
# Call hidden function.
_log_on_refresh(message)
@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
"""
2018-12-05 19:44:56 +00:00
@abstractmethod
def short_desc(self) -> str:
"""
Short whitelist method description - used for startup-messages
-> Please overwrite in subclasses
"""
@abstractmethod
2019-11-09 12:40:36 +00:00
def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]:
2018-12-05 19:44:56 +00:00
"""
2019-11-09 05:55:16 +00:00
Filters and sorts pairlist and returns the whitelist again.
Called on each bot iteration - please use internal caching if necessary
2018-12-05 19:44:56 +00:00
-> Please overwrite in subclasses
2019-11-09 05:55:16 +00:00
:param pairlist: pairlist to filter or sort
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
:return: new whitelist
2018-12-05 19:44:56 +00:00
"""
def verify_blacklist(self, pairlist: List[str], logmethod) -> List[str]:
2019-11-09 06:23:34 +00:00
"""
Proxy method to verify_blacklist for easy access for child classes.
2020-03-09 10:30:13 +00:00
:param pairlist: Pairlist to validate
:param logmethod: Function that'll be called, `logger.info` or `logger.warning`.
2020-03-09 10:30:13 +00:00
:return: pairlist - blacklisted pairs
"""
return self._pairlistmanager.verify_blacklist(pairlist, logmethod)
2019-11-09 06:23:34 +00:00
2019-11-09 13:44:39 +00:00
def _whitelist_for_active_markets(self, pairlist: List[str]) -> List[str]:
2018-12-05 19:44:56 +00:00
"""
Check available markets and remove pair from whitelist if necessary
2019-03-11 20:10:22 +00:00
:param whitelist: the sorted list of pairs the user might want to trade
:return: the list of pairs the user wants to trade without those unavailable or
2018-12-05 19:44:56 +00:00
black_listed
"""
2019-11-09 05:55:16 +00:00
markets = self._exchange.markets
2018-12-05 19:44:56 +00:00
2019-10-30 14:59:52 +00:00
sanitized_whitelist: List[str] = []
2019-11-09 13:44:39 +00:00
for pair in pairlist:
2019-11-09 05:55:16 +00:00
# pair is not in the generated dynamic market or has the wrong stake currency
if pair not in markets:
2019-03-17 17:18:35 +00:00
logger.warning(f"Pair {pair} is not compatible with exchange "
2019-11-09 05:55:16 +00:00
f"{self._exchange.name}. Removing it from whitelist..")
2018-12-05 19:44:56 +00:00
continue
2020-02-24 19:41:45 +00:00
2020-02-26 06:08:09 +00:00
if self._exchange.get_pair_quote_currency(pair) != self._config['stake_currency']:
logger.warning(f"Pair {pair} is not compatible with your stake currency "
f"{self._config['stake_currency']}. Removing it from whitelist..")
continue
# Check if market is active
market = markets[pair]
if not market_is_active(market):
2019-03-21 05:14:43 +00:00
logger.info(f"Ignoring {pair} from whitelist. Market is not active.")
continue
2019-10-30 14:59:52 +00:00
if pair not in sanitized_whitelist:
sanitized_whitelist.append(pair)
2018-12-05 19:44:56 +00:00
# We need to remove pairs that are unknown
2019-10-30 14:59:52 +00:00
return sanitized_whitelist