diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index 29e20a32f..f6e8cb6d4 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -260,7 +260,7 @@ Min price precision for SHITCOIN/BTC is 8 decimals. If its price is 0.00000011 - Shuffles (randomizes) pairs in the pairlist. It can be used for preventing the bot from trading some of the pairs more frequently then others when you want all pairs be treated with the same priority. !!! Tip - You may set the `seed` value for this Pairlist to obtain reproducible results, which can be useful for repeated backtesting sessions. If `seed` is not set, the pairs are shuffled in the non-repeatable random order. + You may set the `seed` value for this Pairlist to obtain reproducible results, which can be useful for repeated backtesting sessions. If `seed` is not set, the pairs are shuffled in the non-repeatable random order. ShuffleFilter will automatically detect runmodes and apply the `seed` only for backtesting modes - if a `seed` value is set. #### SpreadFilter diff --git a/freqtrade/plugins/pairlist/ShuffleFilter.py b/freqtrade/plugins/pairlist/ShuffleFilter.py index 4d3dd29e3..55cf9938f 100644 --- a/freqtrade/plugins/pairlist/ShuffleFilter.py +++ b/freqtrade/plugins/pairlist/ShuffleFilter.py @@ -5,6 +5,7 @@ import logging import random from typing import Any, Dict, List +from freqtrade.enums.runmode import RunMode from freqtrade.plugins.pairlist.IPairList import IPairList @@ -18,7 +19,15 @@ class ShuffleFilter(IPairList): pairlist_pos: int) -> None: super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) - self._seed = pairlistconfig.get('seed') + # Apply seed in backtesting mode to get comparable results, + # but not in live modes to get a non-repeating order of pairs during live modes. + if config.get('runmode') in (RunMode.LIVE, RunMode.DRY_RUN): + self._seed = None + logger.info("Live mode detected, not applying seed.") + else: + self._seed = pairlistconfig.get('seed') + logger.info(f"Backtesting mode detected, applying seed value: {self._seed}") + self._random = random.Random(self._seed) @property diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index 6333266aa..ba8e6c3c3 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -7,6 +7,7 @@ import pytest import time_machine from freqtrade.constants import AVAILABLE_PAIRLISTS +from freqtrade.enums.runmode import RunMode from freqtrade.exceptions import OperationalException from freqtrade.persistence import Trade from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -657,6 +658,22 @@ def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None: assert log_has("PerformanceFilter is not available in this mode.", caplog) +def test_ShuffleFilter_init(mocker, whitelist_conf, caplog) -> None: + whitelist_conf['pairlists'] = [ + {"method": "StaticPairList"}, + {"method": "ShuffleFilter", "seed": 42} + ] + + exchange = get_patched_exchange(mocker, whitelist_conf) + PairListManager(exchange, whitelist_conf) + assert log_has("Backtesting mode detected, applying seed value: 42", caplog) + caplog.clear() + whitelist_conf['runmode'] = RunMode.DRY_RUN + PairListManager(exchange, whitelist_conf) + assert not log_has("Backtesting mode detected, applying seed value: 42", caplog) + assert log_has("Live mode detected, not applying seed.", caplog) + + @pytest.mark.usefixtures("init_persistence") def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee, caplog) -> None: whitelist_conf['exchange']['pair_whitelist'].append('XRP/BTC')