From 1b81de01b48689cb805d20d88cea4b1d0b356901 Mon Sep 17 00:00:00 2001 From: jainanuj94 Date: Thu, 25 Jul 2024 00:04:06 +0530 Subject: [PATCH 01/31] 10348 | run ruff formatter --- freqtrade/plugins/pairlist/PercentVolumeChangePairList.py | 7 +++++-- tests/plugins/test_pairlist.py | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/freqtrade/plugins/pairlist/PercentVolumeChangePairList.py b/freqtrade/plugins/pairlist/PercentVolumeChangePairList.py index 0aee37959..777acda60 100644 --- a/freqtrade/plugins/pairlist/PercentVolumeChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentVolumeChangePairList.py @@ -5,6 +5,7 @@ Provides dynamic pair list based on trade change sorted based on percentage change in volume over a defined period """ + import logging from datetime import timedelta from typing import Any, Dict, List, Literal @@ -118,8 +119,10 @@ class PercentVolumeChangePairList(IPairList): """ Short whitelist method description - used for startup-messages """ - return (f"{self.name} - top {self._pairlistconfig['number_assets']} percent " - f"volume change pairs.") + return ( + f"{self.name} - top {self._pairlistconfig['number_assets']} percent " + f"volume change pairs." + ) @staticmethod def description() -> str: diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index e5a19ea74..7e5fd4c12 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -34,8 +34,9 @@ from tests.conftest import ( # Exclude RemotePairList and PercentVolumeChangePairList from tests. # They have mandatory parameters, and requires special handling, # which happens in test_remotepairlist and test_percentvolumechangepairlist. -TESTABLE_PAIRLISTS = [p for p in AVAILABLE_PAIRLISTS - if p not in ["RemotePairList", "PercentVolumeChangePairList"]] +TESTABLE_PAIRLISTS = [ + p for p in AVAILABLE_PAIRLISTS if p not in ["RemotePairList", "PercentVolumeChangePairList"] +] @pytest.fixture(scope="function") From dad4f30597b693acab57075565d1d6455b535b82 Mon Sep 17 00:00:00 2001 From: jainanuj94 Date: Thu, 25 Jul 2024 23:33:28 +0530 Subject: [PATCH 02/31] Correct calculation for percent calculation and use tickers --- freqtrade/constants.py | 2 +- freqtrade/exchange/exchange.py | 1 + freqtrade/exchange/types.py | 1 + ...gePairList.py => PercentChangePairList.py} | 203 ++++++++++-------- tests/conftest.py | 2 +- tests/plugins/test_pairlist.py | 6 +- ...rlist.py => test_percentchangepairlist.py} | 133 ++++++------ 7 files changed, 195 insertions(+), 153 deletions(-) rename freqtrade/plugins/pairlist/{PercentVolumeChangePairList.py => PercentChangePairList.py} (64%) rename tests/plugins/{test_percentvolumechangepairlist.py => test_percentchangepairlist.py} (82%) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 4d8894c26..17a829955 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -42,7 +42,7 @@ HYPEROPT_LOSS_BUILTIN = [ AVAILABLE_PAIRLISTS = [ "StaticPairList", "VolumePairList", - "PercentVolumeChangePairList", + "PercentChangePairList", "ProducerPairList", "RemotePairList", "MarketCapPairList", diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 62f0ca4de..34ca8a3e8 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -121,6 +121,7 @@ class Exchange: # Check https://github.com/ccxt/ccxt/issues/10767 for removal of ohlcv_volume_currency "ohlcv_volume_currency": "base", # "base" or "quote" "tickers_have_quoteVolume": True, + "tickers_have_percentage": True, "tickers_have_bid_ask": True, # bid / ask empty for fetch_tickers "tickers_have_price": True, "trades_pagination": "time", # Possible are "time" or "id" diff --git a/freqtrade/exchange/types.py b/freqtrade/exchange/types.py index 5568e4336..a0d315c78 100644 --- a/freqtrade/exchange/types.py +++ b/freqtrade/exchange/types.py @@ -12,6 +12,7 @@ class Ticker(TypedDict): last: Optional[float] quoteVolume: Optional[float] baseVolume: Optional[float] + percentage: Optional[float] # Several more - only listing required. diff --git a/freqtrade/plugins/pairlist/PercentVolumeChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py similarity index 64% rename from freqtrade/plugins/pairlist/PercentVolumeChangePairList.py rename to freqtrade/plugins/pairlist/PercentChangePairList.py index 777acda60..a1be6729b 100644 --- a/freqtrade/plugins/pairlist/PercentVolumeChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -8,24 +8,24 @@ defined period import logging from datetime import timedelta -from typing import Any, Dict, List, Literal +from typing import Any, Dict, List, Literal, Optional from cachetools import TTLCache from freqtrade.constants import ListPairsWithTimeframes from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date -from freqtrade.exchange.types import Tickers +from freqtrade.exchange.types import Ticker, Tickers from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter, SupportsBacktesting from freqtrade.util import dt_now, format_ms_time logger = logging.getLogger(__name__) -SORT_VALUES = ["rolling_volume_change"] +SORT_VALUES = ["percentage"] -class PercentVolumeChangePairList(IPairList): +class PercentChangePairList(IPairList): is_pairlist_generator = True supports_backtesting = SupportsBacktesting.NO @@ -50,6 +50,7 @@ class PercentVolumeChangePairList(IPairList): self._lookback_days = self._pairlistconfig.get("lookback_days", 0) self._lookback_timeframe = self._pairlistconfig.get("lookback_timeframe", "1d") self._lookback_period = self._pairlistconfig.get("lookback_period", 0) + self._sort_direction: Optional[str] = self._pairlistconfig.get("sort_direction", "desc") self._def_candletype = self._config["candle_type_def"] if (self._lookback_days > 0) & (self._lookback_period > 0): @@ -80,11 +81,11 @@ class PercentVolumeChangePairList(IPairList): if not self._use_range and not ( self._exchange.exchange_has("fetchTickers") - and self._exchange.get_option("tickers_have_change") + and self._exchange.get_option("tickers_have_percentage") ): raise OperationalException( "Exchange does not support dynamic whitelist in this configuration. " - "Please edit your config and either remove PercentVolumeChangePairList, " + "Please edit your config and either remove PercentChangePairList, " "or switch to using candles. and restart the bot." ) @@ -94,9 +95,7 @@ class PercentVolumeChangePairList(IPairList): candle_limit = self._exchange.ohlcv_candle_limit( self._lookback_timeframe, self._config["candle_type_def"] ) - if self._lookback_period < 4: - raise OperationalException("ChangeFilter requires lookback_period to be >= 4") - self.log_once(f"Candle limit is {candle_limit}", logger.info) + if self._lookback_period > candle_limit: raise OperationalException( "ChangeFilter requires lookback_period to not " @@ -119,14 +118,11 @@ class PercentVolumeChangePairList(IPairList): """ Short whitelist method description - used for startup-messages """ - return ( - f"{self.name} - top {self._pairlistconfig['number_assets']} percent " - f"volume change pairs." - ) + return f"{self.name} - top {self._pairlistconfig['number_assets']} percent change pairs." @staticmethod def description() -> str: - return "Provides dynamic pair list based on percentage volume change." + return "Provides dynamic pair list based on percentage change." @staticmethod def available_parameters() -> Dict[str, PairlistParameter]: @@ -156,12 +152,14 @@ class PercentVolumeChangePairList(IPairList): "description": "Maximum value", "help": "Maximum value to use for filtering the pairlist.", }, - "refresh_period": { - "type": "number", - "default": 1800, - "description": "Refresh period", - "help": "Refresh period in seconds", + "sort_direction": { + "type": "option", + "default": "desc", + "options": ["", "asc", "desc"], + "description": "Sort pairlist", + "help": "Sort Pairlist ascending or descending by rate of change.", }, + **IPairList.refresh_period_parameter(), "lookback_days": { "type": "number", "default": 0, @@ -233,83 +231,24 @@ class PercentVolumeChangePairList(IPairList): :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ - self.log_once(f"Filter ticker is self use range {pairlist}", logger.warning) + filtered_tickers: List[Dict[str, Any]] = [{"symbol": k} for k in pairlist] if self._use_range: - filtered_tickers: List[Dict[str, Any]] = [{"symbol": k} for k in pairlist] - - # get lookback period in ms, for exchange ohlcv fetch - since_ms = ( - int( - timeframe_to_prev_date( - self._lookback_timeframe, - dt_now() - + timedelta( - minutes=-(self._lookback_period * self._tf_in_min) - self._tf_in_min - ), - ).timestamp() - ) - * 1000 - ) - - to_ms = ( - int( - timeframe_to_prev_date( - self._lookback_timeframe, dt_now() - timedelta(minutes=self._tf_in_min) - ).timestamp() - ) - * 1000 - ) - - # todo: utc date output for starting date - self.log_once( - f"Using change range of {self._lookback_period} candles, timeframe: " - f"{self._lookback_timeframe}, starting from {format_ms_time(since_ms)} " - f"till {format_ms_time(to_ms)}", - logger.info, - ) - needed_pairs: ListPairsWithTimeframes = [ - (p, self._lookback_timeframe, self._def_candletype) - for p in [s["symbol"] for s in filtered_tickers] - if p not in self._pair_cache - ] - - candles = self._exchange.refresh_ohlcv_with_cache(needed_pairs, since_ms) - - for i, p in enumerate(filtered_tickers): - pair_candles = ( - candles[(p["symbol"], self._lookback_timeframe, self._def_candletype)] - if (p["symbol"], self._lookback_timeframe, self._def_candletype) in candles - else None - ) - - # in case of candle data calculate typical price and change for candle - if pair_candles is not None and not pair_candles.empty: - pair_candles["rolling_volume_sum"] = ( - pair_candles["volume"].rolling(window=self._lookback_period).sum() - ) - pair_candles["rolling_volume_change"] = ( - pair_candles["rolling_volume_sum"].pct_change() * 100 - ) - - # ensure that a rolling sum over the lookback_period is built - # if pair_candles contains more candles than lookback_period - rolling_volume_change = pair_candles["rolling_volume_change"].fillna(0).iloc[-1] - - # replace change with a range change sum calculated above - filtered_tickers[i]["rolling_volume_change"] = rolling_volume_change - self.log_once(f"ticker {filtered_tickers[i]}", logger.info) - else: - filtered_tickers[i]["rolling_volume_change"] = 0 + # calculating using lookback_period + self.fetch_percent_change_from_lookback_period(filtered_tickers) else: - filtered_tickers = [v for k, v in tickers.items() if k in pairlist] + # Fetching 24h change by default from supported exchange tickers + self.fetch_percent_change_from_tickers(filtered_tickers, tickers) filtered_tickers = [v for v in filtered_tickers if v[self._sort_key] > self._min_value] if self._max_value is not None: filtered_tickers = [v for v in filtered_tickers if v[self._sort_key] < self._max_value] - sorted_tickers = sorted(filtered_tickers, reverse=True, key=lambda t: t[self._sort_key]) + sorted_tickers = sorted( + filtered_tickers, + reverse=self._sort_direction == "desc", + key=lambda t: t[self._sort_key], + ) - self.log_once(f"Sorted Tickers {sorted_tickers}", logger.info) # Validate whitelist to only have active market pairs pairs = self._whitelist_for_active_markets([s["symbol"] for s in sorted_tickers]) pairs = self.verify_blacklist(pairs, logmethod=logger.info) @@ -317,3 +256,91 @@ class PercentVolumeChangePairList(IPairList): pairs = pairs[: self._number_pairs] return pairs + + def fetch_candles_for_lookback_period(self, filtered_tickers): + since_ms = ( + int( + timeframe_to_prev_date( + self._lookback_timeframe, + dt_now() + + timedelta( + minutes=-(self._lookback_period * self._tf_in_min) - self._tf_in_min + ), + ).timestamp() + ) + * 1000 + ) + to_ms = ( + int( + timeframe_to_prev_date( + self._lookback_timeframe, dt_now() - timedelta(minutes=self._tf_in_min) + ).timestamp() + ) + * 1000 + ) + # todo: utc date output for starting date + self.log_once( + f"Using change range of {self._lookback_period} candles, timeframe: " + f"{self._lookback_timeframe}, starting from {format_ms_time(since_ms)} " + f"till {format_ms_time(to_ms)}", + logger.info, + ) + needed_pairs: ListPairsWithTimeframes = [ + (p, self._lookback_timeframe, self._def_candletype) + for p in [s["symbol"] for s in filtered_tickers] + if p not in self._pair_cache + ] + candles = self._exchange.refresh_ohlcv_with_cache(needed_pairs, since_ms) + return candles + + def fetch_percent_change_from_lookback_period(self, filtered_tickers): + # get lookback period in ms, for exchange ohlcv fetch + candles = self.fetch_candles_for_lookback_period(filtered_tickers) + + for i, p in enumerate(filtered_tickers): + pair_candles = ( + candles[(p["symbol"], self._lookback_timeframe, self._def_candletype)] + if (p["symbol"], self._lookback_timeframe, self._def_candletype) in candles + else None + ) + + # in case of candle data calculate typical price and change for candle + if pair_candles is not None and not pair_candles.empty: + current_close = pair_candles["close"].iloc[-1] + previous_close = pair_candles["close"].shift(self._lookback_period).iloc[-1] + pct_change = ( + ((current_close - previous_close) / previous_close) if previous_close > 0 else 0 + ) + + # replace change with a range change sum calculated above + filtered_tickers[i]["percentage"] = pct_change + self.log_once(f"Tickers: {filtered_tickers}", logger.info) + else: + filtered_tickers[i]["percentage"] = 0 + + def fetch_percent_change_from_tickers(self, filtered_tickers, tickers): + for i, p in enumerate(filtered_tickers): + # Filter out assets + if not self._validate_pair( + p["symbol"], tickers[p["symbol"]] if p["symbol"] in tickers else None + ): + filtered_tickers.remove(p) + else: + filtered_tickers[i]["percentage"] = tickers[p["symbol"]]["percentage"] + + def _validate_pair(self, pair: str, ticker: Optional[Ticker]) -> bool: + """ + Check if one price-step (pip) is > than a certain barrier. + :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 + """ + if not ticker or "percentage" not in ticker or ticker["percentage"] is None: + self.log_once( + f"Removed {pair} from whitelist, because " + "ticker['percentage'] is empty (Usually no trade in the last 24h).", + logger.info, + ) + return False + + return True diff --git a/tests/conftest.py b/tests/conftest.py index fee8cab72..22bc2556e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2187,7 +2187,7 @@ def tickers(): "first": None, "last": 530.21, "change": 0.558, - "percentage": None, + "percentage": 2.349, "average": None, "baseVolume": 72300.0659, "quoteVolume": 37670097.3022171, diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index 7e5fd4c12..31e746d5c 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -31,11 +31,11 @@ from tests.conftest import ( ) -# Exclude RemotePairList and PercentVolumeChangePairList from tests. +# Exclude RemotePairList and PercentVolumePairList from tests. # They have mandatory parameters, and requires special handling, -# which happens in test_remotepairlist and test_percentvolumechangepairlist. +# which happens in test_remotepairlist and test_percentchangepairlist. TESTABLE_PAIRLISTS = [ - p for p in AVAILABLE_PAIRLISTS if p not in ["RemotePairList", "PercentVolumeChangePairList"] + p for p in AVAILABLE_PAIRLISTS if p not in ["RemotePairList", "PercentChangePairList"] ] diff --git a/tests/plugins/test_percentvolumechangepairlist.py b/tests/plugins/test_percentchangepairlist.py similarity index 82% rename from tests/plugins/test_percentvolumechangepairlist.py rename to tests/plugins/test_percentchangepairlist.py index b09307151..0a7960d22 100644 --- a/tests/plugins/test_percentvolumechangepairlist.py +++ b/tests/plugins/test_percentchangepairlist.py @@ -7,7 +7,7 @@ import pytest from freqtrade.data.converter import ohlcv_to_dataframe from freqtrade.enums import CandleType from freqtrade.exceptions import OperationalException -from freqtrade.plugins.pairlist.PercentVolumeChangePairList import PercentVolumeChangePairList +from freqtrade.plugins.pairlist.PercentChangePairList import PercentChangePairList from freqtrade.plugins.pairlistmanager import PairListManager from tests.conftest import ( EXMS, @@ -33,9 +33,9 @@ def rpl_config(default_conf): def test_volume_change_pair_list_init_exchange_support(mocker, rpl_config): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, } @@ -44,7 +44,7 @@ def test_volume_change_pair_list_init_exchange_support(mocker, rpl_config): with pytest.raises( OperationalException, match=r"Exchange does not support dynamic whitelist in this configuration. " - r"Please edit your config and either remove PercentVolumeChangePairList, " + r"Please edit your config and either remove PercentChangePairList, " r"or switch to using candles. and restart the bot.", ): get_patched_freqtradebot(mocker, rpl_config) @@ -53,9 +53,9 @@ def test_volume_change_pair_list_init_exchange_support(mocker, rpl_config): def test_volume_change_pair_list_init_wrong_refresh_period(mocker, rpl_config): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "refresh_period": 1800, "lookback_days": 4, @@ -71,12 +71,31 @@ def test_volume_change_pair_list_init_wrong_refresh_period(mocker, rpl_config): get_patched_freqtradebot(mocker, rpl_config) +def test_volume_change_pair_list_init_invalid_sort_key(mocker, rpl_config): + rpl_config["pairlists"] = [ + { + "method": "PercentChangePairList", + "number_assets": 2, + "sort_key": "wrong_key", + "min_value": 0, + "refresh_period": 86400, + "lookback_days": 1, + } + ] + + with pytest.raises( + OperationalException, + match=r"key wrong_key not in \['percentage'\]", + ): + get_patched_freqtradebot(mocker, rpl_config) + + def test_volume_change_pair_list_init_wrong_lookback_period(mocker, rpl_config): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, "lookback_days": 3, @@ -95,41 +114,9 @@ def test_volume_change_pair_list_init_wrong_lookback_period(mocker, rpl_config): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", - "min_value": 0, - "refresh_period": 86400, - "lookback_days": 3, - } - ] - - with pytest.raises( - OperationalException, match=r"ChangeFilter requires lookback_period to be >= 4" - ): - get_patched_freqtradebot(mocker, rpl_config) - - rpl_config["pairlists"] = [ - { - "method": "PercentVolumeChangePairList", - "number_assets": 2, - "sort_key": "rolling_volume_change", - "min_value": 0, - "refresh_period": 86400, - "lookback_period": 3, - } - ] - - with pytest.raises( - OperationalException, match=r"ChangeFilter requires lookback_period to be >= 4" - ): - get_patched_freqtradebot(mocker, rpl_config) - - rpl_config["pairlists"] = [ - { - "method": "PercentVolumeChangePairList", - "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, "lookback_days": 1001, @@ -147,8 +134,8 @@ def test_volume_change_pair_list_init_wrong_lookback_period(mocker, rpl_config): def test_volume_change_pair_list_init_wrong_config(mocker, rpl_config): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", - "sort_key": "rolling_volume_change", + "method": "PercentChangePairList", + "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, } @@ -165,9 +152,9 @@ def test_volume_change_pair_list_init_wrong_config(mocker, rpl_config): def test_gen_pairlist_with_valid_change_pair_list_config(mocker, rpl_config, tickers, time_machine): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, "lookback_days": 4, @@ -210,7 +197,7 @@ def test_gen_pairlist_with_valid_change_pair_list_config(mocker, rpl_config, tic ) ), ("TKN/USDT", "1d", CandleType.SPOT): pd.DataFrame( - # Make sure always have highest rolling_volume_change + # Make sure always have highest percentage { "timestamp": [ "2024-07-01 00:00:00", @@ -234,24 +221,25 @@ def test_gen_pairlist_with_valid_change_pair_list_config(mocker, rpl_config, tic exchange = get_patched_exchange(mocker, rpl_config, exchange="binance") pairlistmanager = PairListManager(exchange, rpl_config) - remote_pairlist = PercentVolumeChangePairList( + remote_pairlist = PercentChangePairList( exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0 ) result = remote_pairlist.gen_pairlist(tickers) assert len(result) == 2 - assert result == ["TKN/USDT", "BTC/USDT"] + assert result == ["NEO/USDT", "TKN/USDT"] def test_filter_pairlist_with_empty_ticker(mocker, rpl_config, tickers, time_machine): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, + "sort_direction": "asc", "lookback_days": 4, } ] @@ -272,7 +260,7 @@ def test_filter_pairlist_with_empty_ticker(mocker, rpl_config, tickers, time_mac "open": [100, 102, 101, 103, 104, 105], "high": [102, 103, 102, 104, 105, 106], "low": [99, 101, 100, 102, 103, 104], - "close": [101, 102, 103, 104, 105, 106], + "close": [101, 102, 103, 104, 105, 105], "volume": [1000, 1500, 2000, 2500, 3000, 3500], } ), @@ -289,8 +277,8 @@ def test_filter_pairlist_with_empty_ticker(mocker, rpl_config, tickers, time_mac "open": [100, 102, 101, 103, 104, 105], "high": [102, 103, 102, 104, 105, 106], "low": [99, 101, 100, 102, 103, 104], - "close": [101, 102, 103, 104, 105, 106], - "volume": [1000, 1500, 2000, 2500, 3000, 3500], + "close": [101, 102, 103, 104, 105, 104], + "volume": [1000, 1500, 2000, 2500, 3000, 3400], } ), } @@ -299,22 +287,22 @@ def test_filter_pairlist_with_empty_ticker(mocker, rpl_config, tickers, time_mac exchange = get_patched_exchange(mocker, rpl_config, exchange="binance") pairlistmanager = PairListManager(exchange, rpl_config) - remote_pairlist = PercentVolumeChangePairList( + remote_pairlist = PercentChangePairList( exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0 ) result = remote_pairlist.filter_pairlist(rpl_config["exchange"]["pair_whitelist"], {}) assert len(result) == 2 - assert result == ["ETH/USDT", "XRP/USDT"] + assert result == ["XRP/USDT", "ETH/USDT"] def test_filter_pairlist_with_max_value_set(mocker, rpl_config, tickers, time_machine): rpl_config["pairlists"] = [ { - "method": "PercentVolumeChangePairList", + "method": "PercentChangePairList", "number_assets": 2, - "sort_key": "rolling_volume_change", + "sort_key": "percentage", "min_value": 0, "max_value": 15, "refresh_period": 86400, @@ -356,7 +344,7 @@ def test_filter_pairlist_with_max_value_set(mocker, rpl_config, tickers, time_ma "open": [100, 102, 101, 103, 104, 105], "high": [102, 103, 102, 104, 105, 106], "low": [99, 101, 100, 102, 103, 104], - "close": [101, 102, 103, 104, 105, 106], + "close": [101, 102, 103, 104, 105, 101], "volume": [1000, 1500, 2000, 2500, 3000, 3500], } ), @@ -366,7 +354,7 @@ def test_filter_pairlist_with_max_value_set(mocker, rpl_config, tickers, time_ma exchange = get_patched_exchange(mocker, rpl_config, exchange="binance") pairlistmanager = PairListManager(exchange, rpl_config) - remote_pairlist = PercentVolumeChangePairList( + remote_pairlist = PercentChangePairList( exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0 ) @@ -374,3 +362,28 @@ def test_filter_pairlist_with_max_value_set(mocker, rpl_config, tickers, time_ma assert len(result) == 1 assert result == ["ETH/USDT"] + + +def test_gen_pairlist_from_tickers(mocker, rpl_config, tickers): + rpl_config["pairlists"] = [ + { + "method": "PercentChangePairList", + "number_assets": 2, + "sort_key": "percentage", + "min_value": 0, + } + ] + + mocker.patch(f"{EXMS}.exchange_has", MagicMock(return_value=True)) + + exchange = get_patched_exchange(mocker, rpl_config, exchange="binance") + pairlistmanager = PairListManager(exchange, rpl_config) + + remote_pairlist = PercentChangePairList( + exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0 + ) + + result = remote_pairlist.gen_pairlist(tickers.return_value) + + assert len(result) == 1 + assert result == ["ETH/USDT"] From 4a768682ea8681e67a13e83bcb2389effcff11a8 Mon Sep 17 00:00:00 2001 From: jainanuj94 Date: Fri, 26 Jul 2024 13:13:26 +0530 Subject: [PATCH 03/31] Remove unnecessary logs and up description --- freqtrade/plugins/pairlist/PercentChangePairList.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/freqtrade/plugins/pairlist/PercentChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py index a1be6729b..b9ffa7e45 100644 --- a/freqtrade/plugins/pairlist/PercentChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -1,9 +1,9 @@ """ -Change PairList provider +Percent Change PairList provider Provides dynamic pair list based on trade change -sorted based on percentage change in volume over a -defined period +sorted based on percentage change in price over a +defined period or as coming from ticker """ import logging @@ -314,7 +314,6 @@ class PercentChangePairList(IPairList): # replace change with a range change sum calculated above filtered_tickers[i]["percentage"] = pct_change - self.log_once(f"Tickers: {filtered_tickers}", logger.info) else: filtered_tickers[i]["percentage"] = 0 From 8637f4a70d835abd3fdf9f3beda7784d3ddc5fbe Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jul 2024 16:04:51 +0200 Subject: [PATCH 04/31] Remove SortKey dynamics and setting --- .../plugins/pairlist/PercentChangePairList.py | 28 ++++--------------- tests/plugins/test_percentchangepairlist.py | 19 ------------- 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/freqtrade/plugins/pairlist/PercentChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py index b9ffa7e45..14b08b2b7 100644 --- a/freqtrade/plugins/pairlist/PercentChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -8,7 +8,7 @@ defined period or as coming from ticker import logging from datetime import timedelta -from typing import Any, Dict, List, Literal, Optional +from typing import Any, Dict, List, Optional from cachetools import TTLCache @@ -22,8 +22,6 @@ from freqtrade.util import dt_now, format_ms_time logger = logging.getLogger(__name__) -SORT_VALUES = ["percentage"] - class PercentChangePairList(IPairList): is_pairlist_generator = True @@ -40,9 +38,6 @@ class PercentChangePairList(IPairList): self._stake_currency = self._config["stake_currency"] self._number_pairs = self._pairlistconfig["number_assets"] - self._sort_key: Literal["rolling_volume_change"] = self._pairlistconfig.get( - "sort_key", "rolling_volume_change" - ) self._min_value = self._pairlistconfig.get("min_value", 0) self._max_value = self._pairlistconfig.get("max_value", None) self._refresh_period = self._pairlistconfig.get("refresh_period", 1800) @@ -89,9 +84,6 @@ class PercentChangePairList(IPairList): "or switch to using candles. and restart the bot." ) - if not self._validate_keys(self._sort_key): - raise OperationalException(f"key {self._sort_key} not in {SORT_VALUES}") - candle_limit = self._exchange.ohlcv_candle_limit( self._lookback_timeframe, self._config["candle_type_def"] ) @@ -111,9 +103,6 @@ class PercentChangePairList(IPairList): """ return not self._use_range - def _validate_keys(self, key): - return key in SORT_VALUES - def short_desc(self) -> str: """ Short whitelist method description - used for startup-messages @@ -133,13 +122,6 @@ class PercentChangePairList(IPairList): "description": "Number of assets", "help": "Number of assets to use from the pairlist", }, - "sort_key": { - "type": "option", - "default": "rolling_volume_change", - "options": SORT_VALUES, - "description": "Sort key", - "help": "Sort key to use for sorting the pairlist.", - }, "min_value": { "type": "number", "default": 0, @@ -210,7 +192,7 @@ class PercentChangePairList(IPairList): for k, v in tickers.items() if ( self._exchange.get_pair_quote_currency(k) == self._stake_currency - and (self._use_range or v.get(self._sort_key) is not None) + and (self._use_range or v.get("percentage") is not None) and v["symbol"] in _pairlist ) ] @@ -239,14 +221,14 @@ class PercentChangePairList(IPairList): # Fetching 24h change by default from supported exchange tickers self.fetch_percent_change_from_tickers(filtered_tickers, tickers) - filtered_tickers = [v for v in filtered_tickers if v[self._sort_key] > self._min_value] + filtered_tickers = [v for v in filtered_tickers if v["percentage"] > self._min_value] if self._max_value is not None: - filtered_tickers = [v for v in filtered_tickers if v[self._sort_key] < self._max_value] + filtered_tickers = [v for v in filtered_tickers if v["percentage"] < self._max_value] sorted_tickers = sorted( filtered_tickers, reverse=self._sort_direction == "desc", - key=lambda t: t[self._sort_key], + key=lambda t: t["percentage"], ) # Validate whitelist to only have active market pairs diff --git a/tests/plugins/test_percentchangepairlist.py b/tests/plugins/test_percentchangepairlist.py index 0a7960d22..df165cf98 100644 --- a/tests/plugins/test_percentchangepairlist.py +++ b/tests/plugins/test_percentchangepairlist.py @@ -71,25 +71,6 @@ def test_volume_change_pair_list_init_wrong_refresh_period(mocker, rpl_config): get_patched_freqtradebot(mocker, rpl_config) -def test_volume_change_pair_list_init_invalid_sort_key(mocker, rpl_config): - rpl_config["pairlists"] = [ - { - "method": "PercentChangePairList", - "number_assets": 2, - "sort_key": "wrong_key", - "min_value": 0, - "refresh_period": 86400, - "lookback_days": 1, - } - ] - - with pytest.raises( - OperationalException, - match=r"key wrong_key not in \['percentage'\]", - ): - get_patched_freqtradebot(mocker, rpl_config) - - def test_volume_change_pair_list_init_wrong_lookback_period(mocker, rpl_config): rpl_config["pairlists"] = [ { From 283e8045d82902bd5d7214b25ece714e9855d457 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jul 2024 16:05:59 +0200 Subject: [PATCH 05/31] PercentChangePairlist should partecipate in regular tests --- tests/plugins/test_pairlist.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index 31e746d5c..37ebdc58b 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -31,12 +31,9 @@ from tests.conftest import ( ) -# Exclude RemotePairList and PercentVolumePairList from tests. -# They have mandatory parameters, and requires special handling, -# which happens in test_remotepairlist and test_percentchangepairlist. -TESTABLE_PAIRLISTS = [ - p for p in AVAILABLE_PAIRLISTS if p not in ["RemotePairList", "PercentChangePairList"] -] +# Exclude RemotePairList from tests. +# It has a mandatory parameter, and requires special handling, which happens in test_remotepairlist. +TESTABLE_PAIRLISTS = [p for p in AVAILABLE_PAIRLISTS if p not in ["RemotePairList"]] @pytest.fixture(scope="function") From 4ac7a4fdab27c7ad341e77b1d4dc50da22fd4f8d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jul 2024 16:07:51 +0200 Subject: [PATCH 06/31] Allow empty min_Value setting... --- freqtrade/plugins/pairlist/PercentChangePairList.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/plugins/pairlist/PercentChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py index 14b08b2b7..457c29275 100644 --- a/freqtrade/plugins/pairlist/PercentChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -38,7 +38,7 @@ class PercentChangePairList(IPairList): self._stake_currency = self._config["stake_currency"] self._number_pairs = self._pairlistconfig["number_assets"] - self._min_value = self._pairlistconfig.get("min_value", 0) + self._min_value = self._pairlistconfig.get("min_value", None) self._max_value = self._pairlistconfig.get("max_value", None) self._refresh_period = self._pairlistconfig.get("refresh_period", 1800) self._pair_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period) @@ -221,7 +221,8 @@ class PercentChangePairList(IPairList): # Fetching 24h change by default from supported exchange tickers self.fetch_percent_change_from_tickers(filtered_tickers, tickers) - filtered_tickers = [v for v in filtered_tickers if v["percentage"] > self._min_value] + if self._min_value is not None: + filtered_tickers = [v for v in filtered_tickers if v["percentage"] > self._min_value] if self._max_value is not None: filtered_tickers = [v for v in filtered_tickers if v["percentage"] < self._max_value] From 206baf7d80c49382b37355cf7691f1003c7c98b3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jul 2024 16:13:17 +0200 Subject: [PATCH 07/31] chore: add a bit of typehinting --- freqtrade/plugins/pairlist/PercentChangePairList.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/freqtrade/plugins/pairlist/PercentChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py index 457c29275..eded33d1d 100644 --- a/freqtrade/plugins/pairlist/PercentChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -11,8 +11,9 @@ from datetime import timedelta from typing import Any, Dict, List, Optional from cachetools import TTLCache +from pandas import DataFrame -from freqtrade.constants import ListPairsWithTimeframes +from freqtrade.constants import ListPairsWithTimeframes, PairWithTimeframe from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date from freqtrade.exchange.types import Ticker, Tickers @@ -168,8 +169,6 @@ class PercentChangePairList(IPairList): :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: List of pairs """ - # Generate dynamic whitelist - # Must always run if this pairlist is not the first in the list. pairlist = self._pair_cache.get("pairlist") if pairlist: # Item found - no refresh necessary @@ -240,7 +239,9 @@ class PercentChangePairList(IPairList): return pairs - def fetch_candles_for_lookback_period(self, filtered_tickers): + def fetch_candles_for_lookback_period( + self, filtered_tickers: List[Dict[str, str]] + ) -> Dict[PairWithTimeframe, DataFrame]: since_ms = ( int( timeframe_to_prev_date( @@ -276,7 +277,7 @@ class PercentChangePairList(IPairList): candles = self._exchange.refresh_ohlcv_with_cache(needed_pairs, since_ms) return candles - def fetch_percent_change_from_lookback_period(self, filtered_tickers): + def fetch_percent_change_from_lookback_period(self, filtered_tickers: List[Dict[str, Any]]): # get lookback period in ms, for exchange ohlcv fetch candles = self.fetch_candles_for_lookback_period(filtered_tickers) @@ -300,7 +301,7 @@ class PercentChangePairList(IPairList): else: filtered_tickers[i]["percentage"] = 0 - def fetch_percent_change_from_tickers(self, filtered_tickers, tickers): + def fetch_percent_change_from_tickers(self, filtered_tickers: List[Dict[str, Any]], tickers): for i, p in enumerate(filtered_tickers): # Filter out assets if not self._validate_pair( From 4932473b3f49c7d3d2e1258d504a66d765ca1a8f Mon Sep 17 00:00:00 2001 From: jainanuj94 Date: Sat, 27 Jul 2024 23:41:32 +0530 Subject: [PATCH 08/31] Add documentation --- docs/includes/pairlists.md | 81 +++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index fbf8f4be0..15f1dbc85 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -2,11 +2,11 @@ Pairlist Handlers define the list of pairs (pairlist) that the bot should trade. They are configured in the `pairlists` section of the configuration settings. -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) Pairlist Handler). +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. -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` or `MarketCapPairList` 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. Inactive markets are always removed from the resulting pairlist. Explicitly blacklisted pairs (those in the `pair_blacklist` configuration setting) are also always removed from the resulting pairlist. @@ -22,6 +22,7 @@ You may also use something like `.*DOWN/BTC` or `.*UP/BTC` to exclude leveraged * [`StaticPairList`](#static-pair-list) (default, if not configured differently) * [`VolumePairList`](#volume-pair-list) +* [`PercentChangePairList`](#percent-change-pair-list) * [`ProducerPairList`](#producerpairlist) * [`RemotePairList`](#remotepairlist) * [`MarketCapPairList`](#marketcappairlist) @@ -152,6 +153,82 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl !!! Note `VolumePairList` does not support backtesting mode. +#### Percent Change Pair List + +`PercentChangePairList` filters and sorts pairs based on the percentage change in their price over the last 24 hours or any defined timeframe as part of advanced options. This allows traders to focus on assets that have experienced significant price movements, either positive or negative. + +**Configuration Options** + +- `number_assets`: Specifies the number of top pairs to select based on the 24-hour percentage change. +- `min_value`: Sets a minimum percentage change threshold. Pairs with a percentage change below this value will be filtered out. +- `max_value`: Sets a maximum percentage change threshold. Pairs with a percentage change above this value will be filtered out. +- `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. + +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. + +`PercentChangePairList` uses ticker data from the exchange, provided via the ccxt library: +The percentage change is calculated as the change in price over the last 24 hours, expressed as a percentage, depending on the exchange. + +??? Tip "Unsupported exchanges" + On some exchanges (like HTX), regular PercentChangePairList does not work as the api does not natively provide 24h percent change in price. This can be worked around by using candle data to calculate the percentage change. To roughly simulate 24h percent change, you can use the following configuration. Please note that These pairlists will only refresh once per day. + ```json + "pairlists": [ + { + "method": "PercentChangePairList", + "number_assets": 20, + "sort_key": "percentage", + "min_value": 0, + "refresh_period": 86400, + "lookback_days": 1 + } + ], + ``` + +**Example Configuration to Read from Ticker** +```json +"pairlists": [ + { + "method": "PercentChangePairList", + "number_assets": 15, + "sort_key": "percentage", + "min_value": -10, + "max_value": 50 + } +], +``` +In this configuration: + +1. The top 15 pairs are selected based on the highest percentage change in price over the last 24 hours. +2. Only pairs with a percentage change between -10% and 50% are considered. + +**Example Configuration to Read from Candles** +```json +"pairlists": [ + { + "method": "PercentChangePairList", + "number_assets": 15, + "sort_key": "percentage", + "min_value": 0, + "refresh_period": 3600, + "lookback_timeframe": "1h", + "lookback_period": 72 + } +], +``` +This example builds the percent change pairs based on a rolling period of 3 days of 1-hour candles by using `lookback_timeframe` for candle size and `lookback_period` which specifies the number of candles. + +!!! Warning "Range look back and refresh period" + When used in conjunction with `lookback_days` and `lookback_timeframe` the `refresh_period` can not be smaller than the candle size in seconds. As this will result in unnecessary requests to the exchanges API. + +!!! Warning "Performance implications when using lookback range" + If used in first position in combination with lookback, the computation of the range-based percent change can be time and resource consuming, as it downloads candles for all tradable pairs. Hence it's highly advised to use the standard approach with `PercentChangePairList` to narrow the pairlist down for further range volume calculation. + +!!! Note Backtesting + `PercentChangePairList` does not support backtesting mode. + #### ProducerPairList With `ProducerPairList`, you can reuse the pairlist from a [Producer](producer-consumer.md) without explicitly defining the pairlist on each consumer. From ac1e405c341c0eb5e1ffd470e8f8a3dce6f348fa Mon Sep 17 00:00:00 2001 From: jainanuj94 Date: Sun, 28 Jul 2024 21:10:20 +0530 Subject: [PATCH 09/31] Update documentation and fix doc test --- docs/includes/pairlists.md | 13 ++++++++----- freqtrade/plugins/pairlist/PercentChangePairList.py | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index 15f1dbc85..9ea797682 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -162,6 +162,7 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl - `number_assets`: Specifies the number of top pairs to select based on the 24-hour percentage change. - `min_value`: Sets a minimum percentage change threshold. Pairs with a percentage change below this value will be filtered out. - `max_value`: Sets a maximum percentage change threshold. Pairs with a percentage change above this value will be filtered out. +- `sort_direction`: Specifies the order in which pairs are sorted based on their percentage change. Accepts two values: `asc` for ascending order and `desc` for descending order. - `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. @@ -170,7 +171,7 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl 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. `PercentChangePairList` uses ticker data from the exchange, provided via the ccxt library: -The percentage change is calculated as the change in price over the last 24 hours, expressed as a percentage, depending on the exchange. +The percentage change is calculated as the change in price over the last 24 hours. ??? Tip "Unsupported exchanges" On some exchanges (like HTX), regular PercentChangePairList does not work as the api does not natively provide 24h percent change in price. This can be worked around by using candle data to calculate the percentage change. To roughly simulate 24h percent change, you can use the following configuration. Please note that These pairlists will only refresh once per day. @@ -179,7 +180,6 @@ The percentage change is calculated as the change in price over the last 24 hour { "method": "PercentChangePairList", "number_assets": 20, - "sort_key": "percentage", "min_value": 0, "refresh_period": 86400, "lookback_days": 1 @@ -193,7 +193,6 @@ The percentage change is calculated as the change in price over the last 24 hour { "method": "PercentChangePairList", "number_assets": 15, - "sort_key": "percentage", "min_value": -10, "max_value": 50 } @@ -220,13 +219,17 @@ In this configuration: ``` This example builds the percent change pairs based on a rolling period of 3 days of 1-hour candles by using `lookback_timeframe` for candle size and `lookback_period` which specifies the number of candles. +The percent change in price is calculated using the following formula, which expresses the percentage difference between the current candle's close price and the previous candle's close price, as defined by the specified timeframe and lookback period: + +$$ Percent Change = (\frac{Current Close - Previous Close}{Previous Close}) * 100 $$ + !!! Warning "Range look back and refresh period" When used in conjunction with `lookback_days` and `lookback_timeframe` the `refresh_period` can not be smaller than the candle size in seconds. As this will result in unnecessary requests to the exchanges API. !!! Warning "Performance implications when using lookback range" - If used in first position in combination with lookback, the computation of the range-based percent change can be time and resource consuming, as it downloads candles for all tradable pairs. Hence it's highly advised to use the standard approach with `PercentChangePairList` to narrow the pairlist down for further range volume calculation. + If used in first position in combination with lookback, the computation of the range-based percent change can be time and resource consuming, as it downloads candles for all tradable pairs. Hence it's highly advised to use the standard approach with `PercentChangePairList` to narrow the pairlist down for further percent-change calculation. -!!! Note Backtesting +!!! Note "Backtesting" `PercentChangePairList` does not support backtesting mode. #### ProducerPairList diff --git a/freqtrade/plugins/pairlist/PercentChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py index eded33d1d..b22891b98 100644 --- a/freqtrade/plugins/pairlist/PercentChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -125,7 +125,7 @@ class PercentChangePairList(IPairList): }, "min_value": { "type": "number", - "default": 0, + "default": None, "description": "Minimum value", "help": "Minimum value to use for filtering the pairlist.", }, From 27aed5cd7ee907cb8a990ee7324d28646994297f Mon Sep 17 00:00:00 2001 From: jainanuj94 Date: Sun, 28 Jul 2024 22:34:34 +0530 Subject: [PATCH 10/31] Update schema.json --- build_helpers/schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/build_helpers/schema.json b/build_helpers/schema.json index c0933d9f8..c2b930558 100644 --- a/build_helpers/schema.json +++ b/build_helpers/schema.json @@ -562,6 +562,7 @@ "enum": [ "StaticPairList", "VolumePairList", + "PercentChangePairList", "ProducerPairList", "RemotePairList", "MarketCapPairList", From faaa1050da244e2ad69701d452f5aa62fcd7de0e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jul 2024 20:10:30 +0200 Subject: [PATCH 11/31] chore: Bump dev version to 2024.8 --- freqtrade/__init__.py | 2 +- ft_client/freqtrade_client/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index 0cb8dd961..be9980671 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,6 +1,6 @@ """Freqtrade bot""" -__version__ = "2024.7-dev" +__version__ = "2024.8-dev" if "dev" in __version__: from pathlib import Path diff --git a/ft_client/freqtrade_client/__init__.py b/ft_client/freqtrade_client/__init__.py index 9311fc85d..68ef44422 100644 --- a/ft_client/freqtrade_client/__init__.py +++ b/ft_client/freqtrade_client/__init__.py @@ -1,7 +1,7 @@ from freqtrade_client.ft_rest_client import FtRestClient -__version__ = "2024.7-dev" +__version__ = "2024.8-dev" if "dev" in __version__: from pathlib import Path From 719889b27a737629cca33ea1f19d3e379415174d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 03:05:45 +0000 Subject: [PATCH 12/31] chore(deps-dev): bump pytest from 8.3.1 to 8.3.2 in the pytest group Bumps the pytest group with 1 update: [pytest](https://github.com/pytest-dev/pytest). Updates `pytest` from 8.3.1 to 8.3.2 - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.3.1...8.3.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:development update-type: version-update:semver-patch dependency-group: pytest ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index a89604996..3557a7c68 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,7 +10,7 @@ coveralls==4.0.1 ruff==0.5.4 mypy==1.11.0 pre-commit==3.7.1 -pytest==8.3.1 +pytest==8.3.2 pytest-asyncio==0.23.8 pytest-cov==5.0.0 pytest-mock==3.14.0 From fd2be958ba721256b3ed4c5d7c2d986a75929487 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 03:06:12 +0000 Subject: [PATCH 13/31] chore(deps): bump mkdocs-material in the mkdocs group Bumps the mkdocs group with 1 update: [mkdocs-material](https://github.com/squidfunk/mkdocs-material). Updates `mkdocs-material` from 9.5.29 to 9.5.30 - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.29...9.5.30) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch dependency-group: mkdocs ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 20beace35..c833d2853 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ markdown==3.6 mkdocs==1.6.0 -mkdocs-material==9.5.29 +mkdocs-material==9.5.30 mdx_truly_sane_lists==1.3 pymdown-extensions==10.8.1 jinja2==3.1.4 From 9fd6d7318ef83de29f99bd21dbedf412b62f4b38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 03:07:22 +0000 Subject: [PATCH 14/31] chore(deps): bump ccxt from 4.3.65 to 4.3.68 Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.3.65 to 4.3.68. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md) - [Commits](https://github.com/ccxt/ccxt/compare/4.3.65...4.3.68) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 570459975..a15ac4f30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ bottleneck==1.4.0 numexpr==2.10.1 pandas-ta==0.3.14b -ccxt==4.3.65 +ccxt==4.3.68 cryptography==43.0.0 aiohttp==3.9.5 SQLAlchemy==2.0.31 From baeced32c32095b8ee0dc4cd077fe6f2cc9f968f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 03:08:10 +0000 Subject: [PATCH 15/31] chore(deps): bump python-rapidjson from 1.18 to 1.19 Bumps [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) from 1.18 to 1.19. - [Changelog](https://github.com/python-rapidjson/python-rapidjson/blob/master/CHANGES.rst) - [Commits](https://github.com/python-rapidjson/python-rapidjson/compare/v1.18...v1.19) --- updated-dependencies: - dependency-name: python-rapidjson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- ft_client/requirements.txt | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ft_client/requirements.txt b/ft_client/requirements.txt index 5e6856e92..c0d627247 100644 --- a/ft_client/requirements.txt +++ b/ft_client/requirements.txt @@ -1,3 +1,3 @@ # Requirements for freqtrade client library requests==2.32.3 -python-rapidjson==1.18 +python-rapidjson==1.19 diff --git a/requirements.txt b/requirements.txt index 570459975..261f3c473 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,7 +30,7 @@ pyarrow==17.0.0; platform_machine != 'armv7l' py_find_1st==1.1.6 # Load ticker files 30% faster -python-rapidjson==1.18 +python-rapidjson==1.19 # Properly format api responses orjson==3.10.6 From 097786c62da98f66bad90fbb253d89804c1ce9c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 03:08:18 +0000 Subject: [PATCH 16/31] chore(deps): bump plotly from 5.22.0 to 5.23.0 Bumps [plotly](https://github.com/plotly/plotly.py) from 5.22.0 to 5.23.0. - [Release notes](https://github.com/plotly/plotly.py/releases) - [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md) - [Commits](https://github.com/plotly/plotly.py/compare/v5.22.0...v5.23.0) --- updated-dependencies: - dependency-name: plotly dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-plot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-plot.txt b/requirements-plot.txt index b4dc2e46c..6641fe524 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,4 +1,4 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==5.22.0 +plotly==5.23.0 From 5e852ebb5d1654fde5bf7b9aa6c02b9a45cc931c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 03:08:24 +0000 Subject: [PATCH 17/31] chore(deps): bump lightgbm from 4.4.0 to 4.5.0 Bumps [lightgbm](https://github.com/microsoft/LightGBM) from 4.4.0 to 4.5.0. - [Release notes](https://github.com/microsoft/LightGBM/releases) - [Commits](https://github.com/microsoft/LightGBM/compare/v4.4.0...v4.5.0) --- updated-dependencies: - dependency-name: lightgbm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-freqai.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-freqai.txt b/requirements-freqai.txt index c57e66d2d..f2d6bd5f5 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -6,7 +6,7 @@ scikit-learn==1.5.1 joblib==1.4.2 catboost==1.2.5; 'arm' not in platform_machine -lightgbm==4.4.0 +lightgbm==4.5.0 xgboost==2.0.3 tensorboard==2.17.0 datasieve==0.1.7 From a1490d07b4326ac4896568bc1d1a47142f0170ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 05:32:28 +0000 Subject: [PATCH 18/31] chore(deps-dev): bump ruff from 0.5.4 to 0.5.5 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.4 to 0.5.5. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.5.4...0.5.5) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 3557a7c68..2b605e8ce 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ -r docs/requirements-docs.txt coveralls==4.0.1 -ruff==0.5.4 +ruff==0.5.5 mypy==1.11.0 pre-commit==3.7.1 pytest==8.3.2 From 3789e1339bb93efc2c8ba99977b9aedb34008855 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 05:32:28 +0000 Subject: [PATCH 19/31] chore(deps): bump pymdown-extensions from 10.8.1 to 10.9 Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.8.1 to 10.9. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.8.1...10.9) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index c833d2853..47fcdaa32 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -2,5 +2,5 @@ markdown==3.6 mkdocs==1.6.0 mkdocs-material==9.5.30 mdx_truly_sane_lists==1.3 -pymdown-extensions==10.8.1 +pymdown-extensions==10.9 jinja2==3.1.4 From c8b75808302733996978a7c2ce936aca2b3e74a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 08:27:01 +0000 Subject: [PATCH 20/31] chore(deps-dev): bump pre-commit from 3.7.1 to 3.8.0 Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.7.1 to 3.8.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v3.7.1...v3.8.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 2b605e8ce..554cf7778 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -9,7 +9,7 @@ coveralls==4.0.1 ruff==0.5.5 mypy==1.11.0 -pre-commit==3.7.1 +pre-commit==3.8.0 pytest==8.3.2 pytest-asyncio==0.23.8 pytest-cov==5.0.0 From 1ebbfffd2ab463eda74f6bd4a36241194c84390d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 29 Jul 2024 19:42:20 +0200 Subject: [PATCH 21/31] chore: hyperliquid doesn't have historic ohlcv --- freqtrade/exchange/hyperliquid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/hyperliquid.py b/freqtrade/exchange/hyperliquid.py index d2b1e1482..9b8598432 100644 --- a/freqtrade/exchange/hyperliquid.py +++ b/freqtrade/exchange/hyperliquid.py @@ -17,7 +17,7 @@ class Hyperliquid(Exchange): _ft_has: Dict = { # Only the most recent 5000 candles are available according to the # exchange's API documentation. - "ohlcv_has_history": True, + "ohlcv_has_history": False, "ohlcv_candle_limit": 5000, "trades_has_history": False, # Trades endpoint doesn't seem available. "exchange_has_overrides": {"fetchTrades": False}, From 40b20c5595cbbad5276a9c59412019766b19e35e Mon Sep 17 00:00:00 2001 From: xmatthias <5024695+xmatthias@users.noreply.github.com> Date: Tue, 30 Jul 2024 03:02:51 +0000 Subject: [PATCH 22/31] chore: update pre-commit hooks --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c78811f30..58c43d454 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: - repo: https://github.com/charliermarsh/ruff-pre-commit # Ruff version. - rev: 'v0.5.4' + rev: 'v0.5.5' hooks: - id: ruff From eb0fc0fc807ffae7c891c4e823a166c8726bd1fa Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 30 Jul 2024 20:29:21 +0200 Subject: [PATCH 23/31] docs: Fix minor typo --- docs/includes/pairlists.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index 9ea797682..b3b69f996 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -159,22 +159,22 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl **Configuration Options** -- `number_assets`: Specifies the number of top pairs to select based on the 24-hour percentage change. -- `min_value`: Sets a minimum percentage change threshold. Pairs with a percentage change below this value will be filtered out. -- `max_value`: Sets a maximum percentage change threshold. Pairs with a percentage change above this value will be filtered out. -- `sort_direction`: Specifies the order in which pairs are sorted based on their percentage change. Accepts two values: `asc` for ascending order and `desc` for descending order. -- `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. +* `number_assets`: Specifies the number of top pairs to select based on the 24-hour percentage change. +* `min_value`: Sets a minimum percentage change threshold. Pairs with a percentage change below this value will be filtered out. +* `max_value`: Sets a maximum percentage change threshold. Pairs with a percentage change above this value will be filtered out. +* `sort_direction`: Specifies the order in which pairs are sorted based on their percentage change. Accepts two values: `asc` for ascending order and `desc` for descending order. +* `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. 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. `PercentChangePairList` uses ticker data from the exchange, provided via the ccxt library: The percentage change is calculated as the change in price over the last 24 hours. -??? Tip "Unsupported exchanges" - On some exchanges (like HTX), regular PercentChangePairList does not work as the api does not natively provide 24h percent change in price. This can be worked around by using candle data to calculate the percentage change. To roughly simulate 24h percent change, you can use the following configuration. Please note that These pairlists will only refresh once per day. +??? Note "Unsupported exchanges" + On some exchanges (like HTX), regular PercentChangePairList does not work as the api does not natively provide 24h percent change in price. This can be worked around by using candle data to calculate the percentage change. To roughly simulate 24h percent change, you can use the following configuration. Please note that these pairlists will only refresh once per day. ```json "pairlists": [ { @@ -188,6 +188,7 @@ The percentage change is calculated as the change in price over the last 24 hour ``` **Example Configuration to Read from Ticker** + ```json "pairlists": [ { @@ -198,12 +199,14 @@ The percentage change is calculated as the change in price over the last 24 hour } ], ``` + In this configuration: 1. The top 15 pairs are selected based on the highest percentage change in price over the last 24 hours. 2. Only pairs with a percentage change between -10% and 50% are considered. **Example Configuration to Read from Candles** + ```json "pairlists": [ { @@ -217,6 +220,7 @@ In this configuration: } ], ``` + This example builds the percent change pairs based on a rolling period of 3 days of 1-hour candles by using `lookback_timeframe` for candle size and `lookback_period` which specifies the number of candles. The percent change in price is calculated using the following formula, which expresses the percentage difference between the current candle's close price and the previous candle's close price, as defined by the specified timeframe and lookback period: From c40ac27d71e57ea2026ad29d710427776c811cb5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 31 Jul 2024 20:36:44 +0200 Subject: [PATCH 24/31] chore: Remove pip pin from ci --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e4ef2faa..bb3ea2221 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - name: Installation - *nix run: | - python -m pip install --upgrade "pip<=24.0" wheel + python -m pip install --upgrade pip wheel export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH export TA_LIBRARY_PATH=${HOME}/dependencies/lib export TA_INCLUDE_PATH=${HOME}/dependencies/include @@ -197,7 +197,7 @@ jobs: - name: Installation (python) run: | - python -m pip install --upgrade "pip<=24.0" wheel + python -m pip install --upgrade pip wheel export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH export TA_LIBRARY_PATH=${HOME}/dependencies/lib export TA_INCLUDE_PATH=${HOME}/dependencies/include @@ -427,7 +427,7 @@ jobs: - name: Installation - *nix run: | - python -m pip install --upgrade "pip<=24.0" wheel + python -m pip install --upgrade pip wheel export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH export TA_LIBRARY_PATH=${HOME}/dependencies/lib export TA_INCLUDE_PATH=${HOME}/dependencies/include From 8105f51603692404d56f0eefcb2b54a2b618e33b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 31 Jul 2024 20:39:12 +0200 Subject: [PATCH 25/31] chore: remove pip lock from Dockerfiles --- Dockerfile | 2 +- docker/Dockerfile.armhf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index cedeafbe6..e435f7f1e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ FROM base as python-deps RUN apt-get update \ && apt-get -y install build-essential libssl-dev git libffi-dev libgfortran5 pkg-config cmake gcc \ && apt-get clean \ - && pip install --upgrade "pip<=24.0" wheel + && pip install --upgrade pip wheel # Install TA-lib COPY build_helpers/* /tmp/ diff --git a/docker/Dockerfile.armhf b/docker/Dockerfile.armhf index fbd952111..688254122 100644 --- a/docker/Dockerfile.armhf +++ b/docker/Dockerfile.armhf @@ -17,7 +17,7 @@ RUN mkdir /freqtrade \ && chown ftuser:ftuser /freqtrade \ # Allow sudoers && echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers \ - && pip install --upgrade "pip<=24.0" + && pip install --upgrade pip WORKDIR /freqtrade From 02621eee74217c38c4bf34adacbd14311903f3d1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 31 Jul 2024 20:39:21 +0200 Subject: [PATCH 26/31] chore: remove pip version lock from instal scripts --- build_helpers/install_windows.ps1 | 2 +- setup.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build_helpers/install_windows.ps1 b/build_helpers/install_windows.ps1 index 5f0c643ac..4aa070992 100644 --- a/build_helpers/install_windows.ps1 +++ b/build_helpers/install_windows.ps1 @@ -1,6 +1,6 @@ # vendored Wheels compiled via https://github.com/xmatthias/ta-lib-python/tree/ta_bundled_040 -python -m pip install --upgrade "pip<=24.0" wheel +python -m pip install --upgrade pip wheel $pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" diff --git a/setup.sh b/setup.sh index f1317c02c..18f7682d8 100755 --- a/setup.sh +++ b/setup.sh @@ -49,7 +49,7 @@ function updateenv() { source .venv/bin/activate SYS_ARCH=$(uname -m) echo "pip install in-progress. Please wait..." - ${PYTHON} -m pip install --upgrade "pip<=24.0" wheel setuptools + ${PYTHON} -m pip install --upgrade pip wheel setuptools REQUIREMENTS_HYPEROPT="" REQUIREMENTS_PLOT="" REQUIREMENTS_FREQAI="" From af554fc3f770915133793a218938ba436c0efe16 Mon Sep 17 00:00:00 2001 From: xmatthias <5024695+xmatthias@users.noreply.github.com> Date: Thu, 1 Aug 2024 03:15:58 +0000 Subject: [PATCH 27/31] chore: update pre-commit hooks --- .../exchange/binance_leverage_tiers.json | 586 ++++++++---------- 1 file changed, 244 insertions(+), 342 deletions(-) diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index 91775fede..ceaa4e486 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -15819,104 +15819,6 @@ } } ], - "GAL/USDT:USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 11.0, - "info": { - "bracket": "1", - "initialLeverage": "11", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "25.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, - "info": { - "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5650.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11900.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386900.0" - } - } - ], "GALA/USDT:USDT": [ { "tier": 1.0, @@ -28526,6 +28428,250 @@ } ], "REEF/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 26.0, + "info": { + "bracket": "1", + "initialLeverage": "26", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.015", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 20000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "2", + "initialLeverage": "25", + "notionalCap": "20000", + "notionalFloor": "5000", + "maintMarginRatio": "0.02", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 20000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "3", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "20000", + "maintMarginRatio": "0.025", + "cum": "125.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 200000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "200000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "750.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 200000.0, + "maxNotional": 400000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "400000", + "notionalFloor": "200000", + "maintMarginRatio": "0.1", + "cum": "10750.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 400000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "500000", + "notionalFloor": "400000", + "maintMarginRatio": "0.125", + "cum": "20750.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.25", + "cum": "83250.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "8", + "initialLeverage": "1", + "notionalCap": "1500000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "333250.0" + } + } + ], + "REN/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.015", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "50000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "600000", + "notionalFloor": "50000", + "maintMarginRatio": "0.05", + "cum": "1300.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 1600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "1600000", + "notionalFloor": "600000", + "maintMarginRatio": "0.1", + "cum": "31300.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1600000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.125", + "cum": "71300.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "321300.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.5", + "cum": "1821300.0" + } + } + ], + "RENDER/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -28655,120 +28801,6 @@ } } ], - "REN/USDT:USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.015", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "50000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "50.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 600000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "600000", - "notionalFloor": "50000", - "maintMarginRatio": "0.05", - "cum": "1300.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 1600000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "1600000", - "notionalFloor": "600000", - "maintMarginRatio": "0.1", - "cum": "31300.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1600000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "2000000", - "notionalFloor": "1600000", - "maintMarginRatio": "0.125", - "cum": "71300.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 6000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "6000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.25", - "cum": "321300.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "6000000", - "maintMarginRatio": "0.5", - "cum": "1821300.0" - } - } - ], "REZ/USDT:USDT": [ { "tier": 1.0, @@ -29127,136 +29159,6 @@ } } ], - "RNDR/USDT:USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 26.0, - "info": { - "bracket": "1", - "initialLeverage": "26", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.015", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "2", - "initialLeverage": "25", - "notionalCap": "50000", - "notionalFloor": "5000", - "maintMarginRatio": "0.02", - "cum": "25.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "3", - "initialLeverage": "20", - "notionalCap": "100000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "275.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "100000", - "maintMarginRatio": "0.05", - "cum": "2775.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "52775.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 2500000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "2500000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "102775.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2500000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "7", - "initialLeverage": "2", - "notionalCap": "5000000", - "notionalFloor": "2500000", - "maintMarginRatio": "0.25", - "cum": "415275.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 6000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "8", - "initialLeverage": "1", - "notionalCap": "6000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.5", - "cum": "1665275.0" - } - } - ], "RONIN/USDT:USDT": [ { "tier": 1.0, From b3ac296cacf071dd0258d50b2480527920491681 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Aug 2024 06:58:17 +0200 Subject: [PATCH 28/31] chore: Improve schema wording --- freqtrade/configuration/config_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/configuration/config_schema.py b/freqtrade/configuration/config_schema.py index 7beed69e6..ca39c10c2 100644 --- a/freqtrade/configuration/config_schema.py +++ b/freqtrade/configuration/config_schema.py @@ -734,7 +734,7 @@ CONF_SCHEMA = { "default": {}, "properties": { "process_throttle_secs": { - "description": "Throttle time in seconds for processing.", + "description": "Minimum loop duration for one bot iteration in seconds.", "type": "integer", }, "interval": { From 8a85077e70679be3f54ad2a09c6b06d48dc6179d Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Aug 2024 07:02:47 +0200 Subject: [PATCH 29/31] chore: add download_trades config key, reorder some keys --- freqtrade/configuration/config_schema.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/freqtrade/configuration/config_schema.py b/freqtrade/configuration/config_schema.py index ca39c10c2..89e7f8b3b 100644 --- a/freqtrade/configuration/config_schema.py +++ b/freqtrade/configuration/config_schema.py @@ -36,11 +36,6 @@ CONF_SCHEMA = { "type": ["integer", "number"], "minimum": -1, }, - "new_pairs_days": { - "description": "Download data of new pairs for given number of days", - "type": "integer", - "default": 30, - }, "timeframe": { "description": ( f"The timeframe to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). {__IN_STRATEGY}" @@ -185,6 +180,7 @@ CONF_SCHEMA = { "type": "boolean", "default": False, }, + # Lookahead analysis section "minimum_trade_amount": { "description": "Minimum amount for a trade - only used for lookahead-analysis", "type": "number", @@ -501,6 +497,7 @@ CONF_SCHEMA = { "required": ["method"], }, }, + # RPC section "telegram": { "description": "Telegram settings.", "type": "object", @@ -701,6 +698,7 @@ CONF_SCHEMA = { }, "required": ["enabled", "listen_ip_address", "listen_port", "username", "password"], }, + # end of RPC section "db_url": { "description": "Database connection URL.", "type": "string", @@ -763,6 +761,16 @@ CONF_SCHEMA = { "description": f"Enable position adjustment. {__IN_STRATEGY}", "type": "boolean", }, + # Download data section + "new_pairs_days": { + "description": "Download data of new pairs for given number of days", + "type": "integer", + "default": 30, + }, + "download_trades": { + "description": "Download trades data by default (instead of ohlcv data).", + "type": "boolean", + }, "max_entry_position_adjustment": { "description": f"Maximum entry position adjustment allowed. {__IN_STRATEGY}", "type": ["integer", "number"], From abef8e376cab91b028b290133548d30827cbb0a2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Aug 2024 07:03:34 +0200 Subject: [PATCH 30/31] feat: add $schema to config examples --- config_examples/config_binance.example.json | 1 + config_examples/config_freqai.example.json | 1 + config_examples/config_full.example.json | 1 + config_examples/config_kraken.example.json | 1 + freqtrade/templates/base_config.json.j2 | 1 + 5 files changed, 5 insertions(+) diff --git a/config_examples/config_binance.example.json b/config_examples/config_binance.example.json index 3a2cea530..6c513f064 100644 --- a/config_examples/config_binance.example.json +++ b/config_examples/config_binance.example.json @@ -1,4 +1,5 @@ { + "$schema": "https://schema.freqtrade.io/schema.json", "max_open_trades": 3, "stake_currency": "USDT", "stake_amount": 0.05, diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 27bc4532c..6751002e4 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -1,4 +1,5 @@ { + "$schema": "https://schema.freqtrade.io/schema.json", "trading_mode": "futures", "margin_mode": "isolated", "max_open_trades": 5, diff --git a/config_examples/config_full.example.json b/config_examples/config_full.example.json index cb2d4797e..04137ed80 100644 --- a/config_examples/config_full.example.json +++ b/config_examples/config_full.example.json @@ -1,4 +1,5 @@ { + "$schema": "https://schema.freqtrade.io/schema.json", "max_open_trades": 3, "stake_currency": "BTC", "stake_amount": 0.05, diff --git a/config_examples/config_kraken.example.json b/config_examples/config_kraken.example.json index 420047627..72f5e6b5f 100644 --- a/config_examples/config_kraken.example.json +++ b/config_examples/config_kraken.example.json @@ -1,4 +1,5 @@ { + "$schema": "https://schema.freqtrade.io/schema.json", "max_open_trades": 5, "stake_currency": "EUR", "stake_amount": 10, diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index 4956cf056..86a717a40 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -6,6 +6,7 @@ "refresh_period": 1800 }' %} { + "$schema": "https://schema.freqtrade.io/schema.json", "max_open_trades": {{ max_open_trades }}, "stake_currency": "{{ stake_currency }}", "stake_amount": {{ stake_amount }}, From 67fdfdf584b081b56dcd8d80b0de738a324fd51f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Aug 2024 19:39:06 +0200 Subject: [PATCH 31/31] chore: Update schema file --- build_helpers/schema.json | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/build_helpers/schema.json b/build_helpers/schema.json index c2b930558..3c37896b1 100644 --- a/build_helpers/schema.json +++ b/build_helpers/schema.json @@ -9,11 +9,6 @@ ], "minimum": -1 }, - "new_pairs_days": { - "description": "Download data of new pairs for given number of days", - "type": "integer", - "default": 30 - }, "timeframe": { "description": "The timeframe to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). \nUsually specified in the strategy and missing in the configuration.", "type": "string" @@ -1065,7 +1060,7 @@ "default": {}, "properties": { "process_throttle_secs": { - "description": "Throttle time in seconds for processing.", + "description": "Minimum loop duration for one bot iteration in seconds.", "type": "integer" }, "interval": { @@ -1106,6 +1101,15 @@ "description": "Enable position adjustment. \nUsually specified in the strategy and missing in the configuration.", "type": "boolean" }, + "new_pairs_days": { + "description": "Download data of new pairs for given number of days", + "type": "integer", + "default": 30 + }, + "download_trades": { + "description": "Download trades data by default (instead of ohlcv data).", + "type": "boolean" + }, "max_entry_position_adjustment": { "description": "Maximum entry position adjustment allowed. \nUsually specified in the strategy and missing in the configuration.", "type": [