add example, make sure to raise error on unsupported exchanges and/or trading mode

This commit is contained in:
Stefano
2025-09-22 15:55:36 +09:00
parent 07d5636d1e
commit 9c0d612729
6 changed files with 32 additions and 11 deletions

View File

@@ -409,7 +409,9 @@ This filter allows freqtrade to ignore pairs until they have been listed for at
#### DelistFilter #### 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). 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). Currently this filter only supports following exchanges:
* Binance (Spot and Futures)
!!! Warning "Backtesting" !!! Warning "Backtesting"
`DelistFilter` does not support backtesting mode. `DelistFilter` does not support backtesting mode.

View File

@@ -84,6 +84,7 @@ Check the [configuration documentation](configuration.md) about how to set the b
**Always use dry mode when testing as this gives you an idea of how your strategy will work in reality without risking capital.** **Always use dry mode when testing as this gives you an idea of how your strategy will work in reality without risking capital.**
## Diving in deeper ## Diving in deeper
**For the following section we will use the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py) **For the following section we will use the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py)
file as reference.** file as reference.**
@@ -775,6 +776,7 @@ Please always check the mode of operation to select the correct method to get da
### Possible options for DataProvider ### Possible options for DataProvider
- [`available_pairs`](#available_pairs) - Property with tuples listing cached pairs with their timeframe (pair, timeframe). - [`available_pairs`](#available_pairs) - Property with tuples listing cached pairs with their timeframe (pair, timeframe).
- [`check_delisting(pair)`](#check_delisting) - Return Datetime of the pair delisting schedule if any, otherwise return None
- [`current_whitelist()`](#current_whitelist) - Returns a current list of whitelisted pairs. Useful for accessing dynamic whitelists (i.e. VolumePairlist) - [`current_whitelist()`](#current_whitelist) - Returns a current list of whitelisted pairs. Useful for accessing dynamic whitelists (i.e. VolumePairlist)
- [`get_pair_dataframe(pair, timeframe)`](#get_pair_dataframepair-timeframe) - This is a universal method, which returns either historical data (for backtesting) or cached live data (for the Dry-Run and Live-Run modes). - [`get_pair_dataframe(pair, timeframe)`](#get_pair_dataframepair-timeframe) - This is a universal method, which returns either historical data (for backtesting) or cached live data (for the Dry-Run and Live-Run modes).
- [`get_analyzed_dataframe(pair, timeframe)`](#get_analyzed_dataframepair-timeframe) - Returns the analyzed dataframe (after calling `populate_indicators()`, `populate_buy()`, `populate_sell()`) and the time of the latest analysis. - [`get_analyzed_dataframe(pair, timeframe)`](#get_analyzed_dataframepair-timeframe) - Returns the analyzed dataframe (after calling `populate_indicators()`, `populate_buy()`, `populate_sell()`) and the time of the latest analysis.
@@ -795,6 +797,15 @@ for pair, timeframe in self.dp.available_pairs:
print(f"available {pair}, {timeframe}") print(f"available {pair}, {timeframe}")
``` ```
### *check_delisting(pair)*
```python
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs):
delisting_dt = self.dp.check_delisting(pair)
if delisting_dt is not None:
return "delist"
```
### *current_whitelist()* ### *current_whitelist()*
Imagine you've developed a strategy that trades the `5m` timeframe using signals generated from a `1d` timeframe on the top 10 exchange pairs by volume. Imagine you've developed a strategy that trades the `5m` timeframe using signals generated from a `1d` timeframe on the top 10 exchange pairs by volume.

View File

@@ -41,6 +41,7 @@ class Binance(Exchange):
"fetch_orders_limit_minutes": None, "fetch_orders_limit_minutes": None,
"l2_limit_range": [5, 10, 20, 50, 100, 500, 1000], "l2_limit_range": [5, 10, 20, 50, 100, 500, 1000],
"ws_enabled": True, "ws_enabled": True,
"has_delisting": True,
} }
_ft_has_futures: FtHas = { _ft_has_futures: FtHas = {
"funding_fee_candle_limit": 1000, "funding_fee_candle_limit": 1000,

View File

@@ -166,6 +166,7 @@ class Exchange:
"proxy_coin_mapping": {}, # Mapping for proxy coins "proxy_coin_mapping": {}, # Mapping for proxy coins
# Expected to be in the format {"fetchOHLCV": True} or {"fetchOHLCV": False} # Expected to be in the format {"fetchOHLCV": True} or {"fetchOHLCV": False}
"ws_enabled": False, # Set to true for exchanges with tested websocket support "ws_enabled": False, # Set to true for exchanges with tested websocket support
"has_delisting": False, # Set to true for exchanges that have delisting pair checks
} }
_ft_has: FtHas = {} _ft_has: FtHas = {}
_ft_has_futures: FtHas = {} _ft_has_futures: FtHas = {}

View File

@@ -63,6 +63,9 @@ class FtHas(TypedDict, total=False):
# Websocket control # Websocket control
ws_enabled: bool ws_enabled: bool
# Delisting check
has_delisting: bool
class Ticker(TypedDict): class Ticker(TypedDict):
symbol: str symbol: str

View File

@@ -5,7 +5,7 @@ Delist pair list filter
import logging import logging
from datetime import UTC, datetime, timedelta from datetime import UTC, datetime, timedelta
from freqtrade.exceptions import OperationalException from freqtrade.exceptions import ConfigurationError
from freqtrade.exchange.exchange_types import Ticker from freqtrade.exchange.exchange_types import Ticker
from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter, SupportsBacktesting from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter, SupportsBacktesting
@@ -21,8 +21,11 @@ class DelistFilter(IPairList):
self._max_days_from_now = self._pairlistconfig.get("max_days_from_now", 0) self._max_days_from_now = self._pairlistconfig.get("max_days_from_now", 0)
if self._max_days_from_now < 0: if self._max_days_from_now < 0:
raise OperationalException("DelistFilter requires max_days_from_now to be >= 0") raise ConfigurationError("DelistFilter requires max_days_from_now to be >= 0")
self._enabled = self._max_days_from_now >= 0 if not self._exchange._ft_has["has_delisting"]:
raise ConfigurationError(
"DelistFilter doesn't support this exchange and trading mode combination.",
)
@property @property
def needstickers(self) -> bool: def needstickers(self) -> bool:
@@ -49,7 +52,7 @@ class DelistFilter(IPairList):
@staticmethod @staticmethod
def description() -> str: def description() -> str:
return "Filter pairs that will bbe delisted on exchange." return "Filter pairs that will be delisted on exchange."
@staticmethod @staticmethod
def available_parameters() -> dict[str, PairlistParameter]: def available_parameters() -> dict[str, PairlistParameter]: