mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-12-14 11:51:19 +00:00
add DelistFilter
This commit is contained in:
@@ -587,6 +587,7 @@
|
|||||||
"RemotePairList",
|
"RemotePairList",
|
||||||
"MarketCapPairList",
|
"MarketCapPairList",
|
||||||
"AgeFilter",
|
"AgeFilter",
|
||||||
|
"DelistFilter",
|
||||||
"FullTradesFilter",
|
"FullTradesFilter",
|
||||||
"OffsetFilter",
|
"OffsetFilter",
|
||||||
"PerformanceFilter",
|
"PerformanceFilter",
|
||||||
|
|||||||
@@ -70,18 +70,38 @@
|
|||||||
"exit": "GTC"
|
"exit": "GTC"
|
||||||
},
|
},
|
||||||
"pairlists": [
|
"pairlists": [
|
||||||
{"method": "StaticPairList"},
|
{
|
||||||
{"method": "FullTradesFilter"},
|
"method": "StaticPairList"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "DelistFilter",
|
||||||
|
"max_days_from_now": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "FullTradesFilter"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"method": "VolumePairList",
|
"method": "VolumePairList",
|
||||||
"number_assets": 20,
|
"number_assets": 20,
|
||||||
"sort_key": "quoteVolume",
|
"sort_key": "quoteVolume",
|
||||||
"refresh_period": 1800
|
"refresh_period": 1800
|
||||||
},
|
},
|
||||||
{"method": "AgeFilter", "min_days_listed": 10},
|
{
|
||||||
{"method": "PrecisionFilter"},
|
"method": "AgeFilter",
|
||||||
{"method": "PriceFilter", "low_price_ratio": 0.01, "min_price": 0.00000010},
|
"min_days_listed": 10
|
||||||
{"method": "SpreadFilter", "max_spread_ratio": 0.005},
|
},
|
||||||
|
{
|
||||||
|
"method": "PrecisionFilter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "PriceFilter",
|
||||||
|
"low_price_ratio": 0.01,
|
||||||
|
"min_price": 0.00000010
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "SpreadFilter",
|
||||||
|
"max_spread_ratio": 0.005
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"method": "RangeStabilityFilter",
|
"method": "RangeStabilityFilter",
|
||||||
"lookback_days": 10,
|
"lookback_days": 10,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Pairlist Handlers define the list of pairs (pairlist) that the bot should trade.
|
|||||||
|
|
||||||
In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) and [`PercentChangePairList`](#percent-change-pair-list) Pairlist Handlers).
|
In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) and [`PercentChangePairList`](#percent-change-pair-list) Pairlist Handlers).
|
||||||
|
|
||||||
Additionally, [`AgeFilter`](#agefilter), [`PrecisionFilter`](#precisionfilter), [`PriceFilter`](#pricefilter), [`ShuffleFilter`](#shufflefilter), [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) act as Pairlist Filters, removing certain pairs and/or moving their positions in the pairlist.
|
Additionally, [`AgeFilter`](#agefilter), [`DelistFilter`](#delistfilter), [`PrecisionFilter`](#precisionfilter), [`PriceFilter`](#pricefilter), [`ShuffleFilter`](#shufflefilter), [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) act as Pairlist Filters, removing certain pairs and/or moving their positions in the pairlist.
|
||||||
|
|
||||||
If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You can define either `StaticPairList`, `VolumePairList`, `ProducerPairList`, `RemotePairList`, `MarketCapPairList` or `PercentChangePairList` as the starting Pairlist Handler.
|
If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You can define either `StaticPairList`, `VolumePairList`, `ProducerPairList`, `RemotePairList`, `MarketCapPairList` or `PercentChangePairList` as the starting Pairlist Handler.
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ You may also use something like `.*DOWN/BTC` or `.*UP/BTC` to exclude leveraged
|
|||||||
* [`RemotePairList`](#remotepairlist)
|
* [`RemotePairList`](#remotepairlist)
|
||||||
* [`MarketCapPairList`](#marketcappairlist)
|
* [`MarketCapPairList`](#marketcappairlist)
|
||||||
* [`AgeFilter`](#agefilter)
|
* [`AgeFilter`](#agefilter)
|
||||||
|
* [`DelistFilter`](#delistfilter)
|
||||||
* [`FullTradesFilter`](#fulltradesfilter)
|
* [`FullTradesFilter`](#fulltradesfilter)
|
||||||
* [`OffsetFilter`](#offsetfilter)
|
* [`OffsetFilter`](#offsetfilter)
|
||||||
* [`PerformanceFilter`](#performancefilter)
|
* [`PerformanceFilter`](#performancefilter)
|
||||||
@@ -270,7 +271,6 @@ You can limit the length of the pairlist with the optional parameter `number_ass
|
|||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
!!! Tip "Combining pairlists"
|
!!! Tip "Combining pairlists"
|
||||||
This pairlist can be combined with all other pairlists and filters for further pairlist reduction, and can also act as an "additional" pairlist, on top of already defined pairs.
|
This pairlist can be combined with all other pairlists and filters for further pairlist reduction, and can also act as an "additional" pairlist, on top of already defined pairs.
|
||||||
`ProducerPairList` can also be used multiple times in sequence, combining the pairs from multiple producers.
|
`ProducerPairList` can also be used multiple times in sequence, combining the pairs from multiple producers.
|
||||||
@@ -407,6 +407,13 @@ be caught out buying before the pair has finished dropping in price.
|
|||||||
|
|
||||||
This filter allows freqtrade to ignore pairs until they have been listed for at least `min_days_listed` days and listed before `max_days_listed`.
|
This filter allows freqtrade to ignore pairs until they have been listed for at least `min_days_listed` days and listed before `max_days_listed`.
|
||||||
|
|
||||||
|
#### DelistFilter
|
||||||
|
|
||||||
|
Removes pairs that will be delisted on the exchange maximum `max_days_from_now` days from now (defaults to `0` which remove all future delisted pairs no matter how far from now).
|
||||||
|
|
||||||
|
!!! Warning "Backtesting"
|
||||||
|
`DelistFilter` does not support backtesting mode.
|
||||||
|
|
||||||
#### FullTradesFilter
|
#### FullTradesFilter
|
||||||
|
|
||||||
Shrink whitelist to consist only in-trade pairs when the trade slots are full (when `max_open_trades` isn't being set to `-1` in the config).
|
Shrink whitelist to consist only in-trade pairs when the trade slots are full (when `max_open_trades` isn't being set to `-1` in the config).
|
||||||
@@ -601,7 +608,7 @@ Adding `"sort_direction": "asc"` or `"sort_direction": "desc"` enables sorting m
|
|||||||
|
|
||||||
### Full example of Pairlist Handlers
|
### Full example of Pairlist Handlers
|
||||||
|
|
||||||
The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, sorting pairs by `quoteVolume` and applies [`PrecisionFilter`](#precisionfilter) and [`PriceFilter`](#pricefilter), filtering all assets where 1 price unit is > 1%. Then the [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) is applied and pairs are finally shuffled with the random seed set to some predefined value.
|
The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, sorting pairs by `quoteVolume`, then filter future delisted pairs using [`DelistFilter`](#delistfilter) and [`AgeFilter`](#agefilter) to remove pairs that are listed less than 10 days ago. After that [`PrecisionFilter`](#precisionfilter) and [`PriceFilter`](#pricefilter) are applied, filtering all assets where 1 price unit is > 1%. Then the [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) are applied and pairs are finally shuffled with the random seed set to some predefined value.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"exchange": {
|
"exchange": {
|
||||||
@@ -614,6 +621,10 @@ The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets,
|
|||||||
"number_assets": 20,
|
"number_assets": 20,
|
||||||
"sort_key": "quoteVolume"
|
"sort_key": "quoteVolume"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"method": "DelistFilter",
|
||||||
|
"max_days_from_now": 0,
|
||||||
|
},
|
||||||
{"method": "AgeFilter", "min_days_listed": 10},
|
{"method": "AgeFilter", "min_days_listed": 10},
|
||||||
{"method": "PrecisionFilter"},
|
{"method": "PrecisionFilter"},
|
||||||
{"method": "PriceFilter", "low_price_ratio": 0.01},
|
{"method": "PriceFilter", "low_price_ratio": 0.01},
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ AVAILABLE_PAIRLISTS = [
|
|||||||
"RemotePairList",
|
"RemotePairList",
|
||||||
"MarketCapPairList",
|
"MarketCapPairList",
|
||||||
"AgeFilter",
|
"AgeFilter",
|
||||||
|
"DelistFilter",
|
||||||
"FullTradesFilter",
|
"FullTradesFilter",
|
||||||
"OffsetFilter",
|
"OffsetFilter",
|
||||||
"PerformanceFilter",
|
"PerformanceFilter",
|
||||||
|
|||||||
93
freqtrade/plugins/pairlist/DelistFilter.py
Normal file
93
freqtrade/plugins/pairlist/DelistFilter.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
"""
|
||||||
|
Delist pair list filter
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from datetime import UTC, datetime, timedelta
|
||||||
|
|
||||||
|
from freqtrade.exceptions import OperationalException
|
||||||
|
from freqtrade.exchange.exchange_types import Ticker
|
||||||
|
from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter, SupportsBacktesting
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DelistFilter(IPairList):
|
||||||
|
supports_backtesting = SupportsBacktesting.NO
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self._max_days_from_now = self._pairlistconfig.get("max_days_from_now", 0)
|
||||||
|
if self._max_days_from_now < 0:
|
||||||
|
raise OperationalException("DelistFilter requires max_days_from_now to be >= 0")
|
||||||
|
self._enabled = self._max_days_from_now >= 0
|
||||||
|
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
f"{self.name} - Filtering pairs that will be delisted"
|
||||||
|
+ (
|
||||||
|
f" in the next {self._max_days_from_now} days"
|
||||||
|
if self._max_days_from_now > 0
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
+ "."
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def description() -> str:
|
||||||
|
return "Filter pairs that will bbe delisted on exchange."
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def available_parameters() -> dict[str, PairlistParameter]:
|
||||||
|
return {
|
||||||
|
"max_days_from_now": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 0,
|
||||||
|
"description": "Max days from now",
|
||||||
|
"help": (
|
||||||
|
"Remove pairs that will be delisted in the next X days. Set to 0 to remove all."
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def _validate_pair(self, pair: str, ticker: Ticker | None) -> bool:
|
||||||
|
"""
|
||||||
|
Check if pair will be delisted.
|
||||||
|
:param pair: Pair that's currently validated
|
||||||
|
:param ticker: ticker dict as returned from ccxt.fetch_ticker
|
||||||
|
:return: True if the pair can stay, false if it should be removed
|
||||||
|
"""
|
||||||
|
delist_date = self._exchange.check_delisting_time(pair)
|
||||||
|
|
||||||
|
if delist_date is not None:
|
||||||
|
if self._max_days_from_now == 0:
|
||||||
|
self.log_once(
|
||||||
|
f"Removed {pair} from whitelist, because it will be delisted on {delist_date}.",
|
||||||
|
logger.info,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
current_datetime = datetime.now(UTC)
|
||||||
|
max_delist_date = current_datetime + timedelta(days=self._max_days_from_now)
|
||||||
|
if delist_date <= max_delist_date:
|
||||||
|
self.log_once(
|
||||||
|
f"Removed {pair} from whitelist, because it will be delisted on {delist_date}.",
|
||||||
|
logger.info,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
Reference in New Issue
Block a user