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.**
@@ -99,9 +100,9 @@ file as reference.**
Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document. Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document.
??? Hint "Lookahead and recursive analysis" ??? Hint "Lookahead and recursive analysis"
Freqtrade includes two helpful commands to help assess common lookahead (using future data) and Freqtrade includes two helpful commands to help assess common lookahead (using future data) and
recursive bias (variance in indicator values) issues. Before running a strategy in dry or live more, recursive bias (variance in indicator values) issues. Before running a strategy in dry or live more,
you should always use these commands first. Please check the relevant documentation for you should always use these commands first. Please check the relevant documentation for
[lookahead](lookahead-analysis.md) and [recursive](recursive-analysis.md) analysis. [lookahead](lookahead-analysis.md) and [recursive](recursive-analysis.md) analysis.
### Dataframe ### Dataframe
@@ -154,7 +155,7 @@ Vectorized operations perform calculations across the whole range of data and ar
!!! Warning "Trade order assumptions" !!! Warning "Trade order assumptions"
In backtesting, signals are generated on candle close. Trades are then initiated immeditely on next candle open. In backtesting, signals are generated on candle close. Trades are then initiated immeditely on next candle open.
In dry and live, this may be delayed due to all pair dataframes needing to be analysed first, then trade processing In dry and live, this may be delayed due to all pair dataframes needing to be analysed first, then trade processing
for each of those pairs happens. This means that in dry/live you need to be mindful of having as low a computation for each of those pairs happens. This means that in dry/live you need to be mindful of having as low a computation
delay as possible, usually by running a low number of pairs and having a CPU with a good clock speed. delay as possible, usually by running a low number of pairs and having a CPU with a good clock speed.
@@ -284,7 +285,7 @@ It's important to always return the dataframe without removing/modifying the col
This method will also define a new column, `"enter_long"` (`"enter_short"` for shorts), which needs to contain `1` for entries, and `0` for "no action". `enter_long` is a mandatory column that must be set even if the strategy is shorting only. This method will also define a new column, `"enter_long"` (`"enter_short"` for shorts), which needs to contain `1` for entries, and `0` for "no action". `enter_long` is a mandatory column that must be set even if the strategy is shorting only.
You can name your entry signals by using the `"enter_tag"` column, which can help debug and assess your strategy later. You can name your entry signals by using the `"enter_tag"` column, which can help debug and assess your strategy later.
Sample from `user_data/strategies/sample_strategy.py`: Sample from `user_data/strategies/sample_strategy.py`:
@@ -555,7 +556,7 @@ A full sample can be found [in the DataProvider section](#complete-dataprovider-
??? Note "Alternative candle types" ??? Note "Alternative candle types"
Informative_pairs can also provide a 3rd tuple element defining the candle type explicitly. Informative_pairs can also provide a 3rd tuple element defining the candle type explicitly.
Availability of alternative candle-types will depend on the trading-mode and the exchange. Availability of alternative candle-types will depend on the trading-mode and the exchange.
In general, spot pairs cannot be used in futures markets, and futures candles can't be used as informative pairs for spot bots. In general, spot pairs cannot be used in futures markets, and futures candles can't be used as informative pairs for spot bots.
Details about this may vary, if they do, this can be found in the exchange documentation. Details about this may vary, if they do, this can be found in the exchange documentation.
@@ -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]: