From 5dd1088d8dae43847a09dc26fec010aa7c35ab8a Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 00:44:26 -0700 Subject: [PATCH 01/16] Adding ignore unparameterized spaces flag --- freqtrade/commands/cli_options.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index e3c7fe464..ef1ec8515 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -552,4 +552,9 @@ AVAILABLE_CLI_OPTIONS = { help='Do not print epoch details header.', action='store_true', ), + "hyperopt_ignore_unparam_space": Arg( + "-u", "--ignore-unparameterized-spaces", + help="Suppress errors for any requested Hyperopt spaces that do not contain any parameters", + action="store_true", + ), } From 08fcd1a0d4977716d466496171e4ae6a5c36b67f Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 00:46:56 -0700 Subject: [PATCH 02/16] Adding ignore space errors to Hyperopt CLI --- freqtrade/commands/arguments.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index d424f3ce7..e58135895 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -31,7 +31,8 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "epochs", "spaces", "print_all", "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", - "hyperopt_loss", "disableparamexport"] + "hyperopt_loss", "disableparamexport", + "hyperopt_ignore_unparam_space"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] From 95227376b609a98b1577633861f90e9c9bb594f0 Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 00:53:46 -0700 Subject: [PATCH 03/16] Adding IUS to optimize args --- freqtrade/configuration/configuration.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 94b108f2b..723ad3795 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -368,6 +368,9 @@ class Configuration: self._args_to_config(config, argname='hyperopt_show_no_header', logstring='Parameter --no-header detected: {}') + + self._args_to_config(config, argname="hyperopt_ignore_unparam_space", + logstring="Paramter --ignore-unparameterized-spaces detected: {}") def _process_plot_options(self, config: Dict[str, Any]) -> None: From df45f467c69e5b0dc64fe8cb5b5af716b42979d7 Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 30 Sep 2021 01:11:02 -0700 Subject: [PATCH 04/16] Adding ability to ignore unparameterized spaces --- freqtrade/optimize/hyperopt.py | 48 +++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 9549b4054..f6c677a6e 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -237,27 +237,63 @@ class Hyperopt: logger.debug("Hyperopt has 'protection' space") # Enable Protections if protection space is selected. self.config['enable_protections'] = True - self.protection_space = self.custom_hyperopt.protection_space() + try: + self.protection_space = self.custom_hyperopt.protection_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'buy'): logger.debug("Hyperopt has 'buy' space") - self.buy_space = self.custom_hyperopt.buy_indicator_space() + try: + self.buy_space = self.custom_hyperopt.buy_indicator_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'sell'): logger.debug("Hyperopt has 'sell' space") - self.sell_space = self.custom_hyperopt.sell_indicator_space() + try: + self.sell_space = self.custom_hyperopt.sell_indicator_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'roi'): logger.debug("Hyperopt has 'roi' space") - self.roi_space = self.custom_hyperopt.roi_space() + try: + self.roi_space = self.custom_hyperopt.roi_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'stoploss'): logger.debug("Hyperopt has 'stoploss' space") - self.stoploss_space = self.custom_hyperopt.stoploss_space() + try: + self.stoploss_space = self.custom_hyperopt.stoploss_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise if HyperoptTools.has_space(self.config, 'trailing'): logger.debug("Hyperopt has 'trailing' space") - self.trailing_space = self.custom_hyperopt.trailing_space() + try: + self.trailing_space = self.custom_hyperopt.trailing_space() + except OperationalException as e: + if self.config["hyperopt_ignore_unparam_space"]: + logger.warning(e) + else: + raise self.dimensions = (self.buy_space + self.sell_space + self.protection_space + self.roi_space + self.stoploss_space + self.trailing_space) From 07750518c3e50711a0b8965f2535537b07402ba5 Mon Sep 17 00:00:00 2001 From: Sergey Khliustin Date: Mon, 4 Oct 2021 18:49:57 +0300 Subject: [PATCH 05/16] Added min_profit param to PerformanceFilter --- freqtrade/plugins/pairlist/PerformanceFilter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index 301ee57ab..f235816b8 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -21,6 +21,7 @@ class PerformanceFilter(IPairList): super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) self._minutes = pairlistconfig.get('minutes', 0) + self._min_profit = pairlistconfig.get('min_profit', None) @property def needstickers(self) -> bool: @@ -68,6 +69,8 @@ class PerformanceFilter(IPairList): sorted_df = list_df.merge(performance, on='pair', how='left')\ .fillna(0).sort_values(by=['count', 'pair'], ascending=True)\ .sort_values(by=['profit'], ascending=False) + if self._min_profit is not None: + sorted_df = sorted_df[sorted_df['profit'] >= self._min_profit] pairlist = sorted_df['pair'].tolist() return pairlist From aed919a05f352de482caddc1dc199d0ba2bd8e85 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 13 Oct 2021 19:54:35 +0200 Subject: [PATCH 06/16] Simplify "no-space-configured" error handling by moving it to hyperopt_auto --- freqtrade/commands/arguments.py | 4 +- freqtrade/commands/cli_options.py | 4 +- freqtrade/configuration/configuration.py | 6 +-- freqtrade/optimize/hyperopt.py | 49 ++++-------------------- freqtrade/optimize/hyperopt_auto.py | 27 +++++++++---- 5 files changed, 33 insertions(+), 57 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index e58135895..167b79afb 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -31,8 +31,8 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "epochs", "spaces", "print_all", "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", - "hyperopt_loss", "disableparamexport", - "hyperopt_ignore_unparam_space"] + "hyperopt_loss", "disableparamexport", + "hyperopt_ignore_missing_space"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index ef1ec8515..1f49b779b 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -552,8 +552,8 @@ AVAILABLE_CLI_OPTIONS = { help='Do not print epoch details header.', action='store_true', ), - "hyperopt_ignore_unparam_space": Arg( - "-u", "--ignore-unparameterized-spaces", + "hyperopt_ignore_missing_space": Arg( + "--ignore-missing-spaces", "--ignore-unparameterized-spaces", help="Suppress errors for any requested Hyperopt spaces that do not contain any parameters", action="store_true", ), diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 723ad3795..12dcff46a 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -368,9 +368,9 @@ class Configuration: self._args_to_config(config, argname='hyperopt_show_no_header', logstring='Parameter --no-header detected: {}') - - self._args_to_config(config, argname="hyperopt_ignore_unparam_space", - logstring="Paramter --ignore-unparameterized-spaces detected: {}") + + self._args_to_config(config, argname="hyperopt_ignore_missing_space", + logstring="Paramter --ignore-missing-space detected: {}") def _process_plot_options(self, config: Dict[str, Any]) -> None: diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index f6c677a6e..6397bbacb 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -237,63 +237,28 @@ class Hyperopt: logger.debug("Hyperopt has 'protection' space") # Enable Protections if protection space is selected. self.config['enable_protections'] = True - try: - self.protection_space = self.custom_hyperopt.protection_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.protection_space = self.custom_hyperopt.protection_space() if HyperoptTools.has_space(self.config, 'buy'): logger.debug("Hyperopt has 'buy' space") - try: - self.buy_space = self.custom_hyperopt.buy_indicator_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.buy_space = self.custom_hyperopt.buy_indicator_space() if HyperoptTools.has_space(self.config, 'sell'): logger.debug("Hyperopt has 'sell' space") - try: - self.sell_space = self.custom_hyperopt.sell_indicator_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.sell_space = self.custom_hyperopt.sell_indicator_space() if HyperoptTools.has_space(self.config, 'roi'): logger.debug("Hyperopt has 'roi' space") - try: - self.roi_space = self.custom_hyperopt.roi_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.roi_space = self.custom_hyperopt.roi_space() if HyperoptTools.has_space(self.config, 'stoploss'): logger.debug("Hyperopt has 'stoploss' space") - try: - self.stoploss_space = self.custom_hyperopt.stoploss_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.stoploss_space = self.custom_hyperopt.stoploss_space() if HyperoptTools.has_space(self.config, 'trailing'): logger.debug("Hyperopt has 'trailing' space") - try: - self.trailing_space = self.custom_hyperopt.trailing_space() - except OperationalException as e: - if self.config["hyperopt_ignore_unparam_space"]: - logger.warning(e) - else: - raise + self.trailing_space = self.custom_hyperopt.trailing_space() + self.dimensions = (self.buy_space + self.sell_space + self.protection_space + self.roi_space + self.stoploss_space + self.trailing_space) diff --git a/freqtrade/optimize/hyperopt_auto.py b/freqtrade/optimize/hyperopt_auto.py index c1c769c72..63b4b14e1 100644 --- a/freqtrade/optimize/hyperopt_auto.py +++ b/freqtrade/optimize/hyperopt_auto.py @@ -3,6 +3,7 @@ HyperOptAuto class. This module implements a convenience auto-hyperopt class, which can be used together with strategies that implement IHyperStrategy interface. """ +import logging from contextlib import suppress from typing import Callable, Dict, List @@ -15,12 +16,19 @@ with suppress(ImportError): from freqtrade.optimize.hyperopt_interface import EstimatorType, IHyperOpt -def _format_exception_message(space: str) -> str: - raise OperationalException( - f"The '{space}' space is included into the hyperoptimization " - f"but no parameter for this space was not found in your Strategy. " - f"Please make sure to have parameters for this space enabled for optimization " - f"or remove the '{space}' space from hyperoptimization.") +logger = logging.getLogger(__name__) + + +def _format_exception_message(space: str, ignore_missing_space: bool) -> None: + msg = (f"The '{space}' space is included into the hyperoptimization " + f"but no parameter for this space was not found in your Strategy. " + ) + if ignore_missing_space: + logger.warning(msg + "This space will be ignored.") + else: + raise OperationalException( + msg + f"Please make sure to have parameters for this space enabled for optimization " + f"or remove the '{space}' space from hyperoptimization.") class HyperOptAuto(IHyperOpt): @@ -48,13 +56,16 @@ class HyperOptAuto(IHyperOpt): if attr.optimize: yield attr.get_space(attr_name) - def _get_indicator_space(self, category): + def _get_indicator_space(self, category) -> List: # TODO: is this necessary, or can we call "generate_space" directly? indicator_space = list(self._generate_indicator_space(category)) if len(indicator_space) > 0: return indicator_space else: - _format_exception_message(category) + _format_exception_message( + category, + self.config.get("hyperopt_ignore_missing_space", False)) + return [] def buy_indicator_space(self) -> List['Dimension']: return self._get_indicator_space('buy') From 3279ea568c0b2da3d5a05a7aa3e011964838d849 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 13 Oct 2021 19:56:34 +0200 Subject: [PATCH 07/16] Add new parameter to hyperopt docs --- docs/hyperopt.md | 4 ++++ freqtrade/commands/cli_options.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 09d43939a..a693513d0 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -51,6 +51,7 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--print-all] [--no-color] [--print-json] [-j JOBS] [--random-state INT] [--min-trades INT] [--hyperopt-loss NAME] [--disable-param-export] + [--ignore-missing-spaces] optional arguments: -h, --help show this help message and exit @@ -117,6 +118,9 @@ optional arguments: SortinoHyperOptLoss, SortinoHyperOptLossDaily --disable-param-export Disable automatic hyperopt parameter export. + --ignore-missing-spaces, --ignore-unparameterized-spaces + Suppress errors for any requested Hyperopt spaces that + do not contain any parameters. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 1f49b779b..f8338bf6a 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -554,7 +554,8 @@ AVAILABLE_CLI_OPTIONS = { ), "hyperopt_ignore_missing_space": Arg( "--ignore-missing-spaces", "--ignore-unparameterized-spaces", - help="Suppress errors for any requested Hyperopt spaces that do not contain any parameters", + help=("Suppress errors for any requested Hyperopt spaces " + "that do not contain any parameters."), action="store_true", ), } From fe8374f2a489418a8628ebeb1387df617d89b211 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Oct 2021 07:06:51 +0200 Subject: [PATCH 08/16] Test for non-failing missing hyperopt space --- tests/optimize/test_hyperopt.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index e4ce29d44..b123fec21 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -702,7 +702,7 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: +def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.hyperopt.file_dump_json') mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', @@ -724,7 +724,13 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) with pytest.raises(OperationalException, match=r"The 'protection' space is included into *"): - hyperopt.start() + hyperopt.init_spaces() + + hyperopt.config['hyperopt_ignore_missing_space'] = True + caplog.clear() + hyperopt.init_spaces() + assert log_has_re(r"The 'protection' space is included into *", caplog) + assert hyperopt.protection_space == [] def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None: From c02a538187340fffe3515396e052c18d4116e467 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Oct 2021 19:33:32 +0200 Subject: [PATCH 09/16] Add documentation and log to PerformanceFilter --- docs/includes/pairlists.md | 9 +++++++-- freqtrade/plugins/pairlist/PerformanceFilter.py | 6 ++++++ tests/plugins/test_pairlist.py | 7 ++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index b612a4ddf..3d10747d3 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -194,17 +194,22 @@ Trade count is used as a tie breaker. You can use the `minutes` parameter to only consider performance of the past X minutes (rolling window). Not defining this parameter (or setting it to 0) will use all-time performance. +The optional `min_profit` parameter defines the minimum profit a pair must have to be considered. +Pairs below this level will be filtered out. +Using this parameter without `minutes` is highly discouraged, as it can lead to an empty pairlist without without a way to recover. + ```json "pairlists": [ // ... { "method": "PerformanceFilter", - "minutes": 1440 // rolling 24h + "minutes": 1440, // rolling 24h + "min_profit": 0.01 } ], ``` -!!! Note +!!! Warning "Backtesting" `PerformanceFilter` does not support backtesting mode. #### PrecisionFilter diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index f235816b8..671b6362b 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -70,7 +70,13 @@ class PerformanceFilter(IPairList): .fillna(0).sort_values(by=['count', 'pair'], ascending=True)\ .sort_values(by=['profit'], ascending=False) if self._min_profit is not None: + removed = sorted_df[sorted_df['profit'] < self._min_profit] + for _, row in removed.iterrows(): + self.log_once( + f"Removing pair {row['pair']} since {row['profit']} is " + f"below {self._min_profit}", logger.info) sorted_df = sorted_df[sorted_df['profit'] >= self._min_profit] + pairlist = sorted_df['pair'].tolist() return pairlist diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index cf918e2a0..c6246dccb 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -665,11 +665,11 @@ def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None: @pytest.mark.usefixtures("init_persistence") -def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee) -> None: +def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee, caplog) -> None: whitelist_conf['exchange']['pair_whitelist'].append('XRP/BTC') whitelist_conf['pairlists'] = [ {"method": "StaticPairList"}, - {"method": "PerformanceFilter", "minutes": 60} + {"method": "PerformanceFilter", "minutes": 60, "min_profit": 0.01} ] mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) exchange = get_patched_exchange(mocker, whitelist_conf) @@ -681,7 +681,8 @@ def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee) -> None: with time_machine.travel("2021-09-01 05:00:00 +00:00") as t: create_mock_trades(fee) pm.refresh_pairlist() - assert pm.whitelist == ['XRP/BTC', 'ETH/BTC', 'TKN/BTC'] + assert pm.whitelist == ['XRP/BTC'] + assert log_has_re(r'Removing pair .* since .* is below .*', caplog) # Move to "outside" of lookback window, so original sorting is restored. t.move_to("2021-09-01 07:00:00 +00:00") From fe9f597eab044f06ae1f68036eded72046db7d4f Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Oct 2021 10:11:25 +0200 Subject: [PATCH 10/16] Don't build ta-lib in parallel, this causes failures --- build_helpers/install_ta-lib.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index d12b16364..00c4417ae 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -11,8 +11,13 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' -o config.guess \ && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \ && ./configure --prefix=${INSTALL_LOC}/ \ - && make -j$(nproc) \ - && which sudo && sudo make install || make install + && make + if [ $? -ne 0 ]; then + echo "Failed building ta-lib." + cd .. && rm -rf ./ta-lib/ + exit 1 + fi + which sudo && sudo make install || make install if [ -x "$(command -v apt-get)" ]; then echo "Updating library path using ldconfig" sudo ldconfig From de5657a91b88eff9e65ff6e24a432d792c539002 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Oct 2021 07:00:07 +0200 Subject: [PATCH 11/16] Fix test failing when UI is installed --- tests/rpc/test_rpc_apiserver.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index ac76bbd11..7aa057d09 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -95,7 +95,7 @@ def test_api_not_found(botclient): assert rc.json() == {"detail": "Not Found"} -def test_api_ui_fallback(botclient): +def test_api_ui_fallback(botclient, mocker): ftbot, client = botclient rc = client_get(client, "/favicon.ico") @@ -109,9 +109,16 @@ def test_api_ui_fallback(botclient): rc = client_get(client, "/something") assert rc.status_code == 200 - # Test directory traversal + # Test directory traversal without mock rc = client_get(client, '%2F%2F%2Fetc/passwd') assert rc.status_code == 200 + # Allow both fallback or real UI + assert '`freqtrade install-ui`' in rc.text or '' in rc.text + + mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[True, False])) + rc = client_get(client, '%2F%2F%2Fetc/passwd') + assert rc.status_code == 200 + assert '`freqtrade install-ui`' in rc.text From 7f1080368b224d9ec7b8485cdf21a6b055494318 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Oct 2021 06:53:15 +0200 Subject: [PATCH 12/16] Commit mock-trades to avoid errors in tests --- tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 49534c88d..470eaa6d8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -226,6 +226,7 @@ def create_mock_trades(fee, use_db: bool = True): add_trade(trade) if use_db: + Trade.commit() Trade.query.session.flush() @@ -259,6 +260,7 @@ def create_mock_trades_usdt(fee, use_db: bool = True): add_trade(trade) if use_db: + Trade.commit() Trade.query.session.flush() From dcefb3eb9c91479ea17f343c339ffc3554c3166d Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Oct 2021 07:11:34 +0200 Subject: [PATCH 13/16] Fix delete_Trade api test --- tests/rpc/test_rpc_apiserver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 7aa057d09..9a03158ae 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -620,10 +620,11 @@ def test_api_delete_trade(botclient, mocker, fee, markets): assert_response(rc, 502) create_mock_trades(fee) - Trade.query.session.flush() + ftbot.strategy.order_types['stoploss_on_exchange'] = True trades = Trade.query.all() trades[1].stoploss_order_id = '1234' + Trade.commit() assert len(trades) > 2 rc = client_delete(client, f"{BASE_URI}/trades/1") From 5ba1d66be7f86ad9bf467e3238fd45b9e709b2e0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Oct 2021 17:57:51 +0200 Subject: [PATCH 14/16] Make sure transactions are reset closes #5719 --- freqtrade/rpc/api_server/deps.py | 2 ++ freqtrade/rpc/telegram.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/deps.py b/freqtrade/rpc/api_server/deps.py index d2459010f..77870722d 100644 --- a/freqtrade/rpc/api_server/deps.py +++ b/freqtrade/rpc/api_server/deps.py @@ -1,5 +1,6 @@ from typing import Any, Dict, Optional +from freqtrade.persistence import Trade from freqtrade.rpc.rpc import RPC, RPCException from .webserver import ApiServer @@ -14,6 +15,7 @@ def get_rpc_optional() -> Optional[RPC]: def get_rpc() -> Optional[RPC]: _rpc = get_rpc_optional() if _rpc: + Trade.query.session.rollback() return _rpc else: raise RPCException('Bot is not in the correct state') diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 059ba9c41..846747f40 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -25,6 +25,7 @@ from freqtrade.constants import DUST_PER_COIN from freqtrade.enums import RPCMessageType from freqtrade.exceptions import OperationalException from freqtrade.misc import chunks, plural, round_coin_value +from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException, RPCHandler @@ -59,7 +60,8 @@ def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]: update.message.chat_id ) return wrapper - + # Rollback session to avoid getting data stored in a transaction. + Trade.query.session.rollback() logger.debug( 'Executing handler: %s for chat_id: %s', command_handler.__name__, From f61dc6d95ada089055e0e12c7927c58350b409ef Mon Sep 17 00:00:00 2001 From: Rik Helsen Date: Sun, 17 Oct 2021 00:14:09 +0200 Subject: [PATCH 15/16] =?UTF-8?q?=F0=9F=93=9D=20`mkdocs.yml`=20-=20Fixed?= =?UTF-8?q?=20darktheme=20toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 05156168f..0daf462c2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -54,8 +54,8 @@ theme: primary: 'blue grey' accent: 'tear' toggle: - icon: material/toggle-switch-off-outline - name: Switch to dark mode + icon: material/toggle-switch + name: Switch to light mode extra_css: - 'stylesheets/ft.extra.css' extra_javascript: From abd5c4f27855c3486badc00b5efb9330e3aeb52b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 17 Oct 2021 10:39:53 +0200 Subject: [PATCH 16/16] Convert additional test to USDT --- tests/test_freqtradebot.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index f57e35ca1..838a158e0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3378,9 +3378,9 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usd mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00000172, - 'ask': 0.00000173, - 'last': 0.00000172 + 'bid': 2.0, + 'ask': 2.0, + 'last': 2.0 }), create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, @@ -3408,7 +3408,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usd # Test if buy-signal is absent patch_get_signal(freqtrade, value=(False, True, None)) assert freqtrade.handle_trade(trade) is True - assert trade.sell_reason == SellType.SELL_SIGNAL.value + assert trade.sell_reason == SellType.ROI.value def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog,