mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-12-14 03:41:14 +00:00
add DelistFilter
This commit is contained in:
@@ -587,6 +587,7 @@
|
||||
"RemotePairList",
|
||||
"MarketCapPairList",
|
||||
"AgeFilter",
|
||||
"DelistFilter",
|
||||
"FullTradesFilter",
|
||||
"OffsetFilter",
|
||||
"PerformanceFilter",
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
"trading_mode": "spot",
|
||||
"margin_mode": "",
|
||||
"minimal_roi": {
|
||||
"40": 0.0,
|
||||
"30": 0.01,
|
||||
"20": 0.02,
|
||||
"0": 0.04
|
||||
"40": 0.0,
|
||||
"30": 0.01,
|
||||
"20": 0.02,
|
||||
"0": 0.04
|
||||
},
|
||||
"stoploss": -0.10,
|
||||
"unfilledtimeout": {
|
||||
@@ -47,7 +47,7 @@
|
||||
"bids_to_ask_delta": 1
|
||||
}
|
||||
},
|
||||
"exit_pricing":{
|
||||
"exit_pricing": {
|
||||
"price_side": "same",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1,
|
||||
@@ -70,18 +70,38 @@
|
||||
"exit": "GTC"
|
||||
},
|
||||
"pairlists": [
|
||||
{"method": "StaticPairList"},
|
||||
{"method": "FullTradesFilter"},
|
||||
{
|
||||
"method": "StaticPairList"
|
||||
},
|
||||
{
|
||||
"method": "DelistFilter",
|
||||
"max_days_from_now": 0,
|
||||
},
|
||||
{
|
||||
"method": "FullTradesFilter"
|
||||
},
|
||||
{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume",
|
||||
"refresh_period": 1800
|
||||
},
|
||||
{"method": "AgeFilter", "min_days_listed": 10},
|
||||
{"method": "PrecisionFilter"},
|
||||
{"method": "PriceFilter", "low_price_ratio": 0.01, "min_price": 0.00000010},
|
||||
{"method": "SpreadFilter", "max_spread_ratio": 0.005},
|
||||
{
|
||||
"method": "AgeFilter",
|
||||
"min_days_listed": 10
|
||||
},
|
||||
{
|
||||
"method": "PrecisionFilter"
|
||||
},
|
||||
{
|
||||
"method": "PriceFilter",
|
||||
"low_price_ratio": 0.01,
|
||||
"min_price": 0.00000010
|
||||
},
|
||||
{
|
||||
"method": "SpreadFilter",
|
||||
"max_spread_ratio": 0.005
|
||||
},
|
||||
{
|
||||
"method": "RangeStabilityFilter",
|
||||
"lookback_days": 10,
|
||||
@@ -166,12 +186,12 @@
|
||||
"external_message_consumer": {
|
||||
"enabled": false,
|
||||
"producers": [
|
||||
{
|
||||
"name": "default",
|
||||
"host": "127.0.0.2",
|
||||
"port": 8080,
|
||||
"ws_token": "secret_ws_t0ken."
|
||||
}
|
||||
{
|
||||
"name": "default",
|
||||
"host": "127.0.0.2",
|
||||
"port": 8080,
|
||||
"ws_token": "secret_ws_t0ken."
|
||||
}
|
||||
],
|
||||
"wait_timeout": 300,
|
||||
"ping_timeout": 10,
|
||||
@@ -195,4 +215,4 @@
|
||||
"reduce_df_footprint": false,
|
||||
"dataformat_ohlcv": "feather",
|
||||
"dataformat_trades": "feather"
|
||||
}
|
||||
}
|
||||
@@ -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).
|
||||
|
||||
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.
|
||||
|
||||
@@ -27,6 +27,7 @@ You may also use something like `.*DOWN/BTC` or `.*UP/BTC` to exclude leveraged
|
||||
* [`RemotePairList`](#remotepairlist)
|
||||
* [`MarketCapPairList`](#marketcappairlist)
|
||||
* [`AgeFilter`](#agefilter)
|
||||
* [`DelistFilter`](#delistfilter)
|
||||
* [`FullTradesFilter`](#fulltradesfilter)
|
||||
* [`OffsetFilter`](#offsetfilter)
|
||||
* [`PerformanceFilter`](#performancefilter)
|
||||
@@ -180,7 +181,7 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl
|
||||
* `refresh_period`: Defines the interval (in seconds) at which the pairlist will be refreshed. The default is 1800 seconds (30 minutes).
|
||||
* `lookback_days`: Number of days to look back. When `lookback_days` is selected, the `lookback_timeframe` is defaulted to 1 day.
|
||||
* `lookback_timeframe`: Timeframe to use for the lookback period.
|
||||
* `lookback_period`: Number of periods to look back at.
|
||||
* `lookback_period`: Number of periods to look back at.
|
||||
|
||||
When PercentChangePairList is used after other Pairlist Handlers, it will operate on the outputs of those handlers. If it is the leading Pairlist Handler, it will select pairs from all available markets with the specified stake currency.
|
||||
|
||||
@@ -270,7 +271,6 @@ You can limit the length of the pairlist with the optional parameter `number_ass
|
||||
],
|
||||
```
|
||||
|
||||
|
||||
!!! 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.
|
||||
`ProducerPairList` can also be used multiple times in sequence, combining the pairs from multiple producers.
|
||||
@@ -312,7 +312,7 @@ The `pairlist_url` option specifies the URL of the remote server where the pairl
|
||||
The `save_to_file` option, when provided with a valid filename, saves the processed pairlist to that file in JSON format. This option is optional, and by default, the pairlist is not saved to a file.
|
||||
|
||||
??? Example "Multi bot with shared pairlist example"
|
||||
|
||||
|
||||
`save_to_file` can be used to save the pairlist to a file with Bot1:
|
||||
|
||||
```json
|
||||
@@ -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`.
|
||||
|
||||
#### 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
|
||||
|
||||
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).
|
||||
@@ -438,7 +445,7 @@ Example to remove the first 10 pairs from the pairlist, and takes the next 20 (t
|
||||
```
|
||||
|
||||
!!! Warning
|
||||
When `OffsetFilter` is used to split a larger pairlist among multiple bots in combination with `VolumeFilter`
|
||||
When `OffsetFilter` is used to split a larger pairlist among multiple bots in combination with `VolumeFilter`
|
||||
it can not be guaranteed that pairs won't overlap due to slightly different refresh intervals for the
|
||||
`VolumeFilter`.
|
||||
|
||||
@@ -601,7 +608,7 @@ Adding `"sort_direction": "asc"` or `"sort_direction": "desc"` enables sorting m
|
||||
|
||||
### 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
|
||||
"exchange": {
|
||||
@@ -614,6 +621,10 @@ The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets,
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume"
|
||||
},
|
||||
{
|
||||
"method": "DelistFilter",
|
||||
"max_days_from_now": 0,
|
||||
},
|
||||
{"method": "AgeFilter", "min_days_listed": 10},
|
||||
{"method": "PrecisionFilter"},
|
||||
{"method": "PriceFilter", "low_price_ratio": 0.01},
|
||||
|
||||
@@ -49,6 +49,7 @@ AVAILABLE_PAIRLISTS = [
|
||||
"RemotePairList",
|
||||
"MarketCapPairList",
|
||||
"AgeFilter",
|
||||
"DelistFilter",
|
||||
"FullTradesFilter",
|
||||
"OffsetFilter",
|
||||
"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