From 683b084323d45e0647327756e71ed4ccd4f1d6dd Mon Sep 17 00:00:00 2001 From: th0rntwig Date: Wed, 28 Sep 2022 18:23:56 +0200 Subject: [PATCH 01/19] Set train-test-split shuffle=False as default and remove stratification --- docs/freqai-parameter-table.md | 3 +-- docs/freqai-running.md | 17 ----------------- freqtrade/freqai/data_kitchen.py | 12 +++--------- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md index 5969f43c6..c4d044ba4 100644 --- a/docs/freqai-parameter-table.md +++ b/docs/freqai-parameter-table.md @@ -27,8 +27,7 @@ Mandatory parameters are marked as **Required** and have to be set in one of the | `weight_factor` | Weight training data points according to their recency (see details [here](freqai-feature-engineering.md#weighting-features-for-temporal-importance)).
**Datatype:** Positive float (typically < 1). | `indicator_max_period_candles` | **No longer used (#7325)**. Replaced by `startup_candle_count` which is set in the [strategy](freqai-configuration.md#building-a-freqai-strategy). `startup_candle_count` is timeframe independent and defines the maximum *period* used in `populate_any_indicators()` for indicator creation. `FreqAI` uses this parameter together with the maximum timeframe in `include_time_frames` to calculate how many data points to download such that the first data point does not include a NaN
**Datatype:** Positive integer. | `indicator_periods_candles` | Time periods to calculate indicators for. The indicators are added to the base indicator dataset.
**Datatype:** List of positive integers. -| `stratify_training_data` | Split the feature set into training and testing datasets. For example, `stratify_training_data: 2` would set every 2nd data point into a separate dataset to be pulled from during training/testing. See details about how it works [here](freqai-running.md#data-stratification-for-training-and-testing-the-model).
**Datatype:** Positive integer. -| `principal_component_analysis` | Automatically reduce the dimensionality of the data set using Principal Component Analysis. See details about how it works [here](#reducing-data-dimensionality-with-principal-component-analysis)
**Datatype:** Boolean. defaults to `false`. +| `principal_component_analysis` | Automatically reduce the dimensionality of the data set using Principal Component Analysis. See details about how it works [here](#reducing-data-dimensionality-with-principal-component-analysis)
**Datatype:** Boolean. defaults to `False`. | `plot_feature_importances` | Create a feature importance plot for each model for the top/bottom `plot_feature_importances` number of features.
**Datatype:** Integer, defaults to `0`. | `DI_threshold` | Activates the use of the Dissimilarity Index for outlier detection when set to > 0. See details about how it works [here](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di).
**Datatype:** Positive float (typically < 1). | `use_SVM_to_remove_outliers` | Train a support vector machine to detect and remove outliers from the training dataset, as well as from incoming data points. See details about how it works [here](freqai-feature-engineering.md#identifying-outliers-using-a-support-vector-machine-svm).
**Datatype:** Boolean. diff --git a/docs/freqai-running.md b/docs/freqai-running.md index 6c7b56da1..bfefe88c2 100644 --- a/docs/freqai-running.md +++ b/docs/freqai-running.md @@ -105,23 +105,6 @@ During dry/live mode, FreqAI trains each coin pair sequentially (on separate thr In the presented example config, the user will only allow predictions on models that are less than 1/2 hours old. -## Data stratification for training and testing the model - -You can stratify (group) the training/testing data using: - -```json - "freqai": { - "feature_parameters" : { - "stratify_training_data": 3 - } - } -``` - -This will split the data chronologically so that every Xth data point is used to test the model after training. In the example above, the user is asking for every third data point in the dataframe to be used for -testing; the other points are used for training. - -The test data is used to evaluate the performance of the model after training. If the test score is high, the model is able to capture the behavior of the data well. If the test score is low, either the model does not capture the complexity of the data, the test data is significantly different from the train data, or a different type of model should be used. - ## Controlling the model learning process Model training parameters are unique to the selected machine learning library. FreqAI allows you to set any parameter for any library using the `model_training_parameters` dictionary in the config. The example config (found in `config_examples/config_freqai.example.json`) shows some of the example parameters associated with `Catboost` and `LightGBM`, but you can add any parameters available in those libraries or any other machine learning library you choose to implement. diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index f4fa4e5fd..9e22667f3 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -134,20 +134,14 @@ class FreqaiDataKitchen: """ feat_dict = self.freqai_config["feature_parameters"] + shuffle = self.freqai_config.get('data_split_parameters', {}).get('shuffle', False) + weights: npt.ArrayLike if feat_dict.get("weight_factor", 0) > 0: weights = self.set_weights_higher_recent(len(filtered_dataframe)) else: weights = np.ones(len(filtered_dataframe)) - if feat_dict.get("stratify_training_data", 0) > 0: - stratification = np.zeros(len(filtered_dataframe)) - for i in range(1, len(stratification)): - if i % feat_dict.get("stratify_training_data", 0) == 0: - stratification[i] = 1 - else: - stratification = None - if self.freqai_config.get('data_split_parameters', {}).get('test_size', 0.1) != 0: ( train_features, @@ -160,7 +154,7 @@ class FreqaiDataKitchen: filtered_dataframe[: filtered_dataframe.shape[0]], labels, weights, - stratify=stratification, + shuffle=shuffle, **self.config["freqai"]["data_split_parameters"], ) else: From 772abfc6f033aec44c414cf3d183485bd5b5979c Mon Sep 17 00:00:00 2001 From: th0rntwig Date: Wed, 28 Sep 2022 19:29:02 +0200 Subject: [PATCH 02/19] Add default value for shuffle in docs --- docs/freqai-parameter-table.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md index c4d044ba4..8e19226ba 100644 --- a/docs/freqai-parameter-table.md +++ b/docs/freqai-parameter-table.md @@ -40,7 +40,7 @@ Mandatory parameters are marked as **Required** and have to be set in one of the | | **Data split parameters** | `data_split_parameters` | Include any additional parameters available from Scikit-learn `test_train_split()`, which are shown [here](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website).
**Datatype:** Dictionary. | `test_size` | The fraction of data that should be used for testing instead of training.
**Datatype:** Positive float < 1. -| `shuffle` | Shuffle the training data points during training. Typically, for time-series forecasting, this is set to `False`.
**Datatype:** Boolean. +| `shuffle` | Shuffle the training data points during training. Typically, to not remove the chronological order of data in time-series forecasting, this is set to `False`.
**Datatype:** Boolean.
Defaut: `False`. | | **Model training parameters** | `model_training_parameters` | A flexible dictionary that includes all parameters available by the selected model library. For example, if you use `LightGBMRegressor`, this dictionary can contain any parameter available by the `LightGBMRegressor` [here](https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRegressor.html) (external website). If you select a different model, this dictionary can contain any parameter from that model.
**Datatype:** Dictionary. | `n_estimators` | The number of boosted trees to fit in regression.
**Datatype:** Integer. From 38aca8e908fb532f44e889d35257961437866b93 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 30 Sep 2022 00:22:31 +0200 Subject: [PATCH 03/19] fix failing svm test --- tests/freqai/test_freqai_datakitchen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index f7446420d..b99ac236d 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -86,7 +86,7 @@ def test_use_SVM_to_remove_outliers_and_outlier_protection(mocker, freqai_conf, freqai_conf['freqai']['feature_parameters'].update({"outlier_protection_percentage": 0.1}) freqai.dk.use_SVM_to_remove_outliers(predict=False) assert log_has_re( - "SVM detected 8.09%", + "SVM detected 8.66%", caplog, ) From be48131185764d0b707e706de4f0aa6d2a688193 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 30 Sep 2022 00:33:08 +0200 Subject: [PATCH 04/19] make shuffle false in constants --- freqtrade/constants.py | 1 + freqtrade/freqai/data_kitchen.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index e14e81343..acab8489c 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -567,6 +567,7 @@ CONF_SCHEMA = { "properties": { "test_size": {"type": "number"}, "random_state": {"type": "integer"}, + "shuffle": {"type": "boolean", "default": False} }, }, "model_training_parameters": { diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 9e22667f3..5cf9b2f03 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -134,7 +134,8 @@ class FreqaiDataKitchen: """ feat_dict = self.freqai_config["feature_parameters"] - shuffle = self.freqai_config.get('data_split_parameters', {}).get('shuffle', False) + if 'shuffle' not in self.freqai_config['data_split_parameters']: + self.freqai_config["data_split_parameters"].update({'shuffle': False}) weights: npt.ArrayLike if feat_dict.get("weight_factor", 0) > 0: @@ -154,7 +155,6 @@ class FreqaiDataKitchen: filtered_dataframe[: filtered_dataframe.shape[0]], labels, weights, - shuffle=shuffle, **self.config["freqai"]["data_split_parameters"], ) else: From cdc01a07819f2634ce33c0bf9dc666924673e1ad Mon Sep 17 00:00:00 2001 From: Emre Date: Fri, 30 Sep 2022 15:22:05 -0700 Subject: [PATCH 05/19] Fix feature list match for pca --- freqtrade/freqai/data_kitchen.py | 5 +++++ freqtrade/freqai/freqai_interface.py | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 400e70fc8..c05900bad 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -1,5 +1,6 @@ import copy import logging +import re import shutil from datetime import datetime, timezone from math import cos, sin @@ -881,6 +882,10 @@ class FreqaiDataKitchen: """ column_names = dataframe.columns features = [c for c in column_names if "%" in c] + pca_features = [c for c in column_names if re.search(r"^PC\d+$", c)] + if not features and pca_features: + features = pca_features + if not features: raise OperationalException("Could not find any features!") diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index d9f917338..bf625b2a7 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -434,6 +434,10 @@ class IFreqaiModel(ABC): feature_list = dk.data["training_features_list_raw"] else: feature_list = dk.data['training_features_list'] + + if self.ft_params.get('principal_component_analysis', False): + feature_list = dk.data['training_features_list'] + if dk.training_features_list != feature_list: raise OperationalException( "Trying to access pretrained model with `identifier` " From fad90269391fb35a92c3fc03fa24d3b51720bc28 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 08:35:51 +0200 Subject: [PATCH 06/19] Update updating docs closes #7507 --- docs/updating.md | 9 +++++++++ docs/windows_installation.md | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/updating.md b/docs/updating.md index 8dc7279a4..893bc846e 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -37,3 +37,12 @@ pip install -e . # Ensure freqUI is at the latest version freqtrade install-ui ``` + +### Problems updating + +Update-problems usually come missing dependencies (you didn't follow the above instructions) - or from updated dependencies, which fail to install (for example TA-lib). +Please refer to the corresponding installation sections (common problems linked below) + +Common problems and their solutions: + +* [ta-lib update on windows](windows_installation.md#2-install-ta-lib) diff --git a/docs/windows_installation.md b/docs/windows_installation.md index 9fbbf8250..5cfae8c10 100644 --- a/docs/windows_installation.md +++ b/docs/windows_installation.md @@ -34,7 +34,7 @@ python -m venv .env .env\Scripts\activate.ps1 # optionally install ta-lib from wheel # Eventually adjust the below filename to match the downloaded wheel -pip install --find-links build_helpers\ TA-Lib +pip install --find-links build_helpers\ TA-Lib -U pip install -r requirements.txt pip install -e . freqtrade From 545d65235261563dbc4b482dea82e2d76f0c5440 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 09:02:05 +0200 Subject: [PATCH 07/19] Update okx exception wording --- freqtrade/exchange/okx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 2db5fb6a9..fe1c94017 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -78,7 +78,7 @@ class Okx(Exchange): raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( - f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e + f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}') from e except ccxt.BaseError as e: raise OperationalException(e) from e From a96aa568bfa81c7c78ba60cc676483f3903a2d74 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 09:21:40 +0200 Subject: [PATCH 08/19] Add binance futures mode checks closes #7505 --- docs/assets/binance_futures_settings.png | Bin 0 -> 81500 bytes docs/exchanges.md | 19 ++++++++++---- freqtrade/exchange/binance.py | 31 +++++++++++++++++++++++ tests/exchange/test_binance.py | 18 +++++++++++++ tests/exchange/test_ccxt_compat.py | 1 + 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 docs/assets/binance_futures_settings.png diff --git a/docs/assets/binance_futures_settings.png b/docs/assets/binance_futures_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..a3f7a2c7032d54c80b2206bad0a38cd5c7729d2a GIT binary patch literal 81500 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ℜ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"` to your blacklist to avoid issues, unless you are willing to maintain enough extra `BNB` on the account or unless you're willing to disable using `BNB` for fees. Binance accounts may use `BNB` for fees, and if a trade happens to be on `BNB`, further trades may consume this position and make the initial BNB trade unsellable as the expected amount is not there anymore. +### Binance sites + +Binance has been split into 2, and users must use the correct ccxt exchange ID for their exchange, otherwise API keys are not recognized. + +* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. +* [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. + ### Binance Futures Binance has specific (unfortunately complex) [Futures Trading Quantitative Rules](https://www.binance.com/en/support/faq/4f462ebe6ff445d4a170be7d9e897272) which need to be followed, and which prohibit a too low stake-amount (among others) for too many orders. @@ -87,12 +94,14 @@ When trading on Binance Futures market, orderbook must be used because there is }, ``` -### Binance sites +#### Binance futures settings -Binance has been split into 2, and users must use the correct ccxt exchange ID for their exchange, otherwise API keys are not recognized. +Users will also have to have the futures-setting "Position Mode" set to "One-way Mode", and "Asset Mode" set to "Single-Asset Mode". +These settings will be checked on startup, and freqtrade will show an error if this setting is wrong. -* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. -* [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. +![Binance futures settings](assets/binance_futures_settings.png) + +Freqtrade will not attempt to change these settings. ## Kraken diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index f9fb4a8b1..a0d4b2d82 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -68,6 +68,37 @@ class Binance(Exchange): tickers = deep_merge_dicts(bidsasks, tickers, allow_null_overrides=False) return tickers + @retrier + def additional_exchange_init(self) -> None: + """ + Additional exchange initialization logic. + .api will be available at this point. + Must be overridden in child methods if required. + """ + try: + if self.trading_mode == TradingMode.FUTURES and not self._config['dry_run']: + position_side = self._api.fapiPrivateGetPositionsideDual() + self._log_exchange_response('position_side_setting', position_side) + assets_margin = self._api.fapiPrivateGetMultiAssetsMargin() + self._log_exchange_response('multi_asset_margin', assets_margin) + msg = "" + if position_side.get('dualSidePosition') is True: + msg += ( + "\nHedge Mode is not supported by freqtrade. " + "Please change 'Position Mode' on your binance futures account.") + if assets_margin.get('multiAssetsMargin') is True: + msg += ("\nMulti-Asset Mode is not supported by freqtrade. " + "Please change 'Asset Mode' on your binance futures account.") + if msg: + raise OperationalException(msg) + except ccxt.DDoSProtection as e: + raise DDosProtection(e) from e + except (ccxt.NetworkError, ccxt.ExchangeError) as e: + raise TemporaryError( + f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e + except ccxt.BaseError as e: + raise OperationalException(e) from e + @retrier def _set_leverage( self, diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index e9f4dfa8a..ef5cb1240 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -501,6 +501,24 @@ def test_fill_leverage_tiers_binance_dryrun(default_conf, mocker, leverage_tiers assert len(v) == len(value) +def test_additional_exchange_init_binance(default_conf, mocker): + api_mock = MagicMock() + api_mock.fapiPrivateGetPositionsideDual = MagicMock(return_value={"dualSidePosition": True}) + api_mock.fapiPrivateGetMultiAssetsMargin = MagicMock(return_value={"multiAssetsMargin": True}) + default_conf['dry_run'] = False + default_conf['trading_mode'] = TradingMode.FUTURES + default_conf['margin_mode'] = MarginMode.ISOLATED + with pytest.raises(OperationalException, + match=r"Hedge Mode is not supported.*\nMulti-Asset Mode is not supported.*"): + get_patched_exchange(mocker, default_conf, id="binance", api_mock=api_mock) + api_mock.fapiPrivateGetPositionsideDual = MagicMock(return_value={"dualSidePosition": False}) + api_mock.fapiPrivateGetMultiAssetsMargin = MagicMock(return_value={"multiAssetsMargin": False}) + exchange = get_patched_exchange(mocker, default_conf, id="binance", api_mock=api_mock) + assert exchange + ccxt_exceptionhandlers(mocker, default_conf, api_mock, 'binance', + "additional_exchange_init", "fapiPrivateGetPositionsideDual") + + def test__set_leverage_binance(mocker, default_conf): api_mock = MagicMock() diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 82be6196a..6798cd2f7 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -137,6 +137,7 @@ def exchange_futures(request, exchange_conf, class_mocker): 'freqtrade.exchange.binance.Binance.fill_leverage_tiers') class_mocker.patch('freqtrade.exchange.exchange.Exchange.fetch_trading_fees') class_mocker.patch('freqtrade.exchange.okx.Okx.additional_exchange_init') + class_mocker.patch('freqtrade.exchange.binance.Binance.additional_exchange_init') class_mocker.patch('freqtrade.exchange.exchange.Exchange.load_cached_leverage_tiers', return_value=None) class_mocker.patch('freqtrade.exchange.exchange.Exchange.cache_leverage_tiers') From 201bbbcee67d33a70dc81e1a04743345fedacd35 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 09:32:16 +0200 Subject: [PATCH 09/19] Okx formatting --- freqtrade/exchange/okx.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index fe1c94017..6792c2cba 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -78,7 +78,8 @@ class Okx(Exchange): raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( - f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}') from e + f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}' + ) from e except ccxt.BaseError as e: raise OperationalException(e) from e From 8f8b5cc28ef82ddeed11c216058cd0c1c47ee710 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 09:35:21 +0200 Subject: [PATCH 10/19] Disable log spam from analyze_df in webhook/discord --- freqtrade/rpc/discord.py | 2 +- freqtrade/rpc/webhook.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index 9efe6f427..c48508300 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -30,9 +30,9 @@ class Discord(Webhook): pass def send_msg(self, msg) -> None: - logger.info(f"Sending discord message: {msg}") if msg['type'].value in self.config['discord']: + logger.info(f"Sending discord message: {msg}") msg['strategy'] = self.strategy msg['timeframe'] = self.timeframe diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index 6109e80bc..bb3b3922f 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -61,6 +61,14 @@ class Webhook(RPCHandler): RPCMessageType.STARTUP, RPCMessageType.WARNING): valuedict = whconfig.get('webhookstatus') + elif msg['type'] in ( + RPCMessageType.PROTECTION_TRIGGER, + RPCMessageType.PROTECTION_TRIGGER_GLOBAL, + RPCMessageType.WHITELIST, + RPCMessageType.ANALYZED_DF, + RPCMessageType.STRATEGY_MSG): + # Don't fail for non-implemented types + return else: raise NotImplementedError('Unknown message type: {}'.format(msg['type'])) if not valuedict: From 6702a1b21905be3a6a8b00222c20e2c5e09bc449 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 09:45:58 +0200 Subject: [PATCH 11/19] Update test to verify webhook won't log-spam on new messagetypes --- tests/rpc/test_rpc_webhook.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index 4d65b4966..3bbb85d54 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -365,6 +365,14 @@ def test_exception_send_msg(default_conf, mocker, caplog): with pytest.raises(NotImplementedError): webhook.send_msg(msg) + # Test no failure for not implemented but known messagetypes + for e in RPCMessageType: + msg = { + 'type': e, + 'status': 'whatever' + } + webhook.send_msg(msg) + def test__send_msg(default_conf, mocker, caplog): default_conf["webhook"] = get_webhook_dict() From f2b875483f671dca812f2298ea1177ca1433b823 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 1 Oct 2022 13:14:59 +0200 Subject: [PATCH 12/19] ensure raw features match when PCA is employed --- freqtrade/freqai/data_kitchen.py | 4 ---- freqtrade/freqai/freqai_interface.py | 13 +++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index c05900bad..766eb981f 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -1,6 +1,5 @@ import copy import logging -import re import shutil from datetime import datetime, timezone from math import cos, sin @@ -882,9 +881,6 @@ class FreqaiDataKitchen: """ column_names = dataframe.columns features = [c for c in column_names if "%" in c] - pca_features = [c for c in column_names if re.search(r"^PC\d+$", c)] - if not features and pca_features: - features = pca_features if not features: raise OperationalException("Could not find any features!") diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index bf625b2a7..5cc6d3f69 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -275,7 +275,8 @@ class IFreqaiModel(ABC): if dk.check_if_backtest_prediction_exists(): self.dd.load_metadata(dk) - self.check_if_feature_list_matches_strategy(dataframe_train, dk) + dk.find_features(dataframe_train) + self.check_if_feature_list_matches_strategy(dk) append_df = dk.get_backtesting_prediction() dk.append_predictions(append_df) else: @@ -296,7 +297,6 @@ class IFreqaiModel(ABC): else: self.model = self.dd.load_data(pair, dk) - # self.check_if_feature_list_matches_strategy(dataframe_train, dk) pred_df, do_preds = self.predict(dataframe_backtest, dk) append_df = dk.get_predictions_to_append(pred_df, do_preds) dk.append_predictions(append_df) @@ -420,7 +420,7 @@ class IFreqaiModel(ABC): return def check_if_feature_list_matches_strategy( - self, dataframe: DataFrame, dk: FreqaiDataKitchen + self, dk: FreqaiDataKitchen ) -> None: """ Ensure user is passing the proper feature set if they are reusing an `identifier` pointing @@ -429,15 +429,12 @@ class IFreqaiModel(ABC): :param dk: FreqaiDataKitchen = non-persistent data container/analyzer for current coin/bot loop """ - dk.find_features(dataframe) + if "training_features_list_raw" in dk.data: feature_list = dk.data["training_features_list_raw"] else: feature_list = dk.data['training_features_list'] - if self.ft_params.get('principal_component_analysis', False): - feature_list = dk.data['training_features_list'] - if dk.training_features_list != feature_list: raise OperationalException( "Trying to access pretrained model with `identifier` " @@ -510,7 +507,7 @@ class IFreqaiModel(ABC): dk.use_DBSCAN_to_remove_outliers(predict=True) # ensure user is feeding the correct indicators to the model - self.check_if_feature_list_matches_strategy(dk.data_dictionary['prediction_features'], dk) + self.check_if_feature_list_matches_strategy(dk) def model_exists(self, dk: FreqaiDataKitchen) -> bool: """ From cd514cf15d35aa53774070c3bdd40ffd0f67ec00 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 1 Oct 2022 14:18:46 +0200 Subject: [PATCH 13/19] fix inlier metric in backtesting --- freqtrade/freqai/base_models/BaseClassifierModel.py | 2 +- freqtrade/freqai/base_models/BaseRegressionModel.py | 2 +- freqtrade/freqai/data_drawer.py | 2 +- freqtrade/freqai/data_kitchen.py | 2 ++ freqtrade/freqai/freqai_interface.py | 8 ++++---- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqai/base_models/BaseClassifierModel.py b/freqtrade/freqai/base_models/BaseClassifierModel.py index 70f212d2a..09f1bf98c 100644 --- a/freqtrade/freqai/base_models/BaseClassifierModel.py +++ b/freqtrade/freqai/base_models/BaseClassifierModel.py @@ -92,7 +92,7 @@ class BaseClassifierModel(IFreqaiModel): filtered_df = dk.normalize_data_from_metadata(filtered_df) dk.data_dictionary["prediction_features"] = filtered_df - self.data_cleaning_predict(dk, filtered_df) + self.data_cleaning_predict(dk) predictions = self.model.predict(dk.data_dictionary["prediction_features"]) pred_df = DataFrame(predictions, columns=dk.label_list) diff --git a/freqtrade/freqai/base_models/BaseRegressionModel.py b/freqtrade/freqai/base_models/BaseRegressionModel.py index 2450bf305..5d89dd356 100644 --- a/freqtrade/freqai/base_models/BaseRegressionModel.py +++ b/freqtrade/freqai/base_models/BaseRegressionModel.py @@ -92,7 +92,7 @@ class BaseRegressionModel(IFreqaiModel): dk.data_dictionary["prediction_features"] = filtered_df # optional additional data cleaning/analysis - self.data_cleaning_predict(dk, filtered_df) + self.data_cleaning_predict(dk) predictions = self.model.predict(dk.data_dictionary["prediction_features"]) pred_df = DataFrame(predictions, columns=dk.label_list) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 1839724f8..471f6875c 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -423,7 +423,7 @@ class FreqaiDataDrawer: dk.data["data_path"] = str(dk.data_path) dk.data["model_filename"] = str(dk.model_filename) - dk.data["training_features_list"] = list(dk.data_dictionary["train_features"].columns) + dk.data["training_features_list"] = dk.training_features_list dk.data["label_list"] = dk.label_list # store the metadata with open(save_path / f"{dk.model_filename}_metadata.json", "w") as fp: diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 766eb981f..7efefd127 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -844,10 +844,12 @@ class FreqaiDataKitchen: self.remove_beginning_points_from_data_dict(set_, no_prev_pts) self.data_dictionary[f'{set_}_features'] = pd.concat( [compute_df, inlier_metric], axis=1) + # self.find_features(self.data_dictionary[f'{set_}_features']) else: self.data_dictionary['prediction_features'] = pd.concat( [compute_df, inlier_metric], axis=1) self.data_dictionary['prediction_features'].fillna(0, inplace=True) + # self.find_features(self.data_dictionary['prediction_features']) logger.info('Inlier metric computed and added to features.') diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 5cc6d3f69..78539bae5 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -482,13 +482,16 @@ class IFreqaiModel(ABC): if self.freqai_info["feature_parameters"].get('noise_standard_deviation', 0): dk.add_noise_to_training_features() - def data_cleaning_predict(self, dk: FreqaiDataKitchen, dataframe: DataFrame) -> None: + def data_cleaning_predict(self, dk: FreqaiDataKitchen) -> None: """ Base data cleaning method for predict. Functions here are complementary to the functions of data_cleaning_train. """ ft_params = self.freqai_info["feature_parameters"] + # ensure user is feeding the correct indicators to the model + self.check_if_feature_list_matches_strategy(dk) + if ft_params.get('inlier_metric_window', 0): dk.compute_inlier_metric(set_='predict') @@ -506,9 +509,6 @@ class IFreqaiModel(ABC): if ft_params.get("use_DBSCAN_to_remove_outliers", False): dk.use_DBSCAN_to_remove_outliers(predict=True) - # ensure user is feeding the correct indicators to the model - self.check_if_feature_list_matches_strategy(dk) - def model_exists(self, dk: FreqaiDataKitchen) -> bool: """ Given a pair and path, check if a model already exists From f4c6b99d63b6da87da9318cbf599e074fa6a50e0 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 1 Oct 2022 14:23:15 +0200 Subject: [PATCH 14/19] remove commented lines --- freqtrade/freqai/data_kitchen.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 7efefd127..766eb981f 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -844,12 +844,10 @@ class FreqaiDataKitchen: self.remove_beginning_points_from_data_dict(set_, no_prev_pts) self.data_dictionary[f'{set_}_features'] = pd.concat( [compute_df, inlier_metric], axis=1) - # self.find_features(self.data_dictionary[f'{set_}_features']) else: self.data_dictionary['prediction_features'] = pd.concat( [compute_df, inlier_metric], axis=1) self.data_dictionary['prediction_features'].fillna(0, inplace=True) - # self.find_features(self.data_dictionary['prediction_features']) logger.info('Inlier metric computed and added to features.') From 2c94ed2e59c5ef7eeb6a33c2caea045ad0a3e491 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Oct 2022 21:20:14 +0200 Subject: [PATCH 15/19] Decrease message throughput fixes memory leak by queue raising indefinitely --- freqtrade/rpc/api_server/webserver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index df4324740..53af91477 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -198,8 +198,10 @@ class ApiServer(RPCHandler): logger.debug(f"Found message of type: {message.get('type')}") # Broadcast it await self._ws_channel_manager.broadcast(message) - # Sleep, make this configurable? - await asyncio.sleep(0.1) + # Limit messages per sec. + # Could cause problems with queue size if too low, and + # problems with network traffik if too high. + await asyncio.sleep(0.001) except asyncio.CancelledError: pass From 564318415eb5d9ed41a3b8c1e85801d65bea7856 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 2 Oct 2022 08:12:03 +0200 Subject: [PATCH 16/19] Improve test resiliance --- tests/rpc/test_rpc_emc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/rpc/test_rpc_emc.py b/tests/rpc/test_rpc_emc.py index 28adc66b9..b73a64f06 100644 --- a/tests/rpc/test_rpc_emc.py +++ b/tests/rpc/test_rpc_emc.py @@ -207,12 +207,15 @@ async def test_emc_create_connection_invalid_port(default_conf, caplog, mocker): }) dp = DataProvider(default_conf, None, None, None) + # Handle start explicitly to avoid messing with threading in tests + mocker.patch("freqtrade.rpc.external_message_consumer.ExternalMessageConsumer.start",) emc = ExternalMessageConsumer(default_conf, dp) try: - await asyncio.sleep(0.01) + await emc._create_connection(emc.producers[0], asyncio.Lock()) assert log_has_re(r".+ is an invalid WebSocket URL .+", caplog) finally: + emc._running = False emc.shutdown() From 308fa430078bea9719fdb40a24cec6cca4c5c0f5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 2 Oct 2022 08:30:19 +0200 Subject: [PATCH 17/19] Don't use magicmock as trade object --- tests/test_freqtradebot.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0f1a05ab4..ca9e63890 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -28,6 +28,7 @@ from tests.conftest import (create_mock_trades, create_mock_trades_usdt, get_pat from tests.conftest_trades import (MOCK_TRADE_COUNT, entry_side, exit_side, mock_order_1, mock_order_2, mock_order_2_sell, mock_order_3, mock_order_3_sell, mock_order_4, mock_order_5_stoploss, mock_order_6_sell) +from tests.conftest_trades_usdt import mock_trade_usdt_4 def patch_RPCManager(mocker) -> MagicMock: @@ -2980,7 +2981,7 @@ def test_manage_open_orders_exception(default_conf_usdt, ticker_usdt, open_trade @pytest.mark.parametrize("is_short", [False, True]) -def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_short) -> None: +def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_short, fee) -> None: patch_RPCManager(mocker) patch_exchange(mocker) l_order = limit_order[entry_side(is_short)] @@ -2994,16 +2995,12 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_ freqtrade = FreqtradeBot(default_conf_usdt) freqtrade._notify_enter_cancel = MagicMock() - # TODO: Convert to real trade - trade = MagicMock() - trade.pair = 'LTC/USDT' - trade.open_rate = 200 - trade.is_short = False - trade.entry_side = "buy" - trade.amount = 100 + trade = mock_trade_usdt_4(fee, is_short) + Trade.query.session.add(trade) + Trade.commit() + l_order['filled'] = 0.0 l_order['status'] = 'open' - trade.nr_of_successful_entries = 0 reason = CANCEL_REASON['TIMEOUT'] assert freqtrade.handle_cancel_enter(trade, l_order, reason) assert cancel_order_mock.call_count == 1 @@ -3035,7 +3032,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_ @pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("limit_buy_order_canceled_empty", ['binance', 'ftx', 'kraken', 'bittrex'], indirect=['limit_buy_order_canceled_empty']) -def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_short, +def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_short, fee, limit_buy_order_canceled_empty) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3046,11 +3043,10 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho freqtrade = FreqtradeBot(default_conf_usdt) reason = CANCEL_REASON['TIMEOUT'] - # TODO: Convert to real trade - trade = MagicMock() - trade.nr_of_successful_entries = 0 - trade.pair = 'LTC/ETH' - trade.entry_side = "sell" if is_short else "buy" + + trade = mock_trade_usdt_4(fee, is_short) + Trade.query.session.add(trade) + Trade.commit() assert freqtrade.handle_cancel_enter(trade, limit_buy_order_canceled_empty, reason) assert cancel_order_mock.call_count == 0 assert log_has_re( From 9bb061073d541867892d7736cba57a7a46b1b96d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 2 Oct 2022 08:36:34 +0200 Subject: [PATCH 18/19] Improve tests --- freqtrade/exchange/exchange.py | 2 +- tests/test_freqtradebot.py | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index f01e464fa..61a6efb45 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1292,7 +1292,7 @@ class Exchange: order = self.fetch_order(order_id, pair) except InvalidOrderException: logger.warning(f"Could not fetch cancelled order {order_id}.") - order = {'fee': {}, 'status': 'canceled', 'amount': amount, 'info': {}} + order = {'id': order_id, 'fee': {}, 'status': 'canceled', 'amount': amount, 'info': {}} return order diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index ca9e63890..e19436a9f 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1061,6 +1061,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True + # TODO: should not be magicmock trade = MagicMock() trade.is_short = is_short trade.open_order_id = None @@ -1102,6 +1103,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ # First case: when stoploss is not yet set but the order is open # should get the stoploss order id immediately # and should return false as no trade actually happened + # TODO: should not be magicmock trade = MagicMock() trade.is_short = is_short trade.is_open = True @@ -1880,6 +1882,7 @@ def test_exit_positions(mocker, default_conf_usdt, limit_order, is_short, caplog return_value=limit_order[entry_side(is_short)]) mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) + # TODO: should not be magicmock trade = MagicMock() trade.is_short = is_short trade.open_order_id = '123' @@ -1903,6 +1906,7 @@ def test_exit_positions_exception(mocker, default_conf_usdt, limit_order, caplog order = limit_order[entry_side(is_short)] mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order) + # TODO: should not be magicmock trade = MagicMock() trade.is_short = is_short trade.open_order_id = None @@ -2043,6 +2047,7 @@ def test_update_trade_state_exception(mocker, default_conf_usdt, is_short, limit freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order) + # TODO: should not be magicmock trade = MagicMock() trade.open_order_id = '123' trade.amount = 123 @@ -2061,6 +2066,7 @@ def test_update_trade_state_orderexception(mocker, default_conf_usdt, caplog) -> mocker.patch('freqtrade.exchange.Exchange.fetch_order', MagicMock(side_effect=InvalidOrderException)) + # TODO: should not be magicmock trade = MagicMock() trade.open_order_id = '123' @@ -3064,7 +3070,7 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho 'String Return value', 123 ]) -def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order, is_short, +def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order, is_short, fee, cancelorder) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3072,20 +3078,15 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order cancel_order_mock = MagicMock(return_value=cancelorder) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - cancel_order=cancel_order_mock + cancel_order=cancel_order_mock, + fetch_order=MagicMock(side_effect=InvalidOrderException) ) freqtrade = FreqtradeBot(default_conf_usdt) freqtrade._notify_enter_cancel = MagicMock() - # TODO: Convert to real trade - trade = MagicMock() - trade.pair = 'LTC/USDT' - trade.entry_side = "buy" - trade.open_rate = 200 - trade.entry_side = "buy" - trade.open_order_id = "open_order_noop" - trade.nr_of_successful_entries = 0 - trade.amount = 100 + trade = mock_trade_usdt_4(fee, is_short) + Trade.query.session.add(trade) + Trade.commit() l_order['filled'] = 0.0 l_order['status'] = 'open' reason = CANCEL_REASON['TIMEOUT'] @@ -3200,6 +3201,7 @@ def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None: freqtrade = FreqtradeBot(default_conf_usdt) + # TODO: should not be magicmock trade = MagicMock() reason = CANCEL_REASON['TIMEOUT'] order = {'remaining': 1, From e686faf1bc8afa77327a9c1ae3774c8eb87716b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 2 Oct 2022 08:37:37 +0200 Subject: [PATCH 19/19] Remove faulty test cleanup --- tests/rpc/test_rpc_emc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rpc/test_rpc_emc.py b/tests/rpc/test_rpc_emc.py index b73a64f06..84a2658a0 100644 --- a/tests/rpc/test_rpc_emc.py +++ b/tests/rpc/test_rpc_emc.py @@ -212,10 +212,10 @@ async def test_emc_create_connection_invalid_port(default_conf, caplog, mocker): emc = ExternalMessageConsumer(default_conf, dp) try: + emc._running = True await emc._create_connection(emc.producers[0], asyncio.Lock()) assert log_has_re(r".+ is an invalid WebSocket URL .+", caplog) finally: - emc._running = False emc.shutdown()