Refactor filter_pairlist()
This commit is contained in:
parent
cd3900549c
commit
7e43574382
@ -3,6 +3,7 @@ PairList Handler base class
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from abc import ABC, abstractmethod, abstractproperty
|
from abc import ABC, abstractmethod, abstractproperty
|
||||||
|
from copy import deepcopy
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from cachetools import TTLCache, cached
|
from cachetools import TTLCache, cached
|
||||||
@ -75,16 +76,40 @@ class IPairList(ABC):
|
|||||||
-> Please overwrite in subclasses
|
-> Please overwrite in subclasses
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
def _validate_pair(self, ticker) -> bool:
|
||||||
|
"""
|
||||||
|
Check one pair against Pairlist Handler's specific conditions.
|
||||||
|
|
||||||
|
Either implement it in the Pairlist Handler or override the generic
|
||||||
|
filter_pairlist() method.
|
||||||
|
|
||||||
|
:param ticker: ticker dict as returned from ccxt.load_markets()
|
||||||
|
:return: True if the pair can stay, false if it should be removed
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]:
|
def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]:
|
||||||
"""
|
"""
|
||||||
Filters and sorts pairlist and returns the whitelist again.
|
Filters and sorts pairlist and returns the whitelist again.
|
||||||
|
|
||||||
Called on each bot iteration - please use internal caching if necessary
|
Called on each bot iteration - please use internal caching if necessary
|
||||||
-> Please overwrite in subclasses
|
This generic implementation calls self._validate_pair() for each pair
|
||||||
|
in the pairlist.
|
||||||
|
|
||||||
|
Some Pairlist Handlers override this generic implementation and employ
|
||||||
|
own filtration.
|
||||||
|
|
||||||
:param pairlist: pairlist to filter or sort
|
:param pairlist: pairlist to filter or sort
|
||||||
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
|
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
|
||||||
:return: new whitelist
|
:return: new whitelist
|
||||||
"""
|
"""
|
||||||
|
# Copy list since we're modifying this list
|
||||||
|
for p in deepcopy(pairlist):
|
||||||
|
# Filter out assets
|
||||||
|
if not self._validate_pair(tickers[p]):
|
||||||
|
pairlist.remove(p)
|
||||||
|
|
||||||
|
return pairlist
|
||||||
|
|
||||||
def verify_blacklist(self, pairlist: List[str], logmethod) -> List[str]:
|
def verify_blacklist(self, pairlist: List[str], logmethod) -> List[str]:
|
||||||
"""
|
"""
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
Precision pair list filter
|
Precision pair list filter
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from copy import deepcopy
|
from typing import Any, Dict
|
||||||
from typing import Any, Dict, List
|
|
||||||
|
|
||||||
from freqtrade.pairlist.IPairList import IPairList
|
from freqtrade.pairlist.IPairList import IPairList
|
||||||
|
|
||||||
@ -36,16 +35,14 @@ class PrecisionFilter(IPairList):
|
|||||||
"""
|
"""
|
||||||
return f"{self.name} - Filtering untradable pairs."
|
return f"{self.name} - Filtering untradable pairs."
|
||||||
|
|
||||||
def _validate_precision_filter(self, ticker: dict, stoploss: float) -> bool:
|
def _validate_pair(self, ticker: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if pair has enough room to add a stoploss to avoid "unsellable" buys of very
|
Check if pair has enough room to add a stoploss to avoid "unsellable" buys of very
|
||||||
low value pairs.
|
low value pairs.
|
||||||
:param ticker: ticker dict as returned from ccxt.load_markets()
|
:param ticker: ticker dict as returned from ccxt.load_markets()
|
||||||
:param stoploss: stoploss value as set in the configuration
|
|
||||||
(already cleaned to be 1 - stoploss)
|
|
||||||
:return: True if the pair can stay, False if it should be removed
|
:return: True if the pair can stay, False if it should be removed
|
||||||
"""
|
"""
|
||||||
stop_price = ticker['ask'] * stoploss
|
stop_price = ticker['ask'] * self._stoploss
|
||||||
|
|
||||||
# Adjust stop-prices to precision
|
# Adjust stop-prices to precision
|
||||||
sp = self._exchange.price_to_precision(ticker["symbol"], stop_price)
|
sp = self._exchange.price_to_precision(ticker["symbol"], stop_price)
|
||||||
@ -60,15 +57,3 @@ class PrecisionFilter(IPairList):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]:
|
|
||||||
"""
|
|
||||||
Filters and sorts pairlists and assigns and returns them again.
|
|
||||||
"""
|
|
||||||
# Copy list since we're modifying this list
|
|
||||||
for p in deepcopy(pairlist):
|
|
||||||
# Filter out assets which would not allow setting a stoploss
|
|
||||||
if not self._validate_precision_filter(tickers[p], self._stoploss):
|
|
||||||
pairlist.remove(p)
|
|
||||||
|
|
||||||
return pairlist
|
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
Price pair list filter
|
Price pair list filter
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from copy import deepcopy
|
from typing import Any, Dict
|
||||||
from typing import Any, Dict, List
|
|
||||||
|
|
||||||
from freqtrade.pairlist.IPairList import IPairList
|
from freqtrade.pairlist.IPairList import IPairList
|
||||||
|
|
||||||
@ -35,12 +34,15 @@ class PriceFilter(IPairList):
|
|||||||
"""
|
"""
|
||||||
return f"{self.name} - Filtering pairs priced below {self._low_price_ratio * 100}%."
|
return f"{self.name} - Filtering pairs priced below {self._low_price_ratio * 100}%."
|
||||||
|
|
||||||
def _validate_ticker_lowprice(self, ticker) -> bool:
|
def _validate_pair(self, ticker) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if if one price-step (pip) is > than a certain barrier.
|
Check if if one price-step (pip) is > than a certain barrier.
|
||||||
:param ticker: ticker dict as returned from ccxt.load_markets()
|
:param ticker: ticker dict as returned from ccxt.load_markets()
|
||||||
:return: True if the pair can stay, false if it should be removed
|
:return: True if the pair can stay, false if it should be removed
|
||||||
"""
|
"""
|
||||||
|
if not self._low_price_ratio:
|
||||||
|
return True
|
||||||
|
|
||||||
if ticker['last'] is None:
|
if ticker['last'] is None:
|
||||||
self.log_on_refresh(logger.info,
|
self.log_on_refresh(logger.info,
|
||||||
f"Removed {ticker['symbol']} from whitelist, because "
|
f"Removed {ticker['symbol']} from whitelist, because "
|
||||||
@ -53,20 +55,3 @@ class PriceFilter(IPairList):
|
|||||||
f"because 1 unit is {changeperc * 100:.3f}%")
|
f"because 1 unit is {changeperc * 100:.3f}%")
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
if self._low_price_ratio:
|
|
||||||
# Copy list since we're modifying this list
|
|
||||||
for p in deepcopy(pairlist):
|
|
||||||
# Filter out assets which would not allow setting a stoploss
|
|
||||||
if not self._validate_ticker_lowprice(tickers[p]):
|
|
||||||
pairlist.remove(p)
|
|
||||||
|
|
||||||
return pairlist
|
|
||||||
|
@ -3,7 +3,7 @@ Shuffle pair list filter
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from typing import Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from freqtrade.pairlist.IPairList import IPairList
|
from freqtrade.pairlist.IPairList import IPairList
|
||||||
|
|
||||||
@ -13,7 +13,8 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class ShuffleFilter(IPairList):
|
class ShuffleFilter(IPairList):
|
||||||
|
|
||||||
def __init__(self, exchange, pairlistmanager, config, pairlistconfig: dict,
|
def __init__(self, exchange, pairlistmanager,
|
||||||
|
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
|
||||||
pairlist_pos: int) -> None:
|
pairlist_pos: int) -> None:
|
||||||
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
Spread pair list filter
|
Spread pair list filter
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from copy import deepcopy
|
from typing import Any, Dict
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from freqtrade.pairlist.IPairList import IPairList
|
from freqtrade.pairlist.IPairList import IPairList
|
||||||
|
|
||||||
@ -13,7 +12,8 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class SpreadFilter(IPairList):
|
class SpreadFilter(IPairList):
|
||||||
|
|
||||||
def __init__(self, exchange, pairlistmanager, config, pairlistconfig: dict,
|
def __init__(self, exchange, pairlistmanager,
|
||||||
|
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
|
||||||
pairlist_pos: int) -> None:
|
pairlist_pos: int) -> None:
|
||||||
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ class SpreadFilter(IPairList):
|
|||||||
return (f"{self.name} - Filtering pairs with ask/bid diff above "
|
return (f"{self.name} - Filtering pairs with ask/bid diff above "
|
||||||
f"{self._max_spread_ratio * 100}%.")
|
f"{self._max_spread_ratio * 100}%.")
|
||||||
|
|
||||||
def _validate_spread(self, ticker: dict) -> bool:
|
def _validate_pair(self, ticker: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Validate spread for the ticker
|
Validate spread for the ticker
|
||||||
:param ticker: ticker dict as returned from ccxt.load_markets()
|
:param ticker: ticker dict as returned from ccxt.load_markets()
|
||||||
@ -51,20 +51,3 @@ class SpreadFilter(IPairList):
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
# Copy list since we're modifying this list
|
|
||||||
for p in deepcopy(pairlist):
|
|
||||||
ticker = tickers[p]
|
|
||||||
# Filter out assets
|
|
||||||
if not self._validate_spread(ticker):
|
|
||||||
pairlist.remove(p)
|
|
||||||
|
|
||||||
return pairlist
|
|
||||||
|
@ -19,7 +19,8 @@ SORT_VALUES = ['askVolume', 'bidVolume', 'quoteVolume']
|
|||||||
|
|
||||||
class VolumePairList(IPairList):
|
class VolumePairList(IPairList):
|
||||||
|
|
||||||
def __init__(self, exchange, pairlistmanager, config: Dict[str, Any], pairlistconfig: dict,
|
def __init__(self, exchange, pairlistmanager,
|
||||||
|
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
|
||||||
pairlist_pos: int) -> None:
|
pairlist_pos: int) -> None:
|
||||||
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user