stable/freqtrade/plugins/pairlist/ExternalPairList.py
2022-08-19 22:40:01 -06:00

113 lines
3.5 KiB
Python

"""
External Pair List provider
Provides pair list from Leader data
"""
import logging
from threading import Event
from typing import Any, Dict, List
from freqtrade.plugins.pairlist.IPairList import IPairList
logger = logging.getLogger(__name__)
class ExternalPairList(IPairList):
"""
PairList plugin for use with replicate follower mode.
Will use pairs given from leader data.
Usage:
"pairlists": [
{
"method": "ExternalPairList",
"number_assets": 5, # We can limit the amount of pairs to use from leader
}
],
"""
def __init__(self, exchange, pairlistmanager,
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
pairlist_pos: int) -> None:
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
# Not sure how to enforce ExternalPairList as the only PairList
self._num_assets = self._pairlistconfig.get('number_assets')
self._leader_pairs: List[str] = []
self._has_data = Event()
def _clamped_pairlist(self):
"""
Return the self._leader_pairs pairlist limited to the maximum set num_assets
or the length of it.
"""
length = len(self._leader_pairs)
if self._num_assets:
return self._leader_pairs[:min(length, self._num_assets)]
else:
return self._leader_pairs
@property
def needstickers(self) -> bool:
"""
Boolean property defining if tickers are necessary.
If no Pairlist requires tickers, an empty Dict is passed
as tickers argument to filter_pairlist
"""
return False
def short_desc(self) -> str:
"""
Short whitelist method description - used for startup-messages
-> Please overwrite in subclasses
"""
return f"{self.name}"
def add_pairlist_data(self, pairlist: List[str]):
"""
Add pairs from Leader
"""
# If some pairs were removed on Leader, remove them here
for pair in self._leader_pairs:
if pair not in pairlist:
logger.debug(f"Leader removed pair: {pair}")
self._leader_pairs.remove(pair)
# Only add new pairs
seen = set(self._leader_pairs)
for pair in pairlist:
if pair in seen:
logger.debug(f"Encountered already existing pair {pair}")
continue
self._leader_pairs.append(pair)
if not self._has_data.is_set():
self._has_data.set()
def gen_pairlist(self, tickers: Dict) -> List[str]:
"""
Generate the pairlist
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
:return: List of pairs
"""
if not self._has_data.is_set():
logger.info("Waiting on pairlists from Leaders...")
self._has_data.wait()
logger.info("Pairlist data received...")
return self._clamped_pairlist()
def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]:
"""
Filters and sorts pairlist and returns the whitelist again.
Called on each bot iteration - please use internal caching if necessary
:param pairlist: pairlist to filter or sort
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
:return: new whitelist
"""
return self._clamped_pairlist()