Add valuefilter to Pricefilters
This commit is contained in:
parent
3006396398
commit
369f19df6b
@ -112,6 +112,7 @@ The `PriceFilter` allows filtering of pairs by price. Currently the following pr
|
||||
|
||||
* `min_price`
|
||||
* `max_price`
|
||||
* `max_value`
|
||||
* `low_price_ratio`
|
||||
|
||||
The `min_price` setting removes pairs where the price is below the specified price. This is useful if you wish to avoid trading very low-priced pairs.
|
||||
@ -120,6 +121,11 @@ This option is disabled by default, and will only apply if set to > 0.
|
||||
The `max_price` setting removes pairs where the price is above the specified price. This is useful if you wish to trade only low-priced pairs.
|
||||
This option is disabled by default, and will only apply if set to > 0.
|
||||
|
||||
The `max_value` setting removes pairs where the minimum value change is above a specified value.
|
||||
This is useful when an exchange has unbalanced limits. For example, if step-size = 1 (so you can only buy 1, or 2, or 3, but not 1.1 Coins) - and the price is pretty high (like 20$) as the coin has risen sharply since the last limit adaption.
|
||||
As a result of the above, you can only buy for 20$, or 40$ - but not for 25$.
|
||||
On exchanges that deduct fees from the receiving currency (e.g. FTX) - this can result in high value coins / amounts that are unsellable as the amount is slightly below the limit.
|
||||
|
||||
The `low_price_ratio` setting removes pairs where a raise of 1 price unit (pip) is above the `low_price_ratio` ratio.
|
||||
This option is disabled by default, and will only apply if set to > 0.
|
||||
|
||||
|
@ -7,7 +7,7 @@ from copy import deepcopy
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange import market_is_active
|
||||
from freqtrade.exchange import Exchange, market_is_active
|
||||
from freqtrade.mixins import LoggingMixin
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class IPairList(LoggingMixin, ABC):
|
||||
|
||||
def __init__(self, exchange, pairlistmanager,
|
||||
def __init__(self, exchange: Exchange, pairlistmanager,
|
||||
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
|
||||
pairlist_pos: int) -> None:
|
||||
"""
|
||||
@ -28,7 +28,7 @@ class IPairList(LoggingMixin, ABC):
|
||||
"""
|
||||
self._enabled = True
|
||||
|
||||
self._exchange = exchange
|
||||
self._exchange: Exchange = exchange
|
||||
self._pairlistmanager = pairlistmanager
|
||||
self._config = config
|
||||
self._pairlistconfig = pairlistconfig
|
||||
|
@ -27,9 +27,13 @@ class PriceFilter(IPairList):
|
||||
self._max_price = pairlistconfig.get('max_price', 0)
|
||||
if self._max_price < 0:
|
||||
raise OperationalException("PriceFilter requires max_price to be >= 0")
|
||||
self._max_value = pairlistconfig.get('max_value', 0)
|
||||
if self._max_value < 0:
|
||||
raise OperationalException("PriceFilter requires max_value to be >= 0")
|
||||
self._enabled = ((self._low_price_ratio > 0) or
|
||||
(self._min_price > 0) or
|
||||
(self._max_price > 0))
|
||||
(self._max_price > 0) or
|
||||
(self._max_value))
|
||||
|
||||
@property
|
||||
def needstickers(self) -> bool:
|
||||
@ -51,6 +55,8 @@ class PriceFilter(IPairList):
|
||||
active_price_filters.append(f"below {self._min_price:.8f}")
|
||||
if self._max_price != 0:
|
||||
active_price_filters.append(f"above {self._max_price:.8f}")
|
||||
if self._max_value != 0:
|
||||
active_price_filters.append(f"Value above {self._max_value:.8f}")
|
||||
|
||||
if len(active_price_filters):
|
||||
return f"{self.name} - Filtering pairs priced {' or '.join(active_price_filters)}."
|
||||
@ -79,6 +85,32 @@ class PriceFilter(IPairList):
|
||||
f"because 1 unit is {changeperc * 100:.3f}%", logger.info)
|
||||
return False
|
||||
|
||||
# Perform low_amount check
|
||||
if self._max_value != 0:
|
||||
price = ticker['last']
|
||||
market = self._exchange.markets[pair]
|
||||
limits = market['limits']
|
||||
if ('amount' in limits and 'min' in limits['amount']
|
||||
and limits['amount']['min'] is not None):
|
||||
min_amount = limits['amount']['min']
|
||||
min_precision = market['precision']['amount']
|
||||
|
||||
min_value = min_amount * price
|
||||
if self._exchange.precisionMode == 4:
|
||||
# tick size
|
||||
next_value = (min_amount + min_precision) * price
|
||||
else:
|
||||
# Decimal places
|
||||
min_precision = pow(0.1, min_precision)
|
||||
next_value = (min_amount + min_precision) * price
|
||||
diff = next_value - min_value
|
||||
|
||||
if diff > self._max_value:
|
||||
self.log_once(f"Removed {pair} from whitelist, "
|
||||
f"because min value change of {diff} > {self._max_value}) ",
|
||||
logger.info)
|
||||
return False
|
||||
|
||||
# Perform min_price check.
|
||||
if self._min_price != 0:
|
||||
if ticker['last'] < self._min_price:
|
||||
@ -89,7 +121,7 @@ class PriceFilter(IPairList):
|
||||
# Perform max_price check.
|
||||
if self._max_price != 0:
|
||||
if ticker['last'] > self._max_price:
|
||||
self.log_once(f"Removed {ticker['symbol']} from whitelist, "
|
||||
self.log_once(f"Removed {pair} from whitelist, "
|
||||
f"because last price > {self._max_price:.8f}", logger.info)
|
||||
return False
|
||||
|
||||
|
@ -800,6 +800,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo
|
||||
"[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.00002000.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "PriceFilter", "max_value": 0.00002000},
|
||||
"[{'PriceFilter': 'PriceFilter - Filtering pairs priced Value above 0.00002000.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "PriceFilter"},
|
||||
"[{'PriceFilter': 'PriceFilter - No price filters configured.'}]",
|
||||
None
|
||||
@ -816,6 +820,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo
|
||||
None,
|
||||
"PriceFilter requires max_price to be >= 0"
|
||||
), # OperationalException expected
|
||||
({"method": "PriceFilter", "max_value": -1.00010000},
|
||||
None,
|
||||
"PriceFilter requires max_value to be >= 0"
|
||||
), # OperationalException expected
|
||||
({"method": "RangeStabilityFilter", "lookback_days": 10, "min_rate_of_change": 0.01},
|
||||
"[{'RangeStabilityFilter': 'RangeStabilityFilter - Filtering pairs with rate of change below "
|
||||
"0.01 over the last days.'}]",
|
||||
|
Loading…
Reference in New Issue
Block a user