From fc837c4daa27a18ff0e86128f4d52089b88fa5fb Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 3 May 2022 10:14:17 +0200 Subject: [PATCH 001/308] add freqao backend machinery, user interface, documentation --- .gitignore | 3 + config_examples/config_freqai.example.json | 100 ++++ docs/freqai.md | 265 +++++++++++ freqtrade/commands/__init__.py | 1 + freqtrade/commands/arguments.py | 5 +- freqtrade/commands/cli_options.py | 12 + freqtrade/commands/freqai_commands.py | 24 + freqtrade/configuration/configuration.py | 12 + freqtrade/constants.py | 1 + freqtrade/enums/runmode.py | 3 +- freqtrade/freqai/data_handler.py | 434 ++++++++++++++++++ freqtrade/freqai/freqai_interface.py | 158 +++++++ freqtrade/freqai/strategy_bridge.py | 12 + freqtrade/optimize/backtesting.py | 6 + freqtrade/resolvers/freqaimodel_resolver.py | 45 ++ freqtrade/templates/ExamplePredictionModel.py | 139 ++++++ freqtrade/templates/FreqaiExampleStrategy.py | 179 ++++++++ mkdocs.yml | 1 + requirements-freqai.txt | 8 + 19 files changed, 1405 insertions(+), 3 deletions(-) create mode 100644 config_examples/config_freqai.example.json create mode 100644 docs/freqai.md create mode 100644 freqtrade/commands/freqai_commands.py create mode 100644 freqtrade/freqai/data_handler.py create mode 100644 freqtrade/freqai/freqai_interface.py create mode 100644 freqtrade/freqai/strategy_bridge.py create mode 100644 freqtrade/resolvers/freqaimodel_resolver.py create mode 100644 freqtrade/templates/ExamplePredictionModel.py create mode 100644 freqtrade/templates/FreqaiExampleStrategy.py create mode 100644 requirements-freqai.txt diff --git a/.gitignore b/.gitignore index 97f77f779..17823f642 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ logfile.txt user_data/* !user_data/strategy/sample_strategy.py !user_data/notebooks +!user_data/models +user_data/models/* user_data/notebooks/* freqtrade-plot.html freqtrade-profit-plot.html @@ -105,3 +107,4 @@ target/ !config_examples/config_ftx.example.json !config_examples/config_full.example.json !config_examples/config_kraken.example.json +!config_examples/config_freqai.example.json diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json new file mode 100644 index 000000000..0092a8c51 --- /dev/null +++ b/config_examples/config_freqai.example.json @@ -0,0 +1,100 @@ +{ + "max_open_trades": 1, + "stake_currency": "USDT", + "stake_amount": 800, + "tradable_balance_ratio": 1, + "fiat_display_currency": "USD", + "dry_run": true, + "timeframe": "5m", + "dry_run_wallet":1000, + "cancel_open_orders_on_exit": true, + "unfilledtimeout": { + "entry": 10, + "exit": 30 + }, + "exchange": { + "name": "ftx", + "key": "", + "secret": "", + "ccxt_config": {"enableRateLimit": true}, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 200 + }, + "pair_whitelist": [ + "BTC/USDT" + ], + "pair_blacklist": [ + ] + }, + "entry_pricing": { + "price_side": "same", + "use_order_book": true, + "order_book_top": 1, + "price_last_balance": 0.0, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "exit_pricing": { + "price_side": "same", + "use_order_book": true, + "order_book_top": 1 + }, + "pairlists": [ + {"method": "StaticPairList"} + ], + + "freqai": { + "btc_pair" : "BTC/USDT", + "timeframes" : ["5m","15m","1h"], + "full_timerange" : "20210601-20220101", + "train_period" : 30, + "backtest_period" : 7, + "identifier" : "example", + "base_features": [ + "rsi", + "close_over_20sma", + "relative_volume", + "bb_width", + "mfi", + "roc", + "pct-change", + "adx", + "macd" + ], + "corr_pairlist": [ + "ETH/USDT", + "LINK/USDT", + "DOT/USDT" + ], + "training_timerange" : "20211220-20220117", + + "feature_parameters" : { + "period": 12, + "shift": 2, + "drop_features": false, + "DI_threshold": 1, + "weight_factor": 0, + "principal_component_analysis": false, + "remove_outliers": false + }, + "data_split_parameters" : { + "test_size": 0.25, + "random_state": 1 + }, + "model_training_parameters" : { + "n_estimators": 2000, + "random_state": 1, + "learning_rate": 0.02, + "task_type": "CPU" + } + }, + "bot_name": "", + "initial_state": "running", + "forcebuy_enable": false, + "internals": { + "process_throttle_secs": 5 + } +} diff --git a/docs/freqai.md b/docs/freqai.md new file mode 100644 index 000000000..6bc1e9365 --- /dev/null +++ b/docs/freqai.md @@ -0,0 +1,265 @@ +# Freqai + +!!! Note + Freqai is still experimental, and should be used at the user's own discretion. + +Freqai is a module designed to automate a variety of tasks associated with +training a regressor to predict signals based on input features. Among the +the features includes: + +* Easy large feature set construction based on simple user input +* Sweep model training and backtesting to simulate consistent model retraining through time +* Smart outlier removal of data points from prediction sets using a Dissimilarity Index. +* Data dimensionality reduction with Principal Component Analysis +* Automatic file management for storage of models to be reused during live +* Smart and safe data standardization +* Cleaning of NaNs from the data set before training and prediction. + +TODO: +* live is not automated, still some architectural work to be done + +## Background and vocabulary + +**Features** are the quantities with which a model is trained. $X_i$ represents the +vector of all features for a single candle. In Freqai, the user +builds the features from anything they can construct in the strategy. + +**Labels** are the target values with which the weights inside a model are trained +toward. Each set of features is associated with a single label, which is also +defined within the strategy by the user. These labels look forward into the +future, and are not available to the model during dryrun/live/backtesting. + +**Training** refers to the process of feeding individual feature sets into the +model with associated labels with the goal of matching input feature sets to +associated labels. + +**Train data** is a subset of the historic data which is fed to the model during +training to adjust weights. This data directly influences weight connections +in the model. + +**Test data** is a subset of the historic data which is used to evaluate the +intermediate performance of the model during training. This data does not +directly influence nodal weights within the model. + +## Configuring the bot +### Example config file +The user interface is isolated to the typical config file. A typical Freqai +config setup includes: + +```json + "freqai": { + "timeframes" : ["5m","15m","4h"], + "full_timerange" : "20211220-20220220", + "train_period" : "month", + "backtest_period" : "week", + "identifier" : "unique-id", + "base_features": [ + "rsi", + "mfi", + "roc", + ], + "corr_pairlist": [ + "ETH/USD", + "LINK/USD", + "BNB/USD" + ], + "train_params" : { + "period": 24, + "shift": 2, + "drop_features": false, + "DI_threshold": 1, + "weight_factor": 0, + }, + "SPLIT_PARAMS" : { + "test_size": 0.25, + "random_state": 42 + }, + "CLASSIFIER_PARAMS" : { + "n_estimators": 100, + "random_state": 42, + "learning_rate": 0.02, + "task_type": "CPU", + }, + }, + +``` + +### Building the feature set + +Most of these parameters are controlling the feature data set. The `base_features` +indicates the basic indicators the user wishes to include in the feature set. +The `timeframes` are the timeframes of each base_feature that the user wishes to +include in the feature set. In the present case, the user is asking for the +`5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, etc. to be included +in the feature set. + +In addition, the user can ask for each of these features to be included from +informative pairs using the `corr_pairlist`. This means that the present feature +set will include all the `base_features` on all the `timeframes` for each of +`ETH/USD`, `LINK/USD`, and `BNB/USD`. + +`shift` is another user controlled parameter which indicates the number of previous +candles to include in the present feature set. In other words, `shift: 2`, tells +Freqai to include the the past 2 candles for each of the features included +in the dataset. + +In total, the number of features the present user has created is:_ + +no. `timeframes` * no. `base_features` * no. `corr_pairlist` * no. `shift`_ +3 * 3 * 3 * 2 = 54._ + +### Deciding the sliding training window and backtesting duration + +`full_timerange` lets the user set the full backtesting range to train and +backtest through. Meanwhile `train_period` is the sliding training window and +`backtest_period` is the sliding backtesting window. In the present example, +the user is asking Freqai to train and backtest the range of `20211220-20220220` (`month`). +The user wishes to backtest each `week` with a newly trained model. This means that +Freqai will train 8 separate models (because the full range comprises 8 weeks), +and then backtest the subsequent week associated with each of the 8 training +data set timerange months. Users can think of this as a "sliding window" which +emulates Freqai retraining itself once per week in live using the previous +month of data. + + +## Running Freqai +### Training and backtesting + +The freqai training/backtesting module can be executed with the following command: + +```bash +freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel ExamplePredictionModel +``` + +where the user needs to have a FreqaiExampleStrategy that fits to the requirements outlined +below. The ExamplePredictionModel is a user built class which lets users design their +own training procedures and data analysis. + +### Building a freqai strategy + +The Freqai strategy requires the user to include the following lines of code in `populate_ any _indicators()` + +```python + from freqtrade.freqai.strategy_bridge import CustomModel + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # the configuration file parameters are stored here + self.freqai_info = self.config['freqai'] + + # the model is instantiated here + self.model = CustomModel(self.config) + + print('Populating indicators...') + + # the following loops are necessary for building the features + # indicated by the user in the configuration file. + for tf in self.freqai_info['timeframes']: + dataframe = self.populate_any_indicators(metadata['pair'], + dataframe.copy(), tf) + for i in self.freqai_info['corr_pairlist']: + dataframe = self.populate_any_indicators(i, + dataframe.copy(), tf, coin=i.split("/")[0]+'-') + + # the model will return 4 values, its prediction, an indication of whether or not the prediction + # should be accepted, the target mean/std values from the labels used during each training period. + (dataframe['prediction'], dataframe['do_predict'], + dataframe['target_mean'], dataframe['target_std']) = self.model.bridge.start(dataframe, metadata) + + return dataframe +``` +The user should also include `populate_any_indicators()` from `templates/FreqaiExampleStrategy.py` which builds +the feature set with a proper naming convention for the IFreqaiModel to use later. + +### Building an IFreqaiModel + +Freqai has a base example model in `templates/ExamplePredictionModel.py`, but users can customize and create +their own prediction models using the `IFreqaiModel` class. Users are encouraged to inherit `train()`, `predict()`, +and `make_labels()` to let them customize various aspects of their training procedures. + +### Running the model live + +After the user has designed a desirable featureset, Freqai can be run in dry/live +using the typical trade command: + +```bash +freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --training_timerange '20211220-20220120' +``` + +Where the user has now specified exactly which of the models from the sliding window +that they wish to run live using `--training_timerange` (typically this would be the most +recent model trained). As of right now, freqai will +not automatically retain itself, so the user needs to manually retrain and then +reload the config file with a new `--training_timerange` in order to update the +model. + + +## Data anylsis techniques +### Controlling the model learning process + +The user can define model settings for the data split `data_split_parameters` and learning parameters +`model_training_parameters`. Users are encouraged to visit the Catboost documentation +for more information on how to select these values. `n_estimators` increases the +computational effort and the fit to the training data. If a user has a GPU +installed in their system, they may benefit from changing `task_type` to `GPU`. +The `weight_factor` allows the user to weight more recent data more strongly +than past data via an exponential function: + +$$ W_i = \exp(\frac{-i}{\alpha*n}) $$ + +where $W_i$ is the weight of data point $i$ in a total set of $n$ data points._ + +`drop_features` tells Freqai to train the model on the user defined features, +followed by a feature importance evaluation where it drops the top and bottom +performing features (there is evidence to suggest the top features may not be +helpful in equity/crypto trading since the ultimate objective is to predict low +frequency patterns, source: numerai)._ + +Finally, `period` defines the offset used for the `labels`. In the present example, +the user is asking for `labels` that are 24 candles in the future. + +### Removing outliers with the Dissimilarity Index + +The Dissimilarity Index (DI) aims to quantiy the uncertainty associated with each +prediction by the model. To do so, Freqai measures the distance between each training +data point and all other training data points: + +$$ d_{ab} = \sqrt{\sum_{j=1}^p(X_{a,j}-X_{b,j})^2} $$ + +where $d_{ab}$ is the distance between the standardized points $a$ and $b$. $p$ +is the number of features i.e. the length of the vector $X$. The +characteristic distance, $\overline{d}$ for a set of training data points is simply the mean +of the average distances: + +$$ \overline{d} = \sum_{a=1}^n(\sum_{b=1}^n(d_{ab}/n)/n) $$ + +$\overline{d}$ quantifies the spread of the training data, which is compared to +the distance between the new prediction feature vectors, $X_k$ and all the training +data: + +$$ d_k = \argmin_i d_{k,i} $$ + +which enables the estimation of a Dissimilarity Index: + +$$ DI_k = d_k/\overline{d} $$ + +Equity and crypto markets suffer from a high level of non-patterned noise in the +form of outlier data points. The dissimilarity index allows predictions which +are outliers and not existent in the model feature space, to be thrown out due +to low levels of certainty. The user can tweak the DI with `DI_threshold` to increase +or decrease the extrapolation of the trained model. + +### Reducing data dimensionality with Principal Component Analysis + +TO BE WRITTEN + +## Additional information +### Feature standardization + +The feature set created by the user is automatically standardized to the training +data only. This includes all test data and unseen prediction data (dry/live/backtest). + +### File structure + +`user_data_dir/models/` contains all the data associated with the trainings and +backtestings. This file structure is heavily controlled and read by the `DataHandler()` +and should thus not be modified. diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 0e637c487..d5aea62be 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -19,6 +19,7 @@ from freqtrade.commands.list_commands import (start_list_exchanges, start_list_m start_show_trades) from freqtrade.commands.optimize_commands import (start_backtesting, start_backtesting_show, start_edge, start_hyperopt) +from freqtrade.commands.freqai_commands import (start_training) from freqtrade.commands.pairlist_commands import start_test_pairlist from freqtrade.commands.plot_commands import start_plot_dataframe, start_plot_profit from freqtrade.commands.trade_commands import start_trading diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 815e28175..4388e84e4 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -12,7 +12,7 @@ from freqtrade.constants import DEFAULT_CONFIG ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_data_dir"] -ARGS_STRATEGY = ["strategy", "strategy_path", "recursive_strategy_search"] +ARGS_STRATEGY = ["strategy", "strategy_path", "recursive_strategy_search", "freqaimodel", "freqaimodel_path"] ARGS_TRADE = ["db_url", "sd_notify", "dry_run", "dry_run_wallet", "fee"] @@ -190,7 +190,8 @@ class Arguments: start_list_markets, start_list_strategies, start_list_timeframes, start_new_config, start_new_strategy, start_plot_dataframe, start_plot_profit, start_show_trades, - start_test_pairlist, start_trading, start_webserver) + start_test_pairlist, start_trading, start_webserver, + start_training) subparsers = self.parser.add_subparsers(dest='command', # Use custom message when no subhandler is added diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index aac9f5713..4061418f7 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -614,4 +614,16 @@ AVAILABLE_CLI_OPTIONS = { "that do not contain any parameters."), action="store_true", ), + + "freqaimodel": Arg( + '--freqaimodel', + help='Specify a custom freqaimodels.', + metavar='NAME', + ), + + "freqaimodel_path": Arg( + '--freqaimodel-path', + help='Specify additional lookup path for freqaimodels.', + metavar='PATH', + ), } diff --git a/freqtrade/commands/freqai_commands.py b/freqtrade/commands/freqai_commands.py new file mode 100644 index 000000000..2733c851a --- /dev/null +++ b/freqtrade/commands/freqai_commands.py @@ -0,0 +1,24 @@ +import logging +from typing import Any, Dict + +from freqtrade import constants +from freqtrade.configuration import setup_utils_configuration +from freqtrade.enums import RunMode +from freqtrade.exceptions import OperationalException +from freqtrade.misc import round_coin_value + + +logger = logging.getLogger(__name__) + +def start_training(args: Dict[str, Any]) -> None: + """ + Train a model for predicting signals + :param args: Cli args from Arguments() + :return: None + """ + from freqtrade.freqai.training import Training + + config = setup_utils_configuration(args, RunMode.FREQAI) + + training = Training(config) + training.start() diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 96b585cd1..e13985270 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -95,6 +95,8 @@ class Configuration: self._process_data_options(config) + self._process_freqai_options(config) + # Check if the exchange set by the user is supported check_exchange(config, config.get('experimental', {}).get('block_bad_exchanges', True)) @@ -446,6 +448,16 @@ class Configuration: config.update({'runmode': self.runmode}) + def _process_freqai_options(self, config: Dict[str, Any]) -> None: + + self._args_to_config(config, argname='freqaimodel', + logstring='Using freqaimodel class name: {}') + + self._args_to_config(config, argname='freqaimodel_path', + logstring='Using freqaimodel path: {}') + + return + def _args_to_config(self, config: Dict[str, Any], argname: str, logstring: str, logfun: Optional[Callable] = None, deprecated_msg: Optional[str] = None) -> None: diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 372472db8..f8a9dc06d 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -55,6 +55,7 @@ FTHYPT_FILEVERSION = 'fthypt_fileversion' USERPATH_HYPEROPTS = 'hyperopts' USERPATH_STRATEGIES = 'strategies' USERPATH_NOTEBOOKS = 'notebooks' +USERPATH_FREQAIMODELS = 'freqaimodels' TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent'] WEBHOOK_FORMAT_OPTIONS = ['form', 'json', 'raw'] diff --git a/freqtrade/enums/runmode.py b/freqtrade/enums/runmode.py index 6545aaec7..c280edf7c 100644 --- a/freqtrade/enums/runmode.py +++ b/freqtrade/enums/runmode.py @@ -15,9 +15,10 @@ class RunMode(Enum): UTIL_NO_EXCHANGE = "util_no_exchange" PLOT = "plot" WEBSERVER = "webserver" + FREQAI = "freqai" OTHER = "other" TRADING_MODES = [RunMode.LIVE, RunMode.DRY_RUN] -OPTIMIZE_MODES = [RunMode.BACKTEST, RunMode.EDGE, RunMode.HYPEROPT] +OPTIMIZE_MODES = [RunMode.BACKTEST, RunMode.EDGE, RunMode.HYPEROPT, RunMode.FREQAI] NON_UTIL_MODES = TRADING_MODES + OPTIMIZE_MODES diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_handler.py new file mode 100644 index 000000000..d399cd12b --- /dev/null +++ b/freqtrade/freqai/data_handler.py @@ -0,0 +1,434 @@ +import json +import os +import copy +import numpy as np +import pandas as pd +from pandas import DataFrame +from joblib import dump +from joblib import load +from sklearn.model_selection import train_test_split +from sklearn.metrics.pairwise import pairwise_distances +import datetime +from typing import Any, Dict, List, Tuple +import pickle as pk +from freqtrade.configuration import TimeRange + +SECONDS_IN_DAY = 86400 + +class DataHandler: + """ + Class designed to handle all the data for the IFreqaiModel class model. + Functionalities include holding, saving, loading, and analyzing the data. + """ + + def __init__(self, config: Dict[str, Any], dataframe: DataFrame, data: List): + self.full_dataframe = dataframe + (self.training_timeranges, + self.backtesting_timeranges) = self.split_timerange( + config['freqai']['full_timerange'], + config['freqai']['train_period'], + config['freqai']['backtest_period']) + self.data = data + self.data_dictionary = {} + self.config = config + self.freq_config = config['freqai'] + + def save_data(self, model: Any) -> None: + """ + Saves all data associated with a model for a single sub-train time range + :params: + :model: User trained model which can be reused for inferencing to generate + predictions + """ + + if not os.path.exists(self.model_path): os.mkdir(self.model_path) + save_path = self.model_path + self.model_filename + # Save the trained model + dump(model, save_path+"_model.joblib") + self.data['model_path'] = self.model_path + self.data['model_filename'] = self.model_filename + self.data['training_features_list'] = list(self.data_dictionary['train_features'].columns) + # store the metadata + with open(save_path+"_metadata.json", 'w') as fp: + json.dump(self.data, fp, default=self.np_encoder) + + # save the train data to file so we can check preds for area of applicability later + self.data_dictionary['train_features'].to_pickle(save_path+"_trained_df.pkl") + + return + + def load_data(self) -> Any: + """ + loads all data required to make a prediction on a sub-train time range + :returns: + :model: User trained model which can be inferenced for new predictions + """ + model = load(self.model_path+self.model_filename+"_model.joblib") + + with open(self.model_path+self.model_filename+"_metadata.json", 'r') as fp: + self.data = json.load(fp) + if self.data.get('training_features_list'): + self.training_features_list = [*self.data.get('training_features_list')] + + self.data_dictionary['train_features'] = pd.read_pickle(self.model_path+ + self.model_filename+"_trained_df.pkl") + + self.model_path = self.data['model_path'] + self.model_filename = self.data['model_filename'] + if self.config['freqai']['feature_parameters']['principal_component_analysis']: + self.pca = pk.load(open(self.model_path+self.model_filename+"_pca_object.pkl","rb")) + + return model + + def make_train_test_datasets(self, filtered_dataframe: DataFrame, labels: DataFrame) -> None: + ''' + Given the dataframe for the full history for training, split the data into + training and test data according to user specified parameters in configuration + file. + :filtered_dataframe: cleaned dataframe ready to be split. + :labels: cleaned labels ready to be split. + ''' + + if self.config['freqai']['feature_parameters']['weight_factor'] > 0: + weights = self.set_weights_higher_recent(len(filtered_dataframe)) + else: weights = np.ones(len(filtered_dataframe)) + + (train_features, test_features, train_labels, + test_labels, train_weights, test_weights) = train_test_split( + filtered_dataframe[:filtered_dataframe.shape[0]], + labels, + weights, + **self.config['freqai']['data_split_parameters'] + ) + + return self.build_data_dictionary( + train_features,test_features, + train_labels,test_labels, + train_weights,test_weights) + + + + def filter_features(self, unfiltered_dataframe: DataFrame, training_feature_list: List, + labels: DataFrame = None, training_filter: bool=True) -> Tuple[DataFrame, DataFrame]: + ''' + Filter the unfiltered dataframe to extract the user requested features and properly + remove all NaNs. Any row with a NaN is removed from training dataset or replaced with + 0s in the prediction dataset. However, prediction dataset do_predict will reflect any + row that had a NaN and will shield user from that prediction. + :params: + :unfiltered_dataframe: the full dataframe for the present training period + :training_feature_list: list, the training feature list constructed by self.build_feature_list() + according to user specified parameters in the configuration file. + :labels: the labels for the dataset + :training_filter: boolean which lets the function know if it is training data or + prediction data to be filtered. + :returns: + :filtered_dataframe: dataframe cleaned of NaNs and only containing the user + requested feature set. + :labels: labels cleaned of NaNs. + ''' + filtered_dataframe = unfiltered_dataframe.filter(training_feature_list, axis=1) + drop_index = pd.isnull(filtered_dataframe).any(1) # get the rows that have NaNs, + + if training_filter: # we don't care about total row number (total no. datapoints) in training, we only care about removing any row with NaNs + drop_index_labels = pd.isnull(labels) + filtered_dataframe = filtered_dataframe[(drop_index==False) & (drop_index_labels==False)] # dropping values + labels = labels[(drop_index==False) & (drop_index_labels==False)] # assuming the labels depend entirely on the dataframe here. + print('dropped',len(unfiltered_dataframe)-len(filtered_dataframe), + 'training data points due to NaNs, ensure you have downloaded all historical training data') + self.data['filter_drop_index_training'] = drop_index + + else: # we are backtesting so we need to preserve row number to send back to strategy, so now we use do_predict to avoid any prediction based on a NaN + drop_index = pd.isnull(filtered_dataframe).any(1) + self.data['filter_drop_index_prediction'] = drop_index + filtered_dataframe.fillna(0, inplace=True) # replacing all NaNs with zeros to avoid issues in 'prediction', but any prediction that was based on a single NaN is ultimately protected from buys with do_predict + drop_index = ~drop_index + self.do_predict = np.array(drop_index.replace(True,1).replace(False,0)) + print('dropped',len(self.do_predict) - self.do_predict.sum(),'of',len(filtered_dataframe), + 'prediction data points due to NaNs. These are protected from prediction with do_predict vector returned to strategy.') + + + return filtered_dataframe, labels + + def build_data_dictionary(self, train_df: DataFrame, test_df: DataFrame, + train_labels: DataFrame, test_labels: DataFrame, + train_weights: Any, test_weights: Any) -> Dict: + + self.data_dictionary = {'train_features': train_df, + 'test_features': test_df, + 'train_labels': train_labels, + 'test_labels': test_labels, + 'train_weights': train_weights, + 'test_weights': test_weights} + + return self.data_dictionary + + def standardize_data(self, data_dictionary: Dict) -> None: + ''' + Standardize all data in the data_dictionary according to the training dataset + :params: + :data_dictionary: dictionary containing the cleaned and split training/test data/labels + :returns: + :data_dictionary: updated dictionary with standardized values. + ''' + # standardize the data by training stats + train_mean = data_dictionary['train_features'].mean() + train_std = data_dictionary['train_features'].std() + data_dictionary['train_features'] = (data_dictionary['train_features'] - train_mean) / train_std + data_dictionary['test_features'] = (data_dictionary['test_features'] - train_mean) / train_std + + train_labels_std = data_dictionary['train_labels'].std() + train_labels_mean = data_dictionary['train_labels'].mean() + data_dictionary['train_labels'] = (data_dictionary['train_labels'] - train_labels_mean) / train_labels_std + data_dictionary['test_labels'] = (data_dictionary['test_labels'] - train_labels_mean) / train_labels_std + + for item in train_std.keys(): + self.data[item+'_std'] = train_std[item] + self.data[item+'_mean'] = train_mean[item] + + self.data['labels_std'] = train_labels_std + self.data['labels_mean'] = train_labels_mean + + return data_dictionary + + def standardize_data_from_metadata(self, df: DataFrame) -> DataFrame: + ''' + Standardizes a set of data using the mean and standard deviation from + the associated training data. + :params: + :df: Dataframe to be standardized + ''' + + for item in df.keys(): + df[item] = (df[item] - self.data[item+'_mean']) / self.data[item+'_std'] + + return df + + def split_timerange(self, tr: Dict, train_split: int=28, bt_split: int=7) -> list: + ''' + Function which takes a single time range (tr) and splits it + into sub timeranges to train and backtest on based on user input + tr: str, full timerange to train on + train_split: the period length for the each training (days). Specified in user + configuration file + bt_split: the backtesting length (dats). Specified in user configuration file + ''' + + train_period = train_split * SECONDS_IN_DAY + bt_period = bt_split * SECONDS_IN_DAY + + full_timerange = TimeRange.parse_timerange(tr) + timerange_train = copy.deepcopy(full_timerange) + timerange_backtest = copy.deepcopy(full_timerange) + + tr_training_list = [] + tr_backtesting_list = [] + first = True + while True: + if not first: timerange_train.startts = timerange_train.startts + bt_period + timerange_train.stopts = timerange_train.startts + train_period + + # if a full training period doesnt fit, we stop + if timerange_train.stopts > full_timerange.stopts: break + first = False + start = datetime.datetime.utcfromtimestamp(timerange_train.startts) + stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) + tr_training_list.append(start.strftime("%Y%m%d")+'-'+stop.strftime("%Y%m%d")) + + ## associated backtest period + timerange_backtest.startts = timerange_train.stopts + timerange_backtest.stopts = timerange_backtest.startts + bt_period + start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) + stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) + tr_backtesting_list.append(start.strftime("%Y%m%d")+'-'+stop.strftime("%Y%m%d")) + + return tr_training_list, tr_backtesting_list + + def slice_dataframe(self, tr: str, df: DataFrame) -> DataFrame: + """ + Given a full dataframe, extract the user desired window + :params: + :tr: timerange string that we wish to extract from df + :df: Dataframe containing all candles to run the entire backtest. Here + it is sliced down to just the present training period. + """ + timerange = TimeRange.parse_timerange(tr) + start = datetime.datetime.fromtimestamp(timerange.startts, tz=datetime.timezone.utc) + stop = datetime.datetime.fromtimestamp(timerange.stopts, tz=datetime.timezone.utc) + df = df.loc[df['date'] >= start, :] + df = df.loc[df['date'] <= stop, :] + + return df + + def principal_component_analysis(self) -> None: + """ + Performs Principal Component Analysis on the data for dimensionality reduction + and outlier detection (see self.remove_outliers()) + No parameters or returns, it acts on the data_dictionary held by the DataHandler. + """ + + from sklearn.decomposition import PCA # avoid importing if we dont need it + + n_components = self.data_dictionary['train_features'].shape[1] + pca = PCA(n_components=n_components) + pca = pca.fit(self.data_dictionary['train_features']) + n_keep_components = np.argmin(pca.explained_variance_ratio_.cumsum() < 0.999) + pca2 = PCA(n_components=n_keep_components) + self.data['n_kept_components'] = n_keep_components + pca2 = pca2.fit(self.data_dictionary['train_features']) + print('reduced feature dimension by',n_components-n_keep_components) + print("explained variance",np.sum(pca2.explained_variance_ratio_)) + train_components = pca2.transform(self.data_dictionary['train_features']) + test_components = pca2.transform(self.data_dictionary['test_features']) + + self.data_dictionary['train_features'] = pd.DataFrame(data=train_components, + columns = ['PC'+str(i) for i in range(0,n_keep_components)], + index = self.data_dictionary['train_features'].index) + + self.data_dictionary['test_features'] = pd.DataFrame(data=test_components, + columns = ['PC'+str(i) for i in range(0,n_keep_components)], + index = self.data_dictionary['test_features'].index) + + self.data['n_kept_components'] = n_keep_components + self.pca = pca2 + if not os.path.exists(self.model_path): os.mkdir(self.model_path) + pk.dump(pca2, open(self.model_path + self.model_filename+"_pca_object.pkl","wb")) + + return None + + def compute_distances(self) -> float: + print('computing average mean distance for all training points') + pairwise = pairwise_distances(self.data_dictionary['train_features'],n_jobs=-1) + avg_mean_dist = pairwise.mean(axis=1).mean() + print('avg_mean_dist',avg_mean_dist) + + return avg_mean_dist + + def remove_outliers(self,predict: bool) -> None: + """ + Remove data that looks like an outlier based on the distribution of each + variable. + :params: + :predict: boolean which tells the function if this is prediction data or + training data coming in. + """ + + lower_quantile = self.data_dictionary['train_features'].quantile(0.001) + upper_quantile = self.data_dictionary['train_features'].quantile(0.999) + + if predict: + + df = self.data_dictionary['prediction_features'][(self.data_dictionary['prediction_features']lower_quantile)] + drop_index = pd.isnull(df).any(1) + self.data_dictionary['prediction_features'].fillna(0,inplace=True) + drop_index = ~drop_index + do_predict = np.array(drop_index.replace(True,1).replace(False,0)) + + print('remove_outliers() tossed',len(do_predict)-do_predict.sum(),'predictions because they were beyond 3 std deviations from training data.') + self.do_predict += do_predict + self.do_predict -= 1 + + else: + + filter_train_df = self.data_dictionary['train_features'][(self.data_dictionary['train_features']lower_quantile)] + drop_index = pd.isnull(filter_train_df).any(1) + self.data_dictionary['train_features'] = self.data_dictionary['train_features'][(drop_index==False)] + self.data_dictionary['train_labels'] = self.data_dictionary['train_labels'][(drop_index==False)] + self.data_dictionary['train_weights'] = self.data_dictionary['train_weights'][(drop_index==False)] + + # do the same for the test data + filter_test_df = self.data_dictionary['test_features'][(self.data_dictionary['test_features']lower_quantile)] + drop_index = pd.isnull(filter_test_df).any(1) + #pdb.set_trace() + self.data_dictionary['test_labels'] = self.data_dictionary['test_labels'][(drop_index==False)] + self.data_dictionary['test_features'] = self.data_dictionary['test_features'][(drop_index==False)] + self.data_dictionary['test_weights'] = self.data_dictionary['test_weights'][(drop_index==False)] + + return + + def build_feature_list(self, config: dict) -> int: + """ + Build the list of features that will be used to filter + the full dataframe. Feature list is construced from the + user configuration file. + :params: + :config: Canonical freqtrade config file containing all + user defined input in config['freqai] dictionary. + """ + features = [] + for tf in config['freqai']['timeframes']: + for ft in config['freqai']['base_features']: + for n in range(config['freqai']['feature_parameters']['shift']+1): + shift='' + if n>0: shift = '_shift-'+str(n) + features.append(ft+shift+'_'+tf) + for p in config['freqai']['corr_pairlist']: + features.append(p.split("/")[0]+'-'+ft+shift+'_'+tf) + + print('number of features',len(features)) + return features + + def check_if_pred_in_training_spaces(self) -> None: + """ + Compares the distance from each prediction point to each training data + point. It uses this information to estimate a Dissimilarity Index (DI) + and avoid making predictions on any points that are too far away + from the training data set. + """ + + print('checking if prediction features are in AOA') + distance = pairwise_distances(self.data_dictionary['train_features'], + self.data_dictionary['prediction_features'],n_jobs=-1) + + do_predict = np.where(distance.min(axis=0) / + self.data['avg_mean_dist'] < self.config['freqai']['feature_parameters']['DI_threshold'],1,0) + + print('Distance checker tossed',len(do_predict)-do_predict.sum(), + 'predictions for being too far from training data') + + self.do_predict += do_predict + self.do_predict -= 1 + + def set_weights_higher_recent(self, num_weights: int) -> int: + """ + Set weights so that recent data is more heavily weighted during + training than older data. + """ + weights = np.zeros(num_weights) + for i in range(1, len(weights)): + weights[len(weights) - i] = np.exp(-i/ + (self.config['freqai']['feature_parameters']['weight_factor']*num_weights)) + return weights + + def append_predictions(self, predictions, do_predict, len_dataframe): + """ + Append backtest prediction from current backtest period to all previous periods + """ + + ones = np.ones(len_dataframe) + s_mean, s_std = ones*self.data['s_mean'], ones*self.data['s_std'] + + self.predictions = np.append(self.predictions,predictions) + self.do_predict = np.append(self.do_predict,do_predict) + self.target_mean = np.append(self.target_mean,s_mean) + self.target_std = np.append(self.target_std,s_std) + + return + + def fill_predictions(self, len_dataframe): + """ + Back fill values to before the backtesting range so that the dataframe matches size + when it goes back to the strategy. These rows are not included in the backtest. + """ + + filler = np.zeros(len_dataframe -len(self.predictions)) # startup_candle_count + self.predictions = np.append(filler,self.predictions) + self.do_predict = np.append(filler,self.do_predict) + self.target_mean = np.append(filler,self.target_mean) + self.target_std = np.append(filler,self.target_std) + + return + + def np_encoder(self, object): + if isinstance(object, np.generic): + return object.item() diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py new file mode 100644 index 000000000..eb15e7e49 --- /dev/null +++ b/freqtrade/freqai/freqai_interface.py @@ -0,0 +1,158 @@ + +import os +import numpy as np +import pandas as pd +from pandas import DataFrame +import shutil +import gc +from typing import Any, Dict, Optional, Tuple +from abc import ABC +from freqtrade.freqai.data_handler import DataHandler + +pd.options.mode.chained_assignment = None + +class IFreqaiModel(ABC): + """ + Class containing all tools for training and prediction in the strategy. + User models should inherit from this class as shown in + templates/ExamplePredictionModel.py where the user overrides + train(), predict(), fit(), and make_labels(). + """ + + def __init__(self, config: Dict[str, Any]) -> None: + + self.config = config + self.freqai_info = config['freqai'] + self.data_split_parameters = config['freqai']['data_split_parameters'] + self.model_training_parameters = config['freqai']['model_training_parameters'] + self.feature_parameters = config['freqai']['feature_parameters'] + self.full_path = (str(config['user_data_dir'])+ + "/models/"+self.freqai_info['full_timerange']+ + '-'+self.freqai_info['identifier']) + self.metadata = {} + self.data = {} + self.time_last_trained = None + self.current_time = None + self.model = None + self.predictions = None + + if not os.path.exists(self.full_path): + os.mkdir(self.full_path) + shutil.copy(self.config['config_files'][0],self.full_path+"/"+self.config['config_files'][0]) + + def start(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Entry point to the FreqaiModel, it will train a new model if + necesssary before making the prediction. + The backtesting and training paradigm is a sliding training window + with a following backtest window. Both windows slide according to the + length of the backtest window. This function is not intended to be + overridden by children of IFreqaiModel, but technically, it can be + if the user wishes to make deeper changes to the sliding window + logic. + :params: + :dataframe: Full dataframe coming from strategy - it contains entire + backtesting timerange + additional historical data necessary to train + the model. + :metadata: pair metadataa coming from strategy. + """ + self.pair = metadata['pair'] + self.dh = DataHandler(self.config, dataframe, self.data) + + print('going to train',len(self.dh.training_timeranges), + 'timeranges:',self.dh.training_timeranges) + predictions = np.array([]) + do_predict = np.array([]) + target_mean = np.array([]) + target_std = np.array([]) + + # Loop enforcing the sliding window training/backtesting paragigm + # tr_train is the training time range e.g. 1 historical month + # tr_backtest is the backtesting time range e.g. the week directly + # following tr_train. Both of these windows slide through the + # entire backtest + for tr_train, tr_backtest in zip(self.dh.training_timeranges, + self.dh.backtesting_timeranges): + gc.collect() + #self.config['timerange'] = tr_train + self.dh.data = {} # clean the pair specific data between models + self.freqai_info['training_timerange'] = tr_train + dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) + dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) + print("training",self.pair,"for",tr_train) + self.dh.model_path = self.full_path+"/"+ 'sub-train'+'-'+str(tr_train)+'/' + if not self.model_exists(self.pair, training_timerange=tr_train): + self.model = self.train(dataframe_train, metadata) + self.dh.save_data(self.model) + else: + self.model = self.dh.load_data(self.dh.model_path) + + preds, do_preds = self.predict(dataframe_backtest) + + self.dh.append_predictions(preds,do_preds,len(dataframe_backtest)) + + self.dh.fill_predictions(len(dataframe)) + + return self.dh.predictions, self.dh.do_predict, self.dh.target_mean, self.dh.target_std + + def make_labels(self, dataframe: DataFrame) -> DataFrame: + """ + User defines the labels here (target values). + :params: + :dataframe: the full dataframe for the present training period + """ + + return dataframe + + def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: + """ + Filter the training data and train a model to it. Train makes heavy use of the datahandler + for storing, saving, loading, and managed. + :params: + :unfiltered_dataframe: Full dataframe for the current training period + :metadata: pair metadata from strategy. + :returns: + :model: Trained model which can be used to inference (self.predict) + """ + + return unfiltered_dataframe, unfiltered_dataframe + + def fit(self) -> Any: + """ + Most regressors use the same function names and arguments e.g. user + can drop in LGBMRegressor in place of CatBoostRegressor and all data + management will be properly handled by Freqai. + :params: + :data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. + """ + + return None + + def predict(self) -> Optional[Tuple[DataFrame, DataFrame]]: + """ + Filter the prediction features data and predict with it. + :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :return: + :predictions: np.array of predictions + :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove + data (NaNs) or felt uncertain about data (PCA and DI index) + """ + + return None + + def model_exists(self, pair: str, training_timerange: str = None) -> bool: + """ + Given a pair and path, check if a model already exists + :param pair: pair e.g. BTC/USD + :param path: path to model + """ + coin,_ = pair.split('/') + self.dh.model_filename = f"cb_"+coin.lower()+"_"+self.freqai_info['trained_stake']+"_"+training_timerange + file_exists = os.path.isfile(self.dh.model_path+ + self.dh.model_filename+"_model.joblib") + if file_exists: + print("Found model at", self.dh.model_path+self.dh.model_filename) + else: print("Could not find model at", + self.dh.model_path+self.dh.model_filename) + return file_exists diff --git a/freqtrade/freqai/strategy_bridge.py b/freqtrade/freqai/strategy_bridge.py new file mode 100644 index 000000000..c336e3c84 --- /dev/null +++ b/freqtrade/freqai/strategy_bridge.py @@ -0,0 +1,12 @@ +from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver + + +class CustomModel: + """ + A bridge between the user defined IFreqaiModel class + and the strategy. + """ + + def __init__(self,config): + + self.bridge = FreqaiModelResolver.load_freqaimodel(config) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 621812b0a..5051a8db0 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -204,6 +204,12 @@ class Backtesting: """ self.progress.init_step(BacktestState.DATALOAD, 1) + if self.config['freqaimodel']: + self.required_startup += int((self.config['freqai']['train_period']*86400) / + timeframe_to_seconds(self.config['timeframe'])) + self.config['startup_candle_count'] = self.required_startup + + data = history.load_data( datadir=self.config['datadir'], pairs=self.pairlists.whitelist, diff --git a/freqtrade/resolvers/freqaimodel_resolver.py b/freqtrade/resolvers/freqaimodel_resolver.py new file mode 100644 index 000000000..9545afd24 --- /dev/null +++ b/freqtrade/resolvers/freqaimodel_resolver.py @@ -0,0 +1,45 @@ +# pragma pylint: disable=attribute-defined-outside-init + +""" +This module load a custom model for freqai +""" +import logging +from pathlib import Path +from typing import Dict + +from freqtrade.constants import USERPATH_FREQAIMODELS +from freqtrade.exceptions import OperationalException +from freqtrade.freqai.freqai_interface import IFreqaiModel +from freqtrade.resolvers import IResolver + +logger = logging.getLogger(__name__) + + +class FreqaiModelResolver(IResolver): + """ + This class contains all the logic to load custom hyperopt loss class + """ + object_type = IFreqaiModel + object_type_str = "FreqaiModel" + user_subdir = USERPATH_FREQAIMODELS + initial_search_path = Path(__file__).parent.parent.joinpath('optimize').resolve() + + @staticmethod + def load_freqaimodel(config: Dict) -> IFreqaiModel: + """ + Load the custom class from config parameter + :param config: configuration dictionary + """ + + freqaimodel_name = config.get('freqaimodel') + if not freqaimodel_name: + raise OperationalException( + "No freqaimodel set. Please use `--freqaimodel` to " + "specify the FreqaiModel class to use.\n" + ) + freqaimodel = FreqaiModelResolver.load_object(freqaimodel_name, + config, kwargs={'config': config}, + extra_dir=config.get('freqaimodel_path')) + + + return freqaimodel diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py new file mode 100644 index 000000000..a5370b5ac --- /dev/null +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -0,0 +1,139 @@ +import numpy as np +import pandas as pd +from catboost import CatBoostRegressor, Pool +from pandas import DataFrame +from typing import Any, Dict, Tuple +from freqtrade.freqai.freqai_interface import IFreqaiModel + +class ExamplePredictionModel(IFreqaiModel): + """ + User created prediction model. The class needs to override three necessary + functions, predict(), train(), fit(). The class inherits ModelHandler which + has its own DataHandler where data is held, saved, loaded, and managed. + """ + + def make_labels(self, dataframe: DataFrame) -> DataFrame: + """ + User defines the labels here (target values). + :params: + :dataframe: the full dataframe for the present training period + """ + + dataframe['s'] = (dataframe['close'].shift(-self.feature_parameters['period']).rolling( + self.feature_parameters['period']).max() / dataframe['close'] - 1) + self.dh.data['s_mean'] = dataframe['s'].mean() + self.dh.data['s_std'] = dataframe['s'].std() + + print('label mean',self.dh.data['s_mean'],'label std',self.dh.data['s_std']) + + return dataframe['s'] + + + def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: + """ + Filter the training data and train a model to it. Train makes heavy use of the datahandler + for storing, saving, loading, and managed. + :params: + :unfiltered_dataframe: Full dataframe for the current training period + :metadata: pair metadata from strategy. + :returns: + :model: Trained model which can be used to inference (self.predict) + """ + print("--------------------Starting training--------------------") + + # create the full feature list based on user config info + self.dh.training_features_list = self.dh.build_feature_list(self.config) + unfiltered_labels = self.make_labels(unfiltered_dataframe) + + # filter the features requested by user in the configuration file and elegantly handle NaNs + features_filtered, labels_filtered = self.dh.filter_features(unfiltered_dataframe, + self.dh.training_features_list, unfiltered_labels, training_filter=True) + + # split data into train/test data. + data_dictionary = self.dh.make_train_test_datasets(features_filtered, labels_filtered) + # standardize all data based on train_dataset only + data_dictionary = self.dh.standardize_data(data_dictionary) + + # optional additional data cleaning + if self.feature_parameters['principal_component_analysis']: + self.dh.principal_component_analysis() + if self.feature_parameters["remove_outliers"]: + self.dh.remove_outliers(predict=False) + if self.feature_parameters['DI_threshold']: + self.dh.data['avg_mean_dist'] = self.dh.compute_distances() + + print("length of train data", len(data_dictionary['train_features'])) + + model = self.fit(data_dictionary) + + print('Finished training') + print(f'--------------------done training {metadata["pair"]}--------------------') + + return model + + def fit(self, data_dictionary: Dict) -> Any: + """ + Most regressors use the same function names and arguments e.g. user + can drop in LGBMRegressor in place of CatBoostRegressor and all data + management will be properly handled by Freqai. + :params: + :data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. + """ + + train_data = Pool( + data=data_dictionary['train_features'], + label=data_dictionary['train_labels'], + weight=data_dictionary['train_weights'] + ) + + test_data = Pool( + data=data_dictionary['test_features'], + label=data_dictionary['test_labels'], + weight=data_dictionary['test_weights'] + ) + + model = CatBoostRegressor(verbose=100, early_stopping_rounds=400, + **self.model_training_parameters) + model.fit(X=train_data, eval_set=test_data) + + return model + + def predict(self, unfiltered_dataframe: DataFrame) -> Tuple[DataFrame, DataFrame]: + """ + Filter the prediction features data and predict with it. + :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :return: + :predictions: np.array of predictions + :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove + data (NaNs) or felt uncertain about data (PCA and DI index) + """ + + print("--------------------Starting prediction--------------------") + + original_feature_list = self.dh.build_feature_list(self.config) + filtered_dataframe, _ = self.dh.filter_features(unfiltered_dataframe, original_feature_list, training_filter=False) + filtered_dataframe = self.dh.standardize_data_from_metadata(filtered_dataframe) + self.dh.data_dictionary['prediction_features'] = filtered_dataframe + + # optional additional data cleaning + if self.feature_parameters['principal_component_analysis']: + pca_components = self.dh.pca.transform(filtered_dataframe) + self.dh.data_dictionary['prediction_features'] = pd.DataFrame(data=pca_components, + columns = ['PC'+str(i) for i in range(0,self.dh.data['n_kept_components'])], + index = filtered_dataframe.index) + + if self.feature_parameters["remove_outliers"]: + self.dh.remove_outliers(predict=True) # creates dropped index + + if self.feature_parameters['DI_threshold']: + self.dh.check_if_pred_in_training_spaces() # sets do_predict + + predictions = self.model.predict(self.dh.data_dictionary['prediction_features']) + + # compute the non-standardized predictions + predictions = predictions * self.dh.data['labels_std'] + self.dh.data['labels_mean'] + + print("--------------------Finished prediction--------------------") + + return (predictions, self.dh.do_predict) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py new file mode 100644 index 000000000..d6b1295ec --- /dev/null +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -0,0 +1,179 @@ +import logging +import talib.abstract as ta +from pandas import DataFrame +import pandas as pd +from technical import qtpylib +import numpy as np +from freqtrade.strategy import (merge_informative_pair) +from freqtrade.strategy.interface import IStrategy +from freqtrade.freqai.strategy_bridge import CustomModel +from functools import reduce +logger = logging.getLogger(__name__) + +class FreqaiExampleStrategy(IStrategy): + """ + Example strategy showing how the user connects their own + IFreqaiModel to the strategy. Namely, the user uses: + self.model = CustomModel(self.config) + self.model.bridge.start(dataframe, metadata) + + to make predictions on their data. populate_any_indicators() automatically + generates the variety of features indicated by the user in the + canonical freqtrade configuration file under config['freqai']. + """ + + minimal_roi = { + "0": 0.01, + "240": -1 + } + + plot_config = { + 'main_plot': { + }, + 'subplots': { + "prediction":{ + 'prediction':{'color':'blue'} + }, + "target_roi":{ + 'target_roi':{'color':'brown'}, + }, + "do_predict":{ + 'do_predict':{'color':'brown'}, + }, + } + } + + stoploss = -0.05 + use_sell_signal = True + startup_candle_count: int = 1000 + + + def informative_pairs(self): + pairs = self.freqai_info['corr_pairlist'] + informative_pairs = [] + for tf in self.timeframes: + informative_pairs.append([(pair, tf) for pair in pairs]) + return informative_pairs + + def populate_any_indicators(self, pair, df, tf, informative=None,coin=''): + """ + Function designed to automatically generate, name and merge features + from user indicated timeframes in the configuration file. User can add + additional features here, but must follow the naming convention. + :params: + :pair: pair to be used as informative + :df: strategy dataframe which will receive merges from informatives + :tf: timeframe of the dataframe which will modify the feature names + :informative: the dataframe associated with the informative pair + :coin: the name of the coin which will modify the feature names. + """ + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) + + informative[coin+'rsi'] = ta.RSI(informative, timeperiod=14) + informative[coin+'mfi'] = ta.MFI(informative, timeperiod=25) + informative[coin+'adx'] = ta.ADX(informative, window=20) + + informative[coin+'20sma'] = ta.SMA(informative,timeperiod=20) + informative[coin+'21ema'] = ta.EMA(informative,timeperiod=21) + informative[coin+'bmsb'] = np.where(informative[coin+'20sma'].lt(informative[coin+'21ema']),1,0) + informative[coin+'close_over_20sma'] = informative['close']/informative[coin+'20sma'] + + informative[coin+'mfi'] = ta.MFI(informative, timeperiod=25) + + informative[coin+'ema21'] = ta.EMA(informative, timeperiod=21) + informative[coin+'sma20'] = ta.SMA(informative, timeperiod=20) + stoch = ta.STOCHRSI(informative, 15, 20, 2, 2) + informative[coin+'srsi-fk'] = stoch['fastk'] + informative[coin+'srsi-fd'] = stoch['fastd'] + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=14, stds=2.2) + informative[coin+'bb_lowerband'] = bollinger['lower'] + informative[coin+'bb_middleband'] = bollinger['mid'] + informative[coin+'bb_upperband'] = bollinger['upper'] + informative[coin+'bb_width'] = ((informative[coin+"bb_upperband"] - informative[coin+"bb_lowerband"]) / informative[coin+"bb_middleband"]) + informative[coin+'close-bb_lower'] = informative['close'] / informative[coin+'bb_lowerband'] + + informative[coin+'roc'] = ta.ROC(informative, timeperiod=3) + informative[coin+'adx'] = ta.ADX(informative, window=14) + + macd = ta.MACD(informative) + informative[coin+'macd'] = macd['macd'] + informative[coin+'pct-change'] = informative['close'].pct_change() + informative[coin+'relative_volume'] = informative['volume'] / informative['volume'].rolling(10).mean() + + informative[coin+'pct-change'] = informative['close'].pct_change() + + indicators = [col for col in informative if col.startswith(coin)] + + for n in range(self.freqai_info['feature_parameters']['shift']+1): + if n==0: continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix('_shift-'+str(n)) + informative = pd.concat((informative,informative_shift),axis=1) + + df = merge_informative_pair(df, informative, self.config['timeframe'], tf, ffill=True) + skip_columns = [(s + '_'+tf) for s in + ['date', 'open', 'high', 'low', 'close', 'volume']] + df = df.drop(columns=skip_columns) + + return df + + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # the configuration file parameters are stored here + self.freqai_info = self.config['freqai'] + + # the model is instantiated here + self.model = CustomModel(self.config) + + print('Populating indicators...') + + # the following loops are necessary for building the features + # indicated by the user in the configuration file. + for tf in self.freqai_info['timeframes']: + dataframe = self.populate_any_indicators(metadata['pair'], + dataframe.copy(), tf) + for i in self.freqai_info['corr_pairlist']: + dataframe = self.populate_any_indicators(i, + dataframe.copy(), tf, coin=i.split("/")[0]+'-') + + # the model will return 4 values, its prediction, an indication of whether or not the prediction + # should be accepted, the target mean/std values from the labels used during each training period. + (dataframe['prediction'], dataframe['do_predict'], + dataframe['target_mean'], dataframe['target_std']) = self.model.bridge.start(dataframe, metadata) + + dataframe['target_roi'] = dataframe['target_mean']+dataframe['target_std']*0.5 + dataframe['sell_roi'] = dataframe['target_mean']-dataframe['target_std']*1.5 + return dataframe + + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + buy_conditions = [ + (dataframe['prediction'] > dataframe['target_roi']) + & + (dataframe['do_predict'] == 1) + ] + + if buy_conditions: + dataframe.loc[reduce(lambda x, y: x | y, buy_conditions), 'buy'] = 1 + + return dataframe + + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # sell_goal = eval('self.'+metadata['pair'].split("/")[0]+'_sell_goal.value') + sell_conditions = [ + (dataframe['prediction'] < dataframe['sell_roi']) + & + (dataframe['do_predict'] == 1) + ] + if sell_conditions: + dataframe.loc[reduce(lambda x, y: x | y, sell_conditions), 'sell'] = 1 + + return dataframe + + def get_ticker_indicator(self): + return int(self.config['timeframe'][:-1]) diff --git a/mkdocs.yml b/mkdocs.yml index a43322f78..64d78363d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -36,6 +36,7 @@ nav: - Advanced Strategy: strategy-advanced.md - Advanced Hyperopt: advanced-hyperopt.md - Sandbox Testing: sandbox-testing.md + - Freqai: freqai.md - FAQ: faq.md - SQL Cheat-sheet: sql_cheatsheet.md - Strategy migration: strategy_migration.md diff --git a/requirements-freqai.txt b/requirements-freqai.txt new file mode 100644 index 000000000..f84d3df07 --- /dev/null +++ b/requirements-freqai.txt @@ -0,0 +1,8 @@ +# Include all requirements to run the bot. +-r requirements.txt + +# Required for freqai +scikit-learn==1.0.2 +scikit-optimize==0.9.0 +joblib==1.1.0 +catboost==1.0.4 From b40f8f88acb40591e338fc728aa5d17ea7374026 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 3 May 2022 10:28:13 +0200 Subject: [PATCH 002/308] cleaning and bug fixing --- freqtrade/freqai/data_handler.py | 5 +++++ freqtrade/freqai/freqai_interface.py | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_handler.py index d399cd12b..373063e42 100644 --- a/freqtrade/freqai/data_handler.py +++ b/freqtrade/freqai/data_handler.py @@ -19,6 +19,7 @@ class DataHandler: """ Class designed to handle all the data for the IFreqaiModel class model. Functionalities include holding, saving, loading, and analyzing the data. + author: Robert Caulk, rob.caulk@gmail.com """ def __init__(self, config: Dict[str, Any], dataframe: DataFrame, data: List): @@ -32,6 +33,10 @@ class DataHandler: self.data_dictionary = {} self.config = config self.freq_config = config['freqai'] + self.predictions = np.array([]) + self.do_predict = np.array([]) + self.target_mean = np.array([]) + self.target_std = np.array([]) def save_data(self, model: Any) -> None: """ diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index eb15e7e49..0f83793f1 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -17,6 +17,7 @@ class IFreqaiModel(ABC): User models should inherit from this class as shown in templates/ExamplePredictionModel.py where the user overrides train(), predict(), fit(), and make_labels(). + Author: Robert Caulk, rob.caulk@gmail.com """ def __init__(self, config: Dict[str, Any]) -> None: @@ -104,10 +105,10 @@ class IFreqaiModel(ABC): return dataframe - def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: + def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Any: """ Filter the training data and train a model to it. Train makes heavy use of the datahandler - for storing, saving, loading, and managed. + for storing, saving, loading, and analyzing the data. :params: :unfiltered_dataframe: Full dataframe for the current training period :metadata: pair metadata from strategy. @@ -115,7 +116,7 @@ class IFreqaiModel(ABC): :model: Trained model which can be used to inference (self.predict) """ - return unfiltered_dataframe, unfiltered_dataframe + return Any def fit(self) -> Any: """ From 630d201546892ad1565f871c594948770f8e44f0 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 3 May 2022 10:36:44 +0200 Subject: [PATCH 003/308] remove trained_stake --- freqtrade/freqai/freqai_interface.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 0f83793f1..2e840127c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -62,10 +62,6 @@ class IFreqaiModel(ABC): print('going to train',len(self.dh.training_timeranges), 'timeranges:',self.dh.training_timeranges) - predictions = np.array([]) - do_predict = np.array([]) - target_mean = np.array([]) - target_std = np.array([]) # Loop enforcing the sliding window training/backtesting paragigm # tr_train is the training time range e.g. 1 historical month @@ -149,7 +145,7 @@ class IFreqaiModel(ABC): :param path: path to model """ coin,_ = pair.split('/') - self.dh.model_filename = f"cb_"+coin.lower()+"_"+self.freqai_info['trained_stake']+"_"+training_timerange + self.dh.model_filename = f"cb_"+coin.lower()+"_"+training_timerange file_exists = os.path.isfile(self.dh.model_path+ self.dh.model_filename+"_model.joblib") if file_exists: From 2600ba4e746a169f262c0c96447ea67df0dc72a7 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 3 May 2022 11:44:54 +0200 Subject: [PATCH 004/308] remove unused remnants --- freqtrade/commands/__init__.py | 1 - freqtrade/commands/arguments.py | 3 +-- freqtrade/commands/freqai_commands.py | 24 ------------------------ 3 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 freqtrade/commands/freqai_commands.py diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index d5aea62be..0e637c487 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -19,7 +19,6 @@ from freqtrade.commands.list_commands import (start_list_exchanges, start_list_m start_show_trades) from freqtrade.commands.optimize_commands import (start_backtesting, start_backtesting_show, start_edge, start_hyperopt) -from freqtrade.commands.freqai_commands import (start_training) from freqtrade.commands.pairlist_commands import start_test_pairlist from freqtrade.commands.plot_commands import start_plot_dataframe, start_plot_profit from freqtrade.commands.trade_commands import start_trading diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 4388e84e4..f47748502 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -190,8 +190,7 @@ class Arguments: start_list_markets, start_list_strategies, start_list_timeframes, start_new_config, start_new_strategy, start_plot_dataframe, start_plot_profit, start_show_trades, - start_test_pairlist, start_trading, start_webserver, - start_training) + start_test_pairlist, start_trading, start_webserver) subparsers = self.parser.add_subparsers(dest='command', # Use custom message when no subhandler is added diff --git a/freqtrade/commands/freqai_commands.py b/freqtrade/commands/freqai_commands.py deleted file mode 100644 index 2733c851a..000000000 --- a/freqtrade/commands/freqai_commands.py +++ /dev/null @@ -1,24 +0,0 @@ -import logging -from typing import Any, Dict - -from freqtrade import constants -from freqtrade.configuration import setup_utils_configuration -from freqtrade.enums import RunMode -from freqtrade.exceptions import OperationalException -from freqtrade.misc import round_coin_value - - -logger = logging.getLogger(__name__) - -def start_training(args: Dict[str, Any]) -> None: - """ - Train a model for predicting signals - :param args: Cli args from Arguments() - :return: None - """ - from freqtrade.freqai.training import Training - - config = setup_utils_configuration(args, RunMode.FREQAI) - - training = Training(config) - training.start() From 99f7e44c30441567615ac01b89bd4920f7b83c06 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 4 May 2022 17:42:34 +0200 Subject: [PATCH 005/308] flake8 passing, use pathlib in lieu of os.path to accommodate windows/mac OS --- config_examples/config_freqai.example.json | 104 ++-- freqtrade/freqai/data_handler.py | 513 +++++++++++------- freqtrade/freqai/freqai_interface.py | 121 +++-- freqtrade/freqai/strategy_bridge.py | 4 +- freqtrade/resolvers/freqaimodel_resolver.py | 16 +- freqtrade/templates/ExamplePredictionModel.py | 100 ++-- freqtrade/templates/FreqaiExampleStrategy.py | 174 +++--- 7 files changed, 593 insertions(+), 439 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 0092a8c51..47109ff31 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -6,17 +6,19 @@ "fiat_display_currency": "USD", "dry_run": true, "timeframe": "5m", - "dry_run_wallet":1000, + "dry_run_wallet": 1000, "cancel_open_orders_on_exit": true, "unfilledtimeout": { "entry": 10, "exit": 30 - }, + }, "exchange": { "name": "ftx", "key": "", "secret": "", - "ccxt_config": {"enableRateLimit": true}, + "ccxt_config": { + "enableRateLimit": true + }, "ccxt_async_config": { "enableRateLimit": true, "rateLimit": 200 @@ -24,8 +26,7 @@ "pair_whitelist": [ "BTC/USDT" ], - "pair_blacklist": [ - ] + "pair_blacklist": [] }, "entry_pricing": { "price_side": "same", @@ -43,54 +44,57 @@ "order_book_top": 1 }, "pairlists": [ - {"method": "StaticPairList"} + { + "method": "StaticPairList" + } ], - "freqai": { - "btc_pair" : "BTC/USDT", - "timeframes" : ["5m","15m","1h"], - "full_timerange" : "20210601-20220101", - "train_period" : 30, - "backtest_period" : 7, - "identifier" : "example", - "base_features": [ - "rsi", - "close_over_20sma", - "relative_volume", - "bb_width", - "mfi", - "roc", - "pct-change", - "adx", - "macd" - ], - "corr_pairlist": [ - "ETH/USDT", - "LINK/USDT", - "DOT/USDT" - ], - "training_timerange" : "20211220-20220117", - - "feature_parameters" : { - "period": 12, - "shift": 2, - "drop_features": false, - "DI_threshold": 1, - "weight_factor": 0, - "principal_component_analysis": false, - "remove_outliers": false - }, - "data_split_parameters" : { - "test_size": 0.25, - "random_state": 1 - }, - "model_training_parameters" : { - "n_estimators": 2000, - "random_state": 1, - "learning_rate": 0.02, - "task_type": "CPU" - } + "btc_pair": "BTC/USDT", + "timeframes": [ + "5m", + "15m" + ], + "full_timerange": "20210601-20210901", + "train_period": 30, + "backtest_period": 7, + "identifier": "example", + "base_features": [ + "rsi", + "close_over_20sma", + "relative_volume", + "bb_width", + "mfi", + "roc", + "pct-change", + "adx", + "macd" + ], + "corr_pairlist": [ + "ETH/USDT", + "LINK/USDT", + "DOT/USDT" + ], + "training_timerange": "20211220-20220117", + "feature_parameters": { + "period": 12, + "shift": 1, + "drop_features": false, + "DI_threshold": 1, + "weight_factor": 0, + "principal_component_analysis": false, + "remove_outliers": false }, + "data_split_parameters": { + "test_size": 0.25, + "random_state": 1 + }, + "model_training_parameters": { + "n_estimators": 2000, + "random_state": 1, + "learning_rate": 0.02, + "task_type": "CPU" + } + }, "bot_name": "", "initial_state": "running", "forcebuy_enable": false, diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_handler.py index 373063e42..7264c6fab 100644 --- a/freqtrade/freqai/data_handler.py +++ b/freqtrade/freqai/data_handler.py @@ -1,64 +1,77 @@ -import json -import os import copy +import datetime +import json +import pickle as pk +from pathlib import Path +from typing import Any, Dict, List, Tuple + import numpy as np import pandas as pd +from joblib import dump, load from pandas import DataFrame -from joblib import dump -from joblib import load -from sklearn.model_selection import train_test_split from sklearn.metrics.pairwise import pairwise_distances -import datetime -from typing import Any, Dict, List, Tuple -import pickle as pk +from sklearn.model_selection import train_test_split + from freqtrade.configuration import TimeRange + SECONDS_IN_DAY = 86400 + class DataHandler: """ - Class designed to handle all the data for the IFreqaiModel class model. + Class designed to handle all the data for the IFreqaiModel class model. Functionalities include holding, saving, loading, and analyzing the data. author: Robert Caulk, rob.caulk@gmail.com """ - def __init__(self, config: Dict[str, Any], dataframe: DataFrame, data: List): + def __init__(self, config: Dict[str, Any], dataframe: DataFrame): self.full_dataframe = dataframe - (self.training_timeranges, - self.backtesting_timeranges) = self.split_timerange( - config['freqai']['full_timerange'], - config['freqai']['train_period'], - config['freqai']['backtest_period']) - self.data = data - self.data_dictionary = {} + (self.training_timeranges, self.backtesting_timeranges) = self.split_timerange( + config["freqai"]["full_timerange"], + config["freqai"]["train_period"], + config["freqai"]["backtest_period"], + ) + self.data: Dict[Any, Any] = {} self.config = config - self.freq_config = config['freqai'] + self.freq_config = config["freqai"] self.predictions = np.array([]) self.do_predict = np.array([]) self.target_mean = np.array([]) self.target_std = np.array([]) + self.model_path = Path() + self.model_filename = "" def save_data(self, model: Any) -> None: """ Saves all data associated with a model for a single sub-train time range :params: - :model: User trained model which can be reused for inferencing to generate + :model: User trained model which can be reused for inferencing to generate predictions """ - if not os.path.exists(self.model_path): os.mkdir(self.model_path) - save_path = self.model_path + self.model_filename + if not self.model_path.is_dir(): + self.model_path.mkdir(parents=True, exist_ok=True) + + save_path = Path(self.model_path) + + # if not os.path.exists(self.model_path): + # os.mkdir(self.model_path) + # save_path = self.model_path + self.model_filename + # Save the trained model - dump(model, save_path+"_model.joblib") - self.data['model_path'] = self.model_path - self.data['model_filename'] = self.model_filename - self.data['training_features_list'] = list(self.data_dictionary['train_features'].columns) + dump(model, save_path / str(self.model_filename + "_model.joblib")) + self.data["model_path"] = self.model_path + self.data["model_filename"] = self.model_filename + self.data["training_features_list"] = list(self.data_dictionary["train_features"].columns) # store the metadata - with open(save_path+"_metadata.json", 'w') as fp: - json.dump(self.data, fp, default=self.np_encoder) + with open(save_path / str(self.model_filename + "_metadata.json"), "w") as fp: + json.dump(self.data, fp, default=self.np_encoder) # save the train data to file so we can check preds for area of applicability later - self.data_dictionary['train_features'].to_pickle(save_path+"_trained_df.pkl") + self.data_dictionary["train_features"].to_pickle( + save_path / str(self.model_filename + "_trained_df.pkl") + ) return @@ -68,156 +81,210 @@ class DataHandler: :returns: :model: User trained model which can be inferenced for new predictions """ - model = load(self.model_path+self.model_filename+"_model.joblib") + model = load(self.model_path / str(self.model_filename + "_model.joblib")) - with open(self.model_path+self.model_filename+"_metadata.json", 'r') as fp: + with open(self.model_path / str(self.model_filename + "_metadata.json"), "r") as fp: self.data = json.load(fp) - if self.data.get('training_features_list'): - self.training_features_list = [*self.data.get('training_features_list')] + self.training_features_list = self.data["training_features_list"] + # if self.data.get("training_features_list"): + # self.training_features_list = [*self.data.get("training_features_list")] - self.data_dictionary['train_features'] = pd.read_pickle(self.model_path+ - self.model_filename+"_trained_df.pkl") + self.data_dictionary["train_features"] = pd.read_pickle( + self.model_path / str(self.model_filename + "_trained_df.pkl") + ) - self.model_path = self.data['model_path'] - self.model_filename = self.data['model_filename'] - if self.config['freqai']['feature_parameters']['principal_component_analysis']: - self.pca = pk.load(open(self.model_path+self.model_filename+"_pca_object.pkl","rb")) + self.model_path = self.data["model_path"] + self.model_filename = self.data["model_filename"] + if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]: + self.pca = pk.load( + open(self.model_path / str(self.model_filename + "_pca_object.pkl"), "rb") + ) return model - def make_train_test_datasets(self, filtered_dataframe: DataFrame, labels: DataFrame) -> None: - ''' - Given the dataframe for the full history for training, split the data into - training and test data according to user specified parameters in configuration - file. + def make_train_test_datasets( + self, filtered_dataframe: DataFrame, labels: DataFrame + ) -> Dict[Any, Any]: + """ + Given the dataframe for the full history for training, split the data into + training and test data according to user specified parameters in configuration + file. :filtered_dataframe: cleaned dataframe ready to be split. :labels: cleaned labels ready to be split. - ''' + """ - if self.config['freqai']['feature_parameters']['weight_factor'] > 0: + if self.config["freqai"]["feature_parameters"]["weight_factor"] > 0: weights = self.set_weights_higher_recent(len(filtered_dataframe)) - else: weights = np.ones(len(filtered_dataframe)) + else: + weights = np.ones(len(filtered_dataframe)) - (train_features, test_features, train_labels, - test_labels, train_weights, test_weights) = train_test_split( - filtered_dataframe[:filtered_dataframe.shape[0]], + ( + train_features, + test_features, + train_labels, + test_labels, + train_weights, + test_weights, + ) = train_test_split( + filtered_dataframe[: filtered_dataframe.shape[0]], labels, weights, - **self.config['freqai']['data_split_parameters'] + **self.config["freqai"]["data_split_parameters"] ) return self.build_data_dictionary( - train_features,test_features, - train_labels,test_labels, - train_weights,test_weights) + train_features, test_features, train_labels, test_labels, train_weights, test_weights + ) - - - def filter_features(self, unfiltered_dataframe: DataFrame, training_feature_list: List, - labels: DataFrame = None, training_filter: bool=True) -> Tuple[DataFrame, DataFrame]: - ''' - Filter the unfiltered dataframe to extract the user requested features and properly - remove all NaNs. Any row with a NaN is removed from training dataset or replaced with - 0s in the prediction dataset. However, prediction dataset do_predict will reflect any + def filter_features( + self, + unfiltered_dataframe: DataFrame, + training_feature_list: List, + labels: DataFrame = pd.DataFrame(), + training_filter: bool = True, + ) -> Tuple[DataFrame, DataFrame]: + """ + Filter the unfiltered dataframe to extract the user requested features and properly + remove all NaNs. Any row with a NaN is removed from training dataset or replaced with + 0s in the prediction dataset. However, prediction dataset do_predict will reflect any row that had a NaN and will shield user from that prediction. :params: :unfiltered_dataframe: the full dataframe for the present training period - :training_feature_list: list, the training feature list constructed by self.build_feature_list() - according to user specified parameters in the configuration file. + :training_feature_list: list, the training feature list constructed by + self.build_feature_list() according to user specified parameters in the configuration file. :labels: the labels for the dataset - :training_filter: boolean which lets the function know if it is training data or - prediction data to be filtered. + :training_filter: boolean which lets the function know if it is training data or + prediction data to be filtered. :returns: :filtered_dataframe: dataframe cleaned of NaNs and only containing the user requested feature set. :labels: labels cleaned of NaNs. - ''' + """ filtered_dataframe = unfiltered_dataframe.filter(training_feature_list, axis=1) - drop_index = pd.isnull(filtered_dataframe).any(1) # get the rows that have NaNs, - - if training_filter: # we don't care about total row number (total no. datapoints) in training, we only care about removing any row with NaNs + drop_index = pd.isnull(filtered_dataframe).any(1) # get the rows that have NaNs, + drop_index = drop_index.replace(True, 1).replace(False, 0) # pep8 requirement. + if ( + training_filter + ): # we don't care about total row number (total no. datapoints) in training, we only care + # about removing any row with NaNs drop_index_labels = pd.isnull(labels) - filtered_dataframe = filtered_dataframe[(drop_index==False) & (drop_index_labels==False)] # dropping values - labels = labels[(drop_index==False) & (drop_index_labels==False)] # assuming the labels depend entirely on the dataframe here. - print('dropped',len(unfiltered_dataframe)-len(filtered_dataframe), - 'training data points due to NaNs, ensure you have downloaded all historical training data') - self.data['filter_drop_index_training'] = drop_index + drop_index_labels = drop_index_labels.replace(True, 1).replace(False, 0) + filtered_dataframe = filtered_dataframe[ + (drop_index == 0) & (drop_index_labels == 0) + ] # dropping values + labels = labels[ + (drop_index == 0) & (drop_index_labels == 0) + ] # assuming the labels depend entirely on the dataframe here. + print( + "dropped", + len(unfiltered_dataframe) - len(filtered_dataframe), + "training data points due to NaNs, ensure you have downloaded", + "all historical training data", + ) + self.data["filter_drop_index_training"] = drop_index - else: # we are backtesting so we need to preserve row number to send back to strategy, so now we use do_predict to avoid any prediction based on a NaN + else: + # we are backtesting so we need to preserve row number to send back to strategy, + # so now we use do_predict to avoid any prediction based on a NaN drop_index = pd.isnull(filtered_dataframe).any(1) - self.data['filter_drop_index_prediction'] = drop_index - filtered_dataframe.fillna(0, inplace=True) # replacing all NaNs with zeros to avoid issues in 'prediction', but any prediction that was based on a single NaN is ultimately protected from buys with do_predict + self.data["filter_drop_index_prediction"] = drop_index + filtered_dataframe.fillna(0, inplace=True) + # replacing all NaNs with zeros to avoid issues in 'prediction', but any prediction + # that was based on a single NaN is ultimately protected from buys with do_predict drop_index = ~drop_index - self.do_predict = np.array(drop_index.replace(True,1).replace(False,0)) - print('dropped',len(self.do_predict) - self.do_predict.sum(),'of',len(filtered_dataframe), - 'prediction data points due to NaNs. These are protected from prediction with do_predict vector returned to strategy.') - + self.do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) + print( + "dropped", + len(self.do_predict) - self.do_predict.sum(), + "of", + len(filtered_dataframe), + "prediction data points due to NaNs. These are protected from prediction", + "with do_predict vector returned to strategy.", + ) return filtered_dataframe, labels - def build_data_dictionary(self, train_df: DataFrame, test_df: DataFrame, - train_labels: DataFrame, test_labels: DataFrame, - train_weights: Any, test_weights: Any) -> Dict: + def build_data_dictionary( + self, + train_df: DataFrame, + test_df: DataFrame, + train_labels: DataFrame, + test_labels: DataFrame, + train_weights: Any, + test_weights: Any, + ) -> Dict: - self.data_dictionary = {'train_features': train_df, - 'test_features': test_df, - 'train_labels': train_labels, - 'test_labels': test_labels, - 'train_weights': train_weights, - 'test_weights': test_weights} + self.data_dictionary = { + "train_features": train_df, + "test_features": test_df, + "train_labels": train_labels, + "test_labels": test_labels, + "train_weights": train_weights, + "test_weights": test_weights, + } return self.data_dictionary - def standardize_data(self, data_dictionary: Dict) -> None: - ''' + def standardize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: + """ Standardize all data in the data_dictionary according to the training dataset :params: :data_dictionary: dictionary containing the cleaned and split training/test data/labels :returns: :data_dictionary: updated dictionary with standardized values. - ''' + """ # standardize the data by training stats - train_mean = data_dictionary['train_features'].mean() - train_std = data_dictionary['train_features'].std() - data_dictionary['train_features'] = (data_dictionary['train_features'] - train_mean) / train_std - data_dictionary['test_features'] = (data_dictionary['test_features'] - train_mean) / train_std + train_mean = data_dictionary["train_features"].mean() + train_std = data_dictionary["train_features"].std() + data_dictionary["train_features"] = ( + data_dictionary["train_features"] - train_mean + ) / train_std + data_dictionary["test_features"] = ( + data_dictionary["test_features"] - train_mean + ) / train_std - train_labels_std = data_dictionary['train_labels'].std() - train_labels_mean = data_dictionary['train_labels'].mean() - data_dictionary['train_labels'] = (data_dictionary['train_labels'] - train_labels_mean) / train_labels_std - data_dictionary['test_labels'] = (data_dictionary['test_labels'] - train_labels_mean) / train_labels_std + train_labels_std = data_dictionary["train_labels"].std() + train_labels_mean = data_dictionary["train_labels"].mean() + data_dictionary["train_labels"] = ( + data_dictionary["train_labels"] - train_labels_mean + ) / train_labels_std + data_dictionary["test_labels"] = ( + data_dictionary["test_labels"] - train_labels_mean + ) / train_labels_std for item in train_std.keys(): - self.data[item+'_std'] = train_std[item] - self.data[item+'_mean'] = train_mean[item] + self.data[item + "_std"] = train_std[item] + self.data[item + "_mean"] = train_mean[item] - self.data['labels_std'] = train_labels_std - self.data['labels_mean'] = train_labels_mean + self.data["labels_std"] = train_labels_std + self.data["labels_mean"] = train_labels_mean return data_dictionary def standardize_data_from_metadata(self, df: DataFrame) -> DataFrame: - ''' - Standardizes a set of data using the mean and standard deviation from + """ + Standardizes a set of data using the mean and standard deviation from the associated training data. :params: :df: Dataframe to be standardized - ''' + """ for item in df.keys(): - df[item] = (df[item] - self.data[item+'_mean']) / self.data[item+'_std'] + df[item] = (df[item] - self.data[item + "_mean"]) / self.data[item + "_std"] return df - def split_timerange(self, tr: Dict, train_split: int=28, bt_split: int=7) -> list: - ''' + def split_timerange( + self, tr: str, train_split: int = 28, bt_split: int = 7 + ) -> Tuple[list, list]: + """ Function which takes a single time range (tr) and splits it into sub timeranges to train and backtest on based on user input tr: str, full timerange to train on train_split: the period length for the each training (days). Specified in user configuration file bt_split: the backtesting length (dats). Specified in user configuration file - ''' + """ train_period = train_split * SECONDS_IN_DAY bt_period = bt_split * SECONDS_IN_DAY @@ -230,22 +297,24 @@ class DataHandler: tr_backtesting_list = [] first = True while True: - if not first: timerange_train.startts = timerange_train.startts + bt_period + if not first: + timerange_train.startts = timerange_train.startts + bt_period timerange_train.stopts = timerange_train.startts + train_period # if a full training period doesnt fit, we stop - if timerange_train.stopts > full_timerange.stopts: break + if timerange_train.stopts > full_timerange.stopts: + break first = False start = datetime.datetime.utcfromtimestamp(timerange_train.startts) stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) - tr_training_list.append(start.strftime("%Y%m%d")+'-'+stop.strftime("%Y%m%d")) + tr_training_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) - ## associated backtest period - timerange_backtest.startts = timerange_train.stopts - timerange_backtest.stopts = timerange_backtest.startts + bt_period + # associated backtest period + timerange_backtest.startts = timerange_train.stopts + timerange_backtest.stopts = timerange_backtest.startts + bt_period start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) - tr_backtesting_list.append(start.strftime("%Y%m%d")+'-'+stop.strftime("%Y%m%d")) + tr_backtesting_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) return tr_training_list, tr_backtesting_list @@ -260,8 +329,8 @@ class DataHandler: timerange = TimeRange.parse_timerange(tr) start = datetime.datetime.fromtimestamp(timerange.startts, tz=datetime.timezone.utc) stop = datetime.datetime.fromtimestamp(timerange.stopts, tz=datetime.timezone.utc) - df = df.loc[df['date'] >= start, :] - df = df.loc[df['date'] <= stop, :] + df = df.loc[df["date"] >= start, :] + df = df.loc[df["date"] <= stop, :] return df @@ -272,128 +341,171 @@ class DataHandler: No parameters or returns, it acts on the data_dictionary held by the DataHandler. """ - from sklearn.decomposition import PCA # avoid importing if we dont need it + from sklearn.decomposition import PCA # avoid importing if we dont need it - n_components = self.data_dictionary['train_features'].shape[1] + n_components = self.data_dictionary["train_features"].shape[1] pca = PCA(n_components=n_components) - pca = pca.fit(self.data_dictionary['train_features']) + pca = pca.fit(self.data_dictionary["train_features"]) n_keep_components = np.argmin(pca.explained_variance_ratio_.cumsum() < 0.999) pca2 = PCA(n_components=n_keep_components) - self.data['n_kept_components'] = n_keep_components - pca2 = pca2.fit(self.data_dictionary['train_features']) - print('reduced feature dimension by',n_components-n_keep_components) - print("explained variance",np.sum(pca2.explained_variance_ratio_)) - train_components = pca2.transform(self.data_dictionary['train_features']) - test_components = pca2.transform(self.data_dictionary['test_features']) + self.data["n_kept_components"] = n_keep_components + pca2 = pca2.fit(self.data_dictionary["train_features"]) + print("reduced feature dimension by", n_components - n_keep_components) + print("explained variance", np.sum(pca2.explained_variance_ratio_)) + train_components = pca2.transform(self.data_dictionary["train_features"]) + test_components = pca2.transform(self.data_dictionary["test_features"]) - self.data_dictionary['train_features'] = pd.DataFrame(data=train_components, - columns = ['PC'+str(i) for i in range(0,n_keep_components)], - index = self.data_dictionary['train_features'].index) + self.data_dictionary["train_features"] = pd.DataFrame( + data=train_components, + columns=["PC" + str(i) for i in range(0, n_keep_components)], + index=self.data_dictionary["train_features"].index, + ) - self.data_dictionary['test_features'] = pd.DataFrame(data=test_components, - columns = ['PC'+str(i) for i in range(0,n_keep_components)], - index = self.data_dictionary['test_features'].index) + self.data_dictionary["test_features"] = pd.DataFrame( + data=test_components, + columns=["PC" + str(i) for i in range(0, n_keep_components)], + index=self.data_dictionary["test_features"].index, + ) - self.data['n_kept_components'] = n_keep_components + self.data["n_kept_components"] = n_keep_components self.pca = pca2 - if not os.path.exists(self.model_path): os.mkdir(self.model_path) - pk.dump(pca2, open(self.model_path + self.model_filename+"_pca_object.pkl","wb")) + + if not self.model_path.is_dir(): + self.model_path.mkdir(parents=True, exist_ok=True) + pk.dump(pca2, open(self.model_path / str(self.model_filename + "_pca_object.pkl"), "wb")) return None def compute_distances(self) -> float: - print('computing average mean distance for all training points') - pairwise = pairwise_distances(self.data_dictionary['train_features'],n_jobs=-1) + print("computing average mean distance for all training points") + pairwise = pairwise_distances(self.data_dictionary["train_features"], n_jobs=-1) avg_mean_dist = pairwise.mean(axis=1).mean() - print('avg_mean_dist',avg_mean_dist) + print("avg_mean_dist", avg_mean_dist) return avg_mean_dist - def remove_outliers(self,predict: bool) -> None: + def remove_outliers(self, predict: bool) -> None: """ - Remove data that looks like an outlier based on the distribution of each - variable. + Remove data that looks like an outlier based on the distribution of each + variable. :params: - :predict: boolean which tells the function if this is prediction data or - training data coming in. + :predict: boolean which tells the function if this is prediction data or + training data coming in. """ - lower_quantile = self.data_dictionary['train_features'].quantile(0.001) - upper_quantile = self.data_dictionary['train_features'].quantile(0.999) + lower_quantile = self.data_dictionary["train_features"].quantile(0.001) + upper_quantile = self.data_dictionary["train_features"].quantile(0.999) if predict: - df = self.data_dictionary['prediction_features'][(self.data_dictionary['prediction_features']lower_quantile)] + df = self.data_dictionary["prediction_features"][ + (self.data_dictionary["prediction_features"] < upper_quantile) + & (self.data_dictionary["prediction_features"] > lower_quantile) + ] drop_index = pd.isnull(df).any(1) - self.data_dictionary['prediction_features'].fillna(0,inplace=True) + self.data_dictionary["prediction_features"].fillna(0, inplace=True) drop_index = ~drop_index - do_predict = np.array(drop_index.replace(True,1).replace(False,0)) - - print('remove_outliers() tossed',len(do_predict)-do_predict.sum(),'predictions because they were beyond 3 std deviations from training data.') + do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) + + print( + "remove_outliers() tossed", + len(do_predict) - do_predict.sum(), + "predictions because they were beyond 3 std deviations from training data.", + ) self.do_predict += do_predict self.do_predict -= 1 else: - filter_train_df = self.data_dictionary['train_features'][(self.data_dictionary['train_features']lower_quantile)] + filter_train_df = self.data_dictionary["train_features"][ + (self.data_dictionary["train_features"] < upper_quantile) + & (self.data_dictionary["train_features"] > lower_quantile) + ] drop_index = pd.isnull(filter_train_df).any(1) - self.data_dictionary['train_features'] = self.data_dictionary['train_features'][(drop_index==False)] - self.data_dictionary['train_labels'] = self.data_dictionary['train_labels'][(drop_index==False)] - self.data_dictionary['train_weights'] = self.data_dictionary['train_weights'][(drop_index==False)] + drop_index = drop_index.replace(True, 1).replace(False, 0) + self.data_dictionary["train_features"] = self.data_dictionary["train_features"][ + (drop_index == 0) + ] + self.data_dictionary["train_labels"] = self.data_dictionary["train_labels"][ + (drop_index == 0) + ] + self.data_dictionary["train_weights"] = self.data_dictionary["train_weights"][ + (drop_index == 0) + ] # do the same for the test data - filter_test_df = self.data_dictionary['test_features'][(self.data_dictionary['test_features']lower_quantile)] + filter_test_df = self.data_dictionary["test_features"][ + (self.data_dictionary["test_features"] < upper_quantile) + & (self.data_dictionary["test_features"] > lower_quantile) + ] drop_index = pd.isnull(filter_test_df).any(1) - #pdb.set_trace() - self.data_dictionary['test_labels'] = self.data_dictionary['test_labels'][(drop_index==False)] - self.data_dictionary['test_features'] = self.data_dictionary['test_features'][(drop_index==False)] - self.data_dictionary['test_weights'] = self.data_dictionary['test_weights'][(drop_index==False)] + drop_index = drop_index.replace(True, 1).replace(False, 0) + self.data_dictionary["test_labels"] = self.data_dictionary["test_labels"][ + (drop_index == 0) + ] + self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ + (drop_index == 0) + ] + self.data_dictionary["test_weights"] = self.data_dictionary["test_weights"][ + (drop_index == 0) + ] return - def build_feature_list(self, config: dict) -> int: + def build_feature_list(self, config: dict) -> list: """ - Build the list of features that will be used to filter - the full dataframe. Feature list is construced from the + Build the list of features that will be used to filter + the full dataframe. Feature list is construced from the user configuration file. :params: :config: Canonical freqtrade config file containing all user defined input in config['freqai] dictionary. """ features = [] - for tf in config['freqai']['timeframes']: - for ft in config['freqai']['base_features']: - for n in range(config['freqai']['feature_parameters']['shift']+1): - shift='' - if n>0: shift = '_shift-'+str(n) - features.append(ft+shift+'_'+tf) - for p in config['freqai']['corr_pairlist']: - features.append(p.split("/")[0]+'-'+ft+shift+'_'+tf) + for tf in config["freqai"]["timeframes"]: + for ft in config["freqai"]["base_features"]: + for n in range(config["freqai"]["feature_parameters"]["shift"] + 1): + shift = "" + if n > 0: + shift = "_shift-" + str(n) + features.append(ft + shift + "_" + tf) + for p in config["freqai"]["corr_pairlist"]: + features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) - print('number of features',len(features)) + print("number of features", len(features)) return features def check_if_pred_in_training_spaces(self) -> None: """ - Compares the distance from each prediction point to each training data + Compares the distance from each prediction point to each training data point. It uses this information to estimate a Dissimilarity Index (DI) - and avoid making predictions on any points that are too far away - from the training data set. + and avoid making predictions on any points that are too far away + from the training data set. """ - print('checking if prediction features are in AOA') - distance = pairwise_distances(self.data_dictionary['train_features'], - self.data_dictionary['prediction_features'],n_jobs=-1) + print("checking if prediction features are in AOA") + distance = pairwise_distances( + self.data_dictionary["train_features"], + self.data_dictionary["prediction_features"], + n_jobs=-1, + ) - do_predict = np.where(distance.min(axis=0) / - self.data['avg_mean_dist'] < self.config['freqai']['feature_parameters']['DI_threshold'],1,0) + do_predict = np.where( + distance.min(axis=0) / self.data["avg_mean_dist"] + < self.config["freqai"]["feature_parameters"]["DI_threshold"], + 1, + 0, + ) - print('Distance checker tossed',len(do_predict)-do_predict.sum(), - 'predictions for being too far from training data') + print( + "Distance checker tossed", + len(do_predict) - do_predict.sum(), + "predictions for being too far from training data", + ) - self.do_predict += do_predict + self.do_predict += do_predict self.do_predict -= 1 - + def set_weights_higher_recent(self, num_weights: int) -> int: """ Set weights so that recent data is more heavily weighted during @@ -401,8 +513,9 @@ class DataHandler: """ weights = np.zeros(num_weights) for i in range(1, len(weights)): - weights[len(weights) - i] = np.exp(-i/ - (self.config['freqai']['feature_parameters']['weight_factor']*num_weights)) + weights[len(weights) - i] = np.exp( + -i / (self.config["freqai"]["feature_parameters"]["weight_factor"] * num_weights) + ) return weights def append_predictions(self, predictions, do_predict, len_dataframe): @@ -411,12 +524,12 @@ class DataHandler: """ ones = np.ones(len_dataframe) - s_mean, s_std = ones*self.data['s_mean'], ones*self.data['s_std'] + s_mean, s_std = ones * self.data["s_mean"], ones * self.data["s_std"] - self.predictions = np.append(self.predictions,predictions) - self.do_predict = np.append(self.do_predict,do_predict) - self.target_mean = np.append(self.target_mean,s_mean) - self.target_std = np.append(self.target_std,s_std) + self.predictions = np.append(self.predictions, predictions) + self.do_predict = np.append(self.do_predict, do_predict) + self.target_mean = np.append(self.target_mean, s_mean) + self.target_std = np.append(self.target_std, s_std) return @@ -426,14 +539,14 @@ class DataHandler: when it goes back to the strategy. These rows are not included in the backtest. """ - filler = np.zeros(len_dataframe -len(self.predictions)) # startup_candle_count - self.predictions = np.append(filler,self.predictions) - self.do_predict = np.append(filler,self.do_predict) - self.target_mean = np.append(filler,self.target_mean) - self.target_std = np.append(filler,self.target_std) + filler = np.zeros(len_dataframe - len(self.predictions)) # startup_candle_count + self.predictions = np.append(filler, self.predictions) + self.do_predict = np.append(filler, self.do_predict) + self.target_mean = np.append(filler, self.target_mean) + self.target_std = np.append(filler, self.target_std) return - + def np_encoder(self, object): if isinstance(object, np.generic): return object.item() diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 2e840127c..9f04b09cd 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -1,20 +1,23 @@ +import gc +import shutil +from abc import ABC +from pathlib import Path +from typing import Any, Dict, Tuple -import os import numpy as np import pandas as pd from pandas import DataFrame -import shutil -import gc -from typing import Any, Dict, Optional, Tuple -from abc import ABC + from freqtrade.freqai.data_handler import DataHandler + pd.options.mode.chained_assignment = None + class IFreqaiModel(ABC): """ Class containing all tools for training and prediction in the strategy. - User models should inherit from this class as shown in + User models should inherit from this class as shown in templates/ExamplePredictionModel.py where the user overrides train(), predict(), fit(), and make_labels(). Author: Robert Caulk, rob.caulk@gmail.com @@ -23,61 +26,71 @@ class IFreqaiModel(ABC): def __init__(self, config: Dict[str, Any]) -> None: self.config = config - self.freqai_info = config['freqai'] - self.data_split_parameters = config['freqai']['data_split_parameters'] - self.model_training_parameters = config['freqai']['model_training_parameters'] - self.feature_parameters = config['freqai']['feature_parameters'] - self.full_path = (str(config['user_data_dir'])+ - "/models/"+self.freqai_info['full_timerange']+ - '-'+self.freqai_info['identifier']) - self.metadata = {} - self.data = {} + self.freqai_info = config["freqai"] + self.data_split_parameters = config["freqai"]["data_split_parameters"] + self.model_training_parameters = config["freqai"]["model_training_parameters"] + self.feature_parameters = config["freqai"]["feature_parameters"] + self.full_path = Path( + config["user_data_dir"] + / "models" + / str(self.freqai_info["full_timerange"] + self.freqai_info["identifier"]) + ) + self.time_last_trained = None self.current_time = None self.model = None self.predictions = None - if not os.path.exists(self.full_path): - os.mkdir(self.full_path) - shutil.copy(self.config['config_files'][0],self.full_path+"/"+self.config['config_files'][0]) + if not self.full_path.is_dir(): + self.full_path.mkdir(parents=True, exist_ok=True) + shutil.copy( + self.config["config_files"][0], + Path(self.full_path / self.config["config_files"][0]), + ) def start(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Entry point to the FreqaiModel, it will train a new model if + Entry point to the FreqaiModel, it will train a new model if necesssary before making the prediction. The backtesting and training paradigm is a sliding training window with a following backtest window. Both windows slide according to the - length of the backtest window. This function is not intended to be - overridden by children of IFreqaiModel, but technically, it can be + length of the backtest window. This function is not intended to be + overridden by children of IFreqaiModel, but technically, it can be if the user wishes to make deeper changes to the sliding window logic. :params: :dataframe: Full dataframe coming from strategy - it contains entire - backtesting timerange + additional historical data necessary to train + backtesting timerange + additional historical data necessary to train the model. - :metadata: pair metadataa coming from strategy. + :metadata: pair metadataa coming from strategy. """ - self.pair = metadata['pair'] - self.dh = DataHandler(self.config, dataframe, self.data) + self.pair = metadata["pair"] + self.dh = DataHandler(self.config, dataframe) - print('going to train',len(self.dh.training_timeranges), - 'timeranges:',self.dh.training_timeranges) + print( + "going to train", + len(self.dh.training_timeranges), + "timeranges:", + self.dh.training_timeranges, + ) # Loop enforcing the sliding window training/backtesting paragigm # tr_train is the training time range e.g. 1 historical month - # tr_backtest is the backtesting time range e.g. the week directly - # following tr_train. Both of these windows slide through the + # tr_backtest is the backtesting time range e.g. the week directly + # following tr_train. Both of these windows slide through the # entire backtest - for tr_train, tr_backtest in zip(self.dh.training_timeranges, - self.dh.backtesting_timeranges): + for tr_train, tr_backtest in zip( + self.dh.training_timeranges, self.dh.backtesting_timeranges + ): gc.collect() - #self.config['timerange'] = tr_train - self.dh.data = {} # clean the pair specific data between models - self.freqai_info['training_timerange'] = tr_train + # self.config['timerange'] = tr_train + self.dh.data = {} # clean the pair specific data between models + self.freqai_info["training_timerange"] = tr_train dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) - print("training",self.pair,"for",tr_train) - self.dh.model_path = self.full_path+"/"+ 'sub-train'+'-'+str(tr_train)+'/' + print("training", self.pair, "for", tr_train) + # self.dh.model_path = self.full_path + "/" + "sub-train" + "-" + str(tr_train) + "/" + self.dh.model_path = Path(self.full_path / str("sub-train" + "-" + str(tr_train))) if not self.model_exists(self.pair, training_timerange=tr_train): self.model = self.train(dataframe_train, metadata) self.dh.save_data(self.model) @@ -86,8 +99,8 @@ class IFreqaiModel(ABC): preds, do_preds = self.predict(dataframe_backtest) - self.dh.append_predictions(preds,do_preds,len(dataframe_backtest)) - + self.dh.append_predictions(preds, do_preds, len(dataframe_backtest)) + self.dh.fill_predictions(len(dataframe)) return self.dh.predictions, self.dh.do_predict, self.dh.target_mean, self.dh.target_std @@ -107,7 +120,7 @@ class IFreqaiModel(ABC): for storing, saving, loading, and analyzing the data. :params: :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. + :metadata: pair metadata from strategy. :returns: :model: Trained model which can be used to inference (self.predict) """ @@ -116,40 +129,40 @@ class IFreqaiModel(ABC): def fit(self) -> Any: """ - Most regressors use the same function names and arguments e.g. user + Most regressors use the same function names and arguments e.g. user can drop in LGBMRegressor in place of CatBoostRegressor and all data management will be properly handled by Freqai. :params: - :data_dictionary: the dictionary constructed by DataHandler to hold + :data_dictionary: the dictionary constructed by DataHandler to hold all the training and test data/labels. """ - return None - - def predict(self) -> Optional[Tuple[DataFrame, DataFrame]]: + return Any + + def predict(self, dataframe: DataFrame) -> Tuple[np.array, np.array]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. - :return: + :return: :predictions: np.array of predictions :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove data (NaNs) or felt uncertain about data (PCA and DI index) """ - return None + return np.array([]), np.array([]) - def model_exists(self, pair: str, training_timerange: str = None) -> bool: + def model_exists(self, pair: str, training_timerange: str) -> bool: """ Given a pair and path, check if a model already exists :param pair: pair e.g. BTC/USD :param path: path to model """ - coin,_ = pair.split('/') - self.dh.model_filename = f"cb_"+coin.lower()+"_"+training_timerange - file_exists = os.path.isfile(self.dh.model_path+ - self.dh.model_filename+"_model.joblib") + coin, _ = pair.split("/") + self.dh.model_filename = "cb_" + coin.lower() + "_" + training_timerange + path_to_modelfile = Path(self.dh.model_path / str(self.dh.model_filename + "_model.joblib")) + file_exists = path_to_modelfile.is_file() if file_exists: - print("Found model at", self.dh.model_path+self.dh.model_filename) - else: print("Could not find model at", - self.dh.model_path+self.dh.model_filename) + print("Found model at", self.dh.model_path / self.dh.model_filename) + else: + print("Could not find model at", self.dh.model_path / self.dh.model_filename) return file_exists diff --git a/freqtrade/freqai/strategy_bridge.py b/freqtrade/freqai/strategy_bridge.py index c336e3c84..bb43084a0 100644 --- a/freqtrade/freqai/strategy_bridge.py +++ b/freqtrade/freqai/strategy_bridge.py @@ -3,10 +3,10 @@ from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver class CustomModel: """ - A bridge between the user defined IFreqaiModel class + A bridge between the user defined IFreqaiModel class and the strategy. """ - def __init__(self,config): + def __init__(self, config): self.bridge = FreqaiModelResolver.load_freqaimodel(config) diff --git a/freqtrade/resolvers/freqaimodel_resolver.py b/freqtrade/resolvers/freqaimodel_resolver.py index 9545afd24..2ba6b3e8a 100644 --- a/freqtrade/resolvers/freqaimodel_resolver.py +++ b/freqtrade/resolvers/freqaimodel_resolver.py @@ -12,6 +12,7 @@ from freqtrade.exceptions import OperationalException from freqtrade.freqai.freqai_interface import IFreqaiModel from freqtrade.resolvers import IResolver + logger = logging.getLogger(__name__) @@ -19,10 +20,11 @@ class FreqaiModelResolver(IResolver): """ This class contains all the logic to load custom hyperopt loss class """ + object_type = IFreqaiModel object_type_str = "FreqaiModel" user_subdir = USERPATH_FREQAIMODELS - initial_search_path = Path(__file__).parent.parent.joinpath('optimize').resolve() + initial_search_path = Path(__file__).parent.parent.joinpath("optimize").resolve() @staticmethod def load_freqaimodel(config: Dict) -> IFreqaiModel: @@ -31,15 +33,17 @@ class FreqaiModelResolver(IResolver): :param config: configuration dictionary """ - freqaimodel_name = config.get('freqaimodel') + freqaimodel_name = config.get("freqaimodel") if not freqaimodel_name: raise OperationalException( "No freqaimodel set. Please use `--freqaimodel` to " "specify the FreqaiModel class to use.\n" ) - freqaimodel = FreqaiModelResolver.load_object(freqaimodel_name, - config, kwargs={'config': config}, - extra_dir=config.get('freqaimodel_path')) - + freqaimodel = FreqaiModelResolver.load_object( + freqaimodel_name, + config, + kwargs={"config": config}, + extra_dir=config.get("freqaimodel_path"), + ) return freqaimodel diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index a5370b5ac..feeed11a9 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -1,15 +1,17 @@ -import numpy as np +from typing import Any, Dict, Tuple + import pandas as pd from catboost import CatBoostRegressor, Pool from pandas import DataFrame -from typing import Any, Dict, Tuple + from freqtrade.freqai.freqai_interface import IFreqaiModel + class ExamplePredictionModel(IFreqaiModel): """ User created prediction model. The class needs to override three necessary functions, predict(), train(), fit(). The class inherits ModelHandler which - has its own DataHandler where data is held, saved, loaded, and managed. + has its own DataHandler where data is held, saved, loaded, and managed. """ def make_labels(self, dataframe: DataFrame) -> DataFrame: @@ -19,15 +21,20 @@ class ExamplePredictionModel(IFreqaiModel): :dataframe: the full dataframe for the present training period """ - dataframe['s'] = (dataframe['close'].shift(-self.feature_parameters['period']).rolling( - self.feature_parameters['period']).max() / dataframe['close'] - 1) - self.dh.data['s_mean'] = dataframe['s'].mean() - self.dh.data['s_std'] = dataframe['s'].std() + dataframe["s"] = ( + dataframe["close"] + .shift(-self.feature_parameters["period"]) + .rolling(self.feature_parameters["period"]) + .max() + / dataframe["close"] + - 1 + ) + self.dh.data["s_mean"] = dataframe["s"].mean() + self.dh.data["s_std"] = dataframe["s"].std() - print('label mean',self.dh.data['s_mean'],'label std',self.dh.data['s_std']) - - return dataframe['s'] + print("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) + return dataframe["s"] def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: """ @@ -35,7 +42,7 @@ class ExamplePredictionModel(IFreqaiModel): for storing, saving, loading, and managed. :params: :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. + :metadata: pair metadata from strategy. :returns: :model: Trained model which can be used to inference (self.predict) """ @@ -46,8 +53,12 @@ class ExamplePredictionModel(IFreqaiModel): unfiltered_labels = self.make_labels(unfiltered_dataframe) # filter the features requested by user in the configuration file and elegantly handle NaNs - features_filtered, labels_filtered = self.dh.filter_features(unfiltered_dataframe, - self.dh.training_features_list, unfiltered_labels, training_filter=True) + features_filtered, labels_filtered = self.dh.filter_features( + unfiltered_dataframe, + self.dh.training_features_list, + unfiltered_labels, + training_filter=True, + ) # split data into train/test data. data_dictionary = self.dh.make_train_test_datasets(features_filtered, labels_filtered) @@ -55,46 +66,47 @@ class ExamplePredictionModel(IFreqaiModel): data_dictionary = self.dh.standardize_data(data_dictionary) # optional additional data cleaning - if self.feature_parameters['principal_component_analysis']: + if self.feature_parameters["principal_component_analysis"]: self.dh.principal_component_analysis() if self.feature_parameters["remove_outliers"]: self.dh.remove_outliers(predict=False) - if self.feature_parameters['DI_threshold']: - self.dh.data['avg_mean_dist'] = self.dh.compute_distances() + if self.feature_parameters["DI_threshold"]: + self.dh.data["avg_mean_dist"] = self.dh.compute_distances() - print("length of train data", len(data_dictionary['train_features'])) + print("length of train data", len(data_dictionary["train_features"])) model = self.fit(data_dictionary) - print('Finished training') + print("Finished training") print(f'--------------------done training {metadata["pair"]}--------------------') return model def fit(self, data_dictionary: Dict) -> Any: """ - Most regressors use the same function names and arguments e.g. user + Most regressors use the same function names and arguments e.g. user can drop in LGBMRegressor in place of CatBoostRegressor and all data management will be properly handled by Freqai. :params: - :data_dictionary: the dictionary constructed by DataHandler to hold + :data_dictionary: the dictionary constructed by DataHandler to hold all the training and test data/labels. """ train_data = Pool( - data=data_dictionary['train_features'], - label=data_dictionary['train_labels'], - weight=data_dictionary['train_weights'] + data=data_dictionary["train_features"], + label=data_dictionary["train_labels"], + weight=data_dictionary["train_weights"], ) test_data = Pool( - data=data_dictionary['test_features'], - label=data_dictionary['test_labels'], - weight=data_dictionary['test_weights'] + data=data_dictionary["test_features"], + label=data_dictionary["test_labels"], + weight=data_dictionary["test_weights"], ) - model = CatBoostRegressor(verbose=100, early_stopping_rounds=400, - **self.model_training_parameters) + model = CatBoostRegressor( + verbose=100, early_stopping_rounds=400, **self.model_training_parameters + ) model.fit(X=train_data, eval_set=test_data) return model @@ -103,7 +115,7 @@ class ExamplePredictionModel(IFreqaiModel): """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. - :return: + :return: :predictions: np.array of predictions :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove data (NaNs) or felt uncertain about data (PCA and DI index) @@ -112,27 +124,31 @@ class ExamplePredictionModel(IFreqaiModel): print("--------------------Starting prediction--------------------") original_feature_list = self.dh.build_feature_list(self.config) - filtered_dataframe, _ = self.dh.filter_features(unfiltered_dataframe, original_feature_list, training_filter=False) + filtered_dataframe, _ = self.dh.filter_features( + unfiltered_dataframe, original_feature_list, training_filter=False + ) filtered_dataframe = self.dh.standardize_data_from_metadata(filtered_dataframe) - self.dh.data_dictionary['prediction_features'] = filtered_dataframe + self.dh.data_dictionary["prediction_features"] = filtered_dataframe - # optional additional data cleaning - if self.feature_parameters['principal_component_analysis']: + # optional additional data cleaning + if self.feature_parameters["principal_component_analysis"]: pca_components = self.dh.pca.transform(filtered_dataframe) - self.dh.data_dictionary['prediction_features'] = pd.DataFrame(data=pca_components, - columns = ['PC'+str(i) for i in range(0,self.dh.data['n_kept_components'])], - index = filtered_dataframe.index) - + self.dh.data_dictionary["prediction_features"] = pd.DataFrame( + data=pca_components, + columns=["PC" + str(i) for i in range(0, self.dh.data["n_kept_components"])], + index=filtered_dataframe.index, + ) + if self.feature_parameters["remove_outliers"]: - self.dh.remove_outliers(predict=True) # creates dropped index + self.dh.remove_outliers(predict=True) # creates dropped index - if self.feature_parameters['DI_threshold']: - self.dh.check_if_pred_in_training_spaces() # sets do_predict + if self.feature_parameters["DI_threshold"]: + self.dh.check_if_pred_in_training_spaces() # sets do_predict - predictions = self.model.predict(self.dh.data_dictionary['prediction_features']) + predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) # compute the non-standardized predictions - predictions = predictions * self.dh.data['labels_std'] + self.dh.data['labels_mean'] + predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] print("--------------------Finished prediction--------------------") diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index d6b1295ec..873b31115 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -1,61 +1,59 @@ import logging +from functools import reduce + +import numpy as np +import pandas as pd import talib.abstract as ta from pandas import DataFrame -import pandas as pd from technical import qtpylib -import numpy as np -from freqtrade.strategy import (merge_informative_pair) -from freqtrade.strategy.interface import IStrategy + from freqtrade.freqai.strategy_bridge import CustomModel -from functools import reduce +from freqtrade.strategy import merge_informative_pair +from freqtrade.strategy.interface import IStrategy + + logger = logging.getLogger(__name__) + class FreqaiExampleStrategy(IStrategy): """ - Example strategy showing how the user connects their own + Example strategy showing how the user connects their own IFreqaiModel to the strategy. Namely, the user uses: self.model = CustomModel(self.config) self.model.bridge.start(dataframe, metadata) - to make predictions on their data. populate_any_indicators() automatically + to make predictions on their data. populate_any_indicators() automatically generates the variety of features indicated by the user in the canonical freqtrade configuration file under config['freqai']. """ - minimal_roi = { - "0": 0.01, - "240": -1 - } + minimal_roi = {"0": 0.01, "240": -1} plot_config = { - 'main_plot': { + "main_plot": {}, + "subplots": { + "prediction": {"prediction": {"color": "blue"}}, + "target_roi": { + "target_roi": {"color": "brown"}, + }, + "do_predict": { + "do_predict": {"color": "brown"}, + }, }, - 'subplots': { - "prediction":{ - 'prediction':{'color':'blue'} - }, - "target_roi":{ - 'target_roi':{'color':'brown'}, - }, - "do_predict":{ - 'do_predict':{'color':'brown'}, - }, - } } stoploss = -0.05 use_sell_signal = True - startup_candle_count: int = 1000 - + startup_candle_count: int = 1000 def informative_pairs(self): - pairs = self.freqai_info['corr_pairlist'] + pairs = self.freqai_info["corr_pairlist"] informative_pairs = [] for tf in self.timeframes: informative_pairs.append([(pair, tf) for pair in pairs]) return informative_pairs - def populate_any_indicators(self, pair, df, tf, informative=None,coin=''): + def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): """ Function designed to automatically generate, name and merge features from user indicated timeframes in the configuration file. User can add @@ -70,110 +68,116 @@ class FreqaiExampleStrategy(IStrategy): if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) - informative[coin+'rsi'] = ta.RSI(informative, timeperiod=14) - informative[coin+'mfi'] = ta.MFI(informative, timeperiod=25) - informative[coin+'adx'] = ta.ADX(informative, window=20) + informative[coin + "rsi"] = ta.RSI(informative, timeperiod=14) + informative[coin + "mfi"] = ta.MFI(informative, timeperiod=25) + informative[coin + "adx"] = ta.ADX(informative, window=20) - informative[coin+'20sma'] = ta.SMA(informative,timeperiod=20) - informative[coin+'21ema'] = ta.EMA(informative,timeperiod=21) - informative[coin+'bmsb'] = np.where(informative[coin+'20sma'].lt(informative[coin+'21ema']),1,0) - informative[coin+'close_over_20sma'] = informative['close']/informative[coin+'20sma'] + informative[coin + "20sma"] = ta.SMA(informative, timeperiod=20) + informative[coin + "21ema"] = ta.EMA(informative, timeperiod=21) + informative[coin + "bmsb"] = np.where( + informative[coin + "20sma"].lt(informative[coin + "21ema"]), 1, 0 + ) + informative[coin + "close_over_20sma"] = informative["close"] / informative[coin + "20sma"] - informative[coin+'mfi'] = ta.MFI(informative, timeperiod=25) + informative[coin + "mfi"] = ta.MFI(informative, timeperiod=25) - informative[coin+'ema21'] = ta.EMA(informative, timeperiod=21) - informative[coin+'sma20'] = ta.SMA(informative, timeperiod=20) + informative[coin + "ema21"] = ta.EMA(informative, timeperiod=21) + informative[coin + "sma20"] = ta.SMA(informative, timeperiod=20) stoch = ta.STOCHRSI(informative, 15, 20, 2, 2) - informative[coin+'srsi-fk'] = stoch['fastk'] - informative[coin+'srsi-fd'] = stoch['fastd'] + informative[coin + "srsi-fk"] = stoch["fastk"] + informative[coin + "srsi-fd"] = stoch["fastd"] bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=14, stds=2.2) - informative[coin+'bb_lowerband'] = bollinger['lower'] - informative[coin+'bb_middleband'] = bollinger['mid'] - informative[coin+'bb_upperband'] = bollinger['upper'] - informative[coin+'bb_width'] = ((informative[coin+"bb_upperband"] - informative[coin+"bb_lowerband"]) / informative[coin+"bb_middleband"]) - informative[coin+'close-bb_lower'] = informative['close'] / informative[coin+'bb_lowerband'] + informative[coin + "bb_lowerband"] = bollinger["lower"] + informative[coin + "bb_middleband"] = bollinger["mid"] + informative[coin + "bb_upperband"] = bollinger["upper"] + informative[coin + "bb_width"] = ( + informative[coin + "bb_upperband"] - informative[coin + "bb_lowerband"] + ) / informative[coin + "bb_middleband"] + informative[coin + "close-bb_lower"] = ( + informative["close"] / informative[coin + "bb_lowerband"] + ) - informative[coin+'roc'] = ta.ROC(informative, timeperiod=3) - informative[coin+'adx'] = ta.ADX(informative, window=14) + informative[coin + "roc"] = ta.ROC(informative, timeperiod=3) + informative[coin + "adx"] = ta.ADX(informative, window=14) macd = ta.MACD(informative) - informative[coin+'macd'] = macd['macd'] - informative[coin+'pct-change'] = informative['close'].pct_change() - informative[coin+'relative_volume'] = informative['volume'] / informative['volume'].rolling(10).mean() + informative[coin + "macd"] = macd["macd"] + informative[coin + "pct-change"] = informative["close"].pct_change() + informative[coin + "relative_volume"] = ( + informative["volume"] / informative["volume"].rolling(10).mean() + ) - informative[coin+'pct-change'] = informative['close'].pct_change() + informative[coin + "pct-change"] = informative["close"].pct_change() indicators = [col for col in informative if col.startswith(coin)] - for n in range(self.freqai_info['feature_parameters']['shift']+1): - if n==0: continue + for n in range(self.freqai_info["feature_parameters"]["shift"] + 1): + if n == 0: + continue informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix('_shift-'+str(n)) - informative = pd.concat((informative,informative_shift),axis=1) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config['timeframe'], tf, ffill=True) - skip_columns = [(s + '_'+tf) for s in - ['date', 'open', 'high', 'low', 'close', 'volume']] + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [(s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"]] df = df.drop(columns=skip_columns) return df - def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # the configuration file parameters are stored here - self.freqai_info = self.config['freqai'] + self.freqai_info = self.config["freqai"] # the model is instantiated here self.model = CustomModel(self.config) - print('Populating indicators...') + print("Populating indicators...") - # the following loops are necessary for building the features + # the following loops are necessary for building the features # indicated by the user in the configuration file. - for tf in self.freqai_info['timeframes']: - dataframe = self.populate_any_indicators(metadata['pair'], - dataframe.copy(), tf) - for i in self.freqai_info['corr_pairlist']: - dataframe = self.populate_any_indicators(i, - dataframe.copy(), tf, coin=i.split("/")[0]+'-') + for tf in self.freqai_info["timeframes"]: + dataframe = self.populate_any_indicators(metadata["pair"], dataframe.copy(), tf) + for i in self.freqai_info["corr_pairlist"]: + dataframe = self.populate_any_indicators( + i, dataframe.copy(), tf, coin=i.split("/")[0] + "-" + ) - # the model will return 4 values, its prediction, an indication of whether or not the prediction - # should be accepted, the target mean/std values from the labels used during each training period. - (dataframe['prediction'], dataframe['do_predict'], - dataframe['target_mean'], dataframe['target_std']) = self.model.bridge.start(dataframe, metadata) + # the model will return 4 values, its prediction, an indication of whether or not the + # prediction should be accepted, the target mean/std values from the labels used during + # each training period. + ( + dataframe["prediction"], + dataframe["do_predict"], + dataframe["target_mean"], + dataframe["target_std"], + ) = self.model.bridge.start(dataframe, metadata) - dataframe['target_roi'] = dataframe['target_mean']+dataframe['target_std']*0.5 - dataframe['sell_roi'] = dataframe['target_mean']-dataframe['target_std']*1.5 + dataframe["target_roi"] = dataframe["target_mean"] + dataframe["target_std"] * 0.5 + dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] * 1.5 return dataframe - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: buy_conditions = [ - (dataframe['prediction'] > dataframe['target_roi']) - & - (dataframe['do_predict'] == 1) + (dataframe["prediction"] > dataframe["target_roi"]) & (dataframe["do_predict"] == 1) ] if buy_conditions: - dataframe.loc[reduce(lambda x, y: x | y, buy_conditions), 'buy'] = 1 + dataframe.loc[reduce(lambda x, y: x | y, buy_conditions), "buy"] = 1 return dataframe - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # sell_goal = eval('self.'+metadata['pair'].split("/")[0]+'_sell_goal.value') + # sell_goal = eval('self.'+metadata['pair'].split("/")[0]+'_sell_goal.value') sell_conditions = [ - (dataframe['prediction'] < dataframe['sell_roi']) - & - (dataframe['do_predict'] == 1) + (dataframe["prediction"] < dataframe["sell_roi"]) & (dataframe["do_predict"] == 1) ] if sell_conditions: - dataframe.loc[reduce(lambda x, y: x | y, sell_conditions), 'sell'] = 1 + dataframe.loc[reduce(lambda x, y: x | y, sell_conditions), "sell"] = 1 return dataframe def get_ticker_indicator(self): - return int(self.config['timeframe'][:-1]) + return int(self.config["timeframe"][:-1]) From 29c2d1d1891f7e804a133908702f435ff4fd8f32 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 4 May 2022 17:53:40 +0200 Subject: [PATCH 006/308] use logger in favor of print --- freqtrade/freqai/data_handler.py | 23 +++++++++++-------- freqtrade/freqai/freqai_interface.py | 15 ++++++++---- freqtrade/templates/ExamplePredictionModel.py | 18 +++++++++------ 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_handler.py index 7264c6fab..9ab47d223 100644 --- a/freqtrade/freqai/data_handler.py +++ b/freqtrade/freqai/data_handler.py @@ -1,6 +1,7 @@ import copy import datetime import json +import logging import pickle as pk from pathlib import Path from typing import Any, Dict, List, Tuple @@ -17,6 +18,8 @@ from freqtrade.configuration import TimeRange SECONDS_IN_DAY = 86400 +logger = logging.getLogger(__name__) + class DataHandler: """ @@ -175,7 +178,7 @@ class DataHandler: labels = labels[ (drop_index == 0) & (drop_index_labels == 0) ] # assuming the labels depend entirely on the dataframe here. - print( + logger.info( "dropped", len(unfiltered_dataframe) - len(filtered_dataframe), "training data points due to NaNs, ensure you have downloaded", @@ -193,7 +196,7 @@ class DataHandler: # that was based on a single NaN is ultimately protected from buys with do_predict drop_index = ~drop_index self.do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) - print( + logger.info( "dropped", len(self.do_predict) - self.do_predict.sum(), "of", @@ -350,8 +353,8 @@ class DataHandler: pca2 = PCA(n_components=n_keep_components) self.data["n_kept_components"] = n_keep_components pca2 = pca2.fit(self.data_dictionary["train_features"]) - print("reduced feature dimension by", n_components - n_keep_components) - print("explained variance", np.sum(pca2.explained_variance_ratio_)) + logger.info("reduced feature dimension by", n_components - n_keep_components) + logger.info("explained variance", np.sum(pca2.explained_variance_ratio_)) train_components = pca2.transform(self.data_dictionary["train_features"]) test_components = pca2.transform(self.data_dictionary["test_features"]) @@ -377,10 +380,10 @@ class DataHandler: return None def compute_distances(self) -> float: - print("computing average mean distance for all training points") + logger.info("computing average mean distance for all training points") pairwise = pairwise_distances(self.data_dictionary["train_features"], n_jobs=-1) avg_mean_dist = pairwise.mean(axis=1).mean() - print("avg_mean_dist", avg_mean_dist) + logger.info("avg_mean_dist", avg_mean_dist) return avg_mean_dist @@ -407,7 +410,7 @@ class DataHandler: drop_index = ~drop_index do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) - print( + logger.info( "remove_outliers() tossed", len(do_predict) - do_predict.sum(), "predictions because they were beyond 3 std deviations from training data.", @@ -472,7 +475,7 @@ class DataHandler: for p in config["freqai"]["corr_pairlist"]: features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) - print("number of features", len(features)) + logger.info("number of features", len(features)) return features def check_if_pred_in_training_spaces(self) -> None: @@ -483,7 +486,7 @@ class DataHandler: from the training data set. """ - print("checking if prediction features are in AOA") + logger.info("checking if prediction features are in AOA") distance = pairwise_distances( self.data_dictionary["train_features"], self.data_dictionary["prediction_features"], @@ -497,7 +500,7 @@ class DataHandler: 0, ) - print( + logger.info( "Distance checker tossed", len(do_predict) - do_predict.sum(), "predictions for being too far from training data", diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 9f04b09cd..05a0594f3 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -1,6 +1,7 @@ import gc +import logging import shutil -from abc import ABC +from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, Tuple @@ -12,6 +13,7 @@ from freqtrade.freqai.data_handler import DataHandler pd.options.mode.chained_assignment = None +logger = logging.getLogger(__name__) class IFreqaiModel(ABC): @@ -67,7 +69,7 @@ class IFreqaiModel(ABC): self.pair = metadata["pair"] self.dh = DataHandler(self.config, dataframe) - print( + logger.info( "going to train", len(self.dh.training_timeranges), "timeranges:", @@ -88,7 +90,7 @@ class IFreqaiModel(ABC): self.freqai_info["training_timerange"] = tr_train dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) - print("training", self.pair, "for", tr_train) + logger.info("training", self.pair, "for", tr_train) # self.dh.model_path = self.full_path + "/" + "sub-train" + "-" + str(tr_train) + "/" self.dh.model_path = Path(self.full_path / str("sub-train" + "-" + str(tr_train))) if not self.model_exists(self.pair, training_timerange=tr_train): @@ -114,6 +116,7 @@ class IFreqaiModel(ABC): return dataframe + @abstractmethod def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Any: """ Filter the training data and train a model to it. Train makes heavy use of the datahandler @@ -127,6 +130,7 @@ class IFreqaiModel(ABC): return Any + @abstractmethod def fit(self) -> Any: """ Most regressors use the same function names and arguments e.g. user @@ -139,6 +143,7 @@ class IFreqaiModel(ABC): return Any + @abstractmethod def predict(self, dataframe: DataFrame) -> Tuple[np.array, np.array]: """ Filter the prediction features data and predict with it. @@ -162,7 +167,7 @@ class IFreqaiModel(ABC): path_to_modelfile = Path(self.dh.model_path / str(self.dh.model_filename + "_model.joblib")) file_exists = path_to_modelfile.is_file() if file_exists: - print("Found model at", self.dh.model_path / self.dh.model_filename) + logger.info("Found model at", self.dh.model_path / self.dh.model_filename) else: - print("Could not find model at", self.dh.model_path / self.dh.model_filename) + logger.info("Could not find model at", self.dh.model_path / self.dh.model_filename) return file_exists diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index feeed11a9..4906b8c04 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -1,3 +1,4 @@ +import logging from typing import Any, Dict, Tuple import pandas as pd @@ -7,6 +8,9 @@ from pandas import DataFrame from freqtrade.freqai.freqai_interface import IFreqaiModel +logger = logging.getLogger(__name__) + + class ExamplePredictionModel(IFreqaiModel): """ User created prediction model. The class needs to override three necessary @@ -32,7 +36,7 @@ class ExamplePredictionModel(IFreqaiModel): self.dh.data["s_mean"] = dataframe["s"].mean() self.dh.data["s_std"] = dataframe["s"].std() - print("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) + logger.info("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) return dataframe["s"] @@ -46,7 +50,7 @@ class ExamplePredictionModel(IFreqaiModel): :returns: :model: Trained model which can be used to inference (self.predict) """ - print("--------------------Starting training--------------------") + logger.info("--------------------Starting training--------------------") # create the full feature list based on user config info self.dh.training_features_list = self.dh.build_feature_list(self.config) @@ -73,12 +77,12 @@ class ExamplePredictionModel(IFreqaiModel): if self.feature_parameters["DI_threshold"]: self.dh.data["avg_mean_dist"] = self.dh.compute_distances() - print("length of train data", len(data_dictionary["train_features"])) + logger.info("length of train data", len(data_dictionary["train_features"])) model = self.fit(data_dictionary) - print("Finished training") - print(f'--------------------done training {metadata["pair"]}--------------------') + logger.info("Finished training") + logger.info(f'--------------------done training {metadata["pair"]}--------------------') return model @@ -121,7 +125,7 @@ class ExamplePredictionModel(IFreqaiModel): data (NaNs) or felt uncertain about data (PCA and DI index) """ - print("--------------------Starting prediction--------------------") + logger.info("--------------------Starting prediction--------------------") original_feature_list = self.dh.build_feature_list(self.config) filtered_dataframe, _ = self.dh.filter_features( @@ -150,6 +154,6 @@ class ExamplePredictionModel(IFreqaiModel): # compute the non-standardized predictions predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] - print("--------------------Finished prediction--------------------") + logger.info("--------------------Finished prediction--------------------") return (predictions, self.dh.do_predict) From 764f9449b428be8b744ebea989ee81b81330aae9 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 5 May 2022 14:37:37 +0200 Subject: [PATCH 007/308] fix logger, debug some flake8 appeasements --- freqtrade/constants.py | 837 ++++++++++-------- freqtrade/freqai/data_handler.py | 29 +- freqtrade/freqai/freqai_interface.py | 15 +- freqtrade/optimize/backtesting.py | 8 +- freqtrade/templates/ExamplePredictionModel.py | 5 +- 5 files changed, 479 insertions(+), 415 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index f8a9dc06d..d9664cff8 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -8,88 +8,133 @@ from typing import List, Literal, Tuple from freqtrade.enums import CandleType -DEFAULT_CONFIG = 'config.json' -DEFAULT_EXCHANGE = 'bittrex' +DEFAULT_CONFIG = "config.json" +DEFAULT_EXCHANGE = "bittrex" PROCESS_THROTTLE_SECS = 5 # sec HYPEROPT_EPOCH = 100 # epochs RETRY_TIMEOUT = 30 # sec -TIMEOUT_UNITS = ['minutes', 'seconds'] -EXPORT_OPTIONS = ['none', 'trades', 'signals'] -DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite' -DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite' -UNLIMITED_STAKE_AMOUNT = 'unlimited' +TIMEOUT_UNITS = ["minutes", "seconds"] +EXPORT_OPTIONS = ["none", "trades", "signals"] +DEFAULT_DB_PROD_URL = "sqlite:///tradesv3.sqlite" +DEFAULT_DB_DRYRUN_URL = "sqlite:///tradesv3.dryrun.sqlite" +UNLIMITED_STAKE_AMOUNT = "unlimited" DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05 -REQUIRED_ORDERTIF = ['entry', 'exit'] -REQUIRED_ORDERTYPES = ['entry', 'exit', 'stoploss', 'stoploss_on_exchange'] -PRICING_SIDES = ['ask', 'bid', 'same', 'other'] -ORDERTYPE_POSSIBILITIES = ['limit', 'market'] -ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] -HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss', - 'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily', - 'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily', - 'CalmarHyperOptLoss', - 'MaxDrawDownHyperOptLoss', 'MaxDrawDownRelativeHyperOptLoss', - 'ProfitDrawDownHyperOptLoss'] -AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', - 'AgeFilter', 'OffsetFilter', 'PerformanceFilter', - 'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter', - 'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter'] -AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard'] -AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5'] -BACKTEST_BREAKDOWNS = ['day', 'week', 'month'] -BACKTEST_CACHE_AGE = ['none', 'day', 'week', 'month'] -BACKTEST_CACHE_DEFAULT = 'day' +REQUIRED_ORDERTIF = ["entry", "exit"] +REQUIRED_ORDERTYPES = ["entry", "exit", "stoploss", "stoploss_on_exchange"] +PRICING_SIDES = ["ask", "bid", "same", "other"] +ORDERTYPE_POSSIBILITIES = ["limit", "market"] +ORDERTIF_POSSIBILITIES = ["gtc", "fok", "ioc"] +HYPEROPT_LOSS_BUILTIN = [ + "ShortTradeDurHyperOptLoss", + "OnlyProfitHyperOptLoss", + "SharpeHyperOptLoss", + "SharpeHyperOptLossDaily", + "SortinoHyperOptLoss", + "SortinoHyperOptLossDaily", + "CalmarHyperOptLoss", + "MaxDrawDownHyperOptLoss", + "MaxDrawDownRelativeHyperOptLoss", + "ProfitDrawDownHyperOptLoss", +] +AVAILABLE_PAIRLISTS = [ + "StaticPairList", + "VolumePairList", + "AgeFilter", + "OffsetFilter", + "PerformanceFilter", + "PrecisionFilter", + "PriceFilter", + "RangeStabilityFilter", + "ShuffleFilter", + "SpreadFilter", + "VolatilityFilter", +] +AVAILABLE_PROTECTIONS = ["CooldownPeriod", "LowProfitPairs", "MaxDrawdown", "StoplossGuard"] +AVAILABLE_DATAHANDLERS = ["json", "jsongz", "hdf5"] +BACKTEST_BREAKDOWNS = ["day", "week", "month"] +BACKTEST_CACHE_AGE = ["none", "day", "week", "month"] +BACKTEST_CACHE_DEFAULT = "day" DRY_RUN_WALLET = 1000 -DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S' +DATETIME_PRINT_FORMAT = "%Y-%m-%d %H:%M:%S" MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons -DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume'] +DEFAULT_DATAFRAME_COLUMNS = ["date", "open", "high", "low", "close", "volume"] # Don't modify sequence of DEFAULT_TRADES_COLUMNS # it has wide consequences for stored trades files -DEFAULT_TRADES_COLUMNS = ['timestamp', 'id', 'type', 'side', 'price', 'amount', 'cost'] -TRADING_MODES = ['spot', 'margin', 'futures'] -MARGIN_MODES = ['cross', 'isolated', ''] +DEFAULT_TRADES_COLUMNS = ["timestamp", "id", "type", "side", "price", "amount", "cost"] +TRADING_MODES = ["spot", "margin", "futures"] +MARGIN_MODES = ["cross", "isolated", ""] -LAST_BT_RESULT_FN = '.last_result.json' -FTHYPT_FILEVERSION = 'fthypt_fileversion' +LAST_BT_RESULT_FN = ".last_result.json" +FTHYPT_FILEVERSION = "fthypt_fileversion" -USERPATH_HYPEROPTS = 'hyperopts' -USERPATH_STRATEGIES = 'strategies' -USERPATH_NOTEBOOKS = 'notebooks' -USERPATH_FREQAIMODELS = 'freqaimodels' +USERPATH_HYPEROPTS = "hyperopts" +USERPATH_STRATEGIES = "strategies" +USERPATH_NOTEBOOKS = "notebooks" +USERPATH_FREQAIMODELS = "freqaimodels" -TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent'] -WEBHOOK_FORMAT_OPTIONS = ['form', 'json', 'raw'] +TELEGRAM_SETTING_OPTIONS = ["on", "off", "silent"] +WEBHOOK_FORMAT_OPTIONS = ["form", "json", "raw"] -ENV_VAR_PREFIX = 'FREQTRADE__' +ENV_VAR_PREFIX = "FREQTRADE__" -NON_OPEN_EXCHANGE_STATES = ('cancelled', 'canceled', 'closed', 'expired') +NON_OPEN_EXCHANGE_STATES = ("cancelled", "canceled", "closed", "expired") # Define decimals per coin for outputs # Only used for outputs. DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's DECIMALS_PER_COIN = { - 'BTC': 8, - 'ETH': 5, + "BTC": 8, + "ETH": 5, } -DUST_PER_COIN = { - 'BTC': 0.0001, - 'ETH': 0.01 -} +DUST_PER_COIN = {"BTC": 0.0001, "ETH": 0.01} # Source files with destination directories within user-directory USER_DATA_FILES = { - 'sample_strategy.py': USERPATH_STRATEGIES, - 'sample_hyperopt_loss.py': USERPATH_HYPEROPTS, - 'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS, + "sample_strategy.py": USERPATH_STRATEGIES, + "sample_hyperopt_loss.py": USERPATH_HYPEROPTS, + "strategy_analysis_example.ipynb": USERPATH_NOTEBOOKS, } SUPPORTED_FIAT = [ - "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", - "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY", - "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", - "RUB", "UAH", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", - "USD", "BTC", "ETH", "XRP", "LTC", "BCH" + "AUD", + "BRL", + "CAD", + "CHF", + "CLP", + "CNY", + "CZK", + "DKK", + "EUR", + "GBP", + "HKD", + "HUF", + "IDR", + "ILS", + "INR", + "JPY", + "KRW", + "MXN", + "MYR", + "NOK", + "NZD", + "PHP", + "PKR", + "PLN", + "RUB", + "UAH", + "SEK", + "SGD", + "THB", + "TRY", + "TWD", + "ZAR", + "USD", + "BTC", + "ETH", + "XRP", + "LTC", + "BCH", ] MINIMAL_CONFIG = { @@ -100,380 +145,416 @@ MINIMAL_CONFIG = { "key": "", "secret": "", "pair_whitelist": [], - "ccxt_async_config": { - } - } + "ccxt_async_config": {}, + }, } # Required json-schema for user specified config CONF_SCHEMA = { - 'type': 'object', - 'properties': { - 'max_open_trades': {'type': ['integer', 'number'], 'minimum': -1}, - 'new_pairs_days': {'type': 'integer', 'default': 30}, - 'timeframe': {'type': 'string'}, - 'stake_currency': {'type': 'string'}, - 'stake_amount': { - 'type': ['number', 'string'], - 'minimum': 0.0001, - 'pattern': UNLIMITED_STAKE_AMOUNT + "type": "object", + "properties": { + "max_open_trades": {"type": ["integer", "number"], "minimum": -1}, + "new_pairs_days": {"type": "integer", "default": 30}, + "timeframe": {"type": "string"}, + "stake_currency": {"type": "string"}, + "stake_amount": { + "type": ["number", "string"], + "minimum": 0.0001, + "pattern": UNLIMITED_STAKE_AMOUNT, }, - 'tradable_balance_ratio': { - 'type': 'number', - 'minimum': 0.0, - 'maximum': 1, - 'default': 0.99 + "tradable_balance_ratio": {"type": "number", "minimum": 0.0, "maximum": 1, "default": 0.99}, + "available_capital": { + "type": "number", + "minimum": 0, }, - 'available_capital': { - 'type': 'number', - 'minimum': 0, + "amend_last_stake_amount": {"type": "boolean", "default": False}, + "last_stake_amount_min_ratio": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "default": 0.5, }, - 'amend_last_stake_amount': {'type': 'boolean', 'default': False}, - 'last_stake_amount_min_ratio': { - 'type': 'number', 'minimum': 0.0, 'maximum': 1.0, 'default': 0.5 + "fiat_display_currency": {"type": "string", "enum": SUPPORTED_FIAT}, + "dry_run": {"type": "boolean"}, + "dry_run_wallet": {"type": "number", "default": DRY_RUN_WALLET}, + "cancel_open_orders_on_exit": {"type": "boolean", "default": False}, + "process_only_new_candles": {"type": "boolean"}, + "minimal_roi": { + "type": "object", + "patternProperties": {"^[0-9.]+$": {"type": "number"}}, + "minProperties": 1, }, - 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, - 'dry_run': {'type': 'boolean'}, - 'dry_run_wallet': {'type': 'number', 'default': DRY_RUN_WALLET}, - 'cancel_open_orders_on_exit': {'type': 'boolean', 'default': False}, - 'process_only_new_candles': {'type': 'boolean'}, - 'minimal_roi': { - 'type': 'object', - 'patternProperties': { - '^[0-9.]+$': {'type': 'number'} + "amount_reserve_percent": {"type": "number", "minimum": 0.0, "maximum": 0.5}, + "stoploss": {"type": "number", "maximum": 0, "exclusiveMaximum": True, "minimum": -1}, + "trailing_stop": {"type": "boolean"}, + "trailing_stop_positive": {"type": "number", "minimum": 0, "maximum": 1}, + "trailing_stop_positive_offset": {"type": "number", "minimum": 0, "maximum": 1}, + "trailing_only_offset_is_reached": {"type": "boolean"}, + "use_exit_signal": {"type": "boolean"}, + "exit_profit_only": {"type": "boolean"}, + "exit_profit_offset": {"type": "number"}, + "ignore_roi_if_entry_signal": {"type": "boolean"}, + "ignore_buying_expired_candle_after": {"type": "number"}, + "trading_mode": {"type": "string", "enum": TRADING_MODES}, + "margin_mode": {"type": "string", "enum": MARGIN_MODES}, + "liquidation_buffer": {"type": "number", "minimum": 0.0, "maximum": 0.99}, + "backtest_breakdown": { + "type": "array", + "items": {"type": "string", "enum": BACKTEST_BREAKDOWNS}, + }, + "bot_name": {"type": "string"}, + "unfilledtimeout": { + "type": "object", + "properties": { + "entry": {"type": "number", "minimum": 1}, + "exit": {"type": "number", "minimum": 1}, + "exit_timeout_count": {"type": "number", "minimum": 0, "default": 0}, + "unit": {"type": "string", "enum": TIMEOUT_UNITS, "default": "minutes"}, }, - 'minProperties': 1 }, - 'amount_reserve_percent': {'type': 'number', 'minimum': 0.0, 'maximum': 0.5}, - 'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True, 'minimum': -1}, - 'trailing_stop': {'type': 'boolean'}, - 'trailing_stop_positive': {'type': 'number', 'minimum': 0, 'maximum': 1}, - 'trailing_stop_positive_offset': {'type': 'number', 'minimum': 0, 'maximum': 1}, - 'trailing_only_offset_is_reached': {'type': 'boolean'}, - 'use_exit_signal': {'type': 'boolean'}, - 'exit_profit_only': {'type': 'boolean'}, - 'exit_profit_offset': {'type': 'number'}, - 'ignore_roi_if_entry_signal': {'type': 'boolean'}, - 'ignore_buying_expired_candle_after': {'type': 'number'}, - 'trading_mode': {'type': 'string', 'enum': TRADING_MODES}, - 'margin_mode': {'type': 'string', 'enum': MARGIN_MODES}, - 'liquidation_buffer': {'type': 'number', 'minimum': 0.0, 'maximum': 0.99}, - 'backtest_breakdown': { - 'type': 'array', - 'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS} - }, - 'bot_name': {'type': 'string'}, - 'unfilledtimeout': { - 'type': 'object', - 'properties': { - 'entry': {'type': 'number', 'minimum': 1}, - 'exit': {'type': 'number', 'minimum': 1}, - 'exit_timeout_count': {'type': 'number', 'minimum': 0, 'default': 0}, - 'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'} - } - }, - 'entry_pricing': { - 'type': 'object', - 'properties': { - 'price_last_balance': { - 'type': 'number', - 'minimum': 0, - 'maximum': 1, - 'exclusiveMaximum': False, + "entry_pricing": { + "type": "object", + "properties": { + "price_last_balance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "exclusiveMaximum": False, }, - 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'}, - 'use_order_book': {'type': 'boolean'}, - 'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, }, - 'check_depth_of_market': { - 'type': 'object', - 'properties': { - 'enabled': {'type': 'boolean'}, - 'bids_to_ask_delta': {'type': 'number', 'minimum': 0}, - } + "price_side": {"type": "string", "enum": PRICING_SIDES, "default": "same"}, + "use_order_book": {"type": "boolean"}, + "order_book_top": { + "type": "integer", + "minimum": 1, + "maximum": 50, + }, + "check_depth_of_market": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "bids_to_ask_delta": {"type": "number", "minimum": 0}, + }, }, }, - 'required': ['price_side'] + "required": ["price_side"], }, - 'exit_pricing': { - 'type': 'object', - 'properties': { - 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'}, - 'price_last_balance': { - 'type': 'number', - 'minimum': 0, - 'maximum': 1, - 'exclusiveMaximum': False, + "exit_pricing": { + "type": "object", + "properties": { + "price_side": {"type": "string", "enum": PRICING_SIDES, "default": "same"}, + "price_last_balance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "exclusiveMaximum": False, }, - 'use_order_book': {'type': 'boolean'}, - 'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, }, - }, - 'required': ['price_side'] - }, - 'custom_price_max_distance_ratio': { - 'type': 'number', 'minimum': 0.0 - }, - 'order_types': { - 'type': 'object', - 'properties': { - 'entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, - 'exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, - 'force_exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, - 'force_entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, - 'emergency_exit': { - 'type': 'string', - 'enum': ORDERTYPE_POSSIBILITIES, - 'default': 'market'}, - 'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, - 'stoploss_on_exchange': {'type': 'boolean'}, - 'stoploss_on_exchange_interval': {'type': 'number'}, - 'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0, - 'maximum': 1.0} - }, - 'required': ['entry', 'exit', 'stoploss', 'stoploss_on_exchange'] - }, - 'order_time_in_force': { - 'type': 'object', - 'properties': { - 'entry': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}, - 'exit': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES} - }, - 'required': REQUIRED_ORDERTIF - }, - 'exchange': {'$ref': '#/definitions/exchange'}, - 'edge': {'$ref': '#/definitions/edge'}, - 'experimental': { - 'type': 'object', - 'properties': { - 'block_bad_exchanges': {'type': 'boolean'} - } - }, - 'pairlists': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'method': {'type': 'string', 'enum': AVAILABLE_PAIRLISTS}, + "use_order_book": {"type": "boolean"}, + "order_book_top": { + "type": "integer", + "minimum": 1, + "maximum": 50, }, - 'required': ['method'], - } + }, + "required": ["price_side"], }, - 'protections': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'method': {'type': 'string', 'enum': AVAILABLE_PROTECTIONS}, - 'stop_duration': {'type': 'number', 'minimum': 0.0}, - 'stop_duration_candles': {'type': 'number', 'minimum': 0}, - 'trade_limit': {'type': 'number', 'minimum': 1}, - 'lookback_period': {'type': 'number', 'minimum': 1}, - 'lookback_period_candles': {'type': 'number', 'minimum': 1}, + "custom_price_max_distance_ratio": {"type": "number", "minimum": 0.0}, + "order_types": { + "type": "object", + "properties": { + "entry": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, + "exit": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, + "force_exit": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, + "force_entry": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, + "emergency_exit": { + "type": "string", + "enum": ORDERTYPE_POSSIBILITIES, + "default": "market", }, - 'required': ['method'], - } + "stoploss": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, + "stoploss_on_exchange": {"type": "boolean"}, + "stoploss_on_exchange_interval": {"type": "number"}, + "stoploss_on_exchange_limit_ratio": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + }, + }, + "required": ["entry", "exit", "stoploss", "stoploss_on_exchange"], }, - 'telegram': { - 'type': 'object', - 'properties': { - 'enabled': {'type': 'boolean'}, - 'token': {'type': 'string'}, - 'chat_id': {'type': 'string'}, - 'balance_dust_level': {'type': 'number', 'minimum': 0.0}, - 'notification_settings': { - 'type': 'object', - 'default': {}, - 'properties': { - 'status': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, - 'warning': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, - 'startup': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, - 'entry': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, - 'entry_cancel': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, - 'entry_fill': {'type': 'string', - 'enum': TELEGRAM_SETTING_OPTIONS, - 'default': 'off' - }, - 'exit': { - 'type': ['string', 'object'], - 'additionalProperties': { - 'type': 'string', - 'enum': TELEGRAM_SETTING_OPTIONS - } + "order_time_in_force": { + "type": "object", + "properties": { + "entry": {"type": "string", "enum": ORDERTIF_POSSIBILITIES}, + "exit": {"type": "string", "enum": ORDERTIF_POSSIBILITIES}, + }, + "required": REQUIRED_ORDERTIF, + }, + "exchange": {"$ref": "#/definitions/exchange"}, + "edge": {"$ref": "#/definitions/edge"}, + "experimental": { + "type": "object", + "properties": {"block_bad_exchanges": {"type": "boolean"}}, + }, + "pairlists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "method": {"type": "string", "enum": AVAILABLE_PAIRLISTS}, + }, + "required": ["method"], + }, + }, + "protections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "method": {"type": "string", "enum": AVAILABLE_PROTECTIONS}, + "stop_duration": {"type": "number", "minimum": 0.0}, + "stop_duration_candles": {"type": "number", "minimum": 0}, + "trade_limit": {"type": "number", "minimum": 1}, + "lookback_period": {"type": "number", "minimum": 1}, + "lookback_period_candles": {"type": "number", "minimum": 1}, + }, + "required": ["method"], + }, + }, + "telegram": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "token": {"type": "string"}, + "chat_id": {"type": "string"}, + "balance_dust_level": {"type": "number", "minimum": 0.0}, + "notification_settings": { + "type": "object", + "default": {}, + "properties": { + "status": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, + "warning": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, + "startup": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, + "entry": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, + "entry_cancel": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, + "entry_fill": { + "type": "string", + "enum": TELEGRAM_SETTING_OPTIONS, + "default": "off", }, - 'exit_cancel': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, - 'exit_fill': { - 'type': 'string', - 'enum': TELEGRAM_SETTING_OPTIONS, - 'default': 'off' + "exit": { + "type": ["string", "object"], + "additionalProperties": { + "type": "string", + "enum": TELEGRAM_SETTING_OPTIONS, + }, }, - 'protection_trigger': { - 'type': 'string', - 'enum': TELEGRAM_SETTING_OPTIONS, - 'default': 'off' + "exit_cancel": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, + "exit_fill": { + "type": "string", + "enum": TELEGRAM_SETTING_OPTIONS, + "default": "off", }, - 'protection_trigger_global': { - 'type': 'string', - 'enum': TELEGRAM_SETTING_OPTIONS, + "protection_trigger": { + "type": "string", + "enum": TELEGRAM_SETTING_OPTIONS, + "default": "off", }, - } + "protection_trigger_global": { + "type": "string", + "enum": TELEGRAM_SETTING_OPTIONS, + }, + }, }, - 'reload': {'type': 'boolean'}, + "reload": {"type": "boolean"}, }, - 'required': ['enabled', 'token', 'chat_id'], + "required": ["enabled", "token", "chat_id"], }, - 'webhook': { - 'type': 'object', - 'properties': { - 'enabled': {'type': 'boolean'}, - 'url': {'type': 'string'}, - 'format': {'type': 'string', 'enum': WEBHOOK_FORMAT_OPTIONS, 'default': 'form'}, - 'retries': {'type': 'integer', 'minimum': 0}, - 'retry_delay': {'type': 'number', 'minimum': 0}, - 'webhookentry': {'type': 'object'}, - 'webhookentrycancel': {'type': 'object'}, - 'webhookentryfill': {'type': 'object'}, - 'webhookexit': {'type': 'object'}, - 'webhookexitcancel': {'type': 'object'}, - 'webhookexitfill': {'type': 'object'}, - 'webhookstatus': {'type': 'object'}, + "webhook": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "url": {"type": "string"}, + "format": {"type": "string", "enum": WEBHOOK_FORMAT_OPTIONS, "default": "form"}, + "retries": {"type": "integer", "minimum": 0}, + "retry_delay": {"type": "number", "minimum": 0}, + "webhookentry": {"type": "object"}, + "webhookentrycancel": {"type": "object"}, + "webhookentryfill": {"type": "object"}, + "webhookexit": {"type": "object"}, + "webhookexitcancel": {"type": "object"}, + "webhookexitfill": {"type": "object"}, + "webhookstatus": {"type": "object"}, }, }, - 'api_server': { - 'type': 'object', - 'properties': { - 'enabled': {'type': 'boolean'}, - 'listen_ip_address': {'format': 'ipv4'}, - 'listen_port': { - 'type': 'integer', - 'minimum': 1024, - 'maximum': 65535 - }, - 'username': {'type': 'string'}, - 'password': {'type': 'string'}, - 'jwt_secret_key': {'type': 'string'}, - 'CORS_origins': {'type': 'array', 'items': {'type': 'string'}}, - 'verbosity': {'type': 'string', 'enum': ['error', 'info']}, + "api_server": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "listen_ip_address": {"format": "ipv4"}, + "listen_port": {"type": "integer", "minimum": 1024, "maximum": 65535}, + "username": {"type": "string"}, + "password": {"type": "string"}, + "jwt_secret_key": {"type": "string"}, + "CORS_origins": {"type": "array", "items": {"type": "string"}}, + "verbosity": {"type": "string", "enum": ["error", "info"]}, }, - 'required': ['enabled', 'listen_ip_address', 'listen_port', 'username', 'password'] + "required": ["enabled", "listen_ip_address", "listen_port", "username", "password"], }, - 'db_url': {'type': 'string'}, - 'export': {'type': 'string', 'enum': EXPORT_OPTIONS, 'default': 'trades'}, - 'disableparamexport': {'type': 'boolean'}, - 'initial_state': {'type': 'string', 'enum': ['running', 'stopped']}, - 'force_entry_enable': {'type': 'boolean'}, - 'disable_dataframe_checks': {'type': 'boolean'}, - 'internals': { - 'type': 'object', - 'default': {}, - 'properties': { - 'process_throttle_secs': {'type': 'integer'}, - 'interval': {'type': 'integer'}, - 'sd_notify': {'type': 'boolean'}, - } + "db_url": {"type": "string"}, + "export": {"type": "string", "enum": EXPORT_OPTIONS, "default": "trades"}, + "disableparamexport": {"type": "boolean"}, + "initial_state": {"type": "string", "enum": ["running", "stopped"]}, + "force_entry_enable": {"type": "boolean"}, + "disable_dataframe_checks": {"type": "boolean"}, + "internals": { + "type": "object", + "default": {}, + "properties": { + "process_throttle_secs": {"type": "integer"}, + "interval": {"type": "integer"}, + "sd_notify": {"type": "boolean"}, + }, }, - 'dataformat_ohlcv': { - 'type': 'string', - 'enum': AVAILABLE_DATAHANDLERS, - 'default': 'json' + "dataformat_ohlcv": {"type": "string", "enum": AVAILABLE_DATAHANDLERS, "default": "json"}, + "dataformat_trades": { + "type": "string", + "enum": AVAILABLE_DATAHANDLERS, + "default": "jsongz", }, - 'dataformat_trades': { - 'type': 'string', - 'enum': AVAILABLE_DATAHANDLERS, - 'default': 'jsongz' - }, - 'position_adjustment_enable': {'type': 'boolean'}, - 'max_entry_position_adjustment': {'type': ['integer', 'number'], 'minimum': -1}, + "position_adjustment_enable": {"type": "boolean"}, + "max_entry_position_adjustment": {"type": ["integer", "number"], "minimum": -1}, }, - 'definitions': { - 'exchange': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'sandbox': {'type': 'boolean', 'default': False}, - 'key': {'type': 'string', 'default': ''}, - 'secret': {'type': 'string', 'default': ''}, - 'password': {'type': 'string', 'default': ''}, - 'uid': {'type': 'string'}, - 'pair_whitelist': { - 'type': 'array', - 'items': { - 'type': 'string', + "definitions": { + "exchange": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "sandbox": {"type": "boolean", "default": False}, + "key": {"type": "string", "default": ""}, + "secret": {"type": "string", "default": ""}, + "password": {"type": "string", "default": ""}, + "uid": {"type": "string"}, + "pair_whitelist": { + "type": "array", + "items": { + "type": "string", }, - 'uniqueItems': True + "uniqueItems": True, }, - 'pair_blacklist': { - 'type': 'array', - 'items': { - 'type': 'string', + "pair_blacklist": { + "type": "array", + "items": { + "type": "string", }, - 'uniqueItems': True + "uniqueItems": True, }, - 'unknown_fee_rate': {'type': 'number'}, - 'outdated_offset': {'type': 'integer', 'minimum': 1}, - 'markets_refresh_interval': {'type': 'integer'}, - 'ccxt_config': {'type': 'object'}, - 'ccxt_async_config': {'type': 'object'} + "unknown_fee_rate": {"type": "number"}, + "outdated_offset": {"type": "integer", "minimum": 1}, + "markets_refresh_interval": {"type": "integer"}, + "ccxt_config": {"type": "object"}, + "ccxt_async_config": {"type": "object"}, }, - 'required': ['name'] + "required": ["name"], }, - 'edge': { - 'type': 'object', - 'properties': { - 'enabled': {'type': 'boolean'}, - 'process_throttle_secs': {'type': 'integer', 'minimum': 600}, - 'calculate_since_number_of_days': {'type': 'integer'}, - 'allowed_risk': {'type': 'number'}, - 'stoploss_range_min': {'type': 'number'}, - 'stoploss_range_max': {'type': 'number'}, - 'stoploss_range_step': {'type': 'number'}, - 'minimum_winrate': {'type': 'number'}, - 'minimum_expectancy': {'type': 'number'}, - 'min_trade_number': {'type': 'number'}, - 'max_trade_duration_minute': {'type': 'integer'}, - 'remove_pumps': {'type': 'boolean'} + "edge": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "process_throttle_secs": {"type": "integer", "minimum": 600}, + "calculate_since_number_of_days": {"type": "integer"}, + "allowed_risk": {"type": "number"}, + "stoploss_range_min": {"type": "number"}, + "stoploss_range_max": {"type": "number"}, + "stoploss_range_step": {"type": "number"}, + "minimum_winrate": {"type": "number"}, + "minimum_expectancy": {"type": "number"}, + "min_trade_number": {"type": "number"}, + "max_trade_duration_minute": {"type": "integer"}, + "remove_pumps": {"type": "boolean"}, }, - 'required': ['process_throttle_secs', 'allowed_risk'] - } + "required": ["process_throttle_secs", "allowed_risk"], + }, + "freqai": { + "type": "object", + "properties": { + "timeframes": {"type": "list"}, + "full_timerange": {"type": "str"}, + "train_period": {"type": "integer", "default": 0}, + "backtest_period": {"type": "integer", "default": 7}, + "identifier": {"type": "str", "default": "example"}, + "base_features": {"type": "list"}, + "corr_pairlist": {"type": "list"}, + "training_timerange": {"type": "string", "default": None}, + "feature_parameters": { + "type": "object", + "properties": { + "period": {"type": "integer"}, + "shift": {"type": "integer", "default": 0}, + "DI_threshold": {"type": "integer", "default": 0}, + "weight_factor": {"type": "number", "default": 0}, + "principal_component_analysis": {"type": "boolean", "default": False}, + "remove_outliers": {"type": "boolean", "default": False}, + }, + }, + "data_split_parameters": { + "type": "object", + "properties": { + "test_size": {"type": "number"}, + "random_state": {"type": "integer"}, + }, + }, + "model_training_parameters": { + "type": "object", + "properties": { + "n_estimators": {"type": "integer", "default": 2000}, + "random_state": {"type": "integer", "default": 1}, + "learning_rate": {"type": "number", "default": 0.02}, + "task_type": {"type": "string", "default": "CPU"}, + }, + }, + }, + }, }, } SCHEMA_TRADE_REQUIRED = [ - 'exchange', - 'timeframe', - 'max_open_trades', - 'stake_currency', - 'stake_amount', - 'tradable_balance_ratio', - 'last_stake_amount_min_ratio', - 'dry_run', - 'dry_run_wallet', - 'exit_pricing', - 'entry_pricing', - 'stoploss', - 'minimal_roi', - 'internals', - 'dataformat_ohlcv', - 'dataformat_trades', + "exchange", + "timeframe", + "max_open_trades", + "stake_currency", + "stake_amount", + "tradable_balance_ratio", + "last_stake_amount_min_ratio", + "dry_run", + "dry_run_wallet", + "exit_pricing", + "entry_pricing", + "stoploss", + "minimal_roi", + "internals", + "dataformat_ohlcv", + "dataformat_trades", ] SCHEMA_BACKTEST_REQUIRED = [ - 'exchange', - 'max_open_trades', - 'stake_currency', - 'stake_amount', - 'dry_run_wallet', - 'dataformat_ohlcv', - 'dataformat_trades', + "exchange", + "max_open_trades", + "stake_currency", + "stake_amount", + "dry_run_wallet", + "dataformat_ohlcv", + "dataformat_trades", ] SCHEMA_BACKTEST_REQUIRED_FINAL = SCHEMA_BACKTEST_REQUIRED + [ - 'stoploss', - 'minimal_roi', + "stoploss", + "minimal_roi", ] SCHEMA_MINIMAL_REQUIRED = [ - 'exchange', - 'dry_run', - 'dataformat_ohlcv', - 'dataformat_trades', + "exchange", + "dry_run", + "dataformat_ohlcv", + "dataformat_trades", ] CANCEL_REASON = { diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_handler.py index 9ab47d223..94df869a1 100644 --- a/freqtrade/freqai/data_handler.py +++ b/freqtrade/freqai/data_handler.py @@ -36,6 +36,7 @@ class DataHandler: config["freqai"]["backtest_period"], ) self.data: Dict[Any, Any] = {} + self.data_dictionary: Dict[Any, Any] = {} self.config = config self.freq_config = config["freqai"] self.predictions = np.array([]) @@ -58,10 +59,6 @@ class DataHandler: save_path = Path(self.model_path) - # if not os.path.exists(self.model_path): - # os.mkdir(self.model_path) - # save_path = self.model_path + self.model_filename - # Save the trained model dump(model, save_path / str(self.model_filename + "_model.joblib")) self.data["model_path"] = self.model_path @@ -179,10 +176,8 @@ class DataHandler: (drop_index == 0) & (drop_index_labels == 0) ] # assuming the labels depend entirely on the dataframe here. logger.info( - "dropped", + "dropped %s training points due to NaNs, ensure all historical data downloaded", len(unfiltered_dataframe) - len(filtered_dataframe), - "training data points due to NaNs, ensure you have downloaded", - "all historical training data", ) self.data["filter_drop_index_training"] = drop_index @@ -197,12 +192,9 @@ class DataHandler: drop_index = ~drop_index self.do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) logger.info( - "dropped", + "dropped %s of %s prediction data points due to NaNs.", len(self.do_predict) - self.do_predict.sum(), - "of", len(filtered_dataframe), - "prediction data points due to NaNs. These are protected from prediction", - "with do_predict vector returned to strategy.", ) return filtered_dataframe, labels @@ -353,8 +345,8 @@ class DataHandler: pca2 = PCA(n_components=n_keep_components) self.data["n_kept_components"] = n_keep_components pca2 = pca2.fit(self.data_dictionary["train_features"]) - logger.info("reduced feature dimension by", n_components - n_keep_components) - logger.info("explained variance", np.sum(pca2.explained_variance_ratio_)) + logger.info("reduced feature dimension by %s", n_components - n_keep_components) + logger.info("explained variance %f", np.sum(pca2.explained_variance_ratio_)) train_components = pca2.transform(self.data_dictionary["train_features"]) test_components = pca2.transform(self.data_dictionary["test_features"]) @@ -383,7 +375,7 @@ class DataHandler: logger.info("computing average mean distance for all training points") pairwise = pairwise_distances(self.data_dictionary["train_features"], n_jobs=-1) avg_mean_dist = pairwise.mean(axis=1).mean() - logger.info("avg_mean_dist", avg_mean_dist) + logger.info("avg_mean_dist %s", avg_mean_dist) return avg_mean_dist @@ -411,9 +403,8 @@ class DataHandler: do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) logger.info( - "remove_outliers() tossed", + "remove_outliers() tossed %s predictions", len(do_predict) - do_predict.sum(), - "predictions because they were beyond 3 std deviations from training data.", ) self.do_predict += do_predict self.do_predict -= 1 @@ -475,7 +466,7 @@ class DataHandler: for p in config["freqai"]["corr_pairlist"]: features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) - logger.info("number of features", len(features)) + logger.info("number of features %s", len(features)) return features def check_if_pred_in_training_spaces(self) -> None: @@ -486,7 +477,6 @@ class DataHandler: from the training data set. """ - logger.info("checking if prediction features are in AOA") distance = pairwise_distances( self.data_dictionary["train_features"], self.data_dictionary["prediction_features"], @@ -501,9 +491,8 @@ class DataHandler: ) logger.info( - "Distance checker tossed", + "Distance checker tossed %s predictions for being too far from training data", len(do_predict) - do_predict.sum(), - "predictions for being too far from training data", ) self.do_predict += do_predict diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 05a0594f3..368ed1635 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -69,12 +69,7 @@ class IFreqaiModel(ABC): self.pair = metadata["pair"] self.dh = DataHandler(self.config, dataframe) - logger.info( - "going to train", - len(self.dh.training_timeranges), - "timeranges:", - self.dh.training_timeranges, - ) + logger.info("going to train %s timeranges", len(self.dh.training_timeranges)) # Loop enforcing the sliding window training/backtesting paragigm # tr_train is the training time range e.g. 1 historical month @@ -90,14 +85,14 @@ class IFreqaiModel(ABC): self.freqai_info["training_timerange"] = tr_train dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) - logger.info("training", self.pair, "for", tr_train) + logger.info("training %s for %s", self.pair, tr_train) # self.dh.model_path = self.full_path + "/" + "sub-train" + "-" + str(tr_train) + "/" self.dh.model_path = Path(self.full_path / str("sub-train" + "-" + str(tr_train))) if not self.model_exists(self.pair, training_timerange=tr_train): self.model = self.train(dataframe_train, metadata) self.dh.save_data(self.model) else: - self.model = self.dh.load_data(self.dh.model_path) + self.model = self.dh.load_data() preds, do_preds = self.predict(dataframe_backtest) @@ -167,7 +162,7 @@ class IFreqaiModel(ABC): path_to_modelfile = Path(self.dh.model_path / str(self.dh.model_filename + "_model.joblib")) file_exists = path_to_modelfile.is_file() if file_exists: - logger.info("Found model at", self.dh.model_path / self.dh.model_filename) + logger.info("Found model at %s", self.dh.model_path / self.dh.model_filename) else: - logger.info("Could not find model at", self.dh.model_path / self.dh.model_filename) + logger.info("Could not find model at %s", self.dh.model_path / self.dh.model_filename) return file_exists diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 5051a8db0..f976b1238 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -204,12 +204,12 @@ class Backtesting: """ self.progress.init_step(BacktestState.DATALOAD, 1) - if self.config['freqaimodel']: - self.required_startup += int((self.config['freqai']['train_period']*86400) / - timeframe_to_seconds(self.config['timeframe'])) + if self.config['freqai']['train_period'] > 0: + self.required_startup += int((self.config['freqai']['train_period'] * 86400) / + timeframe_to_seconds(self.config['timeframe'])) + logger.info("Increasing startup_candle_count for freqai to %s", self.required_startup) self.config['startup_candle_count'] = self.required_startup - data = history.load_data( datadir=self.config['datadir'], pairs=self.pairlists.whitelist, diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index 4906b8c04..35f25775a 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -36,7 +36,7 @@ class ExamplePredictionModel(IFreqaiModel): self.dh.data["s_mean"] = dataframe["s"].mean() self.dh.data["s_std"] = dataframe["s"].std() - logger.info("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) + # logger.info("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) return dataframe["s"] @@ -77,11 +77,10 @@ class ExamplePredictionModel(IFreqaiModel): if self.feature_parameters["DI_threshold"]: self.dh.data["avg_mean_dist"] = self.dh.compute_distances() - logger.info("length of train data", len(data_dictionary["train_features"])) + logger.info("length of train data %s", len(data_dictionary["train_features"])) model = self.fit(data_dictionary) - logger.info("Finished training") logger.info(f'--------------------done training {metadata["pair"]}--------------------') return model From def71a0afedf18378bebed478decc3bb785efad5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 5 May 2022 15:35:51 +0200 Subject: [PATCH 008/308] auto build full_timerange and self manage training_timerange --- config_examples/config_freqai.example.json | 3 -- freqtrade/constants.py | 2 -- freqtrade/freqai/data_handler.py | 41 ++++++++++++++++++---- freqtrade/freqai/freqai_interface.py | 19 ++-------- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 47109ff31..5bd4de6c4 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -49,12 +49,10 @@ } ], "freqai": { - "btc_pair": "BTC/USDT", "timeframes": [ "5m", "15m" ], - "full_timerange": "20210601-20210901", "train_period": 30, "backtest_period": 7, "identifier": "example", @@ -74,7 +72,6 @@ "LINK/USDT", "DOT/USDT" ], - "training_timerange": "20211220-20220117", "feature_parameters": { "period": 12, "shift": 1, diff --git a/freqtrade/constants.py b/freqtrade/constants.py index d9664cff8..d988a164e 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -478,13 +478,11 @@ CONF_SCHEMA = { "type": "object", "properties": { "timeframes": {"type": "list"}, - "full_timerange": {"type": "str"}, "train_period": {"type": "integer", "default": 0}, "backtest_period": {"type": "integer", "default": 7}, "identifier": {"type": "str", "default": "example"}, "base_features": {"type": "list"}, "corr_pairlist": {"type": "list"}, - "training_timerange": {"type": "string", "default": None}, "feature_parameters": { "type": "object", "properties": { diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_handler.py index 94df869a1..e58575970 100644 --- a/freqtrade/freqai/data_handler.py +++ b/freqtrade/freqai/data_handler.py @@ -3,6 +3,7 @@ import datetime import json import logging import pickle as pk +import shutil from pathlib import Path from typing import Any, Dict, List, Tuple @@ -30,15 +31,10 @@ class DataHandler: def __init__(self, config: Dict[str, Any], dataframe: DataFrame): self.full_dataframe = dataframe - (self.training_timeranges, self.backtesting_timeranges) = self.split_timerange( - config["freqai"]["full_timerange"], - config["freqai"]["train_period"], - config["freqai"]["backtest_period"], - ) self.data: Dict[Any, Any] = {} self.data_dictionary: Dict[Any, Any] = {} self.config = config - self.freq_config = config["freqai"] + self.freqai_config = config["freqai"] self.predictions = np.array([]) self.do_predict = np.array([]) self.target_mean = np.array([]) @@ -46,6 +42,16 @@ class DataHandler: self.model_path = Path() self.model_filename = "" + self.full_timerange = self.create_fulltimerange( + self.config["timerange"], self.freqai_config["train_period"] + ) + + (self.training_timeranges, self.backtesting_timeranges) = self.split_timerange( + self.full_timerange, + config["freqai"]["train_period"], + config["freqai"]["backtest_period"], + ) + def save_data(self, model: Any) -> None: """ Saves all data associated with a model for a single sub-train time range @@ -539,6 +545,29 @@ class DataHandler: return + def create_fulltimerange(self, backtest_tr: str, backtest_period: int) -> str: + backtest_timerange = TimeRange.parse_timerange(backtest_tr) + + backtest_timerange.startts = backtest_timerange.startts - backtest_period * SECONDS_IN_DAY + start = datetime.datetime.utcfromtimestamp(backtest_timerange.startts) + stop = datetime.datetime.utcfromtimestamp(backtest_timerange.stopts) + full_timerange = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") + + self.full_path = Path( + self.config["user_data_dir"] + / "models" + / str(full_timerange + self.freqai_config["identifier"]) + ) + + if not self.full_path.is_dir(): + self.full_path.mkdir(parents=True, exist_ok=True) + shutil.copy( + Path(self.config["config_files"][0]).name, + Path(self.full_path / self.config["config_files"][0]), + ) + + return full_timerange + def np_encoder(self, object): if isinstance(object, np.generic): return object.item() diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 368ed1635..62779a4e1 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -1,6 +1,5 @@ import gc import logging -import shutil from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, Tuple @@ -32,24 +31,13 @@ class IFreqaiModel(ABC): self.data_split_parameters = config["freqai"]["data_split_parameters"] self.model_training_parameters = config["freqai"]["model_training_parameters"] self.feature_parameters = config["freqai"]["feature_parameters"] - self.full_path = Path( - config["user_data_dir"] - / "models" - / str(self.freqai_info["full_timerange"] + self.freqai_info["identifier"]) - ) + self.backtest_timerange = config["timerange"] self.time_last_trained = None self.current_time = None self.model = None self.predictions = None - if not self.full_path.is_dir(): - self.full_path.mkdir(parents=True, exist_ok=True) - shutil.copy( - self.config["config_files"][0], - Path(self.full_path / self.config["config_files"][0]), - ) - def start(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Entry point to the FreqaiModel, it will train a new model if @@ -82,12 +70,11 @@ class IFreqaiModel(ABC): gc.collect() # self.config['timerange'] = tr_train self.dh.data = {} # clean the pair specific data between models - self.freqai_info["training_timerange"] = tr_train + self.training_timerange = tr_train dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) logger.info("training %s for %s", self.pair, tr_train) - # self.dh.model_path = self.full_path + "/" + "sub-train" + "-" + str(tr_train) + "/" - self.dh.model_path = Path(self.full_path / str("sub-train" + "-" + str(tr_train))) + self.dh.model_path = Path(self.dh.full_path / str("sub-train" + "-" + str(tr_train))) if not self.model_exists(self.pair, training_timerange=tr_train): self.model = self.train(dataframe_train, metadata) self.dh.save_data(self.model) From 66715c5ba4316be461632777e7f4a68569b52857 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 5 May 2022 15:49:19 +0200 Subject: [PATCH 009/308] update doc --- docs/freqai.md | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 6bc1e9365..844881613 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -49,9 +49,8 @@ config setup includes: ```json "freqai": { "timeframes" : ["5m","15m","4h"], - "full_timerange" : "20211220-20220220", - "train_period" : "month", - "backtest_period" : "week", + "train_period" : 30, + "backtest_period" : 7, "identifier" : "unique-id", "base_features": [ "rsi", @@ -63,18 +62,18 @@ config setup includes: "LINK/USD", "BNB/USD" ], - "train_params" : { + "feature_parameters" : { "period": 24, "shift": 2, "drop_features": false, "DI_threshold": 1, "weight_factor": 0, }, - "SPLIT_PARAMS" : { + "data_split_parameters" : { "test_size": 0.25, "random_state": 42 }, - "CLASSIFIER_PARAMS" : { + "model_training_parameters" : { "n_estimators": 100, "random_state": 42, "learning_rate": 0.02, @@ -110,11 +109,11 @@ no. `timeframes` * no. `base_features` * no. `corr_pairlist` * no. `shift`_ ### Deciding the sliding training window and backtesting duration -`full_timerange` lets the user set the full backtesting range to train and -backtest through. Meanwhile `train_period` is the sliding training window and -`backtest_period` is the sliding backtesting window. In the present example, -the user is asking Freqai to train and backtest the range of `20211220-20220220` (`month`). -The user wishes to backtest each `week` with a newly trained model. This means that +Users define the backtesting timerange with the typical `--timerange` parameter in the user +configuration file. `train_period` is the duration of the sliding training window, while +`backtest_period` is the sliding backtesting window, both in number of days. In the present example, +the user is asking Freqai to use a training period of 30 days and backtest the subsequent 7 days. +This means that if the user sets `--timerange 20210501-20210701`, Freqai will train 8 separate models (because the full range comprises 8 weeks), and then backtest the subsequent week associated with each of the 8 training data set timerange months. Users can think of this as a "sliding window" which @@ -128,7 +127,7 @@ month of data. The freqai training/backtesting module can be executed with the following command: ```bash -freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel ExamplePredictionModel +freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel ExamplePredictionModel --timerange 20210501-20210701 ``` where the user needs to have a FreqaiExampleStrategy that fits to the requirements outlined @@ -178,19 +177,7 @@ and `make_labels()` to let them customize various aspects of their training proc ### Running the model live -After the user has designed a desirable featureset, Freqai can be run in dry/live -using the typical trade command: - -```bash -freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --training_timerange '20211220-20220120' -``` - -Where the user has now specified exactly which of the models from the sliding window -that they wish to run live using `--training_timerange` (typically this would be the most -recent model trained). As of right now, freqai will -not automatically retain itself, so the user needs to manually retrain and then -reload the config file with a new `--training_timerange` in order to update the -model. +TODO: Freqai is not automated for live yet. ## Data anylsis techniques @@ -208,12 +195,6 @@ $$ W_i = \exp(\frac{-i}{\alpha*n}) $$ where $W_i$ is the weight of data point $i$ in a total set of $n$ data points._ -`drop_features` tells Freqai to train the model on the user defined features, -followed by a feature importance evaluation where it drops the top and bottom -performing features (there is evidence to suggest the top features may not be -helpful in equity/crypto trading since the ultimate objective is to predict low -frequency patterns, source: numerai)._ - Finally, `period` defines the offset used for the `labels`. In the present example, the user is asking for `labels` that are 24 candles in the future. From 00ff0c9b917a28f55d676976736cd4e0e25a7bc9 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 12:54:49 +0200 Subject: [PATCH 010/308] ensure user defined timerange truncates final backtest so that we arent mismatching data lengths upon return to strategy. Rename DataHandler class to FreqaiDataKitchen --- .../{data_handler.py => data_kitchen.py} | 24 +++++++++++++++---- freqtrade/freqai/freqai_interface.py | 4 ++-- 2 files changed, 22 insertions(+), 6 deletions(-) rename freqtrade/freqai/{data_handler.py => data_kitchen.py} (96%) diff --git a/freqtrade/freqai/data_handler.py b/freqtrade/freqai/data_kitchen.py similarity index 96% rename from freqtrade/freqai/data_handler.py rename to freqtrade/freqai/data_kitchen.py index e58575970..1bea97697 100644 --- a/freqtrade/freqai/data_handler.py +++ b/freqtrade/freqai/data_kitchen.py @@ -22,7 +22,7 @@ SECONDS_IN_DAY = 86400 logger = logging.getLogger(__name__) -class DataHandler: +class FreqaiDataKitchen: """ Class designed to handle all the data for the IFreqaiModel class model. Functionalities include holding, saving, loading, and analyzing the data. @@ -291,32 +291,48 @@ class DataHandler: bt_period = bt_split * SECONDS_IN_DAY full_timerange = TimeRange.parse_timerange(tr) + config_timerange = TimeRange.parse_timerange(self.config["timerange"]) timerange_train = copy.deepcopy(full_timerange) timerange_backtest = copy.deepcopy(full_timerange) tr_training_list = [] tr_backtesting_list = [] first = True + # within_config_timerange = True while True: if not first: timerange_train.startts = timerange_train.startts + bt_period timerange_train.stopts = timerange_train.startts + train_period - # if a full training period doesnt fit, we stop - if timerange_train.stopts > full_timerange.stopts: - break + # make sure we finish with a full backtest + # if timerange_train.stopts > config_timerange.stopts - bt_period: + # within_config_timerange = False + # timerange_train.stopts = config_timerange.stopts - bt_period + # # if a full training period doesnt fit, we stop + # if timerange_train.stopts > full_timerange.stopts: + # break first = False start = datetime.datetime.utcfromtimestamp(timerange_train.startts) stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) tr_training_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) # associated backtest period + if timerange_backtest.stopts > config_timerange.stopts: + timerange_backtest.stopts = config_timerange.stopts + timerange_backtest.startts = timerange_train.stopts timerange_backtest.stopts = timerange_backtest.startts + bt_period + start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) tr_backtesting_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) + # ensure we are predicting on exactly same amount of data as requested by user defined + # --timerange + if timerange_backtest.stopts == config_timerange.stopts: + break + + print(tr_training_list, tr_backtesting_list) return tr_training_list, tr_backtesting_list def slice_dataframe(self, tr: str, df: DataFrame) -> DataFrame: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 62779a4e1..63e94383c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -8,7 +8,7 @@ import numpy as np import pandas as pd from pandas import DataFrame -from freqtrade.freqai.data_handler import DataHandler +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen pd.options.mode.chained_assignment = None @@ -55,7 +55,7 @@ class IFreqaiModel(ABC): :metadata: pair metadataa coming from strategy. """ self.pair = metadata["pair"] - self.dh = DataHandler(self.config, dataframe) + self.dh = FreqaiDataKitchen(self.config, dataframe) logger.info("going to train %s timeranges", len(self.dh.training_timeranges)) From 3020218096593105e38ce8993068431bda4e3dac Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 13:06:54 +0200 Subject: [PATCH 011/308] fix bug on backtest timerange --- freqtrade/freqai/data_kitchen.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 1bea97697..38d518e23 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -317,11 +317,14 @@ class FreqaiDataKitchen: tr_training_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) # associated backtest period + + timerange_backtest.startts = timerange_train.stopts + if timerange_backtest.stopts > config_timerange.stopts: timerange_backtest.stopts = config_timerange.stopts - timerange_backtest.startts = timerange_train.stopts - timerange_backtest.stopts = timerange_backtest.startts + bt_period + else: + timerange_backtest.stopts = timerange_backtest.startts + bt_period start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) From e9a7b68bc121a13131e6f08aed4477b993cb48e0 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 13:10:47 +0200 Subject: [PATCH 012/308] revert constants.py and add changes --- freqtrade/constants.py | 782 +++++++++++++++++++---------------------- 1 file changed, 370 insertions(+), 412 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index d988a164e..653fa8c67 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -8,133 +8,87 @@ from typing import List, Literal, Tuple from freqtrade.enums import CandleType -DEFAULT_CONFIG = "config.json" -DEFAULT_EXCHANGE = "bittrex" +DEFAULT_CONFIG = 'config.json' +DEFAULT_EXCHANGE = 'bittrex' PROCESS_THROTTLE_SECS = 5 # sec HYPEROPT_EPOCH = 100 # epochs RETRY_TIMEOUT = 30 # sec -TIMEOUT_UNITS = ["minutes", "seconds"] -EXPORT_OPTIONS = ["none", "trades", "signals"] -DEFAULT_DB_PROD_URL = "sqlite:///tradesv3.sqlite" -DEFAULT_DB_DRYRUN_URL = "sqlite:///tradesv3.dryrun.sqlite" -UNLIMITED_STAKE_AMOUNT = "unlimited" +TIMEOUT_UNITS = ['minutes', 'seconds'] +EXPORT_OPTIONS = ['none', 'trades', 'signals'] +DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite' +DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite' +UNLIMITED_STAKE_AMOUNT = 'unlimited' DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05 -REQUIRED_ORDERTIF = ["entry", "exit"] -REQUIRED_ORDERTYPES = ["entry", "exit", "stoploss", "stoploss_on_exchange"] -PRICING_SIDES = ["ask", "bid", "same", "other"] -ORDERTYPE_POSSIBILITIES = ["limit", "market"] -ORDERTIF_POSSIBILITIES = ["gtc", "fok", "ioc"] -HYPEROPT_LOSS_BUILTIN = [ - "ShortTradeDurHyperOptLoss", - "OnlyProfitHyperOptLoss", - "SharpeHyperOptLoss", - "SharpeHyperOptLossDaily", - "SortinoHyperOptLoss", - "SortinoHyperOptLossDaily", - "CalmarHyperOptLoss", - "MaxDrawDownHyperOptLoss", - "MaxDrawDownRelativeHyperOptLoss", - "ProfitDrawDownHyperOptLoss", -] -AVAILABLE_PAIRLISTS = [ - "StaticPairList", - "VolumePairList", - "AgeFilter", - "OffsetFilter", - "PerformanceFilter", - "PrecisionFilter", - "PriceFilter", - "RangeStabilityFilter", - "ShuffleFilter", - "SpreadFilter", - "VolatilityFilter", -] -AVAILABLE_PROTECTIONS = ["CooldownPeriod", "LowProfitPairs", "MaxDrawdown", "StoplossGuard"] -AVAILABLE_DATAHANDLERS = ["json", "jsongz", "hdf5"] -BACKTEST_BREAKDOWNS = ["day", "week", "month"] -BACKTEST_CACHE_AGE = ["none", "day", "week", "month"] -BACKTEST_CACHE_DEFAULT = "day" +REQUIRED_ORDERTIF = ['entry', 'exit'] +REQUIRED_ORDERTYPES = ['entry', 'exit', 'stoploss', 'stoploss_on_exchange'] +PRICING_SIDES = ['ask', 'bid', 'same', 'other'] +ORDERTYPE_POSSIBILITIES = ['limit', 'market'] +ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] +HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss', + 'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily', + 'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily', + 'CalmarHyperOptLoss', + 'MaxDrawDownHyperOptLoss', 'MaxDrawDownRelativeHyperOptLoss', + 'ProfitDrawDownHyperOptLoss'] +AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', + 'AgeFilter', 'OffsetFilter', 'PerformanceFilter', + 'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter', + 'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter'] +AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard'] +AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5'] +BACKTEST_BREAKDOWNS = ['day', 'week', 'month'] +BACKTEST_CACHE_AGE = ['none', 'day', 'week', 'month'] +BACKTEST_CACHE_DEFAULT = 'day' DRY_RUN_WALLET = 1000 -DATETIME_PRINT_FORMAT = "%Y-%m-%d %H:%M:%S" +DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S' MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons -DEFAULT_DATAFRAME_COLUMNS = ["date", "open", "high", "low", "close", "volume"] +DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume'] # Don't modify sequence of DEFAULT_TRADES_COLUMNS # it has wide consequences for stored trades files -DEFAULT_TRADES_COLUMNS = ["timestamp", "id", "type", "side", "price", "amount", "cost"] -TRADING_MODES = ["spot", "margin", "futures"] -MARGIN_MODES = ["cross", "isolated", ""] +DEFAULT_TRADES_COLUMNS = ['timestamp', 'id', 'type', 'side', 'price', 'amount', 'cost'] +TRADING_MODES = ['spot', 'margin', 'futures'] +MARGIN_MODES = ['cross', 'isolated', ''] -LAST_BT_RESULT_FN = ".last_result.json" -FTHYPT_FILEVERSION = "fthypt_fileversion" +LAST_BT_RESULT_FN = '.last_result.json' +FTHYPT_FILEVERSION = 'fthypt_fileversion' -USERPATH_HYPEROPTS = "hyperopts" -USERPATH_STRATEGIES = "strategies" -USERPATH_NOTEBOOKS = "notebooks" -USERPATH_FREQAIMODELS = "freqaimodels" +USERPATH_HYPEROPTS = 'hyperopts' +USERPATH_STRATEGIES = 'strategies' +USERPATH_NOTEBOOKS = 'notebooks' -TELEGRAM_SETTING_OPTIONS = ["on", "off", "silent"] -WEBHOOK_FORMAT_OPTIONS = ["form", "json", "raw"] +TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent'] +WEBHOOK_FORMAT_OPTIONS = ['form', 'json', 'raw'] -ENV_VAR_PREFIX = "FREQTRADE__" +ENV_VAR_PREFIX = 'FREQTRADE__' -NON_OPEN_EXCHANGE_STATES = ("cancelled", "canceled", "closed", "expired") +NON_OPEN_EXCHANGE_STATES = ('cancelled', 'canceled', 'closed', 'expired') # Define decimals per coin for outputs # Only used for outputs. DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's DECIMALS_PER_COIN = { - "BTC": 8, - "ETH": 5, + 'BTC': 8, + 'ETH': 5, } -DUST_PER_COIN = {"BTC": 0.0001, "ETH": 0.01} +DUST_PER_COIN = { + 'BTC': 0.0001, + 'ETH': 0.01 +} # Source files with destination directories within user-directory USER_DATA_FILES = { - "sample_strategy.py": USERPATH_STRATEGIES, - "sample_hyperopt_loss.py": USERPATH_HYPEROPTS, - "strategy_analysis_example.ipynb": USERPATH_NOTEBOOKS, + 'sample_strategy.py': USERPATH_STRATEGIES, + 'sample_hyperopt_loss.py': USERPATH_HYPEROPTS, + 'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS, } SUPPORTED_FIAT = [ - "AUD", - "BRL", - "CAD", - "CHF", - "CLP", - "CNY", - "CZK", - "DKK", - "EUR", - "GBP", - "HKD", - "HUF", - "IDR", - "ILS", - "INR", - "JPY", - "KRW", - "MXN", - "MYR", - "NOK", - "NZD", - "PHP", - "PKR", - "PLN", - "RUB", - "UAH", - "SEK", - "SGD", - "THB", - "TRY", - "TWD", - "ZAR", - "USD", - "BTC", - "ETH", - "XRP", - "LTC", - "BCH", + "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", + "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY", + "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", + "RUB", "UAH", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", + "USD", "BTC", "ETH", "XRP", "LTC", "BCH" ] MINIMAL_CONFIG = { @@ -145,334 +99,338 @@ MINIMAL_CONFIG = { "key": "", "secret": "", "pair_whitelist": [], - "ccxt_async_config": {}, - }, + "ccxt_async_config": { + } + } } # Required json-schema for user specified config CONF_SCHEMA = { - "type": "object", - "properties": { - "max_open_trades": {"type": ["integer", "number"], "minimum": -1}, - "new_pairs_days": {"type": "integer", "default": 30}, - "timeframe": {"type": "string"}, - "stake_currency": {"type": "string"}, - "stake_amount": { - "type": ["number", "string"], - "minimum": 0.0001, - "pattern": UNLIMITED_STAKE_AMOUNT, + 'type': 'object', + 'properties': { + 'max_open_trades': {'type': ['integer', 'number'], 'minimum': -1}, + 'new_pairs_days': {'type': 'integer', 'default': 30}, + 'timeframe': {'type': 'string'}, + 'stake_currency': {'type': 'string'}, + 'stake_amount': { + 'type': ['number', 'string'], + 'minimum': 0.0001, + 'pattern': UNLIMITED_STAKE_AMOUNT }, - "tradable_balance_ratio": {"type": "number", "minimum": 0.0, "maximum": 1, "default": 0.99}, - "available_capital": { - "type": "number", - "minimum": 0, + 'tradable_balance_ratio': { + 'type': 'number', + 'minimum': 0.0, + 'maximum': 1, + 'default': 0.99 }, - "amend_last_stake_amount": {"type": "boolean", "default": False}, - "last_stake_amount_min_ratio": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5, + 'available_capital': { + 'type': 'number', + 'minimum': 0, }, - "fiat_display_currency": {"type": "string", "enum": SUPPORTED_FIAT}, - "dry_run": {"type": "boolean"}, - "dry_run_wallet": {"type": "number", "default": DRY_RUN_WALLET}, - "cancel_open_orders_on_exit": {"type": "boolean", "default": False}, - "process_only_new_candles": {"type": "boolean"}, - "minimal_roi": { - "type": "object", - "patternProperties": {"^[0-9.]+$": {"type": "number"}}, - "minProperties": 1, + 'amend_last_stake_amount': {'type': 'boolean', 'default': False}, + 'last_stake_amount_min_ratio': { + 'type': 'number', 'minimum': 0.0, 'maximum': 1.0, 'default': 0.5 }, - "amount_reserve_percent": {"type": "number", "minimum": 0.0, "maximum": 0.5}, - "stoploss": {"type": "number", "maximum": 0, "exclusiveMaximum": True, "minimum": -1}, - "trailing_stop": {"type": "boolean"}, - "trailing_stop_positive": {"type": "number", "minimum": 0, "maximum": 1}, - "trailing_stop_positive_offset": {"type": "number", "minimum": 0, "maximum": 1}, - "trailing_only_offset_is_reached": {"type": "boolean"}, - "use_exit_signal": {"type": "boolean"}, - "exit_profit_only": {"type": "boolean"}, - "exit_profit_offset": {"type": "number"}, - "ignore_roi_if_entry_signal": {"type": "boolean"}, - "ignore_buying_expired_candle_after": {"type": "number"}, - "trading_mode": {"type": "string", "enum": TRADING_MODES}, - "margin_mode": {"type": "string", "enum": MARGIN_MODES}, - "liquidation_buffer": {"type": "number", "minimum": 0.0, "maximum": 0.99}, - "backtest_breakdown": { - "type": "array", - "items": {"type": "string", "enum": BACKTEST_BREAKDOWNS}, - }, - "bot_name": {"type": "string"}, - "unfilledtimeout": { - "type": "object", - "properties": { - "entry": {"type": "number", "minimum": 1}, - "exit": {"type": "number", "minimum": 1}, - "exit_timeout_count": {"type": "number", "minimum": 0, "default": 0}, - "unit": {"type": "string", "enum": TIMEOUT_UNITS, "default": "minutes"}, + 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, + 'dry_run': {'type': 'boolean'}, + 'dry_run_wallet': {'type': 'number', 'default': DRY_RUN_WALLET}, + 'cancel_open_orders_on_exit': {'type': 'boolean', 'default': False}, + 'process_only_new_candles': {'type': 'boolean'}, + 'minimal_roi': { + 'type': 'object', + 'patternProperties': { + '^[0-9.]+$': {'type': 'number'} }, + 'minProperties': 1 }, - "entry_pricing": { - "type": "object", - "properties": { - "price_last_balance": { - "type": "number", - "minimum": 0, - "maximum": 1, - "exclusiveMaximum": False, + 'amount_reserve_percent': {'type': 'number', 'minimum': 0.0, 'maximum': 0.5}, + 'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True, 'minimum': -1}, + 'trailing_stop': {'type': 'boolean'}, + 'trailing_stop_positive': {'type': 'number', 'minimum': 0, 'maximum': 1}, + 'trailing_stop_positive_offset': {'type': 'number', 'minimum': 0, 'maximum': 1}, + 'trailing_only_offset_is_reached': {'type': 'boolean'}, + 'use_exit_signal': {'type': 'boolean'}, + 'exit_profit_only': {'type': 'boolean'}, + 'exit_profit_offset': {'type': 'number'}, + 'ignore_roi_if_entry_signal': {'type': 'boolean'}, + 'ignore_buying_expired_candle_after': {'type': 'number'}, + 'trading_mode': {'type': 'string', 'enum': TRADING_MODES}, + 'margin_mode': {'type': 'string', 'enum': MARGIN_MODES}, + 'liquidation_buffer': {'type': 'number', 'minimum': 0.0, 'maximum': 0.99}, + 'backtest_breakdown': { + 'type': 'array', + 'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS} + }, + 'bot_name': {'type': 'string'}, + 'unfilledtimeout': { + 'type': 'object', + 'properties': { + 'entry': {'type': 'number', 'minimum': 1}, + 'exit': {'type': 'number', 'minimum': 1}, + 'exit_timeout_count': {'type': 'number', 'minimum': 0, 'default': 0}, + 'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'} + } + }, + 'entry_pricing': { + 'type': 'object', + 'properties': { + 'price_last_balance': { + 'type': 'number', + 'minimum': 0, + 'maximum': 1, + 'exclusiveMaximum': False, }, - "price_side": {"type": "string", "enum": PRICING_SIDES, "default": "same"}, - "use_order_book": {"type": "boolean"}, - "order_book_top": { - "type": "integer", - "minimum": 1, - "maximum": 50, - }, - "check_depth_of_market": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "bids_to_ask_delta": {"type": "number", "minimum": 0}, - }, + 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'}, + 'use_order_book': {'type': 'boolean'}, + 'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, }, + 'check_depth_of_market': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'bids_to_ask_delta': {'type': 'number', 'minimum': 0}, + } }, }, - "required": ["price_side"], + 'required': ['price_side'] }, - "exit_pricing": { - "type": "object", - "properties": { - "price_side": {"type": "string", "enum": PRICING_SIDES, "default": "same"}, - "price_last_balance": { - "type": "number", - "minimum": 0, - "maximum": 1, - "exclusiveMaximum": False, - }, - "use_order_book": {"type": "boolean"}, - "order_book_top": { - "type": "integer", - "minimum": 1, - "maximum": 50, + 'exit_pricing': { + 'type': 'object', + 'properties': { + 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'}, + 'price_last_balance': { + 'type': 'number', + 'minimum': 0, + 'maximum': 1, + 'exclusiveMaximum': False, }, + 'use_order_book': {'type': 'boolean'}, + 'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, }, }, - "required": ["price_side"], + 'required': ['price_side'] }, - "custom_price_max_distance_ratio": {"type": "number", "minimum": 0.0}, - "order_types": { - "type": "object", - "properties": { - "entry": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, - "exit": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, - "force_exit": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, - "force_entry": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, - "emergency_exit": { - "type": "string", - "enum": ORDERTYPE_POSSIBILITIES, - "default": "market", - }, - "stoploss": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES}, - "stoploss_on_exchange": {"type": "boolean"}, - "stoploss_on_exchange_interval": {"type": "number"}, - "stoploss_on_exchange_limit_ratio": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - }, + 'custom_price_max_distance_ratio': { + 'type': 'number', 'minimum': 0.0 + }, + 'order_types': { + 'type': 'object', + 'properties': { + 'entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'force_exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'force_entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'emergency_exit': { + 'type': 'string', + 'enum': ORDERTYPE_POSSIBILITIES, + 'default': 'market'}, + 'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'stoploss_on_exchange': {'type': 'boolean'}, + 'stoploss_on_exchange_interval': {'type': 'number'}, + 'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0, + 'maximum': 1.0} }, - "required": ["entry", "exit", "stoploss", "stoploss_on_exchange"], + 'required': ['entry', 'exit', 'stoploss', 'stoploss_on_exchange'] }, - "order_time_in_force": { - "type": "object", - "properties": { - "entry": {"type": "string", "enum": ORDERTIF_POSSIBILITIES}, - "exit": {"type": "string", "enum": ORDERTIF_POSSIBILITIES}, + 'order_time_in_force': { + 'type': 'object', + 'properties': { + 'entry': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}, + 'exit': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES} }, - "required": REQUIRED_ORDERTIF, + 'required': REQUIRED_ORDERTIF }, - "exchange": {"$ref": "#/definitions/exchange"}, - "edge": {"$ref": "#/definitions/edge"}, - "experimental": { - "type": "object", - "properties": {"block_bad_exchanges": {"type": "boolean"}}, + 'exchange': {'$ref': '#/definitions/exchange'}, + 'edge': {'$ref': '#/definitions/edge'}, + 'experimental': { + 'type': 'object', + 'properties': { + 'block_bad_exchanges': {'type': 'boolean'} + } }, - "pairlists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "method": {"type": "string", "enum": AVAILABLE_PAIRLISTS}, + 'pairlists': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'method': {'type': 'string', 'enum': AVAILABLE_PAIRLISTS}, }, - "required": ["method"], - }, + 'required': ['method'], + } }, - "protections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "method": {"type": "string", "enum": AVAILABLE_PROTECTIONS}, - "stop_duration": {"type": "number", "minimum": 0.0}, - "stop_duration_candles": {"type": "number", "minimum": 0}, - "trade_limit": {"type": "number", "minimum": 1}, - "lookback_period": {"type": "number", "minimum": 1}, - "lookback_period_candles": {"type": "number", "minimum": 1}, + 'protections': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'method': {'type': 'string', 'enum': AVAILABLE_PROTECTIONS}, + 'stop_duration': {'type': 'number', 'minimum': 0.0}, + 'stop_duration_candles': {'type': 'number', 'minimum': 0}, + 'trade_limit': {'type': 'number', 'minimum': 1}, + 'lookback_period': {'type': 'number', 'minimum': 1}, + 'lookback_period_candles': {'type': 'number', 'minimum': 1}, }, - "required": ["method"], - }, + 'required': ['method'], + } }, - "telegram": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "token": {"type": "string"}, - "chat_id": {"type": "string"}, - "balance_dust_level": {"type": "number", "minimum": 0.0}, - "notification_settings": { - "type": "object", - "default": {}, - "properties": { - "status": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, - "warning": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, - "startup": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, - "entry": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, - "entry_cancel": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, - "entry_fill": { - "type": "string", - "enum": TELEGRAM_SETTING_OPTIONS, - "default": "off", + 'telegram': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'token': {'type': 'string'}, + 'chat_id': {'type': 'string'}, + 'balance_dust_level': {'type': 'number', 'minimum': 0.0}, + 'notification_settings': { + 'type': 'object', + 'default': {}, + 'properties': { + 'status': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, + 'warning': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, + 'startup': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, + 'entry': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, + 'entry_cancel': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, + 'entry_fill': {'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS, + 'default': 'off' + }, + 'exit': { + 'type': ['string', 'object'], + 'additionalProperties': { + 'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS + } }, - "exit": { - "type": ["string", "object"], - "additionalProperties": { - "type": "string", - "enum": TELEGRAM_SETTING_OPTIONS, - }, + 'exit_cancel': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS}, + 'exit_fill': { + 'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS, + 'default': 'off' }, - "exit_cancel": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS}, - "exit_fill": { - "type": "string", - "enum": TELEGRAM_SETTING_OPTIONS, - "default": "off", + 'protection_trigger': { + 'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS, + 'default': 'off' }, - "protection_trigger": { - "type": "string", - "enum": TELEGRAM_SETTING_OPTIONS, - "default": "off", + 'protection_trigger_global': { + 'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS, }, - "protection_trigger_global": { - "type": "string", - "enum": TELEGRAM_SETTING_OPTIONS, - }, - }, + } }, - "reload": {"type": "boolean"}, + 'reload': {'type': 'boolean'}, }, - "required": ["enabled", "token", "chat_id"], + 'required': ['enabled', 'token', 'chat_id'], }, - "webhook": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "url": {"type": "string"}, - "format": {"type": "string", "enum": WEBHOOK_FORMAT_OPTIONS, "default": "form"}, - "retries": {"type": "integer", "minimum": 0}, - "retry_delay": {"type": "number", "minimum": 0}, - "webhookentry": {"type": "object"}, - "webhookentrycancel": {"type": "object"}, - "webhookentryfill": {"type": "object"}, - "webhookexit": {"type": "object"}, - "webhookexitcancel": {"type": "object"}, - "webhookexitfill": {"type": "object"}, - "webhookstatus": {"type": "object"}, + 'webhook': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'url': {'type': 'string'}, + 'format': {'type': 'string', 'enum': WEBHOOK_FORMAT_OPTIONS, 'default': 'form'}, + 'retries': {'type': 'integer', 'minimum': 0}, + 'retry_delay': {'type': 'number', 'minimum': 0}, + 'webhookentry': {'type': 'object'}, + 'webhookentrycancel': {'type': 'object'}, + 'webhookentryfill': {'type': 'object'}, + 'webhookexit': {'type': 'object'}, + 'webhookexitcancel': {'type': 'object'}, + 'webhookexitfill': {'type': 'object'}, + 'webhookstatus': {'type': 'object'}, }, }, - "api_server": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "listen_ip_address": {"format": "ipv4"}, - "listen_port": {"type": "integer", "minimum": 1024, "maximum": 65535}, - "username": {"type": "string"}, - "password": {"type": "string"}, - "jwt_secret_key": {"type": "string"}, - "CORS_origins": {"type": "array", "items": {"type": "string"}}, - "verbosity": {"type": "string", "enum": ["error", "info"]}, + 'api_server': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'listen_ip_address': {'format': 'ipv4'}, + 'listen_port': { + 'type': 'integer', + 'minimum': 1024, + 'maximum': 65535 + }, + 'username': {'type': 'string'}, + 'password': {'type': 'string'}, + 'jwt_secret_key': {'type': 'string'}, + 'CORS_origins': {'type': 'array', 'items': {'type': 'string'}}, + 'verbosity': {'type': 'string', 'enum': ['error', 'info']}, }, - "required": ["enabled", "listen_ip_address", "listen_port", "username", "password"], + 'required': ['enabled', 'listen_ip_address', 'listen_port', 'username', 'password'] }, - "db_url": {"type": "string"}, - "export": {"type": "string", "enum": EXPORT_OPTIONS, "default": "trades"}, - "disableparamexport": {"type": "boolean"}, - "initial_state": {"type": "string", "enum": ["running", "stopped"]}, - "force_entry_enable": {"type": "boolean"}, - "disable_dataframe_checks": {"type": "boolean"}, - "internals": { - "type": "object", - "default": {}, - "properties": { - "process_throttle_secs": {"type": "integer"}, - "interval": {"type": "integer"}, - "sd_notify": {"type": "boolean"}, - }, + 'db_url': {'type': 'string'}, + 'export': {'type': 'string', 'enum': EXPORT_OPTIONS, 'default': 'trades'}, + 'disableparamexport': {'type': 'boolean'}, + 'initial_state': {'type': 'string', 'enum': ['running', 'stopped']}, + 'force_entry_enable': {'type': 'boolean'}, + 'disable_dataframe_checks': {'type': 'boolean'}, + 'internals': { + 'type': 'object', + 'default': {}, + 'properties': { + 'process_throttle_secs': {'type': 'integer'}, + 'interval': {'type': 'integer'}, + 'sd_notify': {'type': 'boolean'}, + } }, - "dataformat_ohlcv": {"type": "string", "enum": AVAILABLE_DATAHANDLERS, "default": "json"}, - "dataformat_trades": { - "type": "string", - "enum": AVAILABLE_DATAHANDLERS, - "default": "jsongz", + 'dataformat_ohlcv': { + 'type': 'string', + 'enum': AVAILABLE_DATAHANDLERS, + 'default': 'json' }, - "position_adjustment_enable": {"type": "boolean"}, - "max_entry_position_adjustment": {"type": ["integer", "number"], "minimum": -1}, + 'dataformat_trades': { + 'type': 'string', + 'enum': AVAILABLE_DATAHANDLERS, + 'default': 'jsongz' + }, + 'position_adjustment_enable': {'type': 'boolean'}, + 'max_entry_position_adjustment': {'type': ['integer', 'number'], 'minimum': -1}, }, - "definitions": { - "exchange": { - "type": "object", - "properties": { - "name": {"type": "string"}, - "sandbox": {"type": "boolean", "default": False}, - "key": {"type": "string", "default": ""}, - "secret": {"type": "string", "default": ""}, - "password": {"type": "string", "default": ""}, - "uid": {"type": "string"}, - "pair_whitelist": { - "type": "array", - "items": { - "type": "string", + 'definitions': { + 'exchange': { + 'type': 'object', + 'properties': { + 'name': {'type': 'string'}, + 'sandbox': {'type': 'boolean', 'default': False}, + 'key': {'type': 'string', 'default': ''}, + 'secret': {'type': 'string', 'default': ''}, + 'password': {'type': 'string', 'default': ''}, + 'uid': {'type': 'string'}, + 'pair_whitelist': { + 'type': 'array', + 'items': { + 'type': 'string', }, - "uniqueItems": True, + 'uniqueItems': True }, - "pair_blacklist": { - "type": "array", - "items": { - "type": "string", + 'pair_blacklist': { + 'type': 'array', + 'items': { + 'type': 'string', }, - "uniqueItems": True, + 'uniqueItems': True }, - "unknown_fee_rate": {"type": "number"}, - "outdated_offset": {"type": "integer", "minimum": 1}, - "markets_refresh_interval": {"type": "integer"}, - "ccxt_config": {"type": "object"}, - "ccxt_async_config": {"type": "object"}, + 'unknown_fee_rate': {'type': 'number'}, + 'outdated_offset': {'type': 'integer', 'minimum': 1}, + 'markets_refresh_interval': {'type': 'integer'}, + 'ccxt_config': {'type': 'object'}, + 'ccxt_async_config': {'type': 'object'} }, - "required": ["name"], + 'required': ['name'] }, - "edge": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "process_throttle_secs": {"type": "integer", "minimum": 600}, - "calculate_since_number_of_days": {"type": "integer"}, - "allowed_risk": {"type": "number"}, - "stoploss_range_min": {"type": "number"}, - "stoploss_range_max": {"type": "number"}, - "stoploss_range_step": {"type": "number"}, - "minimum_winrate": {"type": "number"}, - "minimum_expectancy": {"type": "number"}, - "min_trade_number": {"type": "number"}, - "max_trade_duration_minute": {"type": "integer"}, - "remove_pumps": {"type": "boolean"}, + 'edge': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'process_throttle_secs': {'type': 'integer', 'minimum': 600}, + 'calculate_since_number_of_days': {'type': 'integer'}, + 'allowed_risk': {'type': 'number'}, + 'stoploss_range_min': {'type': 'number'}, + 'stoploss_range_max': {'type': 'number'}, + 'stoploss_range_step': {'type': 'number'}, + 'minimum_winrate': {'type': 'number'}, + 'minimum_expectancy': {'type': 'number'}, + 'min_trade_number': {'type': 'number'}, + 'max_trade_duration_minute': {'type': 'integer'}, + 'remove_pumps': {'type': 'boolean'} }, - "required": ["process_throttle_secs", "allowed_risk"], + 'required': ['process_throttle_secs', 'allowed_risk'] }, "freqai": { "type": "object", @@ -516,43 +474,43 @@ CONF_SCHEMA = { } SCHEMA_TRADE_REQUIRED = [ - "exchange", - "timeframe", - "max_open_trades", - "stake_currency", - "stake_amount", - "tradable_balance_ratio", - "last_stake_amount_min_ratio", - "dry_run", - "dry_run_wallet", - "exit_pricing", - "entry_pricing", - "stoploss", - "minimal_roi", - "internals", - "dataformat_ohlcv", - "dataformat_trades", + 'exchange', + 'timeframe', + 'max_open_trades', + 'stake_currency', + 'stake_amount', + 'tradable_balance_ratio', + 'last_stake_amount_min_ratio', + 'dry_run', + 'dry_run_wallet', + 'exit_pricing', + 'entry_pricing', + 'stoploss', + 'minimal_roi', + 'internals', + 'dataformat_ohlcv', + 'dataformat_trades', ] SCHEMA_BACKTEST_REQUIRED = [ - "exchange", - "max_open_trades", - "stake_currency", - "stake_amount", - "dry_run_wallet", - "dataformat_ohlcv", - "dataformat_trades", + 'exchange', + 'max_open_trades', + 'stake_currency', + 'stake_amount', + 'dry_run_wallet', + 'dataformat_ohlcv', + 'dataformat_trades', ] SCHEMA_BACKTEST_REQUIRED_FINAL = SCHEMA_BACKTEST_REQUIRED + [ - "stoploss", - "minimal_roi", + 'stoploss', + 'minimal_roi', ] SCHEMA_MINIMAL_REQUIRED = [ - "exchange", - "dry_run", - "dataformat_ohlcv", - "dataformat_trades", + 'exchange', + 'dry_run', + 'dataformat_ohlcv', + 'dataformat_trades', ] CANCEL_REASON = { @@ -576,4 +534,4 @@ TradeList = List[List] LongShort = Literal['long', 'short'] EntryExit = Literal['entry', 'exit'] -BuySell = Literal['buy', 'sell'] +BuySell = Literal['buy', 'sell'] \ No newline at end of file From b03c7b514ddca28f4b0f49807d0ac42d717d1f0c Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 13:15:06 +0200 Subject: [PATCH 013/308] optional style for interfacing freqai with backtesting --- freqtrade/freqai/data_kitchen.py | 9 +-------- freqtrade/optimize/backtesting.py | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 38d518e23..600f82e21 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -304,13 +304,6 @@ class FreqaiDataKitchen: timerange_train.startts = timerange_train.startts + bt_period timerange_train.stopts = timerange_train.startts + train_period - # make sure we finish with a full backtest - # if timerange_train.stopts > config_timerange.stopts - bt_period: - # within_config_timerange = False - # timerange_train.stopts = config_timerange.stopts - bt_period - # # if a full training period doesnt fit, we stop - # if timerange_train.stopts > full_timerange.stopts: - # break first = False start = datetime.datetime.utcfromtimestamp(timerange_train.startts) stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) @@ -335,7 +328,7 @@ class FreqaiDataKitchen: if timerange_backtest.stopts == config_timerange.stopts: break - print(tr_training_list, tr_backtesting_list) + # print(tr_training_list, tr_backtesting_list) return tr_training_list, tr_backtesting_list def slice_dataframe(self, tr: str, df: DataFrame) -> DataFrame: diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index f976b1238..a753a3b07 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -204,7 +204,7 @@ class Backtesting: """ self.progress.init_step(BacktestState.DATALOAD, 1) - if self.config['freqai']['train_period'] > 0: + if self.config.get('freqai', {}).get('train_period') > 0: self.required_startup += int((self.config['freqai']['train_period'] * 86400) / timeframe_to_seconds(self.config['timeframe'])) logger.info("Increasing startup_candle_count for freqai to %s", self.required_startup) From b08c0888bbfde75171057004dffd1c871930a536 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 13:35:01 +0200 Subject: [PATCH 014/308] add USERPATH_FREQAIMODELS, remove return values from @abstract methods --- freqtrade/constants.py | 1 + freqtrade/freqai/freqai_interface.py | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 653fa8c67..c19a71c61 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -55,6 +55,7 @@ FTHYPT_FILEVERSION = 'fthypt_fileversion' USERPATH_HYPEROPTS = 'hyperopts' USERPATH_STRATEGIES = 'strategies' USERPATH_NOTEBOOKS = 'notebooks' +USERPATH_FREQAIMODELS = 'freqaimodels' TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent'] WEBHOOK_FORMAT_OPTIONS = ['form', 'json', 'raw'] diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 63e94383c..081e69de4 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -110,8 +110,6 @@ class IFreqaiModel(ABC): :model: Trained model which can be used to inference (self.predict) """ - return Any - @abstractmethod def fit(self) -> Any: """ @@ -123,8 +121,6 @@ class IFreqaiModel(ABC): all the training and test data/labels. """ - return Any - @abstractmethod def predict(self, dataframe: DataFrame) -> Tuple[np.array, np.array]: """ @@ -136,8 +132,6 @@ class IFreqaiModel(ABC): data (NaNs) or felt uncertain about data (PCA and DI index) """ - return np.array([]), np.array([]) - def model_exists(self, pair: str, training_timerange: str) -> bool: """ Given a pair and path, check if a model already exists From f653ace24bda2d0b900fdfad3a810242cd98cc48 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 15:10:11 +0200 Subject: [PATCH 015/308] another attempt at fixing datalength bug --- freqtrade/freqai/data_kitchen.py | 29 +++++++++++++++------------- freqtrade/freqai/freqai_interface.py | 5 ++++- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 600f82e21..eac5eac30 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -39,6 +39,10 @@ class FreqaiDataKitchen: self.do_predict = np.array([]) self.target_mean = np.array([]) self.target_std = np.array([]) + self.full_predictions = np.array([]) + self.full_do_predict = np.array([]) + self.full_target_mean = np.array([]) + self.full_target_std = np.array([]) self.model_path = Path() self.model_filename = "" @@ -313,12 +317,11 @@ class FreqaiDataKitchen: timerange_backtest.startts = timerange_train.stopts + timerange_backtest.stopts = timerange_backtest.startts + bt_period + if timerange_backtest.stopts > config_timerange.stopts: timerange_backtest.stopts = config_timerange.stopts - else: - timerange_backtest.stopts = timerange_backtest.startts + bt_period - start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) tr_backtesting_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) @@ -328,7 +331,7 @@ class FreqaiDataKitchen: if timerange_backtest.stopts == config_timerange.stopts: break - # print(tr_training_list, tr_backtesting_list) + print(tr_training_list, tr_backtesting_list) return tr_training_list, tr_backtesting_list def slice_dataframe(self, tr: str, df: DataFrame) -> DataFrame: @@ -536,10 +539,10 @@ class FreqaiDataKitchen: ones = np.ones(len_dataframe) s_mean, s_std = ones * self.data["s_mean"], ones * self.data["s_std"] - self.predictions = np.append(self.predictions, predictions) - self.do_predict = np.append(self.do_predict, do_predict) - self.target_mean = np.append(self.target_mean, s_mean) - self.target_std = np.append(self.target_std, s_std) + self.full_predictions = np.append(self.full_predictions, predictions) + self.full_do_predict = np.append(self.full_do_predict, do_predict) + self.full_target_mean = np.append(self.full_target_mean, s_mean) + self.full_target_std = np.append(self.full_target_std, s_std) return @@ -549,11 +552,11 @@ class FreqaiDataKitchen: when it goes back to the strategy. These rows are not included in the backtest. """ - filler = np.zeros(len_dataframe - len(self.predictions)) # startup_candle_count - self.predictions = np.append(filler, self.predictions) - self.do_predict = np.append(filler, self.do_predict) - self.target_mean = np.append(filler, self.target_mean) - self.target_std = np.append(filler, self.target_std) + filler = np.zeros(len_dataframe - len(self.full_predictions)) # startup_candle_count + self.full_predictions = np.append(filler, self.full_predictions) + self.full_do_predict = np.append(filler, self.full_do_predict) + self.full_target_mean = np.append(filler, self.full_target_mean) + self.full_target_std = np.append(filler, self.full_target_std) return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 081e69de4..002596fee 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -84,10 +84,13 @@ class IFreqaiModel(ABC): preds, do_preds = self.predict(dataframe_backtest) self.dh.append_predictions(preds, do_preds, len(dataframe_backtest)) + print('predictions', len(self.dh.full_predictions), + 'do_predict', len(self.dh.full_do_predict)) self.dh.fill_predictions(len(dataframe)) - return self.dh.predictions, self.dh.do_predict, self.dh.target_mean, self.dh.target_std + return (self.dh.full_predictions, self.dh.full_do_predict, + self.dh.full_target_mean, self.dh.full_target_std) def make_labels(self, dataframe: DataFrame) -> DataFrame: """ From aae233bd6c19e80f8c23a930e3913b2781c455f3 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 15:24:45 +0200 Subject: [PATCH 016/308] try passing the check tests --- freqtrade/optimize/backtesting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index a753a3b07..add864a67 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -204,9 +204,9 @@ class Backtesting: """ self.progress.init_step(BacktestState.DATALOAD, 1) - if self.config.get('freqai', {}).get('train_period') > 0: - self.required_startup += int((self.config['freqai']['train_period'] * 86400) / - timeframe_to_seconds(self.config['timeframe'])) + if self.config.get('freqai') is not None: + self.required_startup += int((self.config.get('freqai', {}).get('train_period') * + 86400) / timeframe_to_seconds(self.config['timeframe'])) logger.info("Increasing startup_candle_count for freqai to %s", self.required_startup) self.config['startup_candle_count'] = self.required_startup From a4f5811a5b1cdb030af85ac63135e331d4ac83fe Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 15:36:15 +0200 Subject: [PATCH 017/308] fix flake8 issue in arguments.py --- 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 f47748502..bdd6e4fb4 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -12,7 +12,8 @@ from freqtrade.constants import DEFAULT_CONFIG ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_data_dir"] -ARGS_STRATEGY = ["strategy", "strategy_path", "recursive_strategy_search", "freqaimodel", "freqaimodel_path"] +ARGS_STRATEGY = ["strategy", "strategy_path", "recursive_strategy_search", "freqaimodel", + "freqaimodel_path"] ARGS_TRADE = ["db_url", "sd_notify", "dry_run", "dry_run_wallet", "fee"] From 178c2014b044632c87c9295b37c7ef861fb0cf37 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 6 May 2022 16:20:52 +0200 Subject: [PATCH 018/308] appease mypy --- freqtrade/freqai/data_kitchen.py | 23 +++++++++++++---------- freqtrade/freqai/freqai_interface.py | 16 ++++++++++++---- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index eac5eac30..b2ea71984 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -8,6 +8,7 @@ from pathlib import Path from typing import Any, Dict, List, Tuple import numpy as np +import numpy.typing as npt import pandas as pd from joblib import dump, load from pandas import DataFrame @@ -35,14 +36,14 @@ class FreqaiDataKitchen: self.data_dictionary: Dict[Any, Any] = {} self.config = config self.freqai_config = config["freqai"] - self.predictions = np.array([]) - self.do_predict = np.array([]) - self.target_mean = np.array([]) - self.target_std = np.array([]) - self.full_predictions = np.array([]) - self.full_do_predict = np.array([]) - self.full_target_mean = np.array([]) - self.full_target_std = np.array([]) + self.predictions: npt.ArrayLike = np.array([]) + self.do_predict: npt.ArrayLike = np.array([]) + self.target_mean: npt.ArrayLike = np.array([]) + self.target_std: npt.ArrayLike = np.array([]) + self.full_predictions: npt.ArrayLike = np.array([]) + self.full_do_predict: npt.ArrayLike = np.array([]) + self.full_target_mean: npt.ArrayLike = np.array([]) + self.full_target_std: npt.ArrayLike = np.array([]) self.model_path = Path() self.model_filename = "" @@ -123,6 +124,7 @@ class FreqaiDataKitchen: :labels: cleaned labels ready to be split. """ + weights: npt.ArrayLike if self.config["freqai"]["feature_parameters"]["weight_factor"] > 0: weights = self.set_weights_higher_recent(len(filtered_dataframe)) else: @@ -519,12 +521,13 @@ class FreqaiDataKitchen: self.do_predict += do_predict self.do_predict -= 1 - def set_weights_higher_recent(self, num_weights: int) -> int: + def set_weights_higher_recent(self, num_weights: int) -> npt.ArrayLike: """ Set weights so that recent data is more heavily weighted during training than older data. """ - weights = np.zeros(num_weights) + + weights = np.zeros_like(num_weights) for i in range(1, len(weights)): weights[len(weights) - i] = np.exp( -i / (self.config["freqai"]["feature_parameters"]["weight_factor"] * num_weights) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 002596fee..16b6fd9f9 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -4,10 +4,12 @@ from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, Tuple -import numpy as np +import numpy.typing as npt import pandas as pd from pandas import DataFrame +from freqtrade.data.dataprovider import DataProvider +from freqtrade.enums import RunMode from freqtrade.freqai.data_kitchen import FreqaiDataKitchen @@ -37,8 +39,9 @@ class IFreqaiModel(ABC): self.current_time = None self.model = None self.predictions = None + self.live_trained_timerange = None - def start(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def start(self, dataframe: DataFrame, metadata: dict, dp: DataProvider) -> DataFrame: """ Entry point to the FreqaiModel, it will train a new model if necesssary before making the prediction. @@ -57,6 +60,9 @@ class IFreqaiModel(ABC): self.pair = metadata["pair"] self.dh = FreqaiDataKitchen(self.config, dataframe) + if dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE): + logger.info('testing live') + logger.info("going to train %s timeranges", len(self.dh.training_timeranges)) # Loop enforcing the sliding window training/backtesting paragigm @@ -99,7 +105,7 @@ class IFreqaiModel(ABC): :dataframe: the full dataframe for the present training period """ - return dataframe + return @abstractmethod def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Any: @@ -124,8 +130,10 @@ class IFreqaiModel(ABC): all the training and test data/labels. """ + return + @abstractmethod - def predict(self, dataframe: DataFrame) -> Tuple[np.array, np.array]: + def predict(self, dataframe: DataFrame) -> Tuple[npt.ArrayLike, npt.ArrayLike]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. From 22bd5556ed21c6483e2b5ebb542e4ea0efa9df0f Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 9 May 2022 15:25:00 +0200 Subject: [PATCH 019/308] add self-retraining functionality for live/dry --- config_examples/config_freqai.example.json | 7 +- freqtrade/constants.py | 2 + freqtrade/freqai/data_kitchen.py | 150 +++++++++++++++--- freqtrade/freqai/freqai_interface.py | 58 ++++++- freqtrade/strategy/interface.py | 16 ++ freqtrade/templates/ExamplePredictionModel.py | 8 +- freqtrade/templates/FreqaiExampleStrategy.py | 21 ++- 7 files changed, 218 insertions(+), 44 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 5bd4de6c4..351585d17 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -13,7 +13,7 @@ "exit": 30 }, "exchange": { - "name": "ftx", + "name": "binance", "key": "", "secret": "", "ccxt_config": { @@ -55,7 +55,9 @@ ], "train_period": 30, "backtest_period": 7, - "identifier": "example", + "identifier": "livetest5", + "live_trained_timerange": "20220330-20220429", + "live_full_backtestrange": "20220302-20220501", "base_features": [ "rsi", "close_over_20sma", @@ -68,6 +70,7 @@ "macd" ], "corr_pairlist": [ + "BTC/USDT", "ETH/USDT", "LINK/USDT", "DOT/USDT" diff --git a/freqtrade/constants.py b/freqtrade/constants.py index c19a71c61..0dc355914 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -440,6 +440,8 @@ CONF_SCHEMA = { "train_period": {"type": "integer", "default": 0}, "backtest_period": {"type": "integer", "default": 7}, "identifier": {"type": "str", "default": "example"}, + "live_trained_timerange": {"type": "str"}, + "live_full_backtestrange": {"type": "str"}, "base_features": {"type": "list"}, "corr_pairlist": {"type": "list"}, "feature_parameters": { diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index b2ea71984..7b6a65a59 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -16,6 +16,10 @@ from sklearn.metrics.pairwise import pairwise_distances from sklearn.model_selection import train_test_split from freqtrade.configuration import TimeRange +from freqtrade.data.history import load_pair_history +from freqtrade.data.history.history_utils import refresh_backtest_ohlcv_data +from freqtrade.resolvers import ExchangeResolver +from freqtrade.strategy.interface import IStrategy SECONDS_IN_DAY = 86400 @@ -30,7 +34,7 @@ class FreqaiDataKitchen: author: Robert Caulk, rob.caulk@gmail.com """ - def __init__(self, config: Dict[str, Any], dataframe: DataFrame): + def __init__(self, config: Dict[str, Any], dataframe: DataFrame, live: bool = False): self.full_dataframe = dataframe self.data: Dict[Any, Any] = {} self.data_dictionary: Dict[Any, Any] = {} @@ -45,17 +49,29 @@ class FreqaiDataKitchen: self.full_target_mean: npt.ArrayLike = np.array([]) self.full_target_std: npt.ArrayLike = np.array([]) self.model_path = Path() - self.model_filename = "" + self.model_filename: str = "" - self.full_timerange = self.create_fulltimerange( - self.config["timerange"], self.freqai_config["train_period"] - ) + if not live: + self.full_timerange = self.create_fulltimerange(self.config["timerange"], + self.freqai_config["train_period"] + ) - (self.training_timeranges, self.backtesting_timeranges) = self.split_timerange( - self.full_timerange, - config["freqai"]["train_period"], - config["freqai"]["backtest_period"], - ) + (self.training_timeranges, self.backtesting_timeranges) = self.split_timerange( + self.full_timerange, + config["freqai"]["train_period"], + config["freqai"]["backtest_period"], + ) + + def set_paths(self) -> None: + self.full_path = Path(self.config['user_data_dir'] / + "models" / + str(self.freqai_config['live_full_backtestrange'] + + self.freqai_config['identifier'])) + + self.model_path = Path(self.full_path / str("sub-train" + "-" + + str(self.freqai_config['live_trained_timerange']))) + + return def save_data(self, model: Any) -> None: """ @@ -187,10 +203,10 @@ class FreqaiDataKitchen: labels = labels[ (drop_index == 0) & (drop_index_labels == 0) ] # assuming the labels depend entirely on the dataframe here. - logger.info( - "dropped %s training points due to NaNs, ensure all historical data downloaded", - len(unfiltered_dataframe) - len(filtered_dataframe), - ) + # logger.info( + # "dropped %s training points due to NaNs, ensure all historical data downloaded", + # len(unfiltered_dataframe) - len(filtered_dataframe), + # ) self.data["filter_drop_index_training"] = drop_index else: @@ -485,11 +501,11 @@ class FreqaiDataKitchen: shift = "" if n > 0: shift = "_shift-" + str(n) - features.append(ft + shift + "_" + tf) + # features.append(ft + shift + "_" + tf) for p in config["freqai"]["corr_pairlist"]: features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) - logger.info("number of features %s", len(features)) + # logger.info("number of features %s", len(features)) return features def check_if_pred_in_training_spaces(self) -> None: @@ -513,10 +529,10 @@ class FreqaiDataKitchen: 0, ) - logger.info( - "Distance checker tossed %s predictions for being too far from training data", - len(do_predict) - do_predict.sum(), - ) + # logger.info( + # "Distance checker tossed %s predictions for being too far from training data", + # len(do_predict) - do_predict.sum(), + # ) self.do_predict += do_predict self.do_predict -= 1 @@ -577,15 +593,105 @@ class FreqaiDataKitchen: / str(full_timerange + self.freqai_config["identifier"]) ) + config_path = Path(self.config["config_files"][0]) + if not self.full_path.is_dir(): self.full_path.mkdir(parents=True, exist_ok=True) shutil.copy( - Path(self.config["config_files"][0]).name, - Path(self.full_path / self.config["config_files"][0]), + config_path.name, + Path(self.full_path / config_path.parts[-1]), ) return full_timerange + def check_if_new_training_required(self, training_timerange: str, + metadata: dict) -> Tuple[bool, str]: + + time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() + + trained_timerange = TimeRange.parse_timerange(training_timerange) + + elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY + + trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + start = datetime.datetime.utcfromtimestamp(trained_timerange.startts) + stop = datetime.datetime.utcfromtimestamp(trained_timerange.stopts) + + new_trained_timerange = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") + + retrain = elapsed_time > self.freqai_config['backtest_period'] + + if retrain: + coin, _ = metadata['pair'].split("/") + # set the new model_path + self.model_path = Path(self.full_path / str("sub-train" + "-" + + str(new_trained_timerange))) + + self.model_filename = "cb_" + coin.lower() + "_" + new_trained_timerange + # this is not persistent at the moment TODO + self.freqai_config['live_trained_timerange'] = new_trained_timerange + # enables persistence, but not fully implemented into save/load data yer + self.data['live_trained_timerange'] = new_trained_timerange + + return retrain, new_trained_timerange + + def download_new_data_for_retraining(self, new_timerange: str, metadata: dict) -> None: + + exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], + self.config, validate=False) + pairs = self.freqai_config['corr_pairlist'] + [metadata['pair']] + timerange = TimeRange.parse_timerange(new_timerange) + # data_handler = get_datahandler(datadir, data_format) + + refresh_backtest_ohlcv_data( + exchange, pairs=pairs, timeframes=self.freqai_config['timeframes'], + datadir=self.config['datadir'], timerange=timerange, + new_pairs_days=self.config['new_pairs_days'], + erase=False, data_format=self.config['dataformat_ohlcv'], + trading_mode=self.config.get('trading_mode', 'spot'), + prepend=self.config.get('prepend_data', False) + ) + + def load_pairs_histories(self, new_timerange: str, metadata: dict) -> Tuple[Dict[Any, Any], + DataFrame]: + corr_dataframes: Dict[Any, Any] = {} + # pair_dataframes: Dict[Any, Any] = {} + pairs = self.freqai_config['corr_pairlist'] # + [metadata['pair']] + timerange = TimeRange.parse_timerange(new_timerange) + + for p in pairs: + corr_dataframes[p] = {} + for tf in self.freqai_config['timeframes']: + corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], + timeframe=tf, + pair=p, timerange=timerange) + + base_dataframe = [dataframe for key, dataframe in corr_dataframes.items() + if metadata['pair'] in key] + + # [0] indexes the lowest tf for the basepair + return corr_dataframes, base_dataframe[0][self.config['timeframe']] + + def use_strategy_to_populate_indicators(self, strategy: IStrategy, metadata: dict, + corr_dataframes: dict, + dataframe: DataFrame) -> DataFrame: + + # dataframe = pair_dataframes[0] # this is the base tf pair df + + for tf in self.freqai_config["timeframes"]: + # dataframe = strategy.populate_any_indicators(metadata["pair"], dataframe.copy, + # tf, pair_dataframes[tf]) + for i in self.freqai_config["corr_pairlist"]: + dataframe = strategy.populate_any_indicators(i, + dataframe.copy(), + tf, + corr_dataframes[i][tf], + coin=i.split("/")[0] + "-" + ) + + return dataframe + def np_encoder(self, object): if isinstance(object, np.generic): return object.item() diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 16b6fd9f9..222061e2a 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -8,9 +8,9 @@ import numpy.typing as npt import pandas as pd from pandas import DataFrame -from freqtrade.data.dataprovider import DataProvider from freqtrade.enums import RunMode from freqtrade.freqai.data_kitchen import FreqaiDataKitchen +from freqtrade.strategy.interface import IStrategy pd.options.mode.chained_assignment = None @@ -33,15 +33,14 @@ class IFreqaiModel(ABC): self.data_split_parameters = config["freqai"]["data_split_parameters"] self.model_training_parameters = config["freqai"]["model_training_parameters"] self.feature_parameters = config["freqai"]["feature_parameters"] - self.backtest_timerange = config["timerange"] + # self.backtest_timerange = config["timerange"] self.time_last_trained = None self.current_time = None self.model = None self.predictions = None - self.live_trained_timerange = None - def start(self, dataframe: DataFrame, metadata: dict, dp: DataProvider) -> DataFrame: + def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ Entry point to the FreqaiModel, it will train a new model if necesssary before making the prediction. @@ -57,11 +56,18 @@ class IFreqaiModel(ABC): the model. :metadata: pair metadataa coming from strategy. """ - self.pair = metadata["pair"] - self.dh = FreqaiDataKitchen(self.config, dataframe) - if dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE): - logger.info('testing live') + live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) + + self.pair = metadata["pair"] + self.dh = FreqaiDataKitchen(self.config, dataframe, live) + + if live: + # logger.info('testing live') + self.start_live(dataframe, metadata, strategy) + + return (self.dh.full_predictions, self.dh.full_do_predict, + self.dh.full_target_mean, self.dh.full_target_std) logger.info("going to train %s timeranges", len(self.dh.training_timeranges)) @@ -98,6 +104,42 @@ class IFreqaiModel(ABC): return (self.dh.full_predictions, self.dh.full_do_predict, self.dh.full_target_mean, self.dh.full_target_std) + def start_live(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> None: + + self.dh.set_paths() + + file_exists = self.model_exists(metadata['pair'], + training_timerange=self.freqai_info[ + 'live_trained_timerange']) + + (retrain, + new_trained_timerange) = self.dh.check_if_new_training_required(self.freqai_info[ + 'live_trained_timerange'], + metadata) + + if retrain or not file_exists: + self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) + # dataframe = download-data + corr_dataframes, pair_dataframes = self.dh.load_pairs_histories(new_trained_timerange, + metadata) + + unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, + metadata, + corr_dataframes, + pair_dataframes) + + self.model = self.train(unfiltered_dataframe, metadata) + self.dh.save_data(self.model) + + self.freqai_info + + self.model = self.dh.load_data() + preds, do_preds = self.predict(dataframe) + self.dh.append_predictions(preds, do_preds, len(dataframe)) + # dataframe should have len 1 here + + return + def make_labels(self, dataframe: DataFrame) -> DataFrame: """ User defines the labels here (target values). diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 57afbf32a..e681d70bd 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -532,6 +532,22 @@ class IStrategy(ABC, HyperStrategyMixin): """ return None + def populate_any_indicators(self, pair: str, df: DataFrame, tf: str, + informative: DataFrame = None, coin: str = "") -> DataFrame: + """ + Function designed to automatically generate, name and merge features + from user indicated timeframes in the configuration file. User can add + additional features here, but must follow the naming convention. + Defined in IStrategy because Freqai needs to know it exists. + :params: + :pair: pair to be used as informative + :df: strategy dataframe which will receive merges from informatives + :tf: timeframe of the dataframe which will modify the feature names + :informative: the dataframe associated with the informative pair + :coin: the name of the coin which will modify the feature names. + """ + return df + ### # END - Intended to be overridden by strategy ### diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index 35f25775a..08f9d2ba9 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -124,7 +124,7 @@ class ExamplePredictionModel(IFreqaiModel): data (NaNs) or felt uncertain about data (PCA and DI index) """ - logger.info("--------------------Starting prediction--------------------") + # logger.info("--------------------Starting prediction--------------------") original_feature_list = self.dh.build_feature_list(self.config) filtered_dataframe, _ = self.dh.filter_features( @@ -151,8 +151,8 @@ class ExamplePredictionModel(IFreqaiModel): predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) # compute the non-standardized predictions - predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] + self.dh.predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] - logger.info("--------------------Finished prediction--------------------") + # logger.info("--------------------Finished prediction--------------------") - return (predictions, self.dh.do_predict) + return (self.dh.predictions, self.dh.do_predict) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 873b31115..13309d8c3 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -44,13 +44,16 @@ class FreqaiExampleStrategy(IStrategy): stoploss = -0.05 use_sell_signal = True - startup_candle_count: int = 1000 + startup_candle_count: int = 300 def informative_pairs(self): - pairs = self.freqai_info["corr_pairlist"] + pairs = self.config["freqai"]["corr_pairlist"] informative_pairs = [] - for tf in self.timeframes: - informative_pairs.append([(pair, tf) for pair in pairs]) + for tf in self.config["freqai"]["timeframes"]: + # informative_pairs.append((self.pair, tf)) + # informative_pairs.append([(pair, tf) for pair in pairs]) + for pair in pairs: + informative_pairs.append((pair, tf)) return informative_pairs def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): @@ -129,6 +132,7 @@ class FreqaiExampleStrategy(IStrategy): # the configuration file parameters are stored here self.freqai_info = self.config["freqai"] + self.pair = metadata['pair'] # the model is instantiated here self.model = CustomModel(self.config) @@ -138,12 +142,13 @@ class FreqaiExampleStrategy(IStrategy): # the following loops are necessary for building the features # indicated by the user in the configuration file. for tf in self.freqai_info["timeframes"]: - dataframe = self.populate_any_indicators(metadata["pair"], dataframe.copy(), tf) - for i in self.freqai_info["corr_pairlist"]: + # dataframe = self.populate_any_indicators(metadata["pair"], dataframe.copy(), tf) + for pair in self.freqai_info["corr_pairlist"]: dataframe = self.populate_any_indicators( - i, dataframe.copy(), tf, coin=i.split("/")[0] + "-" + pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" ) + print('dataframe_built') # the model will return 4 values, its prediction, an indication of whether or not the # prediction should be accepted, the target mean/std values from the labels used during # each training period. @@ -152,7 +157,7 @@ class FreqaiExampleStrategy(IStrategy): dataframe["do_predict"], dataframe["target_mean"], dataframe["target_std"], - ) = self.model.bridge.start(dataframe, metadata) + ) = self.model.bridge.start(dataframe, metadata, self) dataframe["target_roi"] = dataframe["target_mean"] + dataframe["target_std"] * 0.5 dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] * 1.5 From 9b3e5faebeb2235358ccc9ca003014fb89d64567 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 9 May 2022 17:01:49 +0200 Subject: [PATCH 020/308] create more flexible whitelist, avoid duplicating whitelist features into corr_pairlist, update docs --- config_examples/config_freqai.example.json | 5 +- docs/freqai.md | 82 ++++++++++++++++--- freqtrade/freqai/data_kitchen.py | 47 +++++++---- freqtrade/freqai/freqai_interface.py | 12 +-- freqtrade/templates/ExamplePredictionModel.py | 7 +- freqtrade/templates/FreqaiExampleStrategy.py | 5 +- 6 files changed, 119 insertions(+), 39 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 351585d17..d89c835b1 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -24,7 +24,8 @@ "rateLimit": 200 }, "pair_whitelist": [ - "BTC/USDT" + "BTC/USDT", + "ETH/USDT" ], "pair_blacklist": [] }, @@ -55,7 +56,7 @@ ], "train_period": 30, "backtest_period": 7, - "identifier": "livetest5", + "identifier": "new_corrlist", "live_trained_timerange": "20220330-20220429", "live_full_backtestrange": "20220302-20220501", "base_features": [ diff --git a/docs/freqai.md b/docs/freqai.md index 844881613..431705dd9 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -65,8 +65,6 @@ config setup includes: "feature_parameters" : { "period": 24, "shift": 2, - "drop_features": false, - "DI_threshold": 1, "weight_factor": 0, }, "data_split_parameters" : { @@ -79,8 +77,7 @@ config setup includes: "learning_rate": 0.02, "task_type": "CPU", }, - }, - + } ``` ### Building the feature set @@ -153,8 +150,6 @@ The Freqai strategy requires the user to include the following lines of code in # the following loops are necessary for building the features # indicated by the user in the configuration file. for tf in self.freqai_info['timeframes']: - dataframe = self.populate_any_indicators(metadata['pair'], - dataframe.copy(), tf) for i in self.freqai_info['corr_pairlist']: dataframe = self.populate_any_indicators(i, dataframe.copy(), tf, coin=i.split("/")[0]+'-') @@ -177,8 +172,36 @@ and `make_labels()` to let them customize various aspects of their training proc ### Running the model live -TODO: Freqai is not automated for live yet. +Freqai can be run dry/live using the following command +```bash +freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel ExamplePredictionModel +``` + +By default, Freqai will not find find any existing models and will start by training a new one +given the user configuration settings. Following training, it will use that model to predict for the +duration of `backtest_period`. After a full `backtest_period` has elapsed, Freqai will auto retrain +a new model, and begin making predictions with the updated model. + +If the user wishes to start dry/live from a saved model, the following configuration +parameters need to be set: + +```json + "freqai": { + "identifier": "example", + "live_trained_timerange": "20220330-20220429", + "live_full_backtestrange": "20220302-20220501" + } +``` + +Where the `identifier` is the same identifier which was set during the backtesting/training. Meanwhile, +the `live_trained_timerange` is the sub-trained timerange (the training window) which was set +during backtesting/training. These are available to the user inside `user_data/models/*/sub-train-*`. +`live_full_backtestrange` was the full data range assocaited with the backtest/training (the full time +window that the training window and backtesting windows slide through). These values can be located +inside the `user_data/models/` directory. In this case, although Freqai will initiate with a +pretrained model, if a full `backtest_period` has elapsed since the end of the user set +`live_trained_timerange`, it will self retrain. ## Data anylsis techniques ### Controlling the model learning process @@ -226,12 +249,49 @@ $$ DI_k = d_k/\overline{d} $$ Equity and crypto markets suffer from a high level of non-patterned noise in the form of outlier data points. The dissimilarity index allows predictions which are outliers and not existent in the model feature space, to be thrown out due -to low levels of certainty. The user can tweak the DI with `DI_threshold` to increase -or decrease the extrapolation of the trained model. +to low levels of certainty. Activating the Dissimilarity Index can be achieved with: + +```json + "freqai": { + "feature_parameters" : { + "DI_threshold": 1 + } + } +``` + +The user can tweak the DI with `DI_threshold` to increase or decrease the extrapolation of the +trained model. ### Reducing data dimensionality with Principal Component Analysis -TO BE WRITTEN +Users can reduce the dimensionality of their features by activating the `principal_component_analysis`: + +```json + "freqai": { + "feature_parameters" : { + "principal_component_analysis": true + } + } +``` + +Which will perform PCA on the features and reduce the dimensionality of the data so that the explained +variance of the data set is >= 0.999. + +### Removing outliers based on feature statistical distributions + +The user can tell Freqai to remove outlier data points from the trainig/test data sets by setting: + +```json + "freqai": { + "feature_parameters" : { + "remove_outliers": true + } + } +``` + +Freqai will check the statistical distributions of each feature (or component if the user activated +`principal_component_analysis`) and remove any data point that sits more than 3 standard deviations away +from the mean. ## Additional information ### Feature standardization @@ -242,5 +302,5 @@ data only. This includes all test data and unseen prediction data (dry/live/back ### File structure `user_data_dir/models/` contains all the data associated with the trainings and -backtestings. This file structure is heavily controlled and read by the `DataHandler()` +backtestings. This file structure is heavily controlled and read by the `FreqaiDataKitchen()` and should thus not be modified. diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 7b6a65a59..961f26e57 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -485,7 +485,7 @@ class FreqaiDataKitchen: return - def build_feature_list(self, config: dict) -> list: + def build_feature_list(self, config: dict, metadata: dict) -> list: """ Build the list of features that will be used to filter the full dataframe. Feature list is construced from the @@ -501,8 +501,10 @@ class FreqaiDataKitchen: shift = "" if n > 0: shift = "_shift-" + str(n) - # features.append(ft + shift + "_" + tf) + features.append(metadata['pair'].split("/")[0] + "-" + ft + shift + "_" + tf) for p in config["freqai"]["corr_pairlist"]: + if metadata['pair'] in p: + continue # avoid duplicate features features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) # logger.info("number of features %s", len(features)) @@ -640,9 +642,10 @@ class FreqaiDataKitchen: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config, validate=False) - pairs = self.freqai_config['corr_pairlist'] + [metadata['pair']] + pairs = self.freqai_config['corr_pairlist'] + if metadata['pair'] not in pairs: + pairs += metadata['pair'] # dont include pair twice timerange = TimeRange.parse_timerange(new_timerange) - # data_handler = get_datahandler(datadir, data_format) refresh_backtest_ohlcv_data( exchange, pairs=pairs, timeframes=self.freqai_config['timeframes'], @@ -656,33 +659,45 @@ class FreqaiDataKitchen: def load_pairs_histories(self, new_timerange: str, metadata: dict) -> Tuple[Dict[Any, Any], DataFrame]: corr_dataframes: Dict[Any, Any] = {} - # pair_dataframes: Dict[Any, Any] = {} + base_dataframes: Dict[Any, Any] = {} pairs = self.freqai_config['corr_pairlist'] # + [metadata['pair']] timerange = TimeRange.parse_timerange(new_timerange) - for p in pairs: - corr_dataframes[p] = {} - for tf in self.freqai_config['timeframes']: + for tf in self.freqai_config['timeframes']: + base_dataframes[tf] = load_pair_history(datadir=self.config['datadir'], + timeframe=tf, + pair=metadata['pair'], timerange=timerange) + for p in pairs: + if metadata['pair'] in p: + continue # dont repeat anything from whitelist + corr_dataframes[p] = {} corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, pair=p, timerange=timerange) - base_dataframe = [dataframe for key, dataframe in corr_dataframes.items() - if metadata['pair'] in key] + # base_dataframe = [dataframe for key, dataframe in corr_dataframes.items() + # if metadata['pair'] in key] # [0] indexes the lowest tf for the basepair - return corr_dataframes, base_dataframe[0][self.config['timeframe']] + return corr_dataframes, base_dataframes - def use_strategy_to_populate_indicators(self, strategy: IStrategy, metadata: dict, + def use_strategy_to_populate_indicators(self, strategy: IStrategy, corr_dataframes: dict, - dataframe: DataFrame) -> DataFrame: + base_dataframes: dict, + metadata: dict) -> DataFrame: - # dataframe = pair_dataframes[0] # this is the base tf pair df + dataframe = base_dataframes[self.config['timeframe']] for tf in self.freqai_config["timeframes"]: - # dataframe = strategy.populate_any_indicators(metadata["pair"], dataframe.copy, - # tf, pair_dataframes[tf]) + dataframe = strategy.populate_any_indicators(metadata['pair'], + dataframe.copy(), + tf, + base_dataframes[tf], + coin=metadata['pair'].split("/")[0] + "-" + ) for i in self.freqai_config["corr_pairlist"]: + if metadata['pair'] in i: + continue # dont repeat anything from whitelist dataframe = strategy.populate_any_indicators(i, dataframe.copy(), tf, diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 222061e2a..e019eb842 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -93,7 +93,7 @@ class IFreqaiModel(ABC): else: self.model = self.dh.load_data() - preds, do_preds = self.predict(dataframe_backtest) + preds, do_preds = self.predict(dataframe_backtest, metadata) self.dh.append_predictions(preds, do_preds, len(dataframe_backtest)) print('predictions', len(self.dh.full_predictions), @@ -120,13 +120,13 @@ class IFreqaiModel(ABC): if retrain or not file_exists: self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) # dataframe = download-data - corr_dataframes, pair_dataframes = self.dh.load_pairs_histories(new_trained_timerange, + corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, metadata) unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, - metadata, corr_dataframes, - pair_dataframes) + base_dataframes, + metadata) self.model = self.train(unfiltered_dataframe, metadata) self.dh.save_data(self.model) @@ -134,7 +134,7 @@ class IFreqaiModel(ABC): self.freqai_info self.model = self.dh.load_data() - preds, do_preds = self.predict(dataframe) + preds, do_preds = self.predict(dataframe, metadata) self.dh.append_predictions(preds, do_preds, len(dataframe)) # dataframe should have len 1 here @@ -175,7 +175,7 @@ class IFreqaiModel(ABC): return @abstractmethod - def predict(self, dataframe: DataFrame) -> Tuple[npt.ArrayLike, npt.ArrayLike]: + def predict(self, dataframe: DataFrame, metadata: dict) -> Tuple[npt.ArrayLike, npt.ArrayLike]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index 08f9d2ba9..3db8d3aeb 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -53,7 +53,7 @@ class ExamplePredictionModel(IFreqaiModel): logger.info("--------------------Starting training--------------------") # create the full feature list based on user config info - self.dh.training_features_list = self.dh.build_feature_list(self.config) + self.dh.training_features_list = self.dh.build_feature_list(self.config, metadata) unfiltered_labels = self.make_labels(unfiltered_dataframe) # filter the features requested by user in the configuration file and elegantly handle NaNs @@ -114,7 +114,8 @@ class ExamplePredictionModel(IFreqaiModel): return model - def predict(self, unfiltered_dataframe: DataFrame) -> Tuple[DataFrame, DataFrame]: + def predict(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, + DataFrame]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. @@ -126,7 +127,7 @@ class ExamplePredictionModel(IFreqaiModel): # logger.info("--------------------Starting prediction--------------------") - original_feature_list = self.dh.build_feature_list(self.config) + original_feature_list = self.dh.build_feature_list(self.config, metadata) filtered_dataframe, _ = self.dh.filter_features( unfiltered_dataframe, original_feature_list, training_filter=False ) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 13309d8c3..45526e2ac 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -142,8 +142,11 @@ class FreqaiExampleStrategy(IStrategy): # the following loops are necessary for building the features # indicated by the user in the configuration file. for tf in self.freqai_info["timeframes"]: - # dataframe = self.populate_any_indicators(metadata["pair"], dataframe.copy(), tf) + dataframe = self.populate_any_indicators(self.pair, dataframe.copy(), tf, + coin=self.pair.split("/")[0] + "-") for pair in self.freqai_info["corr_pairlist"]: + if metadata['pair'] in pair: + continue # do not include whitelisted pair twice if it is in corr_pairlist dataframe = self.populate_any_indicators( pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" ) From a7029e35b51404424f872e1663d9602f29695607 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 10 May 2022 11:39:01 +0200 Subject: [PATCH 021/308] ensure informative pairs includes any combination of whitelist - corr_pairlist --- freqtrade/templates/FreqaiExampleStrategy.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 45526e2ac..e2bb6e041 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -47,12 +47,15 @@ class FreqaiExampleStrategy(IStrategy): startup_candle_count: int = 300 def informative_pairs(self): - pairs = self.config["freqai"]["corr_pairlist"] + whitelist_pairs = self.dp.current_whitelist() + corr_pairs = self.config["freqai"]["corr_pairlist"] informative_pairs = [] for tf in self.config["freqai"]["timeframes"]: - # informative_pairs.append((self.pair, tf)) - # informative_pairs.append([(pair, tf) for pair in pairs]) - for pair in pairs: + for pair in whitelist_pairs: + informative_pairs.append((pair, tf)) + for pair in corr_pairs: + if pair in whitelist_pairs: + continue # avoid duplication informative_pairs.append((pair, tf)) return informative_pairs From a8022c104a23f0a25e2fc4f6b65c15746be83824 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 15 May 2022 14:01:53 +0200 Subject: [PATCH 022/308] give beta testers more information in the doc --- docs/freqai.md | 17 +++++++++++++++++ freqtrade/freqai/data_kitchen.py | 2 -- freqtrade/templates/ExamplePredictionModel.py | 4 ++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 431705dd9..0fb1fa4c6 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -41,6 +41,23 @@ in the model. intermediate performance of the model during training. This data does not directly influence nodal weights within the model. +## Install prerequisites + +Use `pip` to install the prerequisities with: + +`pip install -r requirements-freqai.txt` + +## Running from the example files + +An example strategy, example prediction model, and example config can all be found in +`freqtrade/templates/ExampleFreqaiStrategy.py`, `freqtrade/templates/ExamplePredictionModel.py`, +`config_examples/config_freqai.example.json`, respectively. Assuming the user has downloaded +the necessary data, Freqai can be executed from these templates with: + +`freqtrade backtesting --config config_examples/config_freqai.example.json--strategy +ExampleFreqaiStrategy --freqaimodel ExamplePredictionModel +--freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates` + ## Configuring the bot ### Example config file The user interface is isolated to the typical config file. A typical Freqai diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 961f26e57..364b503e9 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -113,8 +113,6 @@ class FreqaiDataKitchen: with open(self.model_path / str(self.model_filename + "_metadata.json"), "r") as fp: self.data = json.load(fp) self.training_features_list = self.data["training_features_list"] - # if self.data.get("training_features_list"): - # self.training_features_list = [*self.data.get("training_features_list")] self.data_dictionary["train_features"] = pd.read_pickle( self.model_path / str(self.model_filename + "_trained_df.pkl") diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index 3db8d3aeb..796fb23ed 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -42,8 +42,8 @@ class ExamplePredictionModel(IFreqaiModel): def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: """ - Filter the training data and train a model to it. Train makes heavy use of the datahandler - for storing, saving, loading, and managed. + Filter the training data and train a model to it. Train makes heavy use of the datahkitchen + for storing, saving, loading, and analyzing the data. :params: :unfiltered_dataframe: Full dataframe for the current training period :metadata: pair metadata from strategy. From 717df891b1ecc7ce6c148149c32d51609af47147 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 15 May 2022 14:05:19 +0200 Subject: [PATCH 023/308] use bash visual in doc --- docs/freqai.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 0fb1fa4c6..fd84dffc6 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -54,9 +54,11 @@ An example strategy, example prediction model, and example config can all be fou `config_examples/config_freqai.example.json`, respectively. Assuming the user has downloaded the necessary data, Freqai can be executed from these templates with: -`freqtrade backtesting --config config_examples/config_freqai.example.json--strategy +```bash +freqtrade backtesting --config config_examples/config_freqai.example.json--strategy ExampleFreqaiStrategy --freqaimodel ExamplePredictionModel ---freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates` +--freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates +``` ## Configuring the bot ### Example config file From f4296173e938fe5f32421f1750fa15274f1a1fd9 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 15 May 2022 14:31:26 +0200 Subject: [PATCH 024/308] use bash visual in doc --- docs/freqai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai.md b/docs/freqai.md index fd84dffc6..11ef972c7 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -56,7 +56,7 @@ the necessary data, Freqai can be executed from these templates with: ```bash freqtrade backtesting --config config_examples/config_freqai.example.json--strategy -ExampleFreqaiStrategy --freqaimodel ExamplePredictionModel +FreqaiExampleStrategy --freqaimodel ExamplePredictionModel --freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates ``` From e5759d950b111b60c3650e5a69285718db566645 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 15 May 2022 14:32:17 +0200 Subject: [PATCH 025/308] fix typo --- docs/freqai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai.md b/docs/freqai.md index 11ef972c7..9e9155826 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -55,7 +55,7 @@ An example strategy, example prediction model, and example config can all be fou the necessary data, Freqai can be executed from these templates with: ```bash -freqtrade backtesting --config config_examples/config_freqai.example.json--strategy +freqtrade backtesting --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel ExamplePredictionModel --freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates ``` From 9e94d28860515018e472e8079d9d6e1f9b39886b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 15 May 2022 14:33:39 +0200 Subject: [PATCH 026/308] add timerange to backtest commnad --- docs/freqai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai.md b/docs/freqai.md index 9e9155826..6b7a4d5c8 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -57,7 +57,7 @@ the necessary data, Freqai can be executed from these templates with: ```bash freqtrade backtesting --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel ExamplePredictionModel ---freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates +--freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates --timerange 20220101-220201 ``` ## Configuring the bot From 80dcd88abf33f42510f97d75de6998ce397a2f50 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 15 May 2022 15:26:09 +0200 Subject: [PATCH 027/308] allow user to run config from anywhere on their system --- freqtrade/freqai/data_kitchen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 364b503e9..c9d518418 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -598,7 +598,7 @@ class FreqaiDataKitchen: if not self.full_path.is_dir(): self.full_path.mkdir(parents=True, exist_ok=True) shutil.copy( - config_path.name, + config_path.resolve(), Path(self.full_path / config_path.parts[-1]), ) From 8664e8f9a3f57a1ec19a48c74fdd6ac07236bfe2 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 17 May 2022 17:13:38 +0200 Subject: [PATCH 028/308] create a prediction_models folder where basic prediction models can live (similar to optimize/hyperopt-loss. Update resolver/docs/and gitignore to accommodate change --- .gitignore | 2 + docs/freqai.md | 11 +- freqtrade/freqai/freqai_interface.py | 9 +- .../CatboostPredictionModel.py | 159 ++++++++++++++++++ freqtrade/resolvers/freqaimodel_resolver.py | 3 +- user_data/freqaimodels/.gitkeep | 0 6 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 freqtrade/freqai/prediction_models/CatboostPredictionModel.py create mode 100644 user_data/freqaimodels/.gitkeep diff --git a/.gitignore b/.gitignore index 17823f642..dc87402b4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ user_data/* !user_data/strategy/sample_strategy.py !user_data/notebooks !user_data/models +!user_data/freqaimodels +user_data/freqaimodels/* user_data/models/* user_data/notebooks/* freqtrade-plot.html diff --git a/docs/freqai.md b/docs/freqai.md index 6b7a4d5c8..b5aa587bf 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -49,15 +49,16 @@ Use `pip` to install the prerequisities with: ## Running from the example files -An example strategy, example prediction model, and example config can all be found in -`freqtrade/templates/ExampleFreqaiStrategy.py`, `freqtrade/templates/ExamplePredictionModel.py`, +An example strategy, an example prediction model, and example config can all be found in +`freqtrade/templates/ExampleFreqaiStrategy.py`, +`freqtrade/freqai/prediction_models/CatboostPredictionModel.py`, `config_examples/config_freqai.example.json`, respectively. Assuming the user has downloaded the necessary data, Freqai can be executed from these templates with: ```bash freqtrade backtesting --config config_examples/config_freqai.example.json --strategy -FreqaiExampleStrategy --freqaimodel ExamplePredictionModel ---freqaimodel-path freqtrade/templates --strategy-path freqtrade/templates --timerange 20220101-220201 +FreqaiExampleStrategy --freqaimodel CatboostPredictionModel --strategy-path freqtrade/templates +--timerange 20220101-220201 ``` ## Configuring the bot @@ -185,7 +186,7 @@ the feature set with a proper naming convention for the IFreqaiModel to use late ### Building an IFreqaiModel -Freqai has a base example model in `templates/ExamplePredictionModel.py`, but users can customize and create +Freqai has an example prediction model based on the popular `Catboost` regression (`freqai/prediction_models/CatboostPredictionModel.py`). However, users can customize and create their own prediction models using the `IFreqaiModel` class. Users are encouraged to inherit `train()`, `predict()`, and `make_labels()` to let them customize various aspects of their training procedures. diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index e019eb842..ae05ae33a 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -105,6 +105,11 @@ class IFreqaiModel(ABC): self.dh.full_target_mean, self.dh.full_target_std) def start_live(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> None: + """ + The main broad execution for dry/live. This function will check if a retraining should be + performed, and if so, retrain and reset the model. + + """ self.dh.set_paths() @@ -119,7 +124,6 @@ class IFreqaiModel(ABC): if retrain or not file_exists: self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) - # dataframe = download-data corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, metadata) @@ -131,12 +135,9 @@ class IFreqaiModel(ABC): self.model = self.train(unfiltered_dataframe, metadata) self.dh.save_data(self.model) - self.freqai_info - self.model = self.dh.load_data() preds, do_preds = self.predict(dataframe, metadata) self.dh.append_predictions(preds, do_preds, len(dataframe)) - # dataframe should have len 1 here return diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py new file mode 100644 index 000000000..fecfc2220 --- /dev/null +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -0,0 +1,159 @@ +import logging +from typing import Any, Dict, Tuple + +import pandas as pd +from catboost import CatBoostRegressor, Pool +from pandas import DataFrame + +from freqtrade.freqai.freqai_interface import IFreqaiModel + + +logger = logging.getLogger(__name__) + + +class CatboostPredictionModel(IFreqaiModel): + """ + User created prediction model. The class needs to override three necessary + functions, predict(), train(), fit(). The class inherits ModelHandler which + has its own DataHandler where data is held, saved, loaded, and managed. + """ + + def make_labels(self, dataframe: DataFrame) -> DataFrame: + """ + User defines the labels here (target values). + :params: + :dataframe: the full dataframe for the present training period + """ + + dataframe["s"] = ( + dataframe["close"] + .shift(-self.feature_parameters["period"]) + .rolling(self.feature_parameters["period"]) + .max() + / dataframe["close"] + - 1 + ) + self.dh.data["s_mean"] = dataframe["s"].mean() + self.dh.data["s_std"] = dataframe["s"].std() + + # logger.info("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) + + return dataframe["s"] + + def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: + """ + Filter the training data and train a model to it. Train makes heavy use of the datahkitchen + for storing, saving, loading, and analyzing the data. + :params: + :unfiltered_dataframe: Full dataframe for the current training period + :metadata: pair metadata from strategy. + :returns: + :model: Trained model which can be used to inference (self.predict) + """ + logger.info("--------------------Starting training--------------------") + + # create the full feature list based on user config info + self.dh.training_features_list = self.dh.build_feature_list(self.config, metadata) + unfiltered_labels = self.make_labels(unfiltered_dataframe) + + # filter the features requested by user in the configuration file and elegantly handle NaNs + features_filtered, labels_filtered = self.dh.filter_features( + unfiltered_dataframe, + self.dh.training_features_list, + unfiltered_labels, + training_filter=True, + ) + + # split data into train/test data. + data_dictionary = self.dh.make_train_test_datasets(features_filtered, labels_filtered) + # standardize all data based on train_dataset only + data_dictionary = self.dh.standardize_data(data_dictionary) + + # optional additional data cleaning + if self.feature_parameters["principal_component_analysis"]: + self.dh.principal_component_analysis() + if self.feature_parameters["remove_outliers"]: + self.dh.remove_outliers(predict=False) + if self.feature_parameters["DI_threshold"]: + self.dh.data["avg_mean_dist"] = self.dh.compute_distances() + + logger.info("length of train data %s", len(data_dictionary["train_features"])) + + model = self.fit(data_dictionary) + + logger.info(f'--------------------done training {metadata["pair"]}--------------------') + + return model + + def fit(self, data_dictionary: Dict) -> Any: + """ + Most regressors use the same function names and arguments e.g. user + can drop in LGBMRegressor in place of CatBoostRegressor and all data + management will be properly handled by Freqai. + :params: + :data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. + """ + + train_data = Pool( + data=data_dictionary["train_features"], + label=data_dictionary["train_labels"], + weight=data_dictionary["train_weights"], + ) + + test_data = Pool( + data=data_dictionary["test_features"], + label=data_dictionary["test_labels"], + weight=data_dictionary["test_weights"], + ) + + model = CatBoostRegressor( + verbose=100, early_stopping_rounds=400, **self.model_training_parameters + ) + model.fit(X=train_data, eval_set=test_data) + + return model + + def predict(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, + DataFrame]: + """ + Filter the prediction features data and predict with it. + :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :return: + :predictions: np.array of predictions + :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove + data (NaNs) or felt uncertain about data (PCA and DI index) + """ + + # logger.info("--------------------Starting prediction--------------------") + + original_feature_list = self.dh.build_feature_list(self.config, metadata) + filtered_dataframe, _ = self.dh.filter_features( + unfiltered_dataframe, original_feature_list, training_filter=False + ) + filtered_dataframe = self.dh.standardize_data_from_metadata(filtered_dataframe) + self.dh.data_dictionary["prediction_features"] = filtered_dataframe + + # optional additional data cleaning + if self.feature_parameters["principal_component_analysis"]: + pca_components = self.dh.pca.transform(filtered_dataframe) + self.dh.data_dictionary["prediction_features"] = pd.DataFrame( + data=pca_components, + columns=["PC" + str(i) for i in range(0, self.dh.data["n_kept_components"])], + index=filtered_dataframe.index, + ) + + if self.feature_parameters["remove_outliers"]: + self.dh.remove_outliers(predict=True) # creates dropped index + + if self.feature_parameters["DI_threshold"]: + self.dh.check_if_pred_in_training_spaces() # sets do_predict + + predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) + + # compute the non-standardized predictions + self.dh.predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] + + # logger.info("--------------------Finished prediction--------------------") + + return (self.dh.predictions, self.dh.do_predict) diff --git a/freqtrade/resolvers/freqaimodel_resolver.py b/freqtrade/resolvers/freqaimodel_resolver.py index 2ba6b3e8a..e666b462c 100644 --- a/freqtrade/resolvers/freqaimodel_resolver.py +++ b/freqtrade/resolvers/freqaimodel_resolver.py @@ -24,7 +24,8 @@ class FreqaiModelResolver(IResolver): object_type = IFreqaiModel object_type_str = "FreqaiModel" user_subdir = USERPATH_FREQAIMODELS - initial_search_path = Path(__file__).parent.parent.joinpath("optimize").resolve() + initial_search_path = Path(__file__).parent.parent.joinpath( + "freqai/prediction_models").resolve() @staticmethod def load_freqaimodel(config: Dict) -> IFreqaiModel: diff --git a/user_data/freqaimodels/.gitkeep b/user_data/freqaimodels/.gitkeep new file mode 100644 index 000000000..e69de29bb From d1d451c27e496bf2546993d9060efa1abb6e96b9 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 17 May 2022 18:15:03 +0200 Subject: [PATCH 029/308] auto populate features based on a prepended % in the strategy (remove feature assignment from config). Update doc/constants/example strategy to reflect change --- config_examples/config_freqai.example.json | 13 +---- docs/freqai.md | 35 ++++++++---- freqtrade/constants.py | 3 +- freqtrade/freqai/data_kitchen.py | 53 +++++++++++-------- .../CatboostPredictionModel.py | 5 +- freqtrade/templates/FreqaiExampleStrategy.py | 40 +++++++------- 6 files changed, 80 insertions(+), 69 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index d89c835b1..648f36917 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -56,20 +56,9 @@ ], "train_period": 30, "backtest_period": 7, - "identifier": "new_corrlist", + "identifier": "example", "live_trained_timerange": "20220330-20220429", "live_full_backtestrange": "20220302-20220501", - "base_features": [ - "rsi", - "close_over_20sma", - "relative_volume", - "bb_width", - "mfi", - "roc", - "pct-change", - "adx", - "macd" - ], "corr_pairlist": [ "BTC/USDT", "ETH/USDT", diff --git a/docs/freqai.md b/docs/freqai.md index b5aa587bf..29a45d042 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -72,11 +72,6 @@ config setup includes: "train_period" : 30, "backtest_period" : 7, "identifier" : "unique-id", - "base_features": [ - "rsi", - "mfi", - "roc", - ], "corr_pairlist": [ "ETH/USD", "LINK/USD", @@ -102,11 +97,31 @@ config setup includes: ### Building the feature set -Most of these parameters are controlling the feature data set. The `base_features` -indicates the basic indicators the user wishes to include in the feature set. -The `timeframes` are the timeframes of each base_feature that the user wishes to -include in the feature set. In the present case, the user is asking for the -`5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, etc. to be included +Most of these parameters are controlling the feature data set. Features are added by the user +inside the `populate_any_indicators()` method of the strategy by prepending indicators with `%`: + +```python + def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): + informative['%-''%-' + coin + "rsi"] = ta.RSI(informative, timeperiod=14) + informative['%-' + coin + "mfi"] = ta.MFI(informative, timeperiod=25) + informative['%-' + coin + "adx"] = ta.ADX(informative, window=20) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=14, stds=2.2) + informative[coin + "bb_lowerband"] = bollinger["lower"] + informative[coin + "bb_middleband"] = bollinger["mid"] + informative[coin + "bb_upperband"] = bollinger["upper"] + informative['%-' + coin + "bb_width"] = ( + informative[coin + "bb_upperband"] - informative[coin + "bb_lowerband"] + ) / informative[coin + "bb_middleband"] +``` +The user of the present example does not want to pass the `bb_lowerband` as a feature to the model, +and has therefore not prepended it with `%`. The user does, however, wish to pass `bb_width` to the +model for training/prediction and has therfore prepended it with `%`._ + +(Please see the example script located in `freqtrade/templates/FreqaiExampleStrategy.py` for a full example of `populate_any_indicators()`) + +The `timeframes` from the example config above are the timeframes of each `populate_any_indicator()` + included metric for inclusion in the feature set. In the present case, the user is asking for the +`5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, and `bb_width` to be included in the feature set. In addition, the user can ask for each of these features to be included from diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 0dc355914..686991e2c 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -442,7 +442,6 @@ CONF_SCHEMA = { "identifier": {"type": "str", "default": "example"}, "live_trained_timerange": {"type": "str"}, "live_full_backtestrange": {"type": "str"}, - "base_features": {"type": "list"}, "corr_pairlist": {"type": "list"}, "feature_parameters": { "type": "object", @@ -537,4 +536,4 @@ TradeList = List[List] LongShort = Literal['long', 'short'] EntryExit = Literal['entry', 'exit'] -BuySell = Literal['buy', 'sell'] \ No newline at end of file +BuySell = Literal['buy', 'sell'] diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index c9d518418..cfdbac5f5 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -483,31 +483,38 @@ class FreqaiDataKitchen: return - def build_feature_list(self, config: dict, metadata: dict) -> list: - """ - Build the list of features that will be used to filter - the full dataframe. Feature list is construced from the - user configuration file. - :params: - :config: Canonical freqtrade config file containing all - user defined input in config['freqai] dictionary. - """ - features = [] - for tf in config["freqai"]["timeframes"]: - for ft in config["freqai"]["base_features"]: - for n in range(config["freqai"]["feature_parameters"]["shift"] + 1): - shift = "" - if n > 0: - shift = "_shift-" + str(n) - features.append(metadata['pair'].split("/")[0] + "-" + ft + shift + "_" + tf) - for p in config["freqai"]["corr_pairlist"]: - if metadata['pair'] in p: - continue # avoid duplicate features - features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) - - # logger.info("number of features %s", len(features)) + def find_features(self, dataframe: DataFrame) -> list: + column_names = dataframe.columns + features = [c for c in column_names if '%' in c] + assert features, ("Could not find any features!") return features + # def build_feature_list(self, config: dict, metadata: dict) -> list: + # """ + # SUPERCEDED BY self.find_features() + # Build the list of features that will be used to filter + # the full dataframe. Feature list is construced from the + # user configuration file. + # :params: + # :config: Canonical freqtrade config file containing all + # user defined input in config['freqai] dictionary. + # """ + # features = [] + # for tf in config["freqai"]["timeframes"]: + # for ft in config["freqai"]["base_features"]: + # for n in range(config["freqai"]["feature_parameters"]["shift"] + 1): + # shift = "" + # if n > 0: + # shift = "_shift-" + str(n) + # features.append(metadata['pair'].split("/")[0] + "-" + ft + shift + "_" + tf) + # for p in config["freqai"]["corr_pairlist"]: + # if metadata['pair'] in p: + # continue # avoid duplicate features + # features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) + + # # logger.info("number of features %s", len(features)) + # return features + def check_if_pred_in_training_spaces(self) -> None: """ Compares the distance from each prediction point to each training data diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index fecfc2220..e2ba6bd29 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -53,9 +53,8 @@ class CatboostPredictionModel(IFreqaiModel): logger.info("--------------------Starting training--------------------") # create the full feature list based on user config info - self.dh.training_features_list = self.dh.build_feature_list(self.config, metadata) + self.dh.training_features_list = self.dh.find_features(unfiltered_dataframe) unfiltered_labels = self.make_labels(unfiltered_dataframe) - # filter the features requested by user in the configuration file and elegantly handle NaNs features_filtered, labels_filtered = self.dh.filter_features( unfiltered_dataframe, @@ -127,7 +126,7 @@ class CatboostPredictionModel(IFreqaiModel): # logger.info("--------------------Starting prediction--------------------") - original_feature_list = self.dh.build_feature_list(self.config, metadata) + original_feature_list = self.dh.find_features(unfiltered_dataframe) filtered_dataframe, _ = self.dh.filter_features( unfiltered_dataframe, original_feature_list, training_filter=False ) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index e2bb6e041..f478dd332 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -62,8 +62,11 @@ class FreqaiExampleStrategy(IStrategy): def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): """ Function designed to automatically generate, name and merge features - from user indicated timeframes in the configuration file. User can add - additional features here, but must follow the naming convention. + from user indicated timeframes in the configuration file. User controls the indicators + passed to the training/prediction by prepending indicators with `'%-' + coin ` + (see convention below). I.e. user should not prepend any supporting metrics + (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the + model. :params: :pair: pair to be used as informative :df: strategy dataframe which will receive merges from informatives @@ -74,49 +77,50 @@ class FreqaiExampleStrategy(IStrategy): if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) - informative[coin + "rsi"] = ta.RSI(informative, timeperiod=14) - informative[coin + "mfi"] = ta.MFI(informative, timeperiod=25) - informative[coin + "adx"] = ta.ADX(informative, window=20) + informative['%-' + coin + "rsi"] = ta.RSI(informative, timeperiod=14) + informative['%-' + coin + "mfi"] = ta.MFI(informative, timeperiod=25) + informative['%-' + coin + "adx"] = ta.ADX(informative, window=20) informative[coin + "20sma"] = ta.SMA(informative, timeperiod=20) informative[coin + "21ema"] = ta.EMA(informative, timeperiod=21) - informative[coin + "bmsb"] = np.where( + informative['%-' + coin + "bmsb"] = np.where( informative[coin + "20sma"].lt(informative[coin + "21ema"]), 1, 0 ) - informative[coin + "close_over_20sma"] = informative["close"] / informative[coin + "20sma"] + informative['%-' + coin + "close_over_20sma"] = informative["close"] / informative[ + coin + "20sma"] - informative[coin + "mfi"] = ta.MFI(informative, timeperiod=25) + informative['%-' + coin + "mfi"] = ta.MFI(informative, timeperiod=25) informative[coin + "ema21"] = ta.EMA(informative, timeperiod=21) informative[coin + "sma20"] = ta.SMA(informative, timeperiod=20) stoch = ta.STOCHRSI(informative, 15, 20, 2, 2) - informative[coin + "srsi-fk"] = stoch["fastk"] - informative[coin + "srsi-fd"] = stoch["fastd"] + informative['%-' + coin + "srsi-fk"] = stoch["fastk"] + informative['%-' + coin + "srsi-fd"] = stoch["fastd"] bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=14, stds=2.2) informative[coin + "bb_lowerband"] = bollinger["lower"] informative[coin + "bb_middleband"] = bollinger["mid"] informative[coin + "bb_upperband"] = bollinger["upper"] - informative[coin + "bb_width"] = ( + informative['%-' + coin + "bb_width"] = ( informative[coin + "bb_upperband"] - informative[coin + "bb_lowerband"] ) / informative[coin + "bb_middleband"] - informative[coin + "close-bb_lower"] = ( + informative['%-' + coin + "close-bb_lower"] = ( informative["close"] / informative[coin + "bb_lowerband"] ) - informative[coin + "roc"] = ta.ROC(informative, timeperiod=3) - informative[coin + "adx"] = ta.ADX(informative, window=14) + informative['%-' + coin + "roc"] = ta.ROC(informative, timeperiod=3) + informative['%-' + coin + "adx"] = ta.ADX(informative, window=14) macd = ta.MACD(informative) - informative[coin + "macd"] = macd["macd"] + informative['%-' + coin + "macd"] = macd["macd"] informative[coin + "pct-change"] = informative["close"].pct_change() - informative[coin + "relative_volume"] = ( + informative['%-' + coin + "relative_volume"] = ( informative["volume"] / informative["volume"].rolling(10).mean() ) informative[coin + "pct-change"] = informative["close"].pct_change() - indicators = [col for col in informative if col.startswith(coin)] + indicators = [col for col in informative if col.startswith('%')] for n in range(self.freqai_info["feature_parameters"]["shift"] + 1): if n == 0: @@ -154,7 +158,6 @@ class FreqaiExampleStrategy(IStrategy): pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" ) - print('dataframe_built') # the model will return 4 values, its prediction, an indication of whether or not the # prediction should be accepted, the target mean/std values from the labels used during # each training period. @@ -181,7 +184,6 @@ class FreqaiExampleStrategy(IStrategy): return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # sell_goal = eval('self.'+metadata['pair'].split("/")[0]+'_sell_goal.value') sell_conditions = [ (dataframe["prediction"] < dataframe["sell_roi"]) & (dataframe["do_predict"] == 1) ] From db66b82f6fc432bc16cdb07b4269deb3163a06e5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 17 May 2022 19:50:06 +0200 Subject: [PATCH 030/308] accept open-ended timeranges from user --- freqtrade/freqai/data_kitchen.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index cfdbac5f5..8ccb95dbe 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -312,6 +312,9 @@ class FreqaiDataKitchen: full_timerange = TimeRange.parse_timerange(tr) config_timerange = TimeRange.parse_timerange(self.config["timerange"]) + if config_timerange.stopts == 0: + config_timerange.stopts = int(datetime.datetime.now( + tz=datetime.timezone.utc).timestamp()) timerange_train = copy.deepcopy(full_timerange) timerange_backtest = copy.deepcopy(full_timerange) @@ -589,6 +592,10 @@ class FreqaiDataKitchen: def create_fulltimerange(self, backtest_tr: str, backtest_period: int) -> str: backtest_timerange = TimeRange.parse_timerange(backtest_tr) + if backtest_timerange.stopts == 0: + backtest_timerange.stopts = int(datetime.datetime.now( + tz=datetime.timezone.utc).timestamp()) + backtest_timerange.startts = backtest_timerange.startts - backtest_period * SECONDS_IN_DAY start = datetime.datetime.utcfromtimestamp(backtest_timerange.startts) stop = datetime.datetime.utcfromtimestamp(backtest_timerange.stopts) From c81b9607915bbf3fc916a5f0e0a7fbbd0e0834f2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 16:25:08 +0200 Subject: [PATCH 031/308] Fix some typos --- docs/freqai.md | 35 +++++++++++-------- freqtrade/freqai/freqai_interface.py | 6 ++-- freqtrade/templates/ExamplePredictionModel.py | 2 +- mkdocs.yml | 2 +- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 29a45d042..730f353c8 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -4,8 +4,9 @@ Freqai is still experimental, and should be used at the user's own discretion. Freqai is a module designed to automate a variety of tasks associated with -training a regressor to predict signals based on input features. Among the -the features includes: +training a regressor to predict signals based on input features. + +Among the the features included: * Easy large feature set construction based on simple user input * Sweep model training and backtesting to simulate consistent model retraining through time @@ -16,6 +17,7 @@ the features includes: * Cleaning of NaNs from the data set before training and prediction. TODO: + * live is not automated, still some architectural work to be done ## Background and vocabulary @@ -43,7 +45,7 @@ directly influence nodal weights within the model. ## Install prerequisites -Use `pip` to install the prerequisities with: +Use `pip` to install the prerequisites with: `pip install -r requirements-freqai.txt` @@ -62,7 +64,9 @@ FreqaiExampleStrategy --freqaimodel CatboostPredictionModel --strategy-path freq ``` ## Configuring the bot + ### Example config file + The user interface is isolated to the typical config file. A typical Freqai config setup includes: @@ -152,8 +156,8 @@ data set timerange months. Users can think of this as a "sliding window" which emulates Freqai retraining itself once per week in live using the previous month of data. - ## Running Freqai + ### Training and backtesting The freqai training/backtesting module can be executed with the following command: @@ -196,6 +200,7 @@ The Freqai strategy requires the user to include the following lines of code in return dataframe ``` + The user should also include `populate_any_indicators()` from `templates/FreqaiExampleStrategy.py` which builds the feature set with a proper naming convention for the IFreqaiModel to use later. @@ -216,7 +221,7 @@ freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example. By default, Freqai will not find find any existing models and will start by training a new one given the user configuration settings. Following training, it will use that model to predict for the duration of `backtest_period`. After a full `backtest_period` has elapsed, Freqai will auto retrain -a new model, and begin making predictions with the updated model. +a new model, and begin making predictions with the updated model. If the user wishes to start dry/live from a saved model, the following configuration parameters need to be set: @@ -232,13 +237,14 @@ parameters need to be set: Where the `identifier` is the same identifier which was set during the backtesting/training. Meanwhile, the `live_trained_timerange` is the sub-trained timerange (the training window) which was set during backtesting/training. These are available to the user inside `user_data/models/*/sub-train-*`. -`live_full_backtestrange` was the full data range assocaited with the backtest/training (the full time +`live_full_backtestrange` was the full data range associated with the backtest/training (the full time window that the training window and backtesting windows slide through). These values can be located inside the `user_data/models/` directory. In this case, although Freqai will initiate with a -pretrained model, if a full `backtest_period` has elapsed since the end of the user set -`live_trained_timerange`, it will self retrain. +pre-trained model, if a full `backtest_period` has elapsed since the end of the user set +`live_trained_timerange`, it will self retrain. ## Data anylsis techniques + ### Controlling the model learning process The user can define model settings for the data split `data_split_parameters` and learning parameters @@ -258,7 +264,7 @@ the user is asking for `labels` that are 24 candles in the future. ### Removing outliers with the Dissimilarity Index -The Dissimilarity Index (DI) aims to quantiy the uncertainty associated with each +The Dissimilarity Index (DI) aims to quantity the uncertainty associated with each prediction by the model. To do so, Freqai measures the distance between each training data point and all other training data points: @@ -310,11 +316,11 @@ Users can reduce the dimensionality of their features by activating the `princip ``` Which will perform PCA on the features and reduce the dimensionality of the data so that the explained -variance of the data set is >= 0.999. +variance of the data set is >= 0.999. ### Removing outliers based on feature statistical distributions -The user can tell Freqai to remove outlier data points from the trainig/test data sets by setting: +The user can tell Freqai to remove outlier data points from the training/test data sets by setting: ```json "freqai": { @@ -326,9 +332,10 @@ The user can tell Freqai to remove outlier data points from the trainig/test dat Freqai will check the statistical distributions of each feature (or component if the user activated `principal_component_analysis`) and remove any data point that sits more than 3 standard deviations away -from the mean. +from the mean. ## Additional information + ### Feature standardization The feature set created by the user is automatically standardized to the training @@ -337,5 +344,5 @@ data only. This includes all test data and unseen prediction data (dry/live/back ### File structure `user_data_dir/models/` contains all the data associated with the trainings and -backtestings. This file structure is heavily controlled and read by the `FreqaiDataKitchen()` -and should thus not be modified. +backtests. This file structure is heavily controlled and read by the `FreqaiDataKitchen()` +and should thus not be modified. diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index ae05ae33a..b7c879ff0 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -43,7 +43,7 @@ class IFreqaiModel(ABC): def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ Entry point to the FreqaiModel, it will train a new model if - necesssary before making the prediction. + necessary before making the prediction. The backtesting and training paradigm is a sliding training window with a following backtest window. Both windows slide according to the length of the backtest window. This function is not intended to be @@ -54,7 +54,7 @@ class IFreqaiModel(ABC): :dataframe: Full dataframe coming from strategy - it contains entire backtesting timerange + additional historical data necessary to train the model. - :metadata: pair metadataa coming from strategy. + :metadata: pair metadata coming from strategy. """ live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) @@ -71,7 +71,7 @@ class IFreqaiModel(ABC): logger.info("going to train %s timeranges", len(self.dh.training_timeranges)) - # Loop enforcing the sliding window training/backtesting paragigm + # Loop enforcing the sliding window training/backtesting paradigm # tr_train is the training time range e.g. 1 historical month # tr_backtest is the backtesting time range e.g. the week directly # following tr_train. Both of these windows slide through the diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py index 796fb23ed..3d2b7a808 100644 --- a/freqtrade/templates/ExamplePredictionModel.py +++ b/freqtrade/templates/ExamplePredictionModel.py @@ -42,7 +42,7 @@ class ExamplePredictionModel(IFreqaiModel): def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: """ - Filter the training data and train a model to it. Train makes heavy use of the datahkitchen + Filter the training data and train a model to it. Train makes heavy use of the datakitchen for storing, saving, loading, and analyzing the data. :params: :unfiltered_dataframe: Full dataframe for the current training period diff --git a/mkdocs.yml b/mkdocs.yml index 64d78363d..18744e0d5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,8 +35,8 @@ nav: - Edge Positioning: edge.md - Advanced Strategy: strategy-advanced.md - Advanced Hyperopt: advanced-hyperopt.md - - Sandbox Testing: sandbox-testing.md - Freqai: freqai.md + - Sandbox Testing: sandbox-testing.md - FAQ: faq.md - SQL Cheat-sheet: sql_cheatsheet.md - Strategy migration: strategy_migration.md From c708dd3186a577fdab5ad5afd7a6c9b6b42e718b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 17 May 2022 20:41:42 +0200 Subject: [PATCH 032/308] doc update thanks matthias --- docs/freqai.md | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 730f353c8..df41846a4 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -4,7 +4,7 @@ Freqai is still experimental, and should be used at the user's own discretion. Freqai is a module designed to automate a variety of tasks associated with -training a regressor to predict signals based on input features. +training a predictive model to provide signals based on input features. Among the the features included: @@ -15,10 +15,16 @@ Among the the features included: * Automatic file management for storage of models to be reused during live * Smart and safe data standardization * Cleaning of NaNs from the data set before training and prediction. +* Automated live retraining (still VERY experimental. Proceed with caution.) -TODO: +## General approach -* live is not automated, still some architectural work to be done +The user provides FreqAI with a set of custom indicators (created inside the strategy the same way +a typical Freqtrade strategy is created) as well as a target value (typically some price change into +the future). FreqAI trains a model to predict the target value based on the input of custom indicators. +FreqAI will train and save a new model for each pair in the config whitelist. +Users employ FreqAI to backtest a strategy (emulate reality with retraining a model as new data is +introduced) and run the model live to generate buy and sell signals. ## Background and vocabulary @@ -58,9 +64,7 @@ An example strategy, an example prediction model, and example config can all be the necessary data, Freqai can be executed from these templates with: ```bash -freqtrade backtesting --config config_examples/config_freqai.example.json --strategy -FreqaiExampleStrategy --freqaimodel CatboostPredictionModel --strategy-path freqtrade/templates ---timerange 20220101-220201 +freqtrade backtesting --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel CatboostPredictionModel --strategy-path freqtrade/templates --timerange 20220101-20220201 ``` ## Configuring the bot @@ -163,12 +167,21 @@ month of data. The freqai training/backtesting module can be executed with the following command: ```bash -freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel ExamplePredictionModel --timerange 20210501-20210701 +freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel CatboostPredictionModel --timerange 20210501-20210701 ``` -where the user needs to have a FreqaiExampleStrategy that fits to the requirements outlined -below. The ExamplePredictionModel is a user built class which lets users design their -own training procedures and data analysis. +If this command has never been executed with the existing config file, then it will train a new model +for each pair, for each backtesting window within the bigger `--timerange`._ + +--- +**NOTE** +Once the training is completed, the user can execute this again with the same config file and +FreqAI will find the trained models and load them instead of spending time training. This is useful +if the user wants to tweak (or even hyperopt) buy and sell criteria inside the strategy. IF the user +*wants* to retrain a new model with the same config file, then he/she should simply change the `identifier`. +This way, the user can return to using any model they wish by simply changing the `identifier`. + +--- ### Building a freqai strategy @@ -264,7 +277,7 @@ the user is asking for `labels` that are 24 candles in the future. ### Removing outliers with the Dissimilarity Index -The Dissimilarity Index (DI) aims to quantity the uncertainty associated with each +The Dissimilarity Index (DI) aims to quantify the uncertainty associated with each prediction by the model. To do so, Freqai measures the distance between each training data point and all other training data points: From 89eacf2f47fd02526027400022db7b5c487be23d Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 19 May 2022 17:15:50 +0200 Subject: [PATCH 033/308] Retrain model if FreqAI found a pretrained model but user strategy is not passing the expected features (user has changed the features in the strategy but has passed a the same config[freqai][identifier]). Logger warning output to user. --- freqtrade/freqai/freqai_interface.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index b7c879ff0..6a1d97470 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -92,6 +92,11 @@ class IFreqaiModel(ABC): self.dh.save_data(self.model) else: self.model = self.dh.load_data() + strategy_provided_features = self.dh.find_features(dataframe_train) + if strategy_provided_features != self.dh.training_features_list: + logger.info("User changed input features, retraining model.") + self.model = self.train(dataframe_train, metadata) + self.dh.save_data(self.model) preds, do_preds = self.predict(dataframe_backtest, metadata) From 67eb94c69d88f7b53a1bf9d980faf5dcd4f4b037 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 19 May 2022 17:55:00 +0200 Subject: [PATCH 034/308] download-data will now check if freqai is active in config, and if so will also download data for corr_pairlist --- freqtrade/commands/data_commands.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index a2e2a100a..4588bf67b 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -50,7 +50,13 @@ def start_download_data(args: Dict[str, Any]) -> None: exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) markets = [p for p, m in exchange.markets.items() if market_is_active(m) or config.get('include_inactive')] - expanded_pairs = expand_pairlist(config['pairs'], markets) + if config.get('freqai') is not None: + assert config['freqai'].get('corr_pairlist'), "No corr_pairlist found in config." + full_pairs = config['pairs'] + [pair for pair in config['freqai']['corr_pairlist'] + if pair not in config['pairs']] + expanded_pairs = expand_pairlist(full_pairs, markets) + else: + expanded_pairs = expand_pairlist(config['pairs'], markets) # Manual validations of relevant settings if not config['exchange'].get('skip_pair_validation', False): From 1fae6c9ef794a014c3e8f1a692bda8b66b46b960 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 19 May 2022 19:27:38 +0200 Subject: [PATCH 035/308] keep model accessible in memory to avoid loading objects from disk during live/dry --- freqtrade/freqai/data_kitchen.py | 30 +++++++++++++++----- freqtrade/templates/FreqaiExampleStrategy.py | 6 ++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 8ccb95dbe..e35243f6a 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -50,8 +50,9 @@ class FreqaiDataKitchen: self.full_target_std: npt.ArrayLike = np.array([]) self.model_path = Path() self.model_filename: str = "" - - if not live: + self.model_dictionary: Dict[Any, Any] = {} + self.live = live + if not self.live: self.full_timerange = self.create_fulltimerange(self.config["timerange"], self.freqai_config["train_period"] ) @@ -88,8 +89,8 @@ class FreqaiDataKitchen: # Save the trained model dump(model, save_path / str(self.model_filename + "_model.joblib")) - self.data["model_path"] = self.model_path - self.data["model_filename"] = self.model_filename + self.data["model_path"] = str(self.model_path) + self.data["model_filename"] = str(self.model_filename) self.data["training_features_list"] = list(self.data_dictionary["train_features"].columns) # store the metadata with open(save_path / str(self.model_filename + "_metadata.json"), "w") as fp: @@ -100,6 +101,9 @@ class FreqaiDataKitchen: save_path / str(self.model_filename + "_trained_df.pkl") ) + if self.live: + self.model_dictionary[self.model_filename] = model + return def load_data(self) -> Any: @@ -108,7 +112,6 @@ class FreqaiDataKitchen: :returns: :model: User trained model which can be inferenced for new predictions """ - model = load(self.model_path / str(self.model_filename + "_model.joblib")) with open(self.model_path / str(self.model_filename + "_metadata.json"), "r") as fp: self.data = json.load(fp) @@ -118,8 +121,20 @@ class FreqaiDataKitchen: self.model_path / str(self.model_filename + "_trained_df.pkl") ) - self.model_path = self.data["model_path"] + self.model_path = Path(self.data["model_path"]) self.model_filename = self.data["model_filename"] + + # try to access model in memory instead of loading object from disk to save time + if self.live and self.model_filename in self.model_dictionary: + model = self.model_dictionary[self.model_filename] + else: + model = load(self.model_path / str(self.model_filename + "_model.joblib")) + + assert model, ( + f"Unable to load model, ensure model exists at " + f"{self.model_path} " + ) + if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]: self.pca = pk.load( open(self.model_path / str(self.model_filename + "_pca_object.pkl"), "rb") @@ -682,7 +697,8 @@ class FreqaiDataKitchen: for p in pairs: if metadata['pair'] in p: continue # dont repeat anything from whitelist - corr_dataframes[p] = {} + if p not in corr_dataframes: + corr_dataframes[p] = {} corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, pair=p, timerange=timerange) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index f478dd332..6478ca167 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -59,6 +59,9 @@ class FreqaiExampleStrategy(IStrategy): informative_pairs.append((pair, tf)) return informative_pairs + def bot_start(self): + self.model = CustomModel(self.config) + def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): """ Function designed to automatically generate, name and merge features @@ -141,9 +144,6 @@ class FreqaiExampleStrategy(IStrategy): self.freqai_info = self.config["freqai"] self.pair = metadata['pair'] - # the model is instantiated here - self.model = CustomModel(self.config) - print("Populating indicators...") # the following loops are necessary for building the features From c5ecf941770727908774ba928a96a7a3c1ec32b6 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 19 May 2022 21:15:58 +0200 Subject: [PATCH 036/308] move live retraining to separate thread. --- freqtrade/freqai/freqai_interface.py | 89 ++++++++++++++++---- freqtrade/templates/FreqaiExampleStrategy.py | 2 - 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 6a1d97470..2523cd561 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -1,5 +1,8 @@ +# import contextlib import gc import logging +# import sys +import threading from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, Tuple @@ -16,6 +19,24 @@ from freqtrade.strategy.interface import IStrategy pd.options.mode.chained_assignment = None logger = logging.getLogger(__name__) +# FIXME: suppress stdout for background training +# class DummyFile(object): +# def write(self, x): pass + + +# @contextlib.contextmanager +# def nostdout(): +# save_stdout = sys.stdout +# sys.stdout = DummyFile() +# yield +# sys.stdout = save_stdout + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + return wrapper + class IFreqaiModel(ABC): """ @@ -39,6 +60,8 @@ class IFreqaiModel(ABC): self.current_time = None self.model = None self.predictions = None + self.training_on_separate_thread = False + self.retrain = False def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ @@ -122,25 +145,26 @@ class IFreqaiModel(ABC): training_timerange=self.freqai_info[ 'live_trained_timerange']) - (retrain, - new_trained_timerange) = self.dh.check_if_new_training_required(self.freqai_info[ + if not self.training_on_separate_thread: + # this will also prevent other pairs from trying to train simultaneously. + (self.retrain, + new_trained_timerange) = self.dh.check_if_new_training_required(self.freqai_info[ 'live_trained_timerange'], - metadata) + metadata) + else: + logger.info("FreqAI training a new model on background thread.") + self.retrain = False - if retrain or not file_exists: - self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) - corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, - metadata) - - unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, - corr_dataframes, - base_dataframes, - metadata) - - self.model = self.train(unfiltered_dataframe, metadata) - self.dh.save_data(self.model) + if self.retrain or not file_exists: + self.training_on_separate_thread = True # acts like a lock + self.retrain_model_on_separate_thread(new_trained_timerange, metadata, strategy) self.model = self.dh.load_data() + + strategy_provided_features = self.dh.find_features(dataframe) + if strategy_provided_features != self.dh.training_features_list: + self.train_model_in_series(new_trained_timerange, metadata, strategy) + preds, do_preds = self.predict(dataframe, metadata) self.dh.append_predictions(preds, do_preds, len(dataframe)) @@ -206,3 +230,38 @@ class IFreqaiModel(ABC): else: logger.info("Could not find model at %s", self.dh.model_path / self.dh.model_filename) return file_exists + + @threaded + def retrain_model_on_separate_thread(self, new_trained_timerange: str, metadata: dict, + strategy: IStrategy): + + # with nostdout(): + self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) + corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, + metadata) + + unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, + corr_dataframes, + base_dataframes, + metadata) + + self.model = self.train(unfiltered_dataframe, metadata) + self.dh.save_data(self.model) + + self.training_on_separate_thread = False + self.retrain = False + + def train_model_in_series(self, new_trained_timerange: str, metadata: dict, + strategy: IStrategy): + + self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) + corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, + metadata) + + unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, + corr_dataframes, + base_dataframes, + metadata) + + self.model = self.train(unfiltered_dataframe, metadata) + self.dh.save_data(self.model) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 6478ca167..c8befebcf 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -144,8 +144,6 @@ class FreqaiExampleStrategy(IStrategy): self.freqai_info = self.config["freqai"] self.pair = metadata['pair'] - print("Populating indicators...") - # the following loops are necessary for building the features # indicated by the user in the configuration file. for tf in self.freqai_info["timeframes"]: From 42d95af829738dbb4efc1f69ba9606c01e811230 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 22 May 2022 17:51:49 +0200 Subject: [PATCH 037/308] Aggregated commit. Adding support vector machine for outlier detection, improve user interface to dry/live, better standardization, fix various other bugs --- config_examples/config_freqai.example.json | 11 +- docs/freqai.md | 10 +- freqtrade/freqai/data_kitchen.py | 380 +++++++++++++----- freqtrade/freqai/freqai_interface.py | 56 ++- .../CatboostPredictionModel.py | 82 ++-- freqtrade/templates/ExamplePredictionModel.py | 159 -------- freqtrade/templates/FreqaiExampleStrategy.py | 6 +- 7 files changed, 404 insertions(+), 300 deletions(-) delete mode 100644 freqtrade/templates/ExamplePredictionModel.py diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 648f36917..a895a7341 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -57,8 +57,8 @@ "train_period": 30, "backtest_period": 7, "identifier": "example", - "live_trained_timerange": "20220330-20220429", - "live_full_backtestrange": "20220302-20220501", + "live_trained_timerange": "", + "live_full_backtestrange": "", "corr_pairlist": [ "BTC/USDT", "ETH/USDT", @@ -68,20 +68,19 @@ "feature_parameters": { "period": 12, "shift": 1, - "drop_features": false, "DI_threshold": 1, "weight_factor": 0, "principal_component_analysis": false, - "remove_outliers": false + "use_SVM_to_remove_outliers": false }, "data_split_parameters": { "test_size": 0.25, "random_state": 1 }, "model_training_parameters": { - "n_estimators": 2000, + "n_estimators": 1000, "random_state": 1, - "learning_rate": 0.02, + "learning_rate": 0.1, "task_type": "CPU" } }, diff --git a/docs/freqai.md b/docs/freqai.md index df41846a4..8a37e7d66 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -331,21 +331,21 @@ Users can reduce the dimensionality of their features by activating the `princip Which will perform PCA on the features and reduce the dimensionality of the data so that the explained variance of the data set is >= 0.999. -### Removing outliers based on feature statistical distributions +### Removing outliers using a Support Vector Machine (SVM) The user can tell Freqai to remove outlier data points from the training/test data sets by setting: ```json "freqai": { "feature_parameters" : { - "remove_outliers": true + "use_SVM_to_remove_outliers: true } } ``` -Freqai will check the statistical distributions of each feature (or component if the user activated -`principal_component_analysis`) and remove any data point that sits more than 3 standard deviations away -from the mean. +Freqai will train an SVM on the training data (or components if the user activated +`principal_component_analysis`) and remove any data point that it deems to be sit beyond the +feature space. ## Additional information diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index e35243f6a..f589a1c89 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -10,8 +10,9 @@ from typing import Any, Dict, List, Tuple import numpy as np import numpy.typing as npt import pandas as pd -from joblib import dump, load +from joblib import dump, load # , Parallel, delayed # used for auto distribution assignment from pandas import DataFrame +from sklearn import linear_model from sklearn.metrics.pairwise import pairwise_distances from sklearn.model_selection import train_test_split @@ -22,6 +23,9 @@ from freqtrade.resolvers import ExchangeResolver from freqtrade.strategy.interface import IStrategy +# import scipy as spy # used for auto distribution assignment + + SECONDS_IN_DAY = 86400 logger = logging.getLogger(__name__) @@ -52,6 +56,7 @@ class FreqaiDataKitchen: self.model_filename: str = "" self.model_dictionary: Dict[Any, Any] = {} self.live = live + self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: self.full_timerange = self.create_fulltimerange(self.config["timerange"], self.freqai_config["train_period"] @@ -89,6 +94,10 @@ class FreqaiDataKitchen: # Save the trained model dump(model, save_path / str(self.model_filename + "_model.joblib")) + + if self.svm_model is not None: + dump(self.svm_model, save_path / str(self.model_filename + "_svm_model.joblib")) + self.data["model_path"] = str(self.model_path) self.data["model_filename"] = str(self.model_filename) self.data["training_features_list"] = list(self.data_dictionary["train_features"].columns) @@ -104,6 +113,19 @@ class FreqaiDataKitchen: if self.live: self.model_dictionary[self.model_filename] = model + # TODO add a helper function to let user save/load any data they are custom adding. We + # do not want them having to edit the default save/load methods here. Below is an example + # of what we do NOT want. + + # if self.freqai_config['feature_parameters']['determine_statistical_distributions']: + # self.data_dictionary["upper_quantiles"].to_pickle( + # save_path / str(self.model_filename + "_upper_quantiles.pkl") + # ) + + # self.data_dictionary["lower_quantiles"].to_pickle( + # save_path / str(self.model_filename + "_lower_quantiles.pkl") + # ) + return def load_data(self) -> Any: @@ -121,6 +143,19 @@ class FreqaiDataKitchen: self.model_path / str(self.model_filename + "_trained_df.pkl") ) + # TODO add a helper function to let user save/load any data they are custom adding. We + # do not want them having to edit the default save/load methods here. Below is an example + # of what we do NOT want. + + # if self.freqai_config['feature_parameters']['determine_statistical_distributions']: + # self.data_dictionary["upper_quantiles"] = pd.read_pickle( + # self.model_path / str(self.model_filename + "_upper_quantiles.pkl") + # ) + + # self.data_dictionary["lower_quantiles"] = pd.read_pickle( + # self.model_path / str(self.model_filename + "_lower_quantiles.pkl") + # ) + self.model_path = Path(self.data["model_path"]) self.model_filename = self.data["model_filename"] @@ -130,6 +165,10 @@ class FreqaiDataKitchen: else: model = load(self.model_path / str(self.model_filename + "_model.joblib")) + if Path(self.model_path / str(self.model_filename + + "_svm_model.joblib")).resolve().exists(): + self.svm_model = load(self.model_path / str(self.model_filename + "_svm_model.joblib")) + assert model, ( f"Unable to load model, ensure model exists at " f"{self.model_path} " @@ -159,6 +198,12 @@ class FreqaiDataKitchen: else: weights = np.ones(len(filtered_dataframe)) + if self.config["freqai"]["feature_parameters"]["stratify"] > 0: + stratification = np.zeros(len(filtered_dataframe)) + for i in range(1, len(stratification)): + if i % self.config["freqai"]["feature_parameters"]["stratify"] == 0: + stratification[i] = 1 + ( train_features, test_features, @@ -170,6 +215,8 @@ class FreqaiDataKitchen: filtered_dataframe[: filtered_dataframe.shape[0]], labels, weights, + stratify=stratification, + # shuffle=False, **self.config["freqai"]["data_split_parameters"] ) @@ -261,9 +308,9 @@ class FreqaiDataKitchen: return self.data_dictionary - def standardize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: + def normalize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: """ - Standardize all data in the data_dictionary according to the training dataset + Normalize all data in the data_dictionary according to the training dataset :params: :data_dictionary: dictionary containing the cleaned and split training/test data/labels :returns: @@ -297,6 +344,42 @@ class FreqaiDataKitchen: return data_dictionary + def standardize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: + """ + Standardize all data in the data_dictionary according to the training dataset + :params: + :data_dictionary: dictionary containing the cleaned and split training/test data/labels + :returns: + :data_dictionary: updated dictionary with standardized values. + """ + # standardize the data by training stats + train_max = data_dictionary["train_features"].max() + train_min = data_dictionary["train_features"].min() + data_dictionary["train_features"] = 2 * ( + data_dictionary["train_features"] - train_min + ) / (train_max - train_min) - 1 + data_dictionary["test_features"] = 2 * ( + data_dictionary["test_features"] - train_min + ) / (train_max - train_min) - 1 + + train_labels_max = data_dictionary["train_labels"].max() + train_labels_min = data_dictionary["train_labels"].min() + data_dictionary["train_labels"] = 2 * ( + data_dictionary["train_labels"] - train_labels_min + ) / (train_labels_max - train_labels_min) - 1 + data_dictionary["test_labels"] = 2 * ( + data_dictionary["test_labels"] - train_labels_min + ) / (train_labels_max - train_labels_min) - 1 + + for item in train_max.keys(): + self.data[item + "_max"] = train_max[item] + self.data[item + "_min"] = train_min[item] + + self.data["labels_max"] = train_labels_max + self.data["labels_min"] = train_labels_min + + return data_dictionary + def standardize_data_from_metadata(self, df: DataFrame) -> DataFrame: """ Standardizes a set of data using the mean and standard deviation from @@ -305,6 +388,20 @@ class FreqaiDataKitchen: :df: Dataframe to be standardized """ + for item in df.keys(): + df[item] = 2 * (df[item] - self.data[item + "_min"]) / (self.data[item + "_max"] - + self.data[item + '_min']) - 1 + + return df + + def normalize_data_from_metadata(self, df: DataFrame) -> DataFrame: + """ + Normalizes a set of data using the mean and standard deviation from + the associated training data. + :params: + :df: Dataframe to be standardized + """ + for item in df.keys(): df[item] = (df[item] - self.data[item + "_mean"]) / self.data[item + "_std"] @@ -420,6 +517,8 @@ class FreqaiDataKitchen: self.data["n_kept_components"] = n_keep_components self.pca = pca2 + logger.info(f'PCA reduced total features from {n_components} to {n_keep_components}') + if not self.model_path.is_dir(): self.model_path.mkdir(parents=True, exist_ok=True) pk.dump(pca2, open(self.model_path / str(self.model_filename + "_pca_object.pkl"), "wb")) @@ -434,70 +533,53 @@ class FreqaiDataKitchen: return avg_mean_dist - def remove_outliers(self, predict: bool) -> None: - """ - Remove data that looks like an outlier based on the distribution of each - variable. - :params: - :predict: boolean which tells the function if this is prediction data or - training data coming in. - """ - - lower_quantile = self.data_dictionary["train_features"].quantile(0.001) - upper_quantile = self.data_dictionary["train_features"].quantile(0.999) + def use_SVM_to_remove_outliers(self, predict: bool) -> None: if predict: - - df = self.data_dictionary["prediction_features"][ - (self.data_dictionary["prediction_features"] < upper_quantile) - & (self.data_dictionary["prediction_features"] > lower_quantile) - ] - drop_index = pd.isnull(df).any(1) - self.data_dictionary["prediction_features"].fillna(0, inplace=True) - drop_index = ~drop_index - do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) + assert self.svm_model, "No svm model available for outlier removal" + y_pred = self.svm_model.predict(self.data_dictionary["prediction_features"]) + do_predict = np.where(y_pred == -1, 0, y_pred) logger.info( - "remove_outliers() tossed %s predictions", - len(do_predict) - do_predict.sum(), + f'svm_remove_outliers() tossed {len(do_predict) - do_predict.sum()} predictions' ) self.do_predict += do_predict self.do_predict -= 1 else: + # use SGDOneClassSVM to increase speed? + self.svm_model = linear_model.SGDOneClassSVM(nu=0.1).fit( + self.data_dictionary["train_features"] + ) + y_pred = self.svm_model.predict(self.data_dictionary["train_features"]) + dropped_points = np.where(y_pred == -1, 0, y_pred) + # keep_index = np.where(y_pred == 1) + self.data_dictionary["train_features"] = self.data_dictionary[ + "train_features"][(y_pred == 1)] + self.data_dictionary["train_labels"] = self.data_dictionary[ + "train_labels"][(y_pred == 1)] + self.data_dictionary["train_weights"] = self.data_dictionary[ + "train_weights"][(y_pred == 1)] - filter_train_df = self.data_dictionary["train_features"][ - (self.data_dictionary["train_features"] < upper_quantile) - & (self.data_dictionary["train_features"] > lower_quantile) - ] - drop_index = pd.isnull(filter_train_df).any(1) - drop_index = drop_index.replace(True, 1).replace(False, 0) - self.data_dictionary["train_features"] = self.data_dictionary["train_features"][ - (drop_index == 0) - ] - self.data_dictionary["train_labels"] = self.data_dictionary["train_labels"][ - (drop_index == 0) - ] - self.data_dictionary["train_weights"] = self.data_dictionary["train_weights"][ - (drop_index == 0) - ] + logger.info( + f'svm_remove_outliers() tossed {len(y_pred) - dropped_points.sum()}' + f' train points from {len(y_pred)}' + ) - # do the same for the test data - filter_test_df = self.data_dictionary["test_features"][ - (self.data_dictionary["test_features"] < upper_quantile) - & (self.data_dictionary["test_features"] > lower_quantile) - ] - drop_index = pd.isnull(filter_test_df).any(1) - drop_index = drop_index.replace(True, 1).replace(False, 0) - self.data_dictionary["test_labels"] = self.data_dictionary["test_labels"][ - (drop_index == 0) - ] - self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ - (drop_index == 0) - ] - self.data_dictionary["test_weights"] = self.data_dictionary["test_weights"][ - (drop_index == 0) - ] + # same for test data + y_pred = self.svm_model.predict(self.data_dictionary["test_features"]) + dropped_points = np.where(y_pred == -1, 0, y_pred) + self.data_dictionary["test_features"] = self.data_dictionary[ + "test_features"][(y_pred == 1)] + self.data_dictionary["test_labels"] = self.data_dictionary[ + "test_labels"][(y_pred == 1)] + self.data_dictionary["test_weights"] = self.data_dictionary[ + "test_weights"][(y_pred == 1)] + + logger.info( + f'svm_remove_outliers() tossed {len(y_pred) - dropped_points.sum()}' + f' test points from {len(y_pred)}' + ) return @@ -507,32 +589,6 @@ class FreqaiDataKitchen: assert features, ("Could not find any features!") return features - # def build_feature_list(self, config: dict, metadata: dict) -> list: - # """ - # SUPERCEDED BY self.find_features() - # Build the list of features that will be used to filter - # the full dataframe. Feature list is construced from the - # user configuration file. - # :params: - # :config: Canonical freqtrade config file containing all - # user defined input in config['freqai] dictionary. - # """ - # features = [] - # for tf in config["freqai"]["timeframes"]: - # for ft in config["freqai"]["base_features"]: - # for n in range(config["freqai"]["feature_parameters"]["shift"] + 1): - # shift = "" - # if n > 0: - # shift = "_shift-" + str(n) - # features.append(metadata['pair'].split("/")[0] + "-" + ft + shift + "_" + tf) - # for p in config["freqai"]["corr_pairlist"]: - # if metadata['pair'] in p: - # continue # avoid duplicate features - # features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) - - # # logger.info("number of features %s", len(features)) - # return features - def check_if_pred_in_training_spaces(self) -> None: """ Compares the distance from each prediction point to each training data @@ -568,7 +624,7 @@ class FreqaiDataKitchen: training than older data. """ - weights = np.zeros_like(num_weights) + weights = np.zeros(num_weights) for i in range(1, len(weights)): weights[len(weights) - i] = np.exp( -i / (self.config["freqai"]["feature_parameters"]["weight_factor"] * num_weights) @@ -638,19 +694,23 @@ class FreqaiDataKitchen: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() - trained_timerange = TimeRange.parse_timerange(training_timerange) + if training_timerange: # user passed no live_trained_timerange in config + trained_timerange = TimeRange.parse_timerange(training_timerange) + elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY + trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + retrain = elapsed_time > self.freqai_config['backtest_period'] + else: + trained_timerange = TimeRange.parse_timerange("20000101-20000201") + trained_timerange.startts = int(time - self.freqai_config['train_period'] * + SECONDS_IN_DAY) + trained_timerange.stopts = int(time) + retrain = True - elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY - - trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY - trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY start = datetime.datetime.utcfromtimestamp(trained_timerange.startts) stop = datetime.datetime.utcfromtimestamp(trained_timerange.stopts) - new_trained_timerange = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") - retrain = elapsed_time > self.freqai_config['backtest_period'] - if retrain: coin, _ = metadata['pair'].split("/") # set the new model_path @@ -738,3 +798,141 @@ class FreqaiDataKitchen: def np_encoder(self, object): if isinstance(object, np.generic): return object.item() + + # Functions containing useful data manpulation examples. but not actively in use. + + # def build_feature_list(self, config: dict, metadata: dict) -> list: + # """ + # SUPERCEDED BY self.find_features() + # Build the list of features that will be used to filter + # the full dataframe. Feature list is construced from the + # user configuration file. + # :params: + # :config: Canonical freqtrade config file containing all + # user defined input in config['freqai] dictionary. + # """ + # features = [] + # for tf in config["freqai"]["timeframes"]: + # for ft in config["freqai"]["base_features"]: + # for n in range(config["freqai"]["feature_parameters"]["shift"] + 1): + # shift = "" + # if n > 0: + # shift = "_shift-" + str(n) + # features.append(metadata['pair'].split("/")[0] + "-" + ft + shift + "_" + tf) + # for p in config["freqai"]["corr_pairlist"]: + # if metadata['pair'] in p: + # continue # avoid duplicate features + # features.append(p.split("/")[0] + "-" + ft + shift + "_" + tf) + + # # logger.info("number of features %s", len(features)) + # return features + + # Possibly phasing these outlier removal methods below out in favor of + # use_SVM_to_remove_outliers (computationally more efficient and apparently higher performance). + # But these have good data manipulation examples, so keep them commented here for now. + + # def determine_statistical_distributions(self) -> None: + # from fitter import Fitter + + # logger.info('Determining best model for all features, may take some time') + + # def compute_quantiles(ft): + # f = Fitter(self.data_dictionary["train_features"][ft], + # distributions=['gamma', 'cauchy', 'laplace', + # 'beta', 'uniform', 'lognorm']) + # f.fit() + # # f.summary() + # dist = list(f.get_best().items())[0][0] + # params = f.get_best()[dist] + # upper_q = getattr(spy.stats, list(f.get_best().items())[0][0]).ppf(0.999, **params) + # lower_q = getattr(spy.stats, list(f.get_best().items())[0][0]).ppf(0.001, **params) + + # return ft, upper_q, lower_q, dist + + # quantiles_tuple = Parallel(n_jobs=-1)( + # delayed(compute_quantiles)(ft) for ft in self.data_dictionary[ + # 'train_features'].columns) + + # df = pd.DataFrame(quantiles_tuple, columns=['features', 'upper_quantiles', + # 'lower_quantiles', 'dist']) + # self.data_dictionary['upper_quantiles'] = df['upper_quantiles'] + # self.data_dictionary['lower_quantiles'] = df['lower_quantiles'] + + # return + + # def remove_outliers(self, predict: bool) -> None: + # """ + # Remove data that looks like an outlier based on the distribution of each + # variable. + # :params: + # :predict: boolean which tells the function if this is prediction data or + # training data coming in. + # """ + + # lower_quantile = self.data_dictionary["lower_quantiles"].to_numpy() + # upper_quantile = self.data_dictionary["upper_quantiles"].to_numpy() + + # if predict: + + # df = self.data_dictionary["prediction_features"][ + # (self.data_dictionary["prediction_features"] < upper_quantile) + # & (self.data_dictionary["prediction_features"] > lower_quantile) + # ] + # drop_index = pd.isnull(df).any(1) + # self.data_dictionary["prediction_features"].fillna(0, inplace=True) + # drop_index = ~drop_index + # do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) + + # logger.info( + # "remove_outliers() tossed %s predictions", + # len(do_predict) - do_predict.sum(), + # ) + # self.do_predict += do_predict + # self.do_predict -= 1 + + # else: + + # filter_train_df = self.data_dictionary["train_features"][ + # (self.data_dictionary["train_features"] < upper_quantile) + # & (self.data_dictionary["train_features"] > lower_quantile) + # ] + # drop_index = pd.isnull(filter_train_df).any(1) + # drop_index = drop_index.replace(True, 1).replace(False, 0) + # self.data_dictionary["train_features"] = self.data_dictionary["train_features"][ + # (drop_index == 0) + # ] + # self.data_dictionary["train_labels"] = self.data_dictionary["train_labels"][ + # (drop_index == 0) + # ] + # self.data_dictionary["train_weights"] = self.data_dictionary["train_weights"][ + # (drop_index == 0) + # ] + + # logger.info( + # f'remove_outliers() tossed {drop_index.sum()}' + # f' training points from {len(filter_train_df)}' + # ) + + # # do the same for the test data + # filter_test_df = self.data_dictionary["test_features"][ + # (self.data_dictionary["test_features"] < upper_quantile) + # & (self.data_dictionary["test_features"] > lower_quantile) + # ] + # drop_index = pd.isnull(filter_test_df).any(1) + # drop_index = drop_index.replace(True, 1).replace(False, 0) + # self.data_dictionary["test_labels"] = self.data_dictionary["test_labels"][ + # (drop_index == 0) + # ] + # self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ + # (drop_index == 0) + # ] + # self.data_dictionary["test_weights"] = self.data_dictionary["test_weights"][ + # (drop_index == 0) + # ] + + # logger.info( + # f'remove_outliers() tossed {drop_index.sum()}' + # f' test points from {len(filter_test_df)}' + # ) + + # return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 2523cd561..f1dd5550a 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -62,6 +62,7 @@ class IFreqaiModel(ABC): self.predictions = None self.training_on_separate_thread = False self.retrain = False + self.first = True def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ @@ -80,12 +81,12 @@ class IFreqaiModel(ABC): :metadata: pair metadata coming from strategy. """ - live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) + self.live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) self.pair = metadata["pair"] - self.dh = FreqaiDataKitchen(self.config, dataframe, live) + self.dh = FreqaiDataKitchen(self.config, dataframe, self.live) - if live: + if self.live: # logger.info('testing live') self.start_live(dataframe, metadata, strategy) @@ -115,11 +116,12 @@ class IFreqaiModel(ABC): self.dh.save_data(self.model) else: self.model = self.dh.load_data() - strategy_provided_features = self.dh.find_features(dataframe_train) - if strategy_provided_features != self.dh.training_features_list: - logger.info("User changed input features, retraining model.") - self.model = self.train(dataframe_train, metadata) - self.dh.save_data(self.model) + # strategy_provided_features = self.dh.find_features(dataframe_train) + # # TOFIX doesnt work with PCA + # if strategy_provided_features != self.dh.training_features_list: + # logger.info("User changed input features, retraining model.") + # self.model = self.train(dataframe_train, metadata) + # self.dh.save_data(self.model) preds, do_preds = self.predict(dataframe_backtest, metadata) @@ -148,7 +150,7 @@ class IFreqaiModel(ABC): if not self.training_on_separate_thread: # this will also prevent other pairs from trying to train simultaneously. (self.retrain, - new_trained_timerange) = self.dh.check_if_new_training_required(self.freqai_info[ + self.new_trained_timerange) = self.dh.check_if_new_training_required(self.freqai_info[ 'live_trained_timerange'], metadata) else: @@ -156,14 +158,19 @@ class IFreqaiModel(ABC): self.retrain = False if self.retrain or not file_exists: - self.training_on_separate_thread = True # acts like a lock - self.retrain_model_on_separate_thread(new_trained_timerange, metadata, strategy) + if self.first: + self.train_model_in_series(self.new_trained_timerange, metadata, strategy) + self.first = False + else: + self.training_on_separate_thread = True # acts like a lock + self.retrain_model_on_separate_thread(self.new_trained_timerange, + metadata, strategy) self.model = self.dh.load_data() strategy_provided_features = self.dh.find_features(dataframe) if strategy_provided_features != self.dh.training_features_list: - self.train_model_in_series(new_trained_timerange, metadata, strategy) + self.train_model_in_series(self.new_trained_timerange, metadata, strategy) preds, do_preds = self.predict(dataframe, metadata) self.dh.append_predictions(preds, do_preds, len(dataframe)) @@ -215,12 +222,36 @@ class IFreqaiModel(ABC): data (NaNs) or felt uncertain about data (PCA and DI index) """ + @abstractmethod + def data_cleaning_train(self) -> None: + """ + User can add data analysis and cleaning here. + Any function inside this method should drop training data points from the filtered_dataframe + based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example + of how outlier data points are dropped from the dataframe used for training. + """ + + @abstractmethod + def data_cleaning_predict(self) -> None: + """ + User can add data analysis and cleaning here. + These functions each modify self.dh.do_predict, which is a dataframe with equal length + to the number of candles coming from and returning to the strategy. Inside do_predict, + 1 allows prediction and < 0 signals to the strategy that the model is not confident in + the prediction. + See FreqaiDataKitchen::remove_outliers() for an example + of how the do_predict vector is modified. do_predict is ultimately passed back to strategy + for buy signals. + """ + def model_exists(self, pair: str, training_timerange: str) -> bool: """ Given a pair and path, check if a model already exists :param pair: pair e.g. BTC/USD :param path: path to model """ + if self.live and training_timerange is None: + return False coin, _ = pair.split("/") self.dh.model_filename = "cb_" + coin.lower() + "_" + training_timerange path_to_modelfile = Path(self.dh.model_path / str(self.dh.model_filename + "_model.joblib")) @@ -265,3 +296,4 @@ class IFreqaiModel(ABC): self.model = self.train(unfiltered_dataframe, metadata) self.dh.save_data(self.model) + self.retrain = False diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index e2ba6bd29..8550f3f15 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -29,7 +29,7 @@ class CatboostPredictionModel(IFreqaiModel): dataframe["close"] .shift(-self.feature_parameters["period"]) .rolling(self.feature_parameters["period"]) - .max() + .mean() / dataframe["close"] - 1 ) @@ -68,15 +68,11 @@ class CatboostPredictionModel(IFreqaiModel): # standardize all data based on train_dataset only data_dictionary = self.dh.standardize_data(data_dictionary) - # optional additional data cleaning - if self.feature_parameters["principal_component_analysis"]: - self.dh.principal_component_analysis() - if self.feature_parameters["remove_outliers"]: - self.dh.remove_outliers(predict=False) - if self.feature_parameters["DI_threshold"]: - self.dh.data["avg_mean_dist"] = self.dh.compute_distances() + # optional additional data cleaning/analysis + self.data_cleaning_train() - logger.info("length of train data %s", len(data_dictionary["train_features"])) + logger.info(f'Training model on {len(self.dh.training_features_list)} features') + logger.info(f'Training model on {len(data_dictionary["train_features"])} data points') model = self.fit(data_dictionary) @@ -86,9 +82,7 @@ class CatboostPredictionModel(IFreqaiModel): def fit(self, data_dictionary: Dict) -> Any: """ - Most regressors use the same function names and arguments e.g. user - can drop in LGBMRegressor in place of CatBoostRegressor and all data - management will be properly handled by Freqai. + User sets up the training and test data to fit their desired model here :params: :data_dictionary: the dictionary constructed by DataHandler to hold all the training and test data/labels. @@ -133,7 +127,51 @@ class CatboostPredictionModel(IFreqaiModel): filtered_dataframe = self.dh.standardize_data_from_metadata(filtered_dataframe) self.dh.data_dictionary["prediction_features"] = filtered_dataframe - # optional additional data cleaning + # optional additional data cleaning/analysis + self.data_cleaning_predict(filtered_dataframe) + + predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) + + # compute the non-standardized predictions + self.dh.predictions = (predictions + 1) * (self.dh.data["labels_max"] - + self.dh.data["labels_min"]) / 2 + self.dh.data[ + "labels_min"] + + # logger.info("--------------------Finished prediction--------------------") + + return (self.dh.predictions, self.dh.do_predict) + + def data_cleaning_train(self) -> None: + """ + User can add data analysis and cleaning here. + Any function inside this method should drop training data points from the filtered_dataframe + based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example + of how outlier data points are dropped from the dataframe used for training. + """ + if self.feature_parameters["principal_component_analysis"]: + self.dh.principal_component_analysis() + + # if self.feature_parameters["determine_statistical_distributions"]: + # self.dh.determine_statistical_distributions() + # if self.feature_parameters["remove_outliers"]: + # self.dh.remove_outliers(predict=False) + + if self.feature_parameters["use_SVM_to_remove_outliers"]: + self.dh.use_SVM_to_remove_outliers(predict=False) + if self.feature_parameters["DI_threshold"]: + self.dh.data["avg_mean_dist"] = self.dh.compute_distances() + + def data_cleaning_predict(self, filtered_dataframe: DataFrame) -> None: + """ + User can add data analysis and cleaning here. + These functions each modify self.dh.do_predict, which is a dataframe with equal length + to the number of candles coming from and returning to the strategy. Inside do_predict, + 1 allows prediction and < 0 signals to the strategy that the model is not confident in + the prediction. + See FreqaiDataKitchen::remove_outliers() for an example + of how the do_predict vector is modified. do_predict is ultimately passed back to strategy + for buy signals. + """ if self.feature_parameters["principal_component_analysis"]: pca_components = self.dh.pca.transform(filtered_dataframe) self.dh.data_dictionary["prediction_features"] = pd.DataFrame( @@ -142,17 +180,13 @@ class CatboostPredictionModel(IFreqaiModel): index=filtered_dataframe.index, ) - if self.feature_parameters["remove_outliers"]: - self.dh.remove_outliers(predict=True) # creates dropped index + # if self.feature_parameters["determine_statistical_distributions"]: + # self.dh.determine_statistical_distributions() + # if self.feature_parameters["remove_outliers"]: + # self.dh.remove_outliers(predict=True) # creates dropped index + + if self.feature_parameters["use_SVM_to_remove_outliers"]: + self.dh.use_SVM_to_remove_outliers(predict=True) if self.feature_parameters["DI_threshold"]: self.dh.check_if_pred_in_training_spaces() # sets do_predict - - predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) - - # compute the non-standardized predictions - self.dh.predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] - - # logger.info("--------------------Finished prediction--------------------") - - return (self.dh.predictions, self.dh.do_predict) diff --git a/freqtrade/templates/ExamplePredictionModel.py b/freqtrade/templates/ExamplePredictionModel.py deleted file mode 100644 index 3d2b7a808..000000000 --- a/freqtrade/templates/ExamplePredictionModel.py +++ /dev/null @@ -1,159 +0,0 @@ -import logging -from typing import Any, Dict, Tuple - -import pandas as pd -from catboost import CatBoostRegressor, Pool -from pandas import DataFrame - -from freqtrade.freqai.freqai_interface import IFreqaiModel - - -logger = logging.getLogger(__name__) - - -class ExamplePredictionModel(IFreqaiModel): - """ - User created prediction model. The class needs to override three necessary - functions, predict(), train(), fit(). The class inherits ModelHandler which - has its own DataHandler where data is held, saved, loaded, and managed. - """ - - def make_labels(self, dataframe: DataFrame) -> DataFrame: - """ - User defines the labels here (target values). - :params: - :dataframe: the full dataframe for the present training period - """ - - dataframe["s"] = ( - dataframe["close"] - .shift(-self.feature_parameters["period"]) - .rolling(self.feature_parameters["period"]) - .max() - / dataframe["close"] - - 1 - ) - self.dh.data["s_mean"] = dataframe["s"].mean() - self.dh.data["s_std"] = dataframe["s"].std() - - # logger.info("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) - - return dataframe["s"] - - def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: - """ - Filter the training data and train a model to it. Train makes heavy use of the datakitchen - for storing, saving, loading, and analyzing the data. - :params: - :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. - :returns: - :model: Trained model which can be used to inference (self.predict) - """ - logger.info("--------------------Starting training--------------------") - - # create the full feature list based on user config info - self.dh.training_features_list = self.dh.build_feature_list(self.config, metadata) - unfiltered_labels = self.make_labels(unfiltered_dataframe) - - # filter the features requested by user in the configuration file and elegantly handle NaNs - features_filtered, labels_filtered = self.dh.filter_features( - unfiltered_dataframe, - self.dh.training_features_list, - unfiltered_labels, - training_filter=True, - ) - - # split data into train/test data. - data_dictionary = self.dh.make_train_test_datasets(features_filtered, labels_filtered) - # standardize all data based on train_dataset only - data_dictionary = self.dh.standardize_data(data_dictionary) - - # optional additional data cleaning - if self.feature_parameters["principal_component_analysis"]: - self.dh.principal_component_analysis() - if self.feature_parameters["remove_outliers"]: - self.dh.remove_outliers(predict=False) - if self.feature_parameters["DI_threshold"]: - self.dh.data["avg_mean_dist"] = self.dh.compute_distances() - - logger.info("length of train data %s", len(data_dictionary["train_features"])) - - model = self.fit(data_dictionary) - - logger.info(f'--------------------done training {metadata["pair"]}--------------------') - - return model - - def fit(self, data_dictionary: Dict) -> Any: - """ - Most regressors use the same function names and arguments e.g. user - can drop in LGBMRegressor in place of CatBoostRegressor and all data - management will be properly handled by Freqai. - :params: - :data_dictionary: the dictionary constructed by DataHandler to hold - all the training and test data/labels. - """ - - train_data = Pool( - data=data_dictionary["train_features"], - label=data_dictionary["train_labels"], - weight=data_dictionary["train_weights"], - ) - - test_data = Pool( - data=data_dictionary["test_features"], - label=data_dictionary["test_labels"], - weight=data_dictionary["test_weights"], - ) - - model = CatBoostRegressor( - verbose=100, early_stopping_rounds=400, **self.model_training_parameters - ) - model.fit(X=train_data, eval_set=test_data) - - return model - - def predict(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, - DataFrame]: - """ - Filter the prediction features data and predict with it. - :param: unfiltered_dataframe: Full dataframe for the current backtest period. - :return: - :predictions: np.array of predictions - :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove - data (NaNs) or felt uncertain about data (PCA and DI index) - """ - - # logger.info("--------------------Starting prediction--------------------") - - original_feature_list = self.dh.build_feature_list(self.config, metadata) - filtered_dataframe, _ = self.dh.filter_features( - unfiltered_dataframe, original_feature_list, training_filter=False - ) - filtered_dataframe = self.dh.standardize_data_from_metadata(filtered_dataframe) - self.dh.data_dictionary["prediction_features"] = filtered_dataframe - - # optional additional data cleaning - if self.feature_parameters["principal_component_analysis"]: - pca_components = self.dh.pca.transform(filtered_dataframe) - self.dh.data_dictionary["prediction_features"] = pd.DataFrame( - data=pca_components, - columns=["PC" + str(i) for i in range(0, self.dh.data["n_kept_components"])], - index=filtered_dataframe.index, - ) - - if self.feature_parameters["remove_outliers"]: - self.dh.remove_outliers(predict=True) # creates dropped index - - if self.feature_parameters["DI_threshold"]: - self.dh.check_if_pred_in_training_spaces() # sets do_predict - - predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) - - # compute the non-standardized predictions - self.dh.predictions = predictions * self.dh.data["labels_std"] + self.dh.data["labels_mean"] - - # logger.info("--------------------Finished prediction--------------------") - - return (self.dh.predictions, self.dh.do_predict) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index c8befebcf..a76ea2303 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -166,8 +166,8 @@ class FreqaiExampleStrategy(IStrategy): dataframe["target_std"], ) = self.model.bridge.start(dataframe, metadata, self) - dataframe["target_roi"] = dataframe["target_mean"] + dataframe["target_std"] * 0.5 - dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] * 1.5 + dataframe["target_roi"] = dataframe["target_mean"] + dataframe["target_std"] * 1.5 + dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] * 1 return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -183,7 +183,7 @@ class FreqaiExampleStrategy(IStrategy): def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: sell_conditions = [ - (dataframe["prediction"] < dataframe["sell_roi"]) & (dataframe["do_predict"] == 1) + (dataframe["do_predict"] <= 0) ] if sell_conditions: dataframe.loc[reduce(lambda x, y: x | y, sell_conditions), "sell"] = 1 From af0cc21af919a503ce1a7fd2854ca2ce50935fca Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 00:06:26 +0200 Subject: [PATCH 038/308] Enable hourly/minute retraining in live/dry. Suppress catboost folder output. Update config + constants + docs to reflect updates. --- config_examples/config_freqai.example.json | 3 +- docs/freqai.md | 19 ++++++- freqtrade/constants.py | 4 +- freqtrade/freqai/data_kitchen.py | 54 ++++++++++--------- freqtrade/freqai/freqai_interface.py | 20 ++++--- .../CatboostPredictionModel.py | 1 + 6 files changed, 66 insertions(+), 35 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index a895a7341..ed3782775 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -71,7 +71,8 @@ "DI_threshold": 1, "weight_factor": 0, "principal_component_analysis": false, - "use_SVM_to_remove_outliers": false + "use_SVM_to_remove_outliers": false, + "stratify": 0 }, "data_split_parameters": { "test_size": 0.25, diff --git a/docs/freqai.md b/docs/freqai.md index 8a37e7d66..606b88912 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -151,7 +151,8 @@ no. `timeframes` * no. `base_features` * no. `corr_pairlist` * no. `shift`_ Users define the backtesting timerange with the typical `--timerange` parameter in the user configuration file. `train_period` is the duration of the sliding training window, while -`backtest_period` is the sliding backtesting window, both in number of days. In the present example, +`backtest_period` is the sliding backtesting window, both in number of days (backtest_period can be +a float to indicate sub daily retraining in live/dry mode). In the present example, the user is asking Freqai to use a training period of 30 days and backtest the subsequent 7 days. This means that if the user sets `--timerange 20210501-20210701`, Freqai will train 8 separate models (because the full range comprises 8 weeks), @@ -347,6 +348,22 @@ Freqai will train an SVM on the training data (or components if the user activat `principal_component_analysis`) and remove any data point that it deems to be sit beyond the feature space. +## Stratifying the data + +The user can stratify the training/testing data using: + +```json + "freqai": { + "feature_parameters" : { + "stratify": 3 + } + } +``` + +which will split the data chronolocially so that every X data points is a testing data point. In the +present example, the user is asking for every third data point in the dataframe to be used for +testing, the other points are used for training. + ## Additional information ### Feature standardization diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 686991e2c..05581cc3a 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -438,7 +438,7 @@ CONF_SCHEMA = { "properties": { "timeframes": {"type": "list"}, "train_period": {"type": "integer", "default": 0}, - "backtest_period": {"type": "integer", "default": 7}, + "backtest_period": {"type": "float", "default": 7}, "identifier": {"type": "str", "default": "example"}, "live_trained_timerange": {"type": "str"}, "live_full_backtestrange": {"type": "str"}, @@ -451,7 +451,7 @@ CONF_SCHEMA = { "DI_threshold": {"type": "integer", "default": 0}, "weight_factor": {"type": "number", "default": 0}, "principal_component_analysis": {"type": "boolean", "default": False}, - "remove_outliers": {"type": "boolean", "default": False}, + "use_SVM_to_remove_outliers": {"type": "boolean", "default": False}, }, }, "data_split_parameters": { diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index f589a1c89..e09a2d0d5 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -689,50 +689,58 @@ class FreqaiDataKitchen: return full_timerange - def check_if_new_training_required(self, training_timerange: str, - metadata: dict) -> Tuple[bool, str]: + def check_if_new_training_required(self, trained_timerange: TimeRange, + metadata: dict, + timestamp: int = 0) -> Tuple[bool, TimeRange, int]: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() - if training_timerange: # user passed no live_trained_timerange in config - trained_timerange = TimeRange.parse_timerange(training_timerange) + if trained_timerange.startts != 0: + # trained_timerange = TimeRange.parse_timerange(training_timerange) + # keep hour available incase user wants to train multiple times per day + # training_timerange is a str for day range only, so we add the extra hours + # original_stop_seconds = trained_timerange.stopts + # trained_timerange.stopts += int(timestamp - original_stop_seconds) + # trained_timerange.startts += int(timestamp - original_stop_seconds) elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY - trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY - trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY retrain = elapsed_time > self.freqai_config['backtest_period'] - else: - trained_timerange = TimeRange.parse_timerange("20000101-20000201") + if retrain: + trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + else: # user passed no live_trained_timerange in config + trained_timerange = TimeRange.parse_timerange("20000101-20000201") # arbitrary date trained_timerange.startts = int(time - self.freqai_config['train_period'] * SECONDS_IN_DAY) trained_timerange.stopts = int(time) retrain = True - start = datetime.datetime.utcfromtimestamp(trained_timerange.startts) - stop = datetime.datetime.utcfromtimestamp(trained_timerange.stopts) - new_trained_timerange = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") + timestamp = trained_timerange.stopts + # start = datetime.datetime.utcfromtimestamp(trained_timerange.startts) + # stop = datetime.datetime.utcfromtimestamp(trained_timerange.stopts) + # new_trained_timerange_str = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") if retrain: coin, _ = metadata['pair'].split("/") # set the new model_path self.model_path = Path(self.full_path / str("sub-train" + "-" + - str(new_trained_timerange))) + str(timestamp))) - self.model_filename = "cb_" + coin.lower() + "_" + new_trained_timerange + self.model_filename = "cb_" + coin.lower() + "_" + str(timestamp) # this is not persistent at the moment TODO - self.freqai_config['live_trained_timerange'] = new_trained_timerange + self.freqai_config['live_trained_timerange'] = str(timestamp) # enables persistence, but not fully implemented into save/load data yer - self.data['live_trained_timerange'] = new_trained_timerange + self.data['live_trained_timerange'] = str(timestamp) - return retrain, new_trained_timerange + return retrain, trained_timerange, timestamp - def download_new_data_for_retraining(self, new_timerange: str, metadata: dict) -> None: + def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict) -> None: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config, validate=False) pairs = self.freqai_config['corr_pairlist'] if metadata['pair'] not in pairs: pairs += metadata['pair'] # dont include pair twice - timerange = TimeRange.parse_timerange(new_timerange) + # timerange = TimeRange.parse_timerange(new_timerange) refresh_backtest_ohlcv_data( exchange, pairs=pairs, timeframes=self.freqai_config['timeframes'], @@ -743,12 +751,12 @@ class FreqaiDataKitchen: prepend=self.config.get('prepend_data', False) ) - def load_pairs_histories(self, new_timerange: str, metadata: dict) -> Tuple[Dict[Any, Any], - DataFrame]: + def load_pairs_histories(self, timerange: TimeRange, metadata: dict) -> Tuple[Dict[Any, Any], + DataFrame]: corr_dataframes: Dict[Any, Any] = {} base_dataframes: Dict[Any, Any] = {} pairs = self.freqai_config['corr_pairlist'] # + [metadata['pair']] - timerange = TimeRange.parse_timerange(new_timerange) + # timerange = TimeRange.parse_timerange(new_timerange) for tf in self.freqai_config['timeframes']: base_dataframes[tf] = load_pair_history(datadir=self.config['datadir'], @@ -763,10 +771,6 @@ class FreqaiDataKitchen: timeframe=tf, pair=p, timerange=timerange) - # base_dataframe = [dataframe for key, dataframe in corr_dataframes.items() - # if metadata['pair'] in key] - - # [0] indexes the lowest tf for the basepair return corr_dataframes, base_dataframes def use_strategy_to_populate_indicators(self, strategy: IStrategy, diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index f1dd5550a..6e597531b 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -11,6 +11,7 @@ import numpy.typing as npt import pandas as pd from pandas import DataFrame +from freqtrade.configuration import TimeRange from freqtrade.enums import RunMode from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.strategy.interface import IStrategy @@ -63,6 +64,12 @@ class IFreqaiModel(ABC): self.training_on_separate_thread = False self.retrain = False self.first = True + self.timestamp = 0 + if self.freqai_info['live_trained_timerange']: + self.new_trained_timerange = TimeRange.parse_timerange( + self.freqai_info['live_trained_timerange']) + else: + self.new_trained_timerange = TimeRange() def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ @@ -150,9 +157,10 @@ class IFreqaiModel(ABC): if not self.training_on_separate_thread: # this will also prevent other pairs from trying to train simultaneously. (self.retrain, - self.new_trained_timerange) = self.dh.check_if_new_training_required(self.freqai_info[ - 'live_trained_timerange'], - metadata) + self.new_trained_timerange, + self.timestamp) = self.dh.check_if_new_training_required(self.new_trained_timerange, + metadata, + timestamp=self.timestamp) else: logger.info("FreqAI training a new model on background thread.") self.retrain = False @@ -250,7 +258,7 @@ class IFreqaiModel(ABC): :param pair: pair e.g. BTC/USD :param path: path to model """ - if self.live and training_timerange is None: + if self.live and training_timerange == "": return False coin, _ = pair.split("/") self.dh.model_filename = "cb_" + coin.lower() + "_" + training_timerange @@ -263,7 +271,7 @@ class IFreqaiModel(ABC): return file_exists @threaded - def retrain_model_on_separate_thread(self, new_trained_timerange: str, metadata: dict, + def retrain_model_on_separate_thread(self, new_trained_timerange: TimeRange, metadata: dict, strategy: IStrategy): # with nostdout(): @@ -282,7 +290,7 @@ class IFreqaiModel(ABC): self.training_on_separate_thread = False self.retrain = False - def train_model_in_series(self, new_trained_timerange: str, metadata: dict, + def train_model_in_series(self, new_trained_timerange: TimeRange, metadata: dict, strategy: IStrategy): self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 8550f3f15..3dad6add6 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -101,6 +101,7 @@ class CatboostPredictionModel(IFreqaiModel): ) model = CatBoostRegressor( + allow_writing_files=False, verbose=100, early_stopping_rounds=400, **self.model_training_parameters ) model.fit(X=train_data, eval_set=test_data) From 3587bd82e16b2781e1f12f926114dfde88927cee Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 00:10:36 +0200 Subject: [PATCH 039/308] cleanup superceded code --- freqtrade/freqai/data_kitchen.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index e09a2d0d5..da0d7e4df 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -696,28 +696,19 @@ class FreqaiDataKitchen: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() if trained_timerange.startts != 0: - # trained_timerange = TimeRange.parse_timerange(training_timerange) - # keep hour available incase user wants to train multiple times per day - # training_timerange is a str for day range only, so we add the extra hours - # original_stop_seconds = trained_timerange.stopts - # trained_timerange.stopts += int(timestamp - original_stop_seconds) - # trained_timerange.startts += int(timestamp - original_stop_seconds) elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY retrain = elapsed_time > self.freqai_config['backtest_period'] if retrain: trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY else: # user passed no live_trained_timerange in config - trained_timerange = TimeRange.parse_timerange("20000101-20000201") # arbitrary date + trained_timerange = TimeRange() trained_timerange.startts = int(time - self.freqai_config['train_period'] * SECONDS_IN_DAY) trained_timerange.stopts = int(time) retrain = True timestamp = trained_timerange.stopts - # start = datetime.datetime.utcfromtimestamp(trained_timerange.startts) - # stop = datetime.datetime.utcfromtimestamp(trained_timerange.stopts) - # new_trained_timerange_str = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") if retrain: coin, _ = metadata['pair'].split("/") From ee3cdd0ffec87bc89ec0700196609998ae2a1d21 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 09:55:58 +0200 Subject: [PATCH 040/308] more cleanup --- freqtrade/freqai/data_kitchen.py | 15 ++++++--------- freqtrade/freqai/freqai_interface.py | 8 +++----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index da0d7e4df..3347bbe97 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -690,8 +690,7 @@ class FreqaiDataKitchen: return full_timerange def check_if_new_training_required(self, trained_timerange: TimeRange, - metadata: dict, - timestamp: int = 0) -> Tuple[bool, TimeRange, int]: + metadata: dict) -> Tuple[bool, TimeRange]: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() @@ -708,21 +707,19 @@ class FreqaiDataKitchen: trained_timerange.stopts = int(time) retrain = True - timestamp = trained_timerange.stopts - if retrain: coin, _ = metadata['pair'].split("/") # set the new model_path self.model_path = Path(self.full_path / str("sub-train" + "-" + - str(timestamp))) + str(int(trained_timerange.stopts)))) - self.model_filename = "cb_" + coin.lower() + "_" + str(timestamp) + self.model_filename = "cb_" + coin.lower() + "_" + str(int(trained_timerange.stopts)) # this is not persistent at the moment TODO - self.freqai_config['live_trained_timerange'] = str(timestamp) + self.freqai_config['live_trained_timerange'] = str(int(trained_timerange.stopts)) # enables persistence, but not fully implemented into save/load data yer - self.data['live_trained_timerange'] = str(timestamp) + self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) - return retrain, trained_timerange, timestamp + return retrain, trained_timerange def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict) -> None: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 6e597531b..3ff98b8ee 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -64,7 +64,6 @@ class IFreqaiModel(ABC): self.training_on_separate_thread = False self.retrain = False self.first = True - self.timestamp = 0 if self.freqai_info['live_trained_timerange']: self.new_trained_timerange = TimeRange.parse_timerange( self.freqai_info['live_trained_timerange']) @@ -157,10 +156,9 @@ class IFreqaiModel(ABC): if not self.training_on_separate_thread: # this will also prevent other pairs from trying to train simultaneously. (self.retrain, - self.new_trained_timerange, - self.timestamp) = self.dh.check_if_new_training_required(self.new_trained_timerange, - metadata, - timestamp=self.timestamp) + self.new_trained_timerange) = self.dh.check_if_new_training_required( + self.new_trained_timerange, + metadata) else: logger.info("FreqAI training a new model on background thread.") self.retrain = False From dede12864899094dc9f487fc41edbf96d069a7b0 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 10:15:59 +0200 Subject: [PATCH 041/308] set process_only_new_candles to true in example strat --- freqtrade/templates/FreqaiExampleStrategy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index a76ea2303..690532c10 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -42,6 +42,7 @@ class FreqaiExampleStrategy(IStrategy): }, } + process_only_new_candles = False stoploss = -0.05 use_sell_signal = True startup_candle_count: int = 300 From e1c068ca662ce7f35160659edbf8502f27083a6d Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 12:07:09 +0200 Subject: [PATCH 042/308] add config asserts, use .get method with default values for optional functionality, move data_cleaning_* to freqai_interface (away from user custom pred model) since it is controlled by config params. --- freqtrade/freqai/data_kitchen.py | 105 ++++++++++----- freqtrade/freqai/freqai_interface.py | 127 ++++++++++++------ .../CatboostPredictionModel.py | 21 ++- freqtrade/optimize/backtesting.py | 2 +- 4 files changed, 162 insertions(+), 93 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 3347bbe97..148efd5dd 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -43,6 +43,7 @@ class FreqaiDataKitchen: self.data: Dict[Any, Any] = {} self.data_dictionary: Dict[Any, Any] = {} self.config = config + self.assert_config(self.config, live) self.freqai_config = config["freqai"] self.predictions: npt.ArrayLike = np.array([]) self.do_predict: npt.ArrayLike = np.array([]) @@ -59,7 +60,7 @@ class FreqaiDataKitchen: self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: self.full_timerange = self.create_fulltimerange(self.config["timerange"], - self.freqai_config["train_period"] + self.freqai_config.get("train_period") ) (self.training_timeranges, self.backtesting_timeranges) = self.split_timerange( @@ -68,14 +69,33 @@ class FreqaiDataKitchen: config["freqai"]["backtest_period"], ) + def assert_config(self, config: Dict[str, Any], live: bool) -> None: + assert config.get('freqai'), "No Freqai parameters found in config file." + assert config.get('freqai', {}).get('train_period'), ("No Freqai train_period found in" + "config file.") + assert type(config.get('freqai', {}) + .get('train_period')) is int, ('Can only train on full day period.' + 'No fractional days permitted.') + assert config.get('freqai', {}).get('backtest_period'), ("No Freqai backtest_period found" + "in config file.") + if not live: + assert type(config.get('freqai', {}) + .get('backtest_period')) is int, ('Can only backtest on full day' + 'backtest_period. Only live/dry mode' + 'allows fractions of days') + assert config.get('freqai', {}).get('identifier'), ("No Freqai identifier found in config" + "file.") + assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai feature_parameters" + "found in config file.") + def set_paths(self) -> None: self.full_path = Path(self.config['user_data_dir'] / "models" / - str(self.freqai_config['live_full_backtestrange'] + - self.freqai_config['identifier'])) + str(self.freqai_config.get('live_full_backtestrange') + + self.freqai_config.get('identifier'))) self.model_path = Path(self.full_path / str("sub-train" + "-" + - str(self.freqai_config['live_trained_timerange']))) + str(self.freqai_config.get('live_trained_timerange')))) return @@ -117,7 +137,7 @@ class FreqaiDataKitchen: # do not want them having to edit the default save/load methods here. Below is an example # of what we do NOT want. - # if self.freqai_config['feature_parameters']['determine_statistical_distributions']: + # if self.freqai_config.get('feature_parameters','determine_statistical_distributions'): # self.data_dictionary["upper_quantiles"].to_pickle( # save_path / str(self.model_filename + "_upper_quantiles.pkl") # ) @@ -147,7 +167,7 @@ class FreqaiDataKitchen: # do not want them having to edit the default save/load methods here. Below is an example # of what we do NOT want. - # if self.freqai_config['feature_parameters']['determine_statistical_distributions']: + # if self.freqai_config.get('feature_parameters','determine_statistical_distributions'): # self.data_dictionary["upper_quantiles"] = pd.read_pickle( # self.model_path / str(self.model_filename + "_upper_quantiles.pkl") # ) @@ -193,15 +213,15 @@ class FreqaiDataKitchen: """ weights: npt.ArrayLike - if self.config["freqai"]["feature_parameters"]["weight_factor"] > 0: + if self.freqai_config["feature_parameters"].get("weight_factor", 0) > 0: weights = self.set_weights_higher_recent(len(filtered_dataframe)) else: weights = np.ones(len(filtered_dataframe)) - if self.config["freqai"]["feature_parameters"]["stratify"] > 0: + if self.freqai_config["feature_parameters"].get("stratify", 0) > 0: stratification = np.zeros(len(filtered_dataframe)) for i in range(1, len(stratification)): - if i % self.config["freqai"]["feature_parameters"]["stratify"] == 0: + if i % self.freqai_config.get("feature_parameters", {}).get("stratify", 0) == 0: stratification[i] = 1 ( @@ -525,6 +545,14 @@ class FreqaiDataKitchen: return None + def pca_transform(self, filtered_dataframe: DataFrame) -> None: + pca_components = self.pca.transform(filtered_dataframe) + self.data_dictionary["prediction_features"] = pd.DataFrame( + data=pca_components, + columns=["PC" + str(i) for i in range(0, self.data["n_kept_components"])], + index=filtered_dataframe.index, + ) + def compute_distances(self) -> float: logger.info("computing average mean distance for all training points") pairwise = pairwise_distances(self.data_dictionary["train_features"], n_jobs=-1) @@ -675,7 +703,7 @@ class FreqaiDataKitchen: self.full_path = Path( self.config["user_data_dir"] / "models" - / str(full_timerange + self.freqai_config["identifier"]) + / str(full_timerange + self.freqai_config.get("identifier")) ) config_path = Path(self.config["config_files"][0]) @@ -696,13 +724,15 @@ class FreqaiDataKitchen: if trained_timerange.startts != 0: elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY - retrain = elapsed_time > self.freqai_config['backtest_period'] + retrain = elapsed_time > self.freqai_config.get('backtest_period') if retrain: - trained_timerange.startts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY - trained_timerange.stopts += self.freqai_config['backtest_period'] * SECONDS_IN_DAY + trained_timerange.startts += self.freqai_config.get( + 'backtest_period', 0) * SECONDS_IN_DAY + trained_timerange.stopts += self.freqai_config.get( + 'backtest_period', 0) * SECONDS_IN_DAY else: # user passed no live_trained_timerange in config trained_timerange = TimeRange() - trained_timerange.startts = int(time - self.freqai_config['train_period'] * + trained_timerange.startts = int(time - self.freqai_config.get('train_period') * SECONDS_IN_DAY) trained_timerange.stopts = int(time) retrain = True @@ -725,13 +755,13 @@ class FreqaiDataKitchen: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config, validate=False) - pairs = self.freqai_config['corr_pairlist'] + pairs = self.freqai_config.get('corr_pairlist', []) if metadata['pair'] not in pairs: pairs += metadata['pair'] # dont include pair twice # timerange = TimeRange.parse_timerange(new_timerange) refresh_backtest_ohlcv_data( - exchange, pairs=pairs, timeframes=self.freqai_config['timeframes'], + exchange, pairs=pairs, timeframes=self.freqai_config.get('timeframes'), datadir=self.config['datadir'], timerange=timerange, new_pairs_days=self.config['new_pairs_days'], erase=False, data_format=self.config['dataformat_ohlcv'], @@ -743,21 +773,22 @@ class FreqaiDataKitchen: DataFrame]: corr_dataframes: Dict[Any, Any] = {} base_dataframes: Dict[Any, Any] = {} - pairs = self.freqai_config['corr_pairlist'] # + [metadata['pair']] + pairs = self.freqai_config.get('corr_pairlist', []) # + [metadata['pair']] # timerange = TimeRange.parse_timerange(new_timerange) - for tf in self.freqai_config['timeframes']: + for tf in self.freqai_config.get('timeframes'): base_dataframes[tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, pair=metadata['pair'], timerange=timerange) - for p in pairs: - if metadata['pair'] in p: - continue # dont repeat anything from whitelist - if p not in corr_dataframes: - corr_dataframes[p] = {} - corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], - timeframe=tf, - pair=p, timerange=timerange) + if pairs: + for p in pairs: + if metadata['pair'] in p: + continue # dont repeat anything from whitelist + if p not in corr_dataframes: + corr_dataframes[p] = {} + corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], + timeframe=tf, + pair=p, timerange=timerange) return corr_dataframes, base_dataframes @@ -767,23 +798,25 @@ class FreqaiDataKitchen: metadata: dict) -> DataFrame: dataframe = base_dataframes[self.config['timeframe']] + pairs = self.freqai_config.get("corr_pairlist", []) - for tf in self.freqai_config["timeframes"]: + for tf in self.freqai_config.get("timeframes"): dataframe = strategy.populate_any_indicators(metadata['pair'], dataframe.copy(), tf, base_dataframes[tf], coin=metadata['pair'].split("/")[0] + "-" ) - for i in self.freqai_config["corr_pairlist"]: - if metadata['pair'] in i: - continue # dont repeat anything from whitelist - dataframe = strategy.populate_any_indicators(i, - dataframe.copy(), - tf, - corr_dataframes[i][tf], - coin=i.split("/")[0] + "-" - ) + if pairs: + for i in pairs: + if metadata['pair'] in i: + continue # dont repeat anything from whitelist + dataframe = strategy.populate_any_indicators(i, + dataframe.copy(), + tf, + corr_dataframes[i][tf], + coin=i.split("/")[0] + "-" + ) return dataframe diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 3ff98b8ee..2b3addab3 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -20,7 +20,7 @@ from freqtrade.strategy.interface import IStrategy pd.options.mode.chained_assignment = None logger = logging.getLogger(__name__) -# FIXME: suppress stdout for background training +# FIXME: suppress stdout for background training? # class DummyFile(object): # def write(self, x): pass @@ -51,6 +51,7 @@ class IFreqaiModel(ABC): def __init__(self, config: Dict[str, Any]) -> None: self.config = config + self.assert_config(self.config) self.freqai_info = config["freqai"] self.data_split_parameters = config["freqai"]["data_split_parameters"] self.model_training_parameters = config["freqai"]["model_training_parameters"] @@ -64,12 +65,25 @@ class IFreqaiModel(ABC): self.training_on_separate_thread = False self.retrain = False self.first = True - if self.freqai_info['live_trained_timerange']: + if self.freqai_info.get('live_trained_timerange'): self.new_trained_timerange = TimeRange.parse_timerange( self.freqai_info['live_trained_timerange']) else: self.new_trained_timerange = TimeRange() + def assert_config(self, config: Dict[str, Any]) -> None: + + assert config.get('freqai'), "No Freqai parameters found in config file." + assert config.get('freqai', {}).get('data_split_parameters'), ("No Freqai" + "data_split_parameters" + "in config file.") + assert config.get('freqai', {}).get('model_training_parameters'), ("No Freqai" + "modeltrainingparameters" + "found in config file.") + assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai" + "feature_parameters found in" + "config file.") + def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ Entry point to the FreqaiModel, it will train a new model if @@ -192,55 +206,30 @@ class IFreqaiModel(ABC): return - @abstractmethod - def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Any: - """ - Filter the training data and train a model to it. Train makes heavy use of the datahandler - for storing, saving, loading, and analyzing the data. - :params: - :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. - :returns: - :model: Trained model which can be used to inference (self.predict) - """ - - @abstractmethod - def fit(self) -> Any: - """ - Most regressors use the same function names and arguments e.g. user - can drop in LGBMRegressor in place of CatBoostRegressor and all data - management will be properly handled by Freqai. - :params: - :data_dictionary: the dictionary constructed by DataHandler to hold - all the training and test data/labels. - """ - - return - - @abstractmethod - def predict(self, dataframe: DataFrame, metadata: dict) -> Tuple[npt.ArrayLike, npt.ArrayLike]: - """ - Filter the prediction features data and predict with it. - :param: unfiltered_dataframe: Full dataframe for the current backtest period. - :return: - :predictions: np.array of predictions - :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove - data (NaNs) or felt uncertain about data (PCA and DI index) - """ - - @abstractmethod def data_cleaning_train(self) -> None: """ - User can add data analysis and cleaning here. + Base data cleaning method for train Any function inside this method should drop training data points from the filtered_dataframe based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example of how outlier data points are dropped from the dataframe used for training. """ + if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): + self.dh.principal_component_analysis() - @abstractmethod - def data_cleaning_predict(self) -> None: + # if self.feature_parameters["determine_statistical_distributions"]: + # self.dh.determine_statistical_distributions() + # if self.feature_parameters["remove_outliers"]: + # self.dh.remove_outliers(predict=False) + + if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): + self.dh.use_SVM_to_remove_outliers(predict=False) + + if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): + self.dh.data["avg_mean_dist"] = self.dh.compute_distances() + + def data_cleaning_predict(self, filtered_dataframe: DataFrame) -> None: """ - User can add data analysis and cleaning here. + Base data cleaning method for predict. These functions each modify self.dh.do_predict, which is a dataframe with equal length to the number of candles coming from and returning to the strategy. Inside do_predict, 1 allows prediction and < 0 signals to the strategy that the model is not confident in @@ -249,6 +238,19 @@ class IFreqaiModel(ABC): of how the do_predict vector is modified. do_predict is ultimately passed back to strategy for buy signals. """ + if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): + self.dh.pca_transform() + + # if self.feature_parameters["determine_statistical_distributions"]: + # self.dh.determine_statistical_distributions() + # if self.feature_parameters["remove_outliers"]: + # self.dh.remove_outliers(predict=True) # creates dropped index + + if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): + self.dh.use_SVM_to_remove_outliers(predict=True) + + if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): + self.dh.check_if_pred_in_training_spaces() # sets do_predict def model_exists(self, pair: str, training_timerange: str) -> bool: """ @@ -303,3 +305,42 @@ class IFreqaiModel(ABC): self.model = self.train(unfiltered_dataframe, metadata) self.dh.save_data(self.model) self.retrain = False + + # Methods which are overridden by user made prediction models. + # See freqai/prediction_models/CatboostPredictionModlel.py for an example. + + @abstractmethod + def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Any: + """ + Filter the training data and train a model to it. Train makes heavy use of the datahandler + for storing, saving, loading, and analyzing the data. + :params: + :unfiltered_dataframe: Full dataframe for the current training period + :metadata: pair metadata from strategy. + :returns: + :model: Trained model which can be used to inference (self.predict) + """ + + @abstractmethod + def fit(self) -> Any: + """ + Most regressors use the same function names and arguments e.g. user + can drop in LGBMRegressor in place of CatBoostRegressor and all data + management will be properly handled by Freqai. + :params: + :data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. + """ + + return + + @abstractmethod + def predict(self, dataframe: DataFrame, metadata: dict) -> Tuple[npt.ArrayLike, npt.ArrayLike]: + """ + Filter the prediction features data and predict with it. + :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :return: + :predictions: np.array of predictions + :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove + data (NaNs) or felt uncertain about data (PCA and DI index) + """ diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 3dad6add6..d09554e3e 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -1,7 +1,6 @@ import logging from typing import Any, Dict, Tuple -import pandas as pd from catboost import CatBoostRegressor, Pool from pandas import DataFrame @@ -149,7 +148,7 @@ class CatboostPredictionModel(IFreqaiModel): based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example of how outlier data points are dropped from the dataframe used for training. """ - if self.feature_parameters["principal_component_analysis"]: + if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): self.dh.principal_component_analysis() # if self.feature_parameters["determine_statistical_distributions"]: @@ -157,9 +156,10 @@ class CatboostPredictionModel(IFreqaiModel): # if self.feature_parameters["remove_outliers"]: # self.dh.remove_outliers(predict=False) - if self.feature_parameters["use_SVM_to_remove_outliers"]: + if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): self.dh.use_SVM_to_remove_outliers(predict=False) - if self.feature_parameters["DI_threshold"]: + + if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): self.dh.data["avg_mean_dist"] = self.dh.compute_distances() def data_cleaning_predict(self, filtered_dataframe: DataFrame) -> None: @@ -173,21 +173,16 @@ class CatboostPredictionModel(IFreqaiModel): of how the do_predict vector is modified. do_predict is ultimately passed back to strategy for buy signals. """ - if self.feature_parameters["principal_component_analysis"]: - pca_components = self.dh.pca.transform(filtered_dataframe) - self.dh.data_dictionary["prediction_features"] = pd.DataFrame( - data=pca_components, - columns=["PC" + str(i) for i in range(0, self.dh.data["n_kept_components"])], - index=filtered_dataframe.index, - ) + if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): + self.dh.pca_transform() # if self.feature_parameters["determine_statistical_distributions"]: # self.dh.determine_statistical_distributions() # if self.feature_parameters["remove_outliers"]: # self.dh.remove_outliers(predict=True) # creates dropped index - if self.feature_parameters["use_SVM_to_remove_outliers"]: + if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): self.dh.use_SVM_to_remove_outliers(predict=True) - if self.feature_parameters["DI_threshold"]: + if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): self.dh.check_if_pred_in_training_spaces() # sets do_predict diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index add864a67..3996dd08d 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -207,7 +207,7 @@ class Backtesting: if self.config.get('freqai') is not None: self.required_startup += int((self.config.get('freqai', {}).get('train_period') * 86400) / timeframe_to_seconds(self.config['timeframe'])) - logger.info("Increasing startup_candle_count for freqai to %s", self.required_startup) + logger.info(f'Increasing startup_candle_count for freqai to {self.required_startup}') self.config['startup_candle_count'] = self.required_startup data = history.load_data( From b0d2d13eb19a5a64a4bec8b5314d36544ec21a38 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 21:05:05 +0200 Subject: [PATCH 043/308] improve data persistence/mapping for live/dry. This accommodates quick reloads after crash and handles multi-pair cleanly --- freqtrade/freqai/data_drawer.py | 59 +++++++++ freqtrade/freqai/data_kitchen.py | 123 ++++++++++-------- freqtrade/freqai/freqai_interface.py | 102 ++++++++++----- .../CatboostPredictionModel.py | 46 ------- 4 files changed, 199 insertions(+), 131 deletions(-) create mode 100644 freqtrade/freqai/data_drawer.py diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py new file mode 100644 index 000000000..a27a4b67f --- /dev/null +++ b/freqtrade/freqai/data_drawer.py @@ -0,0 +1,59 @@ + +import json +import logging +from pathlib import Path +from typing import Any, Dict, Tuple + +# import pickle as pk +import numpy as np + + +logger = logging.getLogger(__name__) + + +class FreqaiDataDrawer: + """ + Class aimed at holding all pair models/info in memory for better inferencing/retrainig/saving + /loading to/from disk. + This object remains persistent throughout live/dry, unlike FreqaiDataKitchen, which is + reinstantiated for each coin. + """ + def __init__(self, full_path: Path): + + # dictionary holding all pair metadata necessary to load in from disk + self.pair_dict: Dict[str, Any] = {} + # dictionary holding all actively inferenced models in memory given a model filename + self.model_dictionary: Dict[str, Any] = {} + self.full_path = full_path + self.load_drawer_from_disk() + + def load_drawer_from_disk(self): + exists = Path(self.full_path / str('pair_dictionary.json')).resolve().exists() + if exists: + with open(self.full_path / str('pair_dictionary.json'), "r") as fp: + self.pair_dict = json.load(fp) + else: + logger.info("Could not find existing datadrawer, starting from scratch") + return exists + + def save_drawer_to_disk(self): + with open(self.full_path / str('pair_dictionary.json'), "w") as fp: + json.dump(self.pair_dict, fp, default=self.np_encoder) + + def np_encoder(self, object): + if isinstance(object, np.generic): + return object.item() + + def get_pair_dict_info(self, metadata: dict) -> Tuple[str, int, bool]: + pair_in_dict = self.pair_dict.get(metadata['pair']) + if pair_in_dict: + model_filename = self.pair_dict[metadata['pair']]['model_filename'] + trained_timestamp = self.pair_dict[metadata['pair']]['trained_timestamp'] + coin_first = self.pair_dict[metadata['pair']]['first'] + else: + self.pair_dict[metadata['pair']] = {} + model_filename = self.pair_dict[metadata['pair']]['model_filename'] = '' + coin_first = self.pair_dict[metadata['pair']]['first'] = True + trained_timestamp = self.pair_dict[metadata['pair']]['trained_timestamp'] = 0 + + return model_filename, trained_timestamp, coin_first diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 148efd5dd..f5ddf8462 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -19,6 +19,7 @@ from sklearn.model_selection import train_test_split from freqtrade.configuration import TimeRange from freqtrade.data.history import load_pair_history from freqtrade.data.history.history_utils import refresh_backtest_ohlcv_data +from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.resolvers import ExchangeResolver from freqtrade.strategy.interface import IStrategy @@ -33,13 +34,13 @@ logger = logging.getLogger(__name__) class FreqaiDataKitchen: """ - Class designed to handle all the data for the IFreqaiModel class model. + Class designed to analyze data for a single pair. Employed by the IFreqaiModel class. Functionalities include holding, saving, loading, and analyzing the data. author: Robert Caulk, rob.caulk@gmail.com """ - def __init__(self, config: Dict[str, Any], dataframe: DataFrame, live: bool = False): - self.full_dataframe = dataframe + def __init__(self, config: Dict[str, Any], data_drawer: FreqaiDataDrawer, live: bool = False, + pair: str = ''): self.data: Dict[Any, Any] = {} self.data_dictionary: Dict[Any, Any] = {} self.config = config @@ -53,10 +54,10 @@ class FreqaiDataKitchen: self.full_do_predict: npt.ArrayLike = np.array([]) self.full_target_mean: npt.ArrayLike = np.array([]) self.full_target_std: npt.ArrayLike = np.array([]) - self.model_path = Path() + self.data_path = Path() self.model_filename: str = "" - self.model_dictionary: Dict[Any, Any] = {} self.live = live + self.pair = pair self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: self.full_timerange = self.create_fulltimerange(self.config["timerange"], @@ -69,6 +70,8 @@ class FreqaiDataKitchen: config["freqai"]["backtest_period"], ) + self.data_drawer = data_drawer + def assert_config(self, config: Dict[str, Any], live: bool) -> None: assert config.get('freqai'), "No Freqai parameters found in config file." assert config.get('freqai', {}).get('train_period'), ("No Freqai train_period found in" @@ -88,18 +91,18 @@ class FreqaiDataKitchen: assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai feature_parameters" "found in config file.") - def set_paths(self) -> None: + def set_paths(self, trained_timestamp: int = None) -> None: self.full_path = Path(self.config['user_data_dir'] / "models" / str(self.freqai_config.get('live_full_backtestrange') + self.freqai_config.get('identifier'))) - self.model_path = Path(self.full_path / str("sub-train" + "-" + - str(self.freqai_config.get('live_trained_timerange')))) + self.data_path = Path(self.full_path / str("sub-train" + "-" + self.pair.split("/")[0] + + str(trained_timestamp))) return - def save_data(self, model: Any) -> None: + def save_data(self, model: Any, coin: str = '') -> None: """ Saves all data associated with a model for a single sub-train time range :params: @@ -107,10 +110,10 @@ class FreqaiDataKitchen: predictions """ - if not self.model_path.is_dir(): - self.model_path.mkdir(parents=True, exist_ok=True) + if not self.data_path.is_dir(): + self.data_path.mkdir(parents=True, exist_ok=True) - save_path = Path(self.model_path) + save_path = Path(self.data_path) # Save the trained model dump(model, save_path / str(self.model_filename + "_model.joblib")) @@ -118,7 +121,7 @@ class FreqaiDataKitchen: if self.svm_model is not None: dump(self.svm_model, save_path / str(self.model_filename + "_svm_model.joblib")) - self.data["model_path"] = str(self.model_path) + self.data["data_path"] = str(self.data_path) self.data["model_filename"] = str(self.model_filename) self.data["training_features_list"] = list(self.data_dictionary["train_features"].columns) # store the metadata @@ -131,7 +134,10 @@ class FreqaiDataKitchen: ) if self.live: - self.model_dictionary[self.model_filename] = model + self.data_drawer.model_dictionary[self.model_filename] = model + self.data_drawer.pair_dict[coin]['model_filename'] = self.model_filename + self.data_drawer.pair_dict[coin]['data_path'] = str(self.data_path) + self.data_drawer.save_drawer_to_disk() # TODO add a helper function to let user save/load any data they are custom adding. We # do not want them having to edit the default save/load methods here. Below is an example @@ -148,19 +154,23 @@ class FreqaiDataKitchen: return - def load_data(self) -> Any: + def load_data(self, coin: str = '') -> Any: """ loads all data required to make a prediction on a sub-train time range :returns: :model: User trained model which can be inferenced for new predictions """ - with open(self.model_path / str(self.model_filename + "_metadata.json"), "r") as fp: + if self.live: + self.model_filename = self.data_drawer.pair_dict[coin]['model_filename'] + self.data_path = Path(self.data_drawer.pair_dict[coin]['data_path']) + + with open(self.data_path / str(self.model_filename + "_metadata.json"), "r") as fp: self.data = json.load(fp) self.training_features_list = self.data["training_features_list"] self.data_dictionary["train_features"] = pd.read_pickle( - self.model_path / str(self.model_filename + "_trained_df.pkl") + self.data_path / str(self.model_filename + "_trained_df.pkl") ) # TODO add a helper function to let user save/load any data they are custom adding. We @@ -169,34 +179,34 @@ class FreqaiDataKitchen: # if self.freqai_config.get('feature_parameters','determine_statistical_distributions'): # self.data_dictionary["upper_quantiles"] = pd.read_pickle( - # self.model_path / str(self.model_filename + "_upper_quantiles.pkl") + # self.data_path / str(self.model_filename + "_upper_quantiles.pkl") # ) # self.data_dictionary["lower_quantiles"] = pd.read_pickle( - # self.model_path / str(self.model_filename + "_lower_quantiles.pkl") + # self.data_path / str(self.model_filename + "_lower_quantiles.pkl") # ) - self.model_path = Path(self.data["model_path"]) - self.model_filename = self.data["model_filename"] + # self.data_path = Path(self.data["data_path"]) + # self.model_filename = self.data["model_filename"] # try to access model in memory instead of loading object from disk to save time - if self.live and self.model_filename in self.model_dictionary: - model = self.model_dictionary[self.model_filename] + if self.live and self.model_filename in self.data_drawer.model_dictionary: + model = self.data_drawer.model_dictionary[self.model_filename] else: - model = load(self.model_path / str(self.model_filename + "_model.joblib")) + model = load(self.data_path / str(self.model_filename + "_model.joblib")) - if Path(self.model_path / str(self.model_filename + + if Path(self.data_path / str(self.model_filename + "_svm_model.joblib")).resolve().exists(): - self.svm_model = load(self.model_path / str(self.model_filename + "_svm_model.joblib")) + self.svm_model = load(self.data_path / str(self.model_filename + "_svm_model.joblib")) assert model, ( f"Unable to load model, ensure model exists at " - f"{self.model_path} " + f"{self.data_path} " ) if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]: self.pca = pk.load( - open(self.model_path / str(self.model_filename + "_pca_object.pkl"), "rb") + open(self.data_path / str(self.model_filename + "_pca_object.pkl"), "rb") ) return model @@ -539,9 +549,9 @@ class FreqaiDataKitchen: logger.info(f'PCA reduced total features from {n_components} to {n_keep_components}') - if not self.model_path.is_dir(): - self.model_path.mkdir(parents=True, exist_ok=True) - pk.dump(pca2, open(self.model_path / str(self.model_filename + "_pca_object.pkl"), "wb")) + if not self.data_path.is_dir(): + self.data_path.mkdir(parents=True, exist_ok=True) + pk.dump(pca2, open(self.data_path / str(self.model_filename + "_pca_object.pkl"), "wb")) return None @@ -717,40 +727,51 @@ class FreqaiDataKitchen: return full_timerange - def check_if_new_training_required(self, trained_timerange: TimeRange, - metadata: dict) -> Tuple[bool, TimeRange]: + def check_if_new_training_required(self, trained_timestamp: int) -> Tuple[bool, TimeRange]: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() - - if trained_timerange.startts != 0: - elapsed_time = (time - trained_timerange.stopts) / SECONDS_IN_DAY + trained_timerange = TimeRange() + if trained_timestamp != 0: + elapsed_time = (time - trained_timestamp) / SECONDS_IN_DAY retrain = elapsed_time > self.freqai_config.get('backtest_period') if retrain: - trained_timerange.startts += self.freqai_config.get( - 'backtest_period', 0) * SECONDS_IN_DAY - trained_timerange.stopts += self.freqai_config.get( - 'backtest_period', 0) * SECONDS_IN_DAY + trained_timerange.startts = int(time - self.freqai_config.get( + 'backtest_period', 0) * SECONDS_IN_DAY) + trained_timerange.stopts = int(time) else: # user passed no live_trained_timerange in config - trained_timerange = TimeRange() trained_timerange.startts = int(time - self.freqai_config.get('train_period') * SECONDS_IN_DAY) trained_timerange.stopts = int(time) retrain = True - if retrain: - coin, _ = metadata['pair'].split("/") - # set the new model_path - self.model_path = Path(self.full_path / str("sub-train" + "-" + - str(int(trained_timerange.stopts)))) + # if retrain: + # coin, _ = metadata['pair'].split("/") + # # set the new data_path + # self.data_path = Path(self.full_path / str("sub-train" + "-" + + # str(int(trained_timerange.stopts)))) - self.model_filename = "cb_" + coin.lower() + "_" + str(int(trained_timerange.stopts)) - # this is not persistent at the moment TODO - self.freqai_config['live_trained_timerange'] = str(int(trained_timerange.stopts)) - # enables persistence, but not fully implemented into save/load data yer - self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) + # self.model_filename = "cb_" + coin.lower() + "_" + str(int(trained_timerange.stopts)) + # # this is not persistent at the moment TODO + # self.freqai_config['live_trained_timerange'] = str(int(trained_timerange.stopts)) + # # enables persistence, but not fully implemented into save/load data yer + # self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) return retrain, trained_timerange + def set_new_model_names(self, metadata: dict, trained_timerange: TimeRange): + + coin, _ = metadata['pair'].split("/") + # set the new data_path + self.data_path = Path(self.full_path / str("sub-train" + "-" + + metadata['pair'].split("/")[0] + + str(int(trained_timerange.stopts)))) + + self.model_filename = "cb_" + coin.lower() + "_" + str(int(trained_timerange.stopts)) + # this is not persistent at the moment TODO + self.freqai_config['live_trained_timerange'] = str(int(trained_timerange.stopts)) + # enables persistence, but not fully implemented into save/load data yer + self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) + def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict) -> None: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 2b3addab3..0b1fb3b86 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -13,6 +13,7 @@ from pandas import DataFrame from freqtrade.configuration import TimeRange from freqtrade.enums import RunMode +from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.strategy.interface import IStrategy @@ -65,11 +66,14 @@ class IFreqaiModel(ABC): self.training_on_separate_thread = False self.retrain = False self.first = True - if self.freqai_info.get('live_trained_timerange'): - self.new_trained_timerange = TimeRange.parse_timerange( - self.freqai_info['live_trained_timerange']) - else: - self.new_trained_timerange = TimeRange() + # if self.freqai_info.get('live_trained_timerange'): + # self.new_trained_timerange = TimeRange.parse_timerange( + # self.freqai_info['live_trained_timerange']) + # else: + # self.new_trained_timerange = TimeRange() + + self.set_full_path() + self.data_drawer = FreqaiDataDrawer(Path(self.full_path)) def assert_config(self, config: Dict[str, Any]) -> None: @@ -86,7 +90,7 @@ class IFreqaiModel(ABC): def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ - Entry point to the FreqaiModel, it will train a new model if + Entry point to the FreqaiModel from a specific pair, it will train a new model if necessary before making the prediction. The backtesting and training paradigm is a sliding training window with a following backtest window. Both windows slide according to the @@ -103,8 +107,8 @@ class IFreqaiModel(ABC): self.live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) - self.pair = metadata["pair"] - self.dh = FreqaiDataKitchen(self.config, dataframe, self.live) + # FreqaiDataKitchen is reinstantiated for each coin + self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) if self.live: # logger.info('testing live') @@ -113,7 +117,7 @@ class IFreqaiModel(ABC): return (self.dh.full_predictions, self.dh.full_do_predict, self.dh.full_target_mean, self.dh.full_target_std) - logger.info("going to train %s timeranges", len(self.dh.training_timeranges)) + logger.info(f'Training {len(self.dh.training_timeranges)} timeranges') # Loop enforcing the sliding window training/backtesting paradigm # tr_train is the training time range e.g. 1 historical month @@ -129,9 +133,12 @@ class IFreqaiModel(ABC): self.training_timerange = tr_train dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) - logger.info("training %s for %s", self.pair, tr_train) - self.dh.model_path = Path(self.dh.full_path / str("sub-train" + "-" + str(tr_train))) - if not self.model_exists(self.pair, training_timerange=tr_train): + logger.info("training %s for %s", metadata["pair"], tr_train) + trained_timestamp = TimeRange.parse_timerange(tr_train) + self.dh.data_path = Path(self.dh.full_path / + str("sub-train" + "-" + metadata['pair'].split("/")[0] + + str(int(trained_timestamp.stopts)))) + if not self.model_exists(metadata["pair"], trained_timestamp=trained_timestamp.stopts): self.model = self.train(dataframe_train, metadata) self.dh.save_data(self.model) else: @@ -161,36 +168,40 @@ class IFreqaiModel(ABC): """ - self.dh.set_paths() + (model_filename, + trained_timestamp, + coin_first) = self.data_drawer.get_pair_dict_info(metadata) - file_exists = self.model_exists(metadata['pair'], - training_timerange=self.freqai_info[ - 'live_trained_timerange']) + if trained_timestamp != 0: + self.dh.set_paths(trained_timestamp) + # data_drawer thinks the file eixts, verify here + file_exists = self.model_exists(metadata['pair'], + trained_timestamp=trained_timestamp, + model_filename=model_filename) if not self.training_on_separate_thread: # this will also prevent other pairs from trying to train simultaneously. (self.retrain, - self.new_trained_timerange) = self.dh.check_if_new_training_required( - self.new_trained_timerange, - metadata) + new_trained_timerange) = self.dh.check_if_new_training_required( + trained_timestamp) + self.dh.set_paths(new_trained_timerange.stopts) else: logger.info("FreqAI training a new model on background thread.") self.retrain = False if self.retrain or not file_exists: - if self.first: - self.train_model_in_series(self.new_trained_timerange, metadata, strategy) - self.first = False + if coin_first: + self.train_model_in_series(new_trained_timerange, metadata, strategy) else: self.training_on_separate_thread = True # acts like a lock - self.retrain_model_on_separate_thread(self.new_trained_timerange, + self.retrain_model_on_separate_thread(new_trained_timerange, metadata, strategy) - self.model = self.dh.load_data() + self.model = self.dh.load_data(coin=metadata['pair']) strategy_provided_features = self.dh.find_features(dataframe) if strategy_provided_features != self.dh.training_features_list: - self.train_model_in_series(self.new_trained_timerange, metadata, strategy) + self.train_model_in_series(new_trained_timerange, metadata, strategy) preds, do_preds = self.predict(dataframe, metadata) self.dh.append_predictions(preds, do_preds, len(dataframe)) @@ -252,24 +263,34 @@ class IFreqaiModel(ABC): if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): self.dh.check_if_pred_in_training_spaces() # sets do_predict - def model_exists(self, pair: str, training_timerange: str) -> bool: + def model_exists(self, pair: str, trained_timestamp: int = None, + model_filename: str = '') -> bool: """ Given a pair and path, check if a model already exists :param pair: pair e.g. BTC/USD :param path: path to model """ - if self.live and training_timerange == "": - return False coin, _ = pair.split("/") - self.dh.model_filename = "cb_" + coin.lower() + "_" + training_timerange - path_to_modelfile = Path(self.dh.model_path / str(self.dh.model_filename + "_model.joblib")) + + if self.live and trained_timestamp is None: + self.dh.model_filename = model_filename + else: + self.dh.model_filename = "cb_" + coin.lower() + "_" + str(trained_timestamp) + + path_to_modelfile = Path(self.dh.data_path / str(self.dh.model_filename + "_model.joblib")) file_exists = path_to_modelfile.is_file() if file_exists: - logger.info("Found model at %s", self.dh.model_path / self.dh.model_filename) + logger.info("Found model at %s", self.dh.data_path / self.dh.model_filename) else: - logger.info("Could not find model at %s", self.dh.model_path / self.dh.model_filename) + logger.info("Could not find model at %s", self.dh.data_path / self.dh.model_filename) return file_exists + def set_full_path(self) -> None: + self.full_path = Path(self.config['user_data_dir'] / + "models" / + str(self.freqai_info.get('live_full_backtestrange') + + self.freqai_info.get('identifier'))) + @threaded def retrain_model_on_separate_thread(self, new_trained_timerange: TimeRange, metadata: dict, strategy: IStrategy): @@ -285,7 +306,13 @@ class IFreqaiModel(ABC): metadata) self.model = self.train(unfiltered_dataframe, metadata) - self.dh.save_data(self.model) + + self.data_drawer.pair_dict[metadata['pair']][ + 'trained_timestamp'] = new_trained_timerange.stopts + + self.dh.set_new_model_names(metadata, new_trained_timerange) + + self.dh.save_data(self.model, coin=metadata['pair']) self.training_on_separate_thread = False self.retrain = False @@ -303,7 +330,14 @@ class IFreqaiModel(ABC): metadata) self.model = self.train(unfiltered_dataframe, metadata) - self.dh.save_data(self.model) + + self.data_drawer.pair_dict[metadata['pair']][ + 'trained_timestamp'] = new_trained_timerange.stopts + + self.dh.set_new_model_names(metadata, new_trained_timerange) + + self.data_drawer.pair_dict[metadata['pair']]['first'] = False + self.dh.save_data(self.model, coin=metadata['pair']) self.retrain = False # Methods which are overridden by user made prediction models. diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index d09554e3e..6349174ad 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -140,49 +140,3 @@ class CatboostPredictionModel(IFreqaiModel): # logger.info("--------------------Finished prediction--------------------") return (self.dh.predictions, self.dh.do_predict) - - def data_cleaning_train(self) -> None: - """ - User can add data analysis and cleaning here. - Any function inside this method should drop training data points from the filtered_dataframe - based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example - of how outlier data points are dropped from the dataframe used for training. - """ - if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): - self.dh.principal_component_analysis() - - # if self.feature_parameters["determine_statistical_distributions"]: - # self.dh.determine_statistical_distributions() - # if self.feature_parameters["remove_outliers"]: - # self.dh.remove_outliers(predict=False) - - if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): - self.dh.use_SVM_to_remove_outliers(predict=False) - - if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): - self.dh.data["avg_mean_dist"] = self.dh.compute_distances() - - def data_cleaning_predict(self, filtered_dataframe: DataFrame) -> None: - """ - User can add data analysis and cleaning here. - These functions each modify self.dh.do_predict, which is a dataframe with equal length - to the number of candles coming from and returning to the strategy. Inside do_predict, - 1 allows prediction and < 0 signals to the strategy that the model is not confident in - the prediction. - See FreqaiDataKitchen::remove_outliers() for an example - of how the do_predict vector is modified. do_predict is ultimately passed back to strategy - for buy signals. - """ - if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): - self.dh.pca_transform() - - # if self.feature_parameters["determine_statistical_distributions"]: - # self.dh.determine_statistical_distributions() - # if self.feature_parameters["remove_outliers"]: - # self.dh.remove_outliers(predict=True) # creates dropped index - - if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): - self.dh.use_SVM_to_remove_outliers(predict=True) - - if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): - self.dh.check_if_pred_in_training_spaces() # sets do_predict From 059c28542548374ed4e2402f0f9e5c945a8295e8 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 24 May 2022 12:01:01 +0200 Subject: [PATCH 044/308] paying closer attention to managing live retraining on separate thread without affecting prediction of other coins on master thread --- freqtrade/freqai/data_drawer.py | 1 + freqtrade/freqai/data_kitchen.py | 7 +- freqtrade/freqai/freqai_interface.py | 198 ++++++++++-------- .../CatboostPredictionModel.py | 51 ++--- 4 files changed, 139 insertions(+), 118 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index a27a4b67f..51f56fae6 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -24,6 +24,7 @@ class FreqaiDataDrawer: self.pair_dict: Dict[str, Any] = {} # dictionary holding all actively inferenced models in memory given a model filename self.model_dictionary: Dict[str, Any] = {} + self.pair_data_dict: Dict[str, Any] = {} self.full_path = full_path self.load_drawer_from_disk() diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index f5ddf8462..a4867d7eb 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -91,14 +91,15 @@ class FreqaiDataKitchen: assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai feature_parameters" "found in config file.") - def set_paths(self, trained_timestamp: int = None) -> None: + def set_paths(self, metadata: dict, trained_timestamp: int = None,) -> None: self.full_path = Path(self.config['user_data_dir'] / "models" / str(self.freqai_config.get('live_full_backtestrange') + self.freqai_config.get('identifier'))) - self.data_path = Path(self.full_path / str("sub-train" + "-" + self.pair.split("/")[0] + - str(trained_timestamp))) + self.data_path = Path(self.full_path / str("sub-train" + "-" + + metadata['pair'].split("/")[0] + + str(trained_timestamp))) return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 0b1fb3b86..19b7dbb27 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -108,14 +108,22 @@ class IFreqaiModel(ABC): self.live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) # FreqaiDataKitchen is reinstantiated for each coin - self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) - if self.live: - # logger.info('testing live') - self.start_live(dataframe, metadata, strategy) + if not self.training_on_separate_thread: + self.dh = FreqaiDataKitchen(self.config, self.data_drawer, + self.live, metadata["pair"]) + dh = self.start_live(dataframe, metadata, strategy, self.dh) + else: + # we will have at max 2 separate instances of the kitchen at once. + self.dh_fg = FreqaiDataKitchen(self.config, self.data_drawer, + self.live, metadata["pair"]) + dh = self.start_live(dataframe, metadata, strategy, self.dh_fg) - return (self.dh.full_predictions, self.dh.full_do_predict, - self.dh.full_target_mean, self.dh.full_target_std) + return (dh.full_predictions, dh.full_do_predict, + dh.full_target_mean, dh.full_target_std) + + # Backtesting only + self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) logger.info(f'Training {len(self.dh.training_timeranges)} timeranges') @@ -138,8 +146,9 @@ class IFreqaiModel(ABC): self.dh.data_path = Path(self.dh.full_path / str("sub-train" + "-" + metadata['pair'].split("/")[0] + str(int(trained_timestamp.stopts)))) - if not self.model_exists(metadata["pair"], trained_timestamp=trained_timestamp.stopts): - self.model = self.train(dataframe_train, metadata) + if not self.model_exists(metadata["pair"], self.dh, + trained_timestamp=trained_timestamp.stopts): + self.model = self.train(dataframe_train, metadata, self.dh) self.dh.save_data(self.model) else: self.model = self.dh.load_data() @@ -150,7 +159,7 @@ class IFreqaiModel(ABC): # self.model = self.train(dataframe_train, metadata) # self.dh.save_data(self.model) - preds, do_preds = self.predict(dataframe_backtest, metadata) + preds, do_preds = self.predict(dataframe_backtest, self.dh) self.dh.append_predictions(preds, do_preds, len(dataframe_backtest)) print('predictions', len(self.dh.full_predictions), @@ -161,7 +170,8 @@ class IFreqaiModel(ABC): return (self.dh.full_predictions, self.dh.full_do_predict, self.dh.full_target_mean, self.dh.full_target_std) - def start_live(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> None: + def start_live(self, dataframe: DataFrame, metadata: dict, + strategy: IStrategy, dh: FreqaiDataKitchen) -> FreqaiDataKitchen: """ The main broad execution for dry/live. This function will check if a retraining should be performed, and if so, retrain and reset the model. @@ -172,52 +182,49 @@ class IFreqaiModel(ABC): trained_timestamp, coin_first) = self.data_drawer.get_pair_dict_info(metadata) - if trained_timestamp != 0: - self.dh.set_paths(trained_timestamp) - # data_drawer thinks the file eixts, verify here - file_exists = self.model_exists(metadata['pair'], - trained_timestamp=trained_timestamp, - model_filename=model_filename) - if not self.training_on_separate_thread: + file_exists = False + + if trained_timestamp != 0: + dh.set_paths(metadata, trained_timestamp) + # data_drawer thinks the file eixts, verify here + file_exists = self.model_exists(metadata['pair'], + dh, + trained_timestamp=trained_timestamp, + model_filename=model_filename) + + # if not self.training_on_separate_thread: # this will also prevent other pairs from trying to train simultaneously. (self.retrain, - new_trained_timerange) = self.dh.check_if_new_training_required( - trained_timestamp) - self.dh.set_paths(new_trained_timerange.stopts) + new_trained_timerange) = dh.check_if_new_training_required(trained_timestamp) + dh.set_paths(metadata, new_trained_timerange.stopts) + # if self.training_on_separate_thread: + # logger.info("FreqAI training a new model on background thread.") + # self.retrain = False + + if self.retrain or not file_exists: + if coin_first: + self.train_model_in_series(new_trained_timerange, metadata, strategy, dh) + else: + self.training_on_separate_thread = True # acts like a lock + self.retrain_model_on_separate_thread(new_trained_timerange, + metadata, strategy, dh) + else: logger.info("FreqAI training a new model on background thread.") - self.retrain = False - if self.retrain or not file_exists: - if coin_first: - self.train_model_in_series(new_trained_timerange, metadata, strategy) - else: - self.training_on_separate_thread = True # acts like a lock - self.retrain_model_on_separate_thread(new_trained_timerange, - metadata, strategy) + self.model = dh.load_data(coin=metadata['pair']) - self.model = self.dh.load_data(coin=metadata['pair']) + # strategy_provided_features = dh.find_features(dataframe) + # if strategy_provided_features != dh.training_features_list: + # self.train_model_in_series(new_trained_timerange, metadata, strategy) - strategy_provided_features = self.dh.find_features(dataframe) - if strategy_provided_features != self.dh.training_features_list: - self.train_model_in_series(new_trained_timerange, metadata, strategy) + preds, do_preds = self.predict(dataframe, dh) + dh.append_predictions(preds, do_preds, len(dataframe)) - preds, do_preds = self.predict(dataframe, metadata) - self.dh.append_predictions(preds, do_preds, len(dataframe)) + return dh - return - - def make_labels(self, dataframe: DataFrame) -> DataFrame: - """ - User defines the labels here (target values). - :params: - :dataframe: the full dataframe for the present training period - """ - - return - - def data_cleaning_train(self) -> None: + def data_cleaning_train(self, dh: FreqaiDataKitchen) -> None: """ Base data cleaning method for train Any function inside this method should drop training data points from the filtered_dataframe @@ -225,23 +232,23 @@ class IFreqaiModel(ABC): of how outlier data points are dropped from the dataframe used for training. """ if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): - self.dh.principal_component_analysis() + dh.principal_component_analysis() # if self.feature_parameters["determine_statistical_distributions"]: - # self.dh.determine_statistical_distributions() + # dh.determine_statistical_distributions() # if self.feature_parameters["remove_outliers"]: - # self.dh.remove_outliers(predict=False) + # dh.remove_outliers(predict=False) if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): - self.dh.use_SVM_to_remove_outliers(predict=False) + dh.use_SVM_to_remove_outliers(predict=False) if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): - self.dh.data["avg_mean_dist"] = self.dh.compute_distances() + dh.data["avg_mean_dist"] = dh.compute_distances() - def data_cleaning_predict(self, filtered_dataframe: DataFrame) -> None: + def data_cleaning_predict(self, dh: FreqaiDataKitchen) -> None: """ Base data cleaning method for predict. - These functions each modify self.dh.do_predict, which is a dataframe with equal length + These functions each modify dh.do_predict, which is a dataframe with equal length to the number of candles coming from and returning to the strategy. Inside do_predict, 1 allows prediction and < 0 signals to the strategy that the model is not confident in the prediction. @@ -250,20 +257,20 @@ class IFreqaiModel(ABC): for buy signals. """ if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): - self.dh.pca_transform() + dh.pca_transform() # if self.feature_parameters["determine_statistical_distributions"]: - # self.dh.determine_statistical_distributions() + # dh.determine_statistical_distributions() # if self.feature_parameters["remove_outliers"]: - # self.dh.remove_outliers(predict=True) # creates dropped index + # dh.remove_outliers(predict=True) # creates dropped index if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): - self.dh.use_SVM_to_remove_outliers(predict=True) + dh.use_SVM_to_remove_outliers(predict=True) if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): - self.dh.check_if_pred_in_training_spaces() # sets do_predict + dh.check_if_pred_in_training_spaces() # sets do_predict - def model_exists(self, pair: str, trained_timestamp: int = None, + def model_exists(self, pair: str, dh: FreqaiDataKitchen, trained_timestamp: int = None, model_filename: str = '') -> bool: """ Given a pair and path, check if a model already exists @@ -272,17 +279,17 @@ class IFreqaiModel(ABC): """ coin, _ = pair.split("/") - if self.live and trained_timestamp is None: - self.dh.model_filename = model_filename - else: - self.dh.model_filename = "cb_" + coin.lower() + "_" + str(trained_timestamp) + # if self.live and trained_timestamp == 0: + # dh.model_filename = model_filename + if not self.live: + dh.model_filename = model_filename = "cb_" + coin.lower() + "_" + str(trained_timestamp) - path_to_modelfile = Path(self.dh.data_path / str(self.dh.model_filename + "_model.joblib")) + path_to_modelfile = Path(dh.data_path / str(model_filename + "_model.joblib")) file_exists = path_to_modelfile.is_file() if file_exists: - logger.info("Found model at %s", self.dh.data_path / self.dh.model_filename) + logger.info("Found model at %s", dh.data_path / dh.model_filename) else: - logger.info("Could not find model at %s", self.dh.data_path / self.dh.model_filename) + logger.info("Could not find model at %s", dh.data_path / dh.model_filename) return file_exists def set_full_path(self) -> None: @@ -293,58 +300,58 @@ class IFreqaiModel(ABC): @threaded def retrain_model_on_separate_thread(self, new_trained_timerange: TimeRange, metadata: dict, - strategy: IStrategy): + strategy: IStrategy, dh: FreqaiDataKitchen): # with nostdout(): - self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) - corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, - metadata) + dh.download_new_data_for_retraining(new_trained_timerange, metadata) + corr_dataframes, base_dataframes = dh.load_pairs_histories(new_trained_timerange, + metadata) - unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, - corr_dataframes, - base_dataframes, - metadata) + unfiltered_dataframe = dh.use_strategy_to_populate_indicators(strategy, + corr_dataframes, + base_dataframes, + metadata) - self.model = self.train(unfiltered_dataframe, metadata) + self.model = self.train(unfiltered_dataframe, metadata, dh) self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts - self.dh.set_new_model_names(metadata, new_trained_timerange) + dh.set_new_model_names(metadata, new_trained_timerange) - self.dh.save_data(self.model, coin=metadata['pair']) + dh.save_data(self.model, coin=metadata['pair']) self.training_on_separate_thread = False self.retrain = False def train_model_in_series(self, new_trained_timerange: TimeRange, metadata: dict, - strategy: IStrategy): + strategy: IStrategy, dh: FreqaiDataKitchen): - self.dh.download_new_data_for_retraining(new_trained_timerange, metadata) - corr_dataframes, base_dataframes = self.dh.load_pairs_histories(new_trained_timerange, - metadata) + dh.download_new_data_for_retraining(new_trained_timerange, metadata) + corr_dataframes, base_dataframes = dh.load_pairs_histories(new_trained_timerange, + metadata) - unfiltered_dataframe = self.dh.use_strategy_to_populate_indicators(strategy, - corr_dataframes, - base_dataframes, - metadata) + unfiltered_dataframe = dh.use_strategy_to_populate_indicators(strategy, + corr_dataframes, + base_dataframes, + metadata) - self.model = self.train(unfiltered_dataframe, metadata) + self.model = self.train(unfiltered_dataframe, metadata, dh) self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts - self.dh.set_new_model_names(metadata, new_trained_timerange) + dh.set_new_model_names(metadata, new_trained_timerange) self.data_drawer.pair_dict[metadata['pair']]['first'] = False - self.dh.save_data(self.model, coin=metadata['pair']) + dh.save_data(self.model, coin=metadata['pair']) self.retrain = False # Methods which are overridden by user made prediction models. # See freqai/prediction_models/CatboostPredictionModlel.py for an example. @abstractmethod - def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Any: + def train(self, unfiltered_dataframe: DataFrame, metadata: dict, dh: FreqaiDataKitchen) -> Any: """ Filter the training data and train a model to it. Train makes heavy use of the datahandler for storing, saving, loading, and analyzing the data. @@ -369,7 +376,8 @@ class IFreqaiModel(ABC): return @abstractmethod - def predict(self, dataframe: DataFrame, metadata: dict) -> Tuple[npt.ArrayLike, npt.ArrayLike]: + def predict(self, dataframe: DataFrame, + dh: FreqaiDataKitchen) -> Tuple[npt.ArrayLike, npt.ArrayLike]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. @@ -378,3 +386,13 @@ class IFreqaiModel(ABC): :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove data (NaNs) or felt uncertain about data (PCA and DI index) """ + + @abstractmethod + def make_labels(self, dataframe: DataFrame, dh: FreqaiDataKitchen) -> DataFrame: + """ + User defines the labels here (target values). + :params: + :dataframe: the full dataframe for the present training period + """ + + return diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 6349174ad..87ddfdb66 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -4,6 +4,7 @@ from typing import Any, Dict, Tuple from catboost import CatBoostRegressor, Pool from pandas import DataFrame +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.freqai.freqai_interface import IFreqaiModel @@ -17,7 +18,7 @@ class CatboostPredictionModel(IFreqaiModel): has its own DataHandler where data is held, saved, loaded, and managed. """ - def make_labels(self, dataframe: DataFrame) -> DataFrame: + def make_labels(self, dataframe: DataFrame, dh: FreqaiDataKitchen) -> DataFrame: """ User defines the labels here (target values). :params: @@ -32,14 +33,15 @@ class CatboostPredictionModel(IFreqaiModel): / dataframe["close"] - 1 ) - self.dh.data["s_mean"] = dataframe["s"].mean() - self.dh.data["s_std"] = dataframe["s"].std() + dh.data["s_mean"] = dataframe["s"].mean() + dh.data["s_std"] = dataframe["s"].std() - # logger.info("label mean", self.dh.data["s_mean"], "label std", self.dh.data["s_std"]) + # logger.info("label mean", dh.data["s_mean"], "label std", dh.data["s_std"]) return dataframe["s"] - def train(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, DataFrame]: + def train(self, unfiltered_dataframe: DataFrame, + metadata: dict, dh: FreqaiDataKitchen) -> Tuple[DataFrame, DataFrame]: """ Filter the training data and train a model to it. Train makes heavy use of the datahkitchen for storing, saving, loading, and analyzing the data. @@ -52,25 +54,25 @@ class CatboostPredictionModel(IFreqaiModel): logger.info("--------------------Starting training--------------------") # create the full feature list based on user config info - self.dh.training_features_list = self.dh.find_features(unfiltered_dataframe) - unfiltered_labels = self.make_labels(unfiltered_dataframe) + dh.training_features_list = dh.find_features(unfiltered_dataframe) + unfiltered_labels = self.make_labels(unfiltered_dataframe, dh) # filter the features requested by user in the configuration file and elegantly handle NaNs - features_filtered, labels_filtered = self.dh.filter_features( + features_filtered, labels_filtered = dh.filter_features( unfiltered_dataframe, - self.dh.training_features_list, + dh.training_features_list, unfiltered_labels, training_filter=True, ) # split data into train/test data. - data_dictionary = self.dh.make_train_test_datasets(features_filtered, labels_filtered) + data_dictionary = dh.make_train_test_datasets(features_filtered, labels_filtered) # standardize all data based on train_dataset only - data_dictionary = self.dh.standardize_data(data_dictionary) + data_dictionary = dh.standardize_data(data_dictionary) # optional additional data cleaning/analysis - self.data_cleaning_train() + self.data_cleaning_train(dh) - logger.info(f'Training model on {len(self.dh.training_features_list)} features') + logger.info(f'Training model on {len(dh.training_features_list)} features') logger.info(f'Training model on {len(data_dictionary["train_features"])} data points') model = self.fit(data_dictionary) @@ -107,8 +109,8 @@ class CatboostPredictionModel(IFreqaiModel): return model - def predict(self, unfiltered_dataframe: DataFrame, metadata: dict) -> Tuple[DataFrame, - DataFrame]: + def predict(self, unfiltered_dataframe: DataFrame, + dh: FreqaiDataKitchen) -> Tuple[DataFrame, DataFrame]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. @@ -120,23 +122,22 @@ class CatboostPredictionModel(IFreqaiModel): # logger.info("--------------------Starting prediction--------------------") - original_feature_list = self.dh.find_features(unfiltered_dataframe) - filtered_dataframe, _ = self.dh.filter_features( + original_feature_list = dh.find_features(unfiltered_dataframe) + filtered_dataframe, _ = dh.filter_features( unfiltered_dataframe, original_feature_list, training_filter=False ) - filtered_dataframe = self.dh.standardize_data_from_metadata(filtered_dataframe) - self.dh.data_dictionary["prediction_features"] = filtered_dataframe + filtered_dataframe = dh.standardize_data_from_metadata(filtered_dataframe) + dh.data_dictionary["prediction_features"] = filtered_dataframe # optional additional data cleaning/analysis - self.data_cleaning_predict(filtered_dataframe) + self.data_cleaning_predict(dh) - predictions = self.model.predict(self.dh.data_dictionary["prediction_features"]) + predictions = self.model.predict(dh.data_dictionary["prediction_features"]) # compute the non-standardized predictions - self.dh.predictions = (predictions + 1) * (self.dh.data["labels_max"] - - self.dh.data["labels_min"]) / 2 + self.dh.data[ - "labels_min"] + dh.predictions = (predictions + 1) * (dh.data["labels_max"] - + dh.data["labels_min"]) / 2 + dh.data["labels_min"] # logger.info("--------------------Finished prediction--------------------") - return (self.dh.predictions, self.dh.do_predict) + return (dh.predictions, dh.do_predict) From 255d35976e2737573fc09aabee65a5e776f18f09 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 24 May 2022 12:58:53 +0200 Subject: [PATCH 045/308] add priority metadata to pairs to avoid a sync of train time + train period --- freqtrade/freqai/data_drawer.py | 13 +++++++++++++ freqtrade/freqai/freqai_interface.py | 10 +++++++++- .../prediction_models/CatboostPredictionModel.py | 4 +++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 51f56fae6..a47ff6ec2 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -56,5 +56,18 @@ class FreqaiDataDrawer: model_filename = self.pair_dict[metadata['pair']]['model_filename'] = '' coin_first = self.pair_dict[metadata['pair']]['first'] = True trained_timestamp = self.pair_dict[metadata['pair']]['trained_timestamp'] = 0 + self.pair_dict[metadata['pair']]['priority'] = 1 return model_filename, trained_timestamp, coin_first + + def set_pair_dict_info(self, metadata: dict) -> None: + pair_in_dict = self.pair_dict.get(metadata['pair']) + if pair_in_dict: + return + else: + self.pair_dict[metadata['pair']] = {} + self.pair_dict[metadata['pair']]['model_filename'] = '' + self.pair_dict[metadata['pair']]['first'] = True + self.pair_dict[metadata['pair']]['trained_timestamp'] = 0 + self.pair_dict[metadata['pair']]['priority'] = 1 + return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 19b7dbb27..3fdd379dc 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -109,7 +109,10 @@ class IFreqaiModel(ABC): # FreqaiDataKitchen is reinstantiated for each coin if self.live: - if not self.training_on_separate_thread: + self.data_drawer.set_pair_dict_info(metadata) + if (not self.training_on_separate_thread and + self.data_drawer.pair_dict[metadata['pair']]['priority'] == 1): + self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) dh = self.start_live(dataframe, metadata, strategy, self.dh) @@ -212,6 +215,7 @@ class IFreqaiModel(ABC): else: logger.info("FreqAI training a new model on background thread.") + self.data_drawer.pair_dict[metadata['pair']]['priority'] = 1 self.model = dh.load_data(coin=metadata['pair']) @@ -319,6 +323,9 @@ class IFreqaiModel(ABC): dh.set_new_model_names(metadata, new_trained_timerange) + # set this coin to lower priority to allow other coins in white list to get trained + self.data_drawer.pair_dict[metadata['pair']]['priority'] = 0 + dh.save_data(self.model, coin=metadata['pair']) self.training_on_separate_thread = False @@ -344,6 +351,7 @@ class IFreqaiModel(ABC): dh.set_new_model_names(metadata, new_trained_timerange) self.data_drawer.pair_dict[metadata['pair']]['first'] = False + dh.save_data(self.model, coin=metadata['pair']) self.retrain = False diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 87ddfdb66..73ea46032 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -51,7 +51,9 @@ class CatboostPredictionModel(IFreqaiModel): :returns: :model: Trained model which can be used to inference (self.predict) """ - logger.info("--------------------Starting training--------------------") + + logger.info('--------------------Starting training' + f'{metadata["pair"]} --------------------') # create the full feature list based on user config info dh.training_features_list = dh.find_features(unfiltered_dataframe) From 31ae2b30606f3c52fb7ee1e3d170e59a8bc06b31 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 24 May 2022 14:46:16 +0200 Subject: [PATCH 046/308] alleviate FutureWarning in sklearn about ensuring svm model features are passed with identical order --- docs/freqai.md | 41 ++++++++++++++++++-- freqtrade/freqai/data_kitchen.py | 8 +++- freqtrade/strategy/interface.py | 2 +- freqtrade/templates/FreqaiExampleStrategy.py | 21 +++++++--- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 606b88912..27d393d0a 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -105,11 +105,11 @@ config setup includes: ### Building the feature set -Most of these parameters are controlling the feature data set. Features are added by the user -inside the `populate_any_indicators()` method of the strategy by prepending indicators with `%`: +Features are added by the user inside the `populate_any_indicators()` method of the strategy +by prepending indicators with `%`: ```python - def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): + def populate_any_indicators(self, metadata, pair, df, tf, informative=None, coin=""): informative['%-''%-' + coin + "rsi"] = ta.RSI(informative, timeperiod=14) informative['%-' + coin + "mfi"] = ta.MFI(informative, timeperiod=25) informative['%-' + coin + "adx"] = ta.ADX(informative, window=20) @@ -120,11 +120,46 @@ inside the `populate_any_indicators()` method of the strategy by prepending indi informative['%-' + coin + "bb_width"] = ( informative[coin + "bb_upperband"] - informative[coin + "bb_lowerband"] ) / informative[coin + "bb_middleband"] + + + + # The following code automatically adds features according to the `shift` parameter passed + # in the config. Do not remove + indicators = [col for col in informative if col.startswith('%')] + for n in range(self.freqai_info["feature_parameters"]["shift"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) + + # The following code safely merges into the base timeframe. + # Do not remove. + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [(s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"]] + df = df.drop(columns=skip_columns) ``` The user of the present example does not want to pass the `bb_lowerband` as a feature to the model, and has therefore not prepended it with `%`. The user does, however, wish to pass `bb_width` to the model for training/prediction and has therfore prepended it with `%`._ +Note: features **must** be defined in `populate_any_indicators()`. Making features in `populate_indicators()` +will fail in live/dry. If the user wishes to add generalized features that are not associated with +a specific pair or timeframe, they should use the following structure inside `populate_any_indicators()` +(as exemplified in `freqtrade/templates/FreqaiExampleStrategy.py`: + +```python + def populate_any_indicators(self, metadata, pair, df, tf, informative=None, coin=""): + + + # Add generalized indicators here (because in live, it will call only this function to populate + # indicators for retraining). Notice how we ensure not to add them multiple times by associating + # these generalized indicators to the basepair/timeframe + if pair == metadata['pair'] and tf == self.timeframe: + df['%-day_of_week'] = (df["date"].dt.dayofweek + 1) / 7 + df['%-hour_of_day'] = (df['date'].dt.hour + 1) / 25 + + (Please see the example script located in `freqtrade/templates/FreqaiExampleStrategy.py` for a full example of `populate_any_indicators()`) The `timeframes` from the example config above are the timeframes of each `populate_any_indicator()` diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index a4867d7eb..765c58a37 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -823,7 +823,9 @@ class FreqaiDataKitchen: pairs = self.freqai_config.get("corr_pairlist", []) for tf in self.freqai_config.get("timeframes"): - dataframe = strategy.populate_any_indicators(metadata['pair'], + dataframe = strategy.populate_any_indicators( + metadata, + metadata['pair'], dataframe.copy(), tf, base_dataframes[tf], @@ -833,7 +835,9 @@ class FreqaiDataKitchen: for i in pairs: if metadata['pair'] in i: continue # dont repeat anything from whitelist - dataframe = strategy.populate_any_indicators(i, + dataframe = strategy.populate_any_indicators( + metadata, + i, dataframe.copy(), tf, corr_dataframes[i][tf], diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index e681d70bd..6237e3397 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -532,7 +532,7 @@ class IStrategy(ABC, HyperStrategyMixin): """ return None - def populate_any_indicators(self, pair: str, df: DataFrame, tf: str, + def populate_any_indicators(self, metadata: dict, pair: str, df: DataFrame, tf: str, informative: DataFrame = None, coin: str = "") -> DataFrame: """ Function designed to automatically generate, name and merge features diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 690532c10..d2eb2c306 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -63,7 +63,7 @@ class FreqaiExampleStrategy(IStrategy): def bot_start(self): self.model = CustomModel(self.config) - def populate_any_indicators(self, pair, df, tf, informative=None, coin=""): + def populate_any_indicators(self, metadata, pair, df, tf, informative=None, coin=""): """ Function designed to automatically generate, name and merge features from user indicated timeframes in the configuration file. User controls the indicators @@ -124,8 +124,9 @@ class FreqaiExampleStrategy(IStrategy): informative[coin + "pct-change"] = informative["close"].pct_change() + # The following code automatically adds features according to the `shift` parameter passed + # in the config. Do not remove indicators = [col for col in informative if col.startswith('%')] - for n in range(self.freqai_info["feature_parameters"]["shift"] + 1): if n == 0: continue @@ -133,28 +134,38 @@ class FreqaiExampleStrategy(IStrategy): informative_shift = informative_shift.add_suffix("_shift-" + str(n)) informative = pd.concat((informative, informative_shift), axis=1) + # The following code safely merges into the base timeframe. + # Do not remove. df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) skip_columns = [(s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"]] df = df.drop(columns=skip_columns) + # Add generalized indicators (not associated to any individual coin or timeframe) here + # because in live, it will call this function to populate + # indicators during training. Notice how we ensure not to add them multiple times + if pair == metadata['pair'] and tf == self.timeframe: + df['%-day_of_week'] = (df["date"].dt.dayofweek + 1) / 7 + df['%-hour_of_day'] = (df['date'].dt.hour + 1) / 25 + return df def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # the configuration file parameters are stored here self.freqai_info = self.config["freqai"] self.pair = metadata['pair'] # the following loops are necessary for building the features # indicated by the user in the configuration file. + # All indicators must be populated by populate_any_indicators() for live functionality + # to work correctly. for tf in self.freqai_info["timeframes"]: - dataframe = self.populate_any_indicators(self.pair, dataframe.copy(), tf, + dataframe = self.populate_any_indicators(metadata, self.pair, dataframe.copy(), tf, coin=self.pair.split("/")[0] + "-") for pair in self.freqai_info["corr_pairlist"]: if metadata['pair'] in pair: continue # do not include whitelisted pair twice if it is in corr_pairlist dataframe = self.populate_any_indicators( - pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" + metadata, pair, dataframe.copy(), tf, coin=pair.split("/")[0] + "-" ) # the model will return 4 values, its prediction, an indication of whether or not the From 58b5abbaa6a3f937dc7c7cf13ebba248a2430219 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 24 May 2022 15:28:38 +0200 Subject: [PATCH 047/308] improve multithreaded training queue system --- freqtrade/freqai/data_drawer.py | 16 +++++++++++++++- freqtrade/freqai/freqai_interface.py | 11 +++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index a47ff6ec2..a5d8a2123 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -18,7 +18,7 @@ class FreqaiDataDrawer: This object remains persistent throughout live/dry, unlike FreqaiDataKitchen, which is reinstantiated for each coin. """ - def __init__(self, full_path: Path): + def __init__(self, full_path: Path, pair_whitelist): # dictionary holding all pair metadata necessary to load in from disk self.pair_dict: Dict[str, Any] = {} @@ -27,6 +27,8 @@ class FreqaiDataDrawer: self.pair_data_dict: Dict[str, Any] = {} self.full_path = full_path self.load_drawer_from_disk() + self.training_queue: Dict[str, int] = {} + self.create_training_queue(pair_whitelist) def load_drawer_from_disk(self): exists = Path(self.full_path / str('pair_dictionary.json')).resolve().exists() @@ -71,3 +73,15 @@ class FreqaiDataDrawer: self.pair_dict[metadata['pair']]['trained_timestamp'] = 0 self.pair_dict[metadata['pair']]['priority'] = 1 return + + def create_training_queue(self, pairs: list) -> None: + for i, pair in enumerate(pairs): + self.training_queue[pair] = i + 1 + + def pair_to_end_of_training_queue(self, pair: str) -> None: + # march all pairs up in the queue + for p in self.training_queue: + self.training_queue[p] -= 1 + + # send pair to end of queue + self.training_queue[pair] = len(self.training_queue) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 3fdd379dc..55733b844 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -73,7 +73,8 @@ class IFreqaiModel(ABC): # self.new_trained_timerange = TimeRange() self.set_full_path() - self.data_drawer = FreqaiDataDrawer(Path(self.full_path)) + self.data_drawer = FreqaiDataDrawer(Path(self.full_path), + self.config['exchange']['pair_whitelist']) def assert_config(self, config: Dict[str, Any]) -> None: @@ -110,8 +111,9 @@ class IFreqaiModel(ABC): # FreqaiDataKitchen is reinstantiated for each coin if self.live: self.data_drawer.set_pair_dict_info(metadata) + print('Current train queue:', self.data_drawer.training_queue) if (not self.training_on_separate_thread and - self.data_drawer.pair_dict[metadata['pair']]['priority'] == 1): + self.data_drawer.training_queue == 1): self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) @@ -323,8 +325,9 @@ class IFreqaiModel(ABC): dh.set_new_model_names(metadata, new_trained_timerange) - # set this coin to lower priority to allow other coins in white list to get trained - self.data_drawer.pair_dict[metadata['pair']]['priority'] = 0 + # send the pair to the end of the queue so other coins can take on the background thread + # retraining + self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) dh.save_data(self.model, coin=metadata['pair']) From 35bed842cb5ce5ef780544c1a5f6cedb1d6b5532 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 11:31:03 +0200 Subject: [PATCH 048/308] cleanup, add clarity to comments and docstrings --- freqtrade/freqai/freqai_interface.py | 169 +++++++++++++-------------- 1 file changed, 81 insertions(+), 88 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 55733b844..d60f37ffb 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -21,18 +21,6 @@ from freqtrade.strategy.interface import IStrategy pd.options.mode.chained_assignment = None logger = logging.getLogger(__name__) -# FIXME: suppress stdout for background training? -# class DummyFile(object): -# def write(self, x): pass - - -# @contextlib.contextmanager -# def nostdout(): -# save_stdout = sys.stdout -# sys.stdout = DummyFile() -# yield -# sys.stdout = save_stdout - def threaded(fn): def wrapper(*args, **kwargs): @@ -57,8 +45,6 @@ class IFreqaiModel(ABC): self.data_split_parameters = config["freqai"]["data_split_parameters"] self.model_training_parameters = config["freqai"]["model_training_parameters"] self.feature_parameters = config["freqai"]["feature_parameters"] - # self.backtest_timerange = config["timerange"] - self.time_last_trained = None self.current_time = None self.model = None @@ -66,12 +52,6 @@ class IFreqaiModel(ABC): self.training_on_separate_thread = False self.retrain = False self.first = True - # if self.freqai_info.get('live_trained_timerange'): - # self.new_trained_timerange = TimeRange.parse_timerange( - # self.freqai_info['live_trained_timerange']) - # else: - # self.new_trained_timerange = TimeRange() - self.set_full_path() self.data_drawer = FreqaiDataDrawer(Path(self.full_path), self.config['exchange']['pair_whitelist']) @@ -93,12 +73,7 @@ class IFreqaiModel(ABC): """ Entry point to the FreqaiModel from a specific pair, it will train a new model if necessary before making the prediction. - The backtesting and training paradigm is a sliding training window - with a following backtest window. Both windows slide according to the - length of the backtest window. This function is not intended to be - overridden by children of IFreqaiModel, but technically, it can be - if the user wishes to make deeper changes to the sliding window - logic. + :params: :dataframe: Full dataframe coming from strategy - it contains entire backtesting timerange + additional historical data necessary to train @@ -108,10 +83,12 @@ class IFreqaiModel(ABC): self.live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) - # FreqaiDataKitchen is reinstantiated for each coin + # For live, we may be training new models on a separate thread while other pairs still need + # to inference their historical models. Here we use a training queue system to handle this + # and we keep the flag self.training_on_separate_threaad in the current object to help + # determine what the current pair will do if self.live: self.data_drawer.set_pair_dict_info(metadata) - print('Current train queue:', self.data_drawer.training_queue) if (not self.training_on_separate_thread and self.data_drawer.training_queue == 1): @@ -124,13 +101,38 @@ class IFreqaiModel(ABC): self.live, metadata["pair"]) dh = self.start_live(dataframe, metadata, strategy, self.dh_fg) - return (dh.full_predictions, dh.full_do_predict, - dh.full_target_mean, dh.full_target_std) + # return (dh.full_predictions, dh.full_do_predict, + # dh.full_target_mean, dh.full_target_std) - # Backtesting only - self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) + # For backtesting, each pair enters and then gets trained for each window along the + # sliding window defined by "train_period" (training window) and "backtest_period" + # (backtest window, i.e. window immediately following the training window). + # FreqAI slides the window and sequentially builds the backtesting results before returning + # the concatenated results for the full backtesting period back to the strategy. + else: + self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) + logger.info(f'Training {len(self.dh.training_timeranges)} timeranges') + dh = self.start_backtesting(dataframe, metadata, self.dh) - logger.info(f'Training {len(self.dh.training_timeranges)} timeranges') + return (dh.full_predictions, dh.full_do_predict, + dh.full_target_mean, dh.full_target_std) + + def start_backtesting(self, dataframe: DataFrame, metadata: dict, + dh: FreqaiDataKitchen) -> FreqaiDataKitchen: + """ + The main broad execution for backtesting. For backtesting, each pair enters and then gets + trained for each window along the sliding window defined by "train_period" (training window) + and "backtest_period" (backtest window, i.e. window immediately following the + training window). FreqAI slides the window and sequentially builds the backtesting results + before returning the concatenated results for the full backtesting period back to the + strategy. + :params: + dataframe: DataFrame = strategy passed dataframe + metadata: Dict = pair metadata + dh: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + :returns: + dh: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + """ # Loop enforcing the sliding window training/backtesting paradigm # tr_train is the training time range e.g. 1 historical month @@ -138,49 +140,54 @@ class IFreqaiModel(ABC): # following tr_train. Both of these windows slide through the # entire backtest for tr_train, tr_backtest in zip( - self.dh.training_timeranges, self.dh.backtesting_timeranges + dh.training_timeranges, dh.backtesting_timeranges ): gc.collect() - # self.config['timerange'] = tr_train - self.dh.data = {} # clean the pair specific data between models + dh.data = {} # clean the pair specific data between training window sliding self.training_timerange = tr_train - dataframe_train = self.dh.slice_dataframe(tr_train, dataframe) - dataframe_backtest = self.dh.slice_dataframe(tr_backtest, dataframe) + dataframe_train = dh.slice_dataframe(tr_train, dataframe) + dataframe_backtest = dh.slice_dataframe(tr_backtest, dataframe) logger.info("training %s for %s", metadata["pair"], tr_train) trained_timestamp = TimeRange.parse_timerange(tr_train) - self.dh.data_path = Path(self.dh.full_path / - str("sub-train" + "-" + metadata['pair'].split("/")[0] + - str(int(trained_timestamp.stopts)))) - if not self.model_exists(metadata["pair"], self.dh, + dh.data_path = Path(dh.full_path / + str("sub-train" + "-" + metadata['pair'].split("/")[0] + + str(int(trained_timestamp.stopts)))) + if not self.model_exists(metadata["pair"], dh, trained_timestamp=trained_timestamp.stopts): - self.model = self.train(dataframe_train, metadata, self.dh) - self.dh.save_data(self.model) + self.model = self.train(dataframe_train, metadata, dh) + dh.save_data(self.model) else: - self.model = self.dh.load_data() + self.model = dh.load_data() + # strategy_provided_features = self.dh.find_features(dataframe_train) - # # TOFIX doesnt work with PCA + # # FIXME doesnt work with PCA # if strategy_provided_features != self.dh.training_features_list: # logger.info("User changed input features, retraining model.") # self.model = self.train(dataframe_train, metadata) # self.dh.save_data(self.model) - preds, do_preds = self.predict(dataframe_backtest, self.dh) + preds, do_preds = self.predict(dataframe_backtest, dh) - self.dh.append_predictions(preds, do_preds, len(dataframe_backtest)) - print('predictions', len(self.dh.full_predictions), - 'do_predict', len(self.dh.full_do_predict)) + dh.append_predictions(preds, do_preds, len(dataframe_backtest)) + print('predictions', len(dh.full_predictions), + 'do_predict', len(dh.full_do_predict)) - self.dh.fill_predictions(len(dataframe)) + dh.fill_predictions(len(dataframe)) - return (self.dh.full_predictions, self.dh.full_do_predict, - self.dh.full_target_mean, self.dh.full_target_std) + return dh def start_live(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy, dh: FreqaiDataKitchen) -> FreqaiDataKitchen: """ The main broad execution for dry/live. This function will check if a retraining should be performed, and if so, retrain and reset the model. - + :params: + dataframe: DataFrame = strategy passed dataframe + metadata: Dict = pair metadata + strategy: IStrategy = currently employed strategy + dh: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + :returns: + dh: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only """ (model_filename, @@ -190,22 +197,16 @@ class IFreqaiModel(ABC): if not self.training_on_separate_thread: file_exists = False - if trained_timestamp != 0: + if trained_timestamp != 0: # historical model available dh.set_paths(metadata, trained_timestamp) - # data_drawer thinks the file eixts, verify here file_exists = self.model_exists(metadata['pair'], dh, trained_timestamp=trained_timestamp, model_filename=model_filename) - # if not self.training_on_separate_thread: - # this will also prevent other pairs from trying to train simultaneously. (self.retrain, new_trained_timerange) = dh.check_if_new_training_required(trained_timestamp) dh.set_paths(metadata, new_trained_timerange.stopts) - # if self.training_on_separate_thread: - # logger.info("FreqAI training a new model on background thread.") - # self.retrain = False if self.retrain or not file_exists: if coin_first: @@ -217,10 +218,10 @@ class IFreqaiModel(ABC): else: logger.info("FreqAI training a new model on background thread.") - self.data_drawer.pair_dict[metadata['pair']]['priority'] = 1 self.model = dh.load_data(coin=metadata['pair']) + # FIXME # strategy_provided_features = dh.find_features(dataframe) # if strategy_provided_features != dh.training_features_list: # self.train_model_in_series(new_trained_timerange, metadata, strategy) @@ -240,17 +241,17 @@ class IFreqaiModel(ABC): if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): dh.principal_component_analysis() - # if self.feature_parameters["determine_statistical_distributions"]: - # dh.determine_statistical_distributions() - # if self.feature_parameters["remove_outliers"]: - # dh.remove_outliers(predict=False) - if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): dh.use_SVM_to_remove_outliers(predict=False) if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): dh.data["avg_mean_dist"] = dh.compute_distances() + # if self.feature_parameters["determine_statistical_distributions"]: + # dh.determine_statistical_distributions() + # if self.feature_parameters["remove_outliers"]: + # dh.remove_outliers(predict=False) + def data_cleaning_predict(self, dh: FreqaiDataKitchen) -> None: """ Base data cleaning method for predict. @@ -265,16 +266,16 @@ class IFreqaiModel(ABC): if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): dh.pca_transform() - # if self.feature_parameters["determine_statistical_distributions"]: - # dh.determine_statistical_distributions() - # if self.feature_parameters["remove_outliers"]: - # dh.remove_outliers(predict=True) # creates dropped index - if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): dh.use_SVM_to_remove_outliers(predict=True) if self.freqai_info.get('feature_parameters', {}).get('DI_threshold'): - dh.check_if_pred_in_training_spaces() # sets do_predict + dh.check_if_pred_in_training_spaces() + + # if self.feature_parameters["determine_statistical_distributions"]: + # dh.determine_statistical_distributions() + # if self.feature_parameters["remove_outliers"]: + # dh.remove_outliers(predict=True) # creates dropped index def model_exists(self, pair: str, dh: FreqaiDataKitchen, trained_timestamp: int = None, model_filename: str = '') -> bool: @@ -285,8 +286,6 @@ class IFreqaiModel(ABC): """ coin, _ = pair.split("/") - # if self.live and trained_timestamp == 0: - # dh.model_filename = model_filename if not self.live: dh.model_filename = model_filename = "cb_" + coin.lower() + "_" + str(trained_timestamp) @@ -312,7 +311,6 @@ class IFreqaiModel(ABC): dh.download_new_data_for_retraining(new_trained_timerange, metadata) corr_dataframes, base_dataframes = dh.load_pairs_histories(new_trained_timerange, metadata) - unfiltered_dataframe = dh.use_strategy_to_populate_indicators(strategy, corr_dataframes, base_dataframes, @@ -322,13 +320,8 @@ class IFreqaiModel(ABC): self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts - dh.set_new_model_names(metadata, new_trained_timerange) - - # send the pair to the end of the queue so other coins can take on the background thread - # retraining self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) - dh.save_data(self.model, coin=metadata['pair']) self.training_on_separate_thread = False @@ -350,11 +343,8 @@ class IFreqaiModel(ABC): self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts - dh.set_new_model_names(metadata, new_trained_timerange) - self.data_drawer.pair_dict[metadata['pair']]['first'] = False - dh.save_data(self.model, coin=metadata['pair']) self.retrain = False @@ -380,7 +370,7 @@ class IFreqaiModel(ABC): can drop in LGBMRegressor in place of CatBoostRegressor and all data management will be properly handled by Freqai. :params: - :data_dictionary: the dictionary constructed by DataHandler to hold + data_dictionary: Dict = the dictionary constructed by DataHandler to hold all the training and test data/labels. """ @@ -391,11 +381,13 @@ class IFreqaiModel(ABC): dh: FreqaiDataKitchen) -> Tuple[npt.ArrayLike, npt.ArrayLike]: """ Filter the prediction features data and predict with it. - :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :param: + unfiltered_dataframe: Full dataframe for the current backtest period. + dh: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only :return: :predictions: np.array of predictions :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove - data (NaNs) or felt uncertain about data (PCA and DI index) + data (NaNs) or felt uncertain about data (i.e. SVM and/or DI index) """ @abstractmethod @@ -403,7 +395,8 @@ class IFreqaiModel(ABC): """ User defines the labels here (target values). :params: - :dataframe: the full dataframe for the present training period + dataframe: DataFrame = the full dataframe for the present training period + dh: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only """ return From 7ff32586075fdb4266ce53027e8f99054385388c Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 11:43:45 +0200 Subject: [PATCH 049/308] remove assertions, log error if user has not assigned freqai in config, fix stratify bug --- config_examples/config_freqai.example.json | 1 - freqtrade/freqai/data_kitchen.py | 39 ++++++++++++---------- freqtrade/freqai/freqai_interface.py | 23 +++++++------ 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index ed3782775..5f7f38373 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -62,7 +62,6 @@ "corr_pairlist": [ "BTC/USDT", "ETH/USDT", - "LINK/USDT", "DOT/USDT" ], "feature_parameters": { diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 765c58a37..b0eb8b40d 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -73,23 +73,26 @@ class FreqaiDataKitchen: self.data_drawer = data_drawer def assert_config(self, config: Dict[str, Any], live: bool) -> None: - assert config.get('freqai'), "No Freqai parameters found in config file." - assert config.get('freqai', {}).get('train_period'), ("No Freqai train_period found in" - "config file.") - assert type(config.get('freqai', {}) - .get('train_period')) is int, ('Can only train on full day period.' - 'No fractional days permitted.') - assert config.get('freqai', {}).get('backtest_period'), ("No Freqai backtest_period found" - "in config file.") - if not live: - assert type(config.get('freqai', {}) - .get('backtest_period')) is int, ('Can only backtest on full day' - 'backtest_period. Only live/dry mode' - 'allows fractions of days') - assert config.get('freqai', {}).get('identifier'), ("No Freqai identifier found in config" - "file.") - assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai feature_parameters" - "found in config file.") + if not config.get('freqai'): + logger.error('No Freqai parameters found in config file.') + + # assert config.get('freqai'), "No Freqai parameters found in config file." + # assert config.get('freqai', {}).get('train_period'), ("No Freqai train_period found in" + # "config file.") + # assert type(config.get('freqai', {}) + # .get('train_period')) is int, ('Can only train on full day period.' + # 'No fractional days permitted.') + # assert config.get('freqai', {}).get('backtest_period'), ("No Freqai backtest_period found" + # "in config file.") + # if not live: + # assert type(config.get('freqai', {}) + # .get('backtest_period')) is int, ('Can only backtest on full day' + # 'backtest_period. Only live/dry mode' + # 'allows fractions of days') + # assert config.get('freqai', {}).get('identifier'), ("No Freqai identifier found in config" + # "file.") + # assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai feature_parameters" + # "found in config file.") def set_paths(self, metadata: dict, trained_timestamp: int = None,) -> None: self.full_path = Path(self.config['user_data_dir'] / @@ -234,6 +237,8 @@ class FreqaiDataKitchen: for i in range(1, len(stratification)): if i % self.freqai_config.get("feature_parameters", {}).get("stratify", 0) == 0: stratification[i] = 1 + else: + stratification = None ( train_features, diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index d60f37ffb..041343683 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -57,17 +57,18 @@ class IFreqaiModel(ABC): self.config['exchange']['pair_whitelist']) def assert_config(self, config: Dict[str, Any]) -> None: - - assert config.get('freqai'), "No Freqai parameters found in config file." - assert config.get('freqai', {}).get('data_split_parameters'), ("No Freqai" - "data_split_parameters" - "in config file.") - assert config.get('freqai', {}).get('model_training_parameters'), ("No Freqai" - "modeltrainingparameters" - "found in config file.") - assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai" - "feature_parameters found in" - "config file.") + if not config.get('freqai'): + logger.error('No Freqai parameters found in config file.') + # assert config.get('freqai'), "No Freqai parameters found in config file." + # assert config.get('freqai', {}).get('data_split_parameters'), ("No Freqai" + # "data_split_parameters" + # "in config file.") + # assert config.get('freqai', {}).get('model_training_parameters'), ("No Freqai" + # "modeltrainingparameters" + # "found in config file.") + # assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai" + # "feature_parameters found in" + # "config file.") def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ From 7486d9d9e2880b27591d3bb94498273019ce3f95 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 12:37:25 +0200 Subject: [PATCH 050/308] proper validation of freqai config parameters --- freqtrade/configuration/config_validation.py | 16 ++++++++++++++ freqtrade/constants.py | 11 ++++++++++ freqtrade/enums/runmode.py | 3 +-- freqtrade/freqai/data_kitchen.py | 23 -------------------- freqtrade/freqai/freqai_interface.py | 18 +++++---------- 5 files changed, 34 insertions(+), 37 deletions(-) diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index ee846e7e6..5f1f68554 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -85,6 +85,7 @@ def validate_config_consistency(conf: Dict[str, Any], preliminary: bool = False) _validate_unlimited_amount(conf) _validate_ask_orderbook(conf) validate_migrated_strategy_settings(conf) + _validate_freqai(conf) # validate configuration before returning logger.info('Validating configuration ...') @@ -163,6 +164,21 @@ def _validate_edge(conf: Dict[str, Any]) -> None: ) +def _validate_freqai(conf: Dict[str, Any]) -> None: + """ + Freqai param validator + """ + + if not conf.get('freqai', {}): + return + + for param in constants.SCHEMA_FREQAI_REQUIRED: + if param not in conf.get('freqai', {}): + raise OperationalException( + f'{param} not found in Freqai config' + ) + + def _validate_whitelist(conf: Dict[str, Any]) -> None: """ Dynamic whitelist does not require pair_whitelist to be set - however StaticWhitelist does. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 05581cc3a..eea657d84 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -515,6 +515,17 @@ SCHEMA_MINIMAL_REQUIRED = [ 'dataformat_trades', ] +SCHEMA_FREQAI_REQUIRED = [ + 'timeframes', + 'train_period', + 'backtest_period', + 'identifier', + 'corr_pairlist', + 'feature_parameters', + 'data_split_parameters', + 'model_training_parameters' +] + CANCEL_REASON = { "TIMEOUT": "cancelled due to timeout", "PARTIALLY_FILLED_KEEP_OPEN": "partially filled - keeping order open", diff --git a/freqtrade/enums/runmode.py b/freqtrade/enums/runmode.py index c280edf7c..6545aaec7 100644 --- a/freqtrade/enums/runmode.py +++ b/freqtrade/enums/runmode.py @@ -15,10 +15,9 @@ class RunMode(Enum): UTIL_NO_EXCHANGE = "util_no_exchange" PLOT = "plot" WEBSERVER = "webserver" - FREQAI = "freqai" OTHER = "other" TRADING_MODES = [RunMode.LIVE, RunMode.DRY_RUN] -OPTIMIZE_MODES = [RunMode.BACKTEST, RunMode.EDGE, RunMode.HYPEROPT, RunMode.FREQAI] +OPTIMIZE_MODES = [RunMode.BACKTEST, RunMode.EDGE, RunMode.HYPEROPT] NON_UTIL_MODES = TRADING_MODES + OPTIMIZE_MODES diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index b0eb8b40d..c5f57bf86 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -44,7 +44,6 @@ class FreqaiDataKitchen: self.data: Dict[Any, Any] = {} self.data_dictionary: Dict[Any, Any] = {} self.config = config - self.assert_config(self.config, live) self.freqai_config = config["freqai"] self.predictions: npt.ArrayLike = np.array([]) self.do_predict: npt.ArrayLike = np.array([]) @@ -72,28 +71,6 @@ class FreqaiDataKitchen: self.data_drawer = data_drawer - def assert_config(self, config: Dict[str, Any], live: bool) -> None: - if not config.get('freqai'): - logger.error('No Freqai parameters found in config file.') - - # assert config.get('freqai'), "No Freqai parameters found in config file." - # assert config.get('freqai', {}).get('train_period'), ("No Freqai train_period found in" - # "config file.") - # assert type(config.get('freqai', {}) - # .get('train_period')) is int, ('Can only train on full day period.' - # 'No fractional days permitted.') - # assert config.get('freqai', {}).get('backtest_period'), ("No Freqai backtest_period found" - # "in config file.") - # if not live: - # assert type(config.get('freqai', {}) - # .get('backtest_period')) is int, ('Can only backtest on full day' - # 'backtest_period. Only live/dry mode' - # 'allows fractions of days') - # assert config.get('freqai', {}).get('identifier'), ("No Freqai identifier found in config" - # "file.") - # assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai feature_parameters" - # "found in config file.") - def set_paths(self, metadata: dict, trained_timestamp: int = None,) -> None: self.full_path = Path(self.config['user_data_dir'] / "models" / diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 041343683..71807ad19 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -13,6 +13,7 @@ from pandas import DataFrame from freqtrade.configuration import TimeRange from freqtrade.enums import RunMode +from freqtrade.exceptions import OperationalException from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.strategy.interface import IStrategy @@ -57,18 +58,11 @@ class IFreqaiModel(ABC): self.config['exchange']['pair_whitelist']) def assert_config(self, config: Dict[str, Any]) -> None: - if not config.get('freqai'): - logger.error('No Freqai parameters found in config file.') - # assert config.get('freqai'), "No Freqai parameters found in config file." - # assert config.get('freqai', {}).get('data_split_parameters'), ("No Freqai" - # "data_split_parameters" - # "in config file.") - # assert config.get('freqai', {}).get('model_training_parameters'), ("No Freqai" - # "modeltrainingparameters" - # "found in config file.") - # assert config.get('freqai', {}).get('feature_parameters'), ("No Freqai" - # "feature_parameters found in" - # "config file.") + + if not config.get('freqai', {}): + raise OperationalException( + "No freqai parameters found in configuration file." + ) def start(self, dataframe: DataFrame, metadata: dict, strategy: IStrategy) -> DataFrame: """ From b79d4e8876dc612b6f56db75ed8cf18d1c62d7c5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 14:40:32 +0200 Subject: [PATCH 051/308] Allow user to go live and start from pretrained models (after a completed backtest) by simply reusing the `identifier` config parameter while dry/live. --- config_examples/config_freqai.example.json | 5 ++-- docs/freqai.md | 23 ++++++++---------- freqtrade/constants.py | 4 +--- freqtrade/freqai/data_kitchen.py | 27 +++++++++++----------- freqtrade/freqai/freqai_interface.py | 13 +++++++---- 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 5f7f38373..7582afef0 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -55,10 +55,9 @@ "15m" ], "train_period": 30, - "backtest_period": 7, + "backtest_period": 10, "identifier": "example", - "live_trained_timerange": "", - "live_full_backtestrange": "", + "live_trained_timestamp": 0, "corr_pairlist": [ "BTC/USDT", "ETH/USDT", diff --git a/docs/freqai.md b/docs/freqai.md index 27d393d0a..1c6a4ec4a 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -158,7 +158,7 @@ a specific pair or timeframe, they should use the following structure inside `po if pair == metadata['pair'] and tf == self.timeframe: df['%-day_of_week'] = (df["date"].dt.dayofweek + 1) / 7 df['%-hour_of_day'] = (df['date'].dt.hour + 1) / 25 - +``` (Please see the example script located in `freqtrade/templates/FreqaiExampleStrategy.py` for a full example of `populate_any_indicators()`) @@ -270,27 +270,22 @@ freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example. By default, Freqai will not find find any existing models and will start by training a new one given the user configuration settings. Following training, it will use that model to predict for the duration of `backtest_period`. After a full `backtest_period` has elapsed, Freqai will auto retrain -a new model, and begin making predictions with the updated model. +a new model, and begin making predictions with the updated model. FreqAI in live mode permits +the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent +retraining. -If the user wishes to start dry/live from a saved model, the following configuration -parameters need to be set: +If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse +the same `identifier` parameter ```json "freqai": { "identifier": "example", - "live_trained_timerange": "20220330-20220429", - "live_full_backtestrange": "20220302-20220501" } ``` -Where the `identifier` is the same identifier which was set during the backtesting/training. Meanwhile, -the `live_trained_timerange` is the sub-trained timerange (the training window) which was set -during backtesting/training. These are available to the user inside `user_data/models/*/sub-train-*`. -`live_full_backtestrange` was the full data range associated with the backtest/training (the full time -window that the training window and backtesting windows slide through). These values can be located -inside the `user_data/models/` directory. In this case, although Freqai will initiate with a -pre-trained model, if a full `backtest_period` has elapsed since the end of the user set -`live_trained_timerange`, it will self retrain. +In this case, although Freqai will initiate with a +pre-trained model, it will still check to see how much time has elapsed since the model was trained, +and if a full `backtest_period` has elapsed since the end of the loaded model, FreqAI will self retrain. ## Data anylsis techniques diff --git a/freqtrade/constants.py b/freqtrade/constants.py index eea657d84..f6ef462c3 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -440,15 +440,13 @@ CONF_SCHEMA = { "train_period": {"type": "integer", "default": 0}, "backtest_period": {"type": "float", "default": 7}, "identifier": {"type": "str", "default": "example"}, - "live_trained_timerange": {"type": "str"}, - "live_full_backtestrange": {"type": "str"}, "corr_pairlist": {"type": "list"}, "feature_parameters": { "type": "object", "properties": { "period": {"type": "integer"}, "shift": {"type": "integer", "default": 0}, - "DI_threshold": {"type": "integer", "default": 0}, + "DI_threshold": {"type": "float", "default": 0}, "weight_factor": {"type": "number", "default": 0}, "principal_component_analysis": {"type": "boolean", "default": False}, "use_SVM_to_remove_outliers": {"type": "boolean", "default": False}, diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index c5f57bf86..eafb9cc46 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -74,8 +74,7 @@ class FreqaiDataKitchen: def set_paths(self, metadata: dict, trained_timestamp: int = None,) -> None: self.full_path = Path(self.config['user_data_dir'] / "models" / - str(self.freqai_config.get('live_full_backtestrange') + - self.freqai_config.get('identifier'))) + str(self.freqai_config.get('identifier'))) self.data_path = Path(self.full_path / str("sub-train" + "-" + metadata['pair'].split("/")[0] + @@ -114,11 +113,11 @@ class FreqaiDataKitchen: save_path / str(self.model_filename + "_trained_df.pkl") ) - if self.live: - self.data_drawer.model_dictionary[self.model_filename] = model - self.data_drawer.pair_dict[coin]['model_filename'] = self.model_filename - self.data_drawer.pair_dict[coin]['data_path'] = str(self.data_path) - self.data_drawer.save_drawer_to_disk() + # if self.live: + self.data_drawer.model_dictionary[self.model_filename] = model + self.data_drawer.pair_dict[coin]['model_filename'] = self.model_filename + self.data_drawer.pair_dict[coin]['data_path'] = str(self.data_path) + self.data_drawer.save_drawer_to_disk() # TODO add a helper function to let user save/load any data they are custom adding. We # do not want them having to edit the default save/load methods here. Below is an example @@ -142,9 +141,9 @@ class FreqaiDataKitchen: :model: User trained model which can be inferenced for new predictions """ - if self.live: - self.model_filename = self.data_drawer.pair_dict[coin]['model_filename'] - self.data_path = Path(self.data_drawer.pair_dict[coin]['data_path']) + # if self.live: + self.model_filename = self.data_drawer.pair_dict[coin]['model_filename'] + self.data_path = Path(self.data_drawer.pair_dict[coin]['data_path']) with open(self.data_path / str(self.model_filename + "_metadata.json"), "r") as fp: self.data = json.load(fp) @@ -696,7 +695,7 @@ class FreqaiDataKitchen: self.full_path = Path( self.config["user_data_dir"] / "models" - / str(full_timerange + self.freqai_config.get("identifier")) + / str(self.freqai_config.get("identifier")) ) config_path = Path(self.config["config_files"][0]) @@ -750,10 +749,10 @@ class FreqaiDataKitchen: str(int(trained_timerange.stopts)))) self.model_filename = "cb_" + coin.lower() + "_" + str(int(trained_timerange.stopts)) - # this is not persistent at the moment TODO - self.freqai_config['live_trained_timerange'] = str(int(trained_timerange.stopts)) + + # self.freqai_config['live_trained_timerange'] = str(int(trained_timerange.stopts)) # enables persistence, but not fully implemented into save/load data yer - self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) + # self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict) -> None: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 71807ad19..d7bbc549a 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -77,13 +77,13 @@ class IFreqaiModel(ABC): """ self.live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) + self.data_drawer.set_pair_dict_info(metadata) # For live, we may be training new models on a separate thread while other pairs still need # to inference their historical models. Here we use a training queue system to handle this # and we keep the flag self.training_on_separate_threaad in the current object to help # determine what the current pair will do if self.live: - self.data_drawer.set_pair_dict_info(metadata) if (not self.training_on_separate_thread and self.data_drawer.training_queue == 1): @@ -137,6 +137,7 @@ class IFreqaiModel(ABC): for tr_train, tr_backtest in zip( dh.training_timeranges, dh.backtesting_timeranges ): + (_, _, _) = self.data_drawer.get_pair_dict_info(metadata) gc.collect() dh.data = {} # clean the pair specific data between training window sliding self.training_timerange = tr_train @@ -150,9 +151,12 @@ class IFreqaiModel(ABC): if not self.model_exists(metadata["pair"], dh, trained_timestamp=trained_timestamp.stopts): self.model = self.train(dataframe_train, metadata, dh) - dh.save_data(self.model) + self.data_drawer.pair_dict[metadata['pair']][ + 'trained_timestamp'] = trained_timestamp.stopts + dh.set_new_model_names(metadata, trained_timestamp) + dh.save_data(self.model, metadata['pair']) else: - self.model = dh.load_data() + self.model = dh.load_data(metadata['pair']) # strategy_provided_features = self.dh.find_features(dataframe_train) # # FIXME doesnt work with PCA @@ -295,8 +299,7 @@ class IFreqaiModel(ABC): def set_full_path(self) -> None: self.full_path = Path(self.config['user_data_dir'] / "models" / - str(self.freqai_info.get('live_full_backtestrange') + - self.freqai_info.get('identifier'))) + str(self.freqai_info.get('identifier'))) @threaded def retrain_model_on_separate_thread(self, new_trained_timerange: TimeRange, metadata: dict, From 7593339c14c0f45011f88f6d7034e845ee6363f8 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 14:42:46 +0200 Subject: [PATCH 052/308] small cleanup --- docs/freqai.md | 2 +- freqtrade/commands/data_commands.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 1c6a4ec4a..403145525 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -110,7 +110,7 @@ by prepending indicators with `%`: ```python def populate_any_indicators(self, metadata, pair, df, tf, informative=None, coin=""): - informative['%-''%-' + coin + "rsi"] = ta.RSI(informative, timeperiod=14) + informative['%-' + coin + "rsi"] = ta.RSI(informative, timeperiod=14) informative['%-' + coin + "mfi"] = ta.MFI(informative, timeperiod=25) informative['%-' + coin + "adx"] = ta.ADX(informative, window=20) bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=14, stds=2.2) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 4588bf67b..c7e6a7b84 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -51,7 +51,6 @@ def start_download_data(args: Dict[str, Any]) -> None: markets = [p for p, m in exchange.markets.items() if market_is_active(m) or config.get('include_inactive')] if config.get('freqai') is not None: - assert config['freqai'].get('corr_pairlist'), "No corr_pairlist found in config." full_pairs = config['pairs'] + [pair for pair in config['freqai']['corr_pairlist'] if pair not in config['pairs']] expanded_pairs = expand_pairlist(full_pairs, markets) From d79983c791a3534d083960358d86631a80648d10 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 14:55:19 +0200 Subject: [PATCH 053/308] try to pass flake8 --- freqtrade/commands/data_commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index c7e6a7b84..2019413b5 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -50,7 +50,7 @@ def start_download_data(args: Dict[str, Any]) -> None: exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) markets = [p for p, m in exchange.markets.items() if market_is_active(m) or config.get('include_inactive')] - if config.get('freqai') is not None: + if config.get('freqai', {}): full_pairs = config['pairs'] + [pair for pair in config['freqai']['corr_pairlist'] if pair not in config['pairs']] expanded_pairs = expand_pairlist(full_pairs, markets) From ff531c416f185ddaba02a38f0393f118e288afb4 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 25 May 2022 15:31:50 +0200 Subject: [PATCH 054/308] reduce `complexity` inside start_download_data() in an effort to appease flake8 --- freqtrade/commands/data_commands.py | 10 +++------- freqtrade/plugins/pairlist/pairlist_helpers.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 2019413b5..21b7a3194 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -12,7 +12,7 @@ from freqtrade.enums import CandleType, RunMode, TradingMode from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes from freqtrade.exchange.exchange import market_is_active -from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist +from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist, expand_pairlist from freqtrade.resolvers import ExchangeResolver @@ -50,12 +50,8 @@ def start_download_data(args: Dict[str, Any]) -> None: exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) markets = [p for p, m in exchange.markets.items() if market_is_active(m) or config.get('include_inactive')] - if config.get('freqai', {}): - full_pairs = config['pairs'] + [pair for pair in config['freqai']['corr_pairlist'] - if pair not in config['pairs']] - expanded_pairs = expand_pairlist(full_pairs, markets) - else: - expanded_pairs = expand_pairlist(config['pairs'], markets) + + expanded_pairs = dynamic_expand_pairlist(config, markets) # Manual validations of relevant settings if not config['exchange'].get('skip_pair_validation', False): diff --git a/freqtrade/plugins/pairlist/pairlist_helpers.py b/freqtrade/plugins/pairlist/pairlist_helpers.py index 1de27fcbd..23233481a 100644 --- a/freqtrade/plugins/pairlist/pairlist_helpers.py +++ b/freqtrade/plugins/pairlist/pairlist_helpers.py @@ -40,3 +40,14 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], except re.error as err: raise ValueError(f"Wildcard error in {pair_wc}, {err}") return result + + +def dynamic_expand_pairlist(config: dict, markets: list) -> List[str]: + if config.get('freqai', {}): + full_pairs = config['pairs'] + [pair for pair in config['freqai']['corr_pairlist'] + if pair not in config['pairs']] + expanded_pairs = expand_pairlist(full_pairs, markets) + else: + expanded_pairs = expand_pairlist(config['pairs'], markets) + + return expanded_pairs From 6193205012f681d233933fee50df66f33b63ddcc Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 26 May 2022 21:07:50 +0200 Subject: [PATCH 055/308] fix bug for target_mean/std array merging in backtesting --- config_examples/config_freqai.example.json | 19 ++- docs/freqai.md | 106 +++++++++++--- freqtrade/freqai/data_kitchen.py | 131 ++++++++++-------- freqtrade/freqai/freqai_interface.py | 23 +-- .../CatboostPredictionModel.py | 13 +- freqtrade/templates/FreqaiExampleStrategy.py | 4 +- 6 files changed, 186 insertions(+), 110 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index 7582afef0..b6c7ba7d8 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -1,7 +1,7 @@ { "max_open_trades": 1, "stake_currency": "USDT", - "stake_amount": 800, + "stake_amount": 900, "tradable_balance_ratio": 1, "fiat_display_currency": "USD", "dry_run": true, @@ -24,8 +24,7 @@ "rateLimit": 200 }, "pair_whitelist": [ - "BTC/USDT", - "ETH/USDT" + "BTC/USDT" ], "pair_blacklist": [] }, @@ -55,7 +54,7 @@ "15m" ], "train_period": 30, - "backtest_period": 10, + "backtest_period": 7, "identifier": "example", "live_trained_timestamp": 0, "corr_pairlist": [ @@ -64,16 +63,16 @@ "DOT/USDT" ], "feature_parameters": { - "period": 12, + "period": 24, "shift": 1, - "DI_threshold": 1, - "weight_factor": 0, + "DI_threshold": 0, + "weight_factor": 0.9, "principal_component_analysis": false, - "use_SVM_to_remove_outliers": false, - "stratify": 0 + "use_SVM_to_remove_outliers": true, + "stratify": 3 }, "data_split_parameters": { - "test_size": 0.25, + "test_size": 0.33, "random_state": 1 }, "model_training_parameters": { diff --git a/docs/freqai.md b/docs/freqai.md index 403145525..821f42258 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -221,33 +221,43 @@ This way, the user can return to using any model they wish by simply changing th ### Building a freqai strategy -The Freqai strategy requires the user to include the following lines of code in `populate_ any _indicators()` +The Freqai strategy requires the user to include the following lines of code in the strategy: ```python - from freqtrade.freqai.strategy_bridge import CustomModel + from freqtrade.freqai.strategy_bridge import CustomModel - def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # the configuration file parameters are stored here - self.freqai_info = self.config['freqai'] + def informative_pairs(self): + whitelist_pairs = self.dp.current_whitelist() + corr_pairs = self.config["freqai"]["corr_pairlist"] + informative_pairs = [] + for tf in self.config["freqai"]["timeframes"]: + for pair in whitelist_pairs: + informative_pairs.append((pair, tf)) + for pair in corr_pairs: + if pair in whitelist_pairs: + continue # avoid duplication + informative_pairs.append((pair, tf)) + return informative_pairs - # the model is instantiated here - self.model = CustomModel(self.config) + def bot_start(self): + self.model = CustomModel(self.config) - print('Populating indicators...') + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + self.freqai_info = self.config['freqai'] - # the following loops are necessary for building the features - # indicated by the user in the configuration file. - for tf in self.freqai_info['timeframes']: - for i in self.freqai_info['corr_pairlist']: - dataframe = self.populate_any_indicators(i, - dataframe.copy(), tf, coin=i.split("/")[0]+'-') + # the following loops are necessary for building the features + # indicated by the user in the configuration file. + for tf in self.freqai_info['timeframes']: + for i in self.freqai_info['corr_pairlist']: + dataframe = self.populate_any_indicators(i, + dataframe.copy(), tf, coin=i.split("/")[0]+'-') - # the model will return 4 values, its prediction, an indication of whether or not the prediction - # should be accepted, the target mean/std values from the labels used during each training period. - (dataframe['prediction'], dataframe['do_predict'], - dataframe['target_mean'], dataframe['target_std']) = self.model.bridge.start(dataframe, metadata) + # the model will return 4 values, its prediction, an indication of whether or not the prediction + # should be accepted, the target mean/std values from the labels used during each training period. + (dataframe['prediction'], dataframe['do_predict'], + dataframe['target_mean'], dataframe['target_std']) = self.model.bridge.start(dataframe, metadata) - return dataframe + return dataframe ``` The user should also include `populate_any_indicators()` from `templates/FreqaiExampleStrategy.py` which builds @@ -314,7 +324,7 @@ data point and all other training data points: $$ d_{ab} = \sqrt{\sum_{j=1}^p(X_{a,j}-X_{b,j})^2} $$ -where $d_{ab}$ is the distance between the standardized points $a$ and $b$. $p$ +where $d_{ab}$ is the distance between the normalized points $a$ and $b$. $p$ is the number of features i.e. the length of the vector $X$. The characteristic distance, $\overline{d}$ for a set of training data points is simply the mean of the average distances: @@ -392,13 +402,63 @@ The user can stratify the training/testing data using: which will split the data chronolocially so that every X data points is a testing data point. In the present example, the user is asking for every third data point in the dataframe to be used for -testing, the other points are used for training. +testing, the other points are used for training. + + + + ## Additional information -### Feature standardization +### Feature normalization -The feature set created by the user is automatically standardized to the training +The feature set created by the user is automatically normalized to the training data only. This includes all test data and unseen prediction data (dry/live/backtest). ### File structure diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index eafb9cc46..b5f1f6edb 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -141,9 +141,9 @@ class FreqaiDataKitchen: :model: User trained model which can be inferenced for new predictions """ - # if self.live: - self.model_filename = self.data_drawer.pair_dict[coin]['model_filename'] - self.data_path = Path(self.data_drawer.pair_dict[coin]['data_path']) + if self.live: + self.model_filename = self.data_drawer.pair_dict[coin]['model_filename'] + self.data_path = Path(self.data_drawer.pair_dict[coin]['data_path']) with open(self.data_path / str(self.model_filename + "_metadata.json"), "r") as fp: self.data = json.load(fp) @@ -329,42 +329,6 @@ class FreqaiDataKitchen: :data_dictionary: updated dictionary with standardized values. """ # standardize the data by training stats - train_mean = data_dictionary["train_features"].mean() - train_std = data_dictionary["train_features"].std() - data_dictionary["train_features"] = ( - data_dictionary["train_features"] - train_mean - ) / train_std - data_dictionary["test_features"] = ( - data_dictionary["test_features"] - train_mean - ) / train_std - - train_labels_std = data_dictionary["train_labels"].std() - train_labels_mean = data_dictionary["train_labels"].mean() - data_dictionary["train_labels"] = ( - data_dictionary["train_labels"] - train_labels_mean - ) / train_labels_std - data_dictionary["test_labels"] = ( - data_dictionary["test_labels"] - train_labels_mean - ) / train_labels_std - - for item in train_std.keys(): - self.data[item + "_std"] = train_std[item] - self.data[item + "_mean"] = train_mean[item] - - self.data["labels_std"] = train_labels_std - self.data["labels_mean"] = train_labels_mean - - return data_dictionary - - def standardize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: - """ - Standardize all data in the data_dictionary according to the training dataset - :params: - :data_dictionary: dictionary containing the cleaned and split training/test data/labels - :returns: - :data_dictionary: updated dictionary with standardized values. - """ - # standardize the data by training stats train_max = data_dictionary["train_features"].max() train_min = data_dictionary["train_features"].min() data_dictionary["train_features"] = 2 * ( @@ -392,9 +356,9 @@ class FreqaiDataKitchen: return data_dictionary - def standardize_data_from_metadata(self, df: DataFrame) -> DataFrame: + def normalize_data_from_metadata(self, df: DataFrame) -> DataFrame: """ - Standardizes a set of data using the mean and standard deviation from + Normalize a set of data using the mean and standard deviation from the associated training data. :params: :df: Dataframe to be standardized @@ -406,19 +370,6 @@ class FreqaiDataKitchen: return df - def normalize_data_from_metadata(self, df: DataFrame) -> DataFrame: - """ - Normalizes a set of data using the mean and standard deviation from - the associated training data. - :params: - :df: Dataframe to be standardized - """ - - for item in df.keys(): - df[item] = (df[item] - self.data[item + "_mean"]) / self.data[item + "_std"] - - return df - def split_timerange( self, tr: str, train_split: int = 28, bt_split: int = 7 ) -> Tuple[list, list]: @@ -657,12 +608,12 @@ class FreqaiDataKitchen: """ ones = np.ones(len_dataframe) - s_mean, s_std = ones * self.data["s_mean"], ones * self.data["s_std"] + target_mean, target_std = ones * self.data["target_mean"], ones * self.data["target_std"] self.full_predictions = np.append(self.full_predictions, predictions) self.full_do_predict = np.append(self.full_do_predict, do_predict) - self.full_target_mean = np.append(self.full_target_mean, s_mean) - self.full_target_std = np.append(self.full_target_std, s_std) + self.full_target_mean = np.append(self.full_target_mean, target_mean) + self.full_target_std = np.append(self.full_target_std, target_std) return @@ -827,6 +778,23 @@ class FreqaiDataKitchen: return dataframe + def fit_labels(self) -> None: + import scipy as spy + + f = spy.stats.norm.fit(self.data_dictionary["train_labels"]) + + # KEEPME incase we want to let user start to grab quantiles. + # upper_q = spy.stats.norm.ppf(self.freqai_config['feature_parameters'][ + # 'target_quantile'], *f) + # lower_q = spy.stats.norm.ppf(1 - self.freqai_config['feature_parameters'][ + # 'target_quantile'], *f) + + self.data["target_mean"], self.data["target_std"] = f[0], f[1] + # self.data["upper_quantile"] = upper_q + # self.data["lower_quantile"] = lower_q + + return + def np_encoder(self, object): if isinstance(object, np.generic): return object.item() @@ -968,3 +936,52 @@ class FreqaiDataKitchen: # ) # return + + # def standardize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: + # """ + # standardize all data in the data_dictionary according to the training dataset + # :params: + # :data_dictionary: dictionary containing the cleaned and split training/test data/labels + # :returns: + # :data_dictionary: updated dictionary with standardized values. + # """ + # # standardize the data by training stats + # train_mean = data_dictionary["train_features"].mean() + # train_std = data_dictionary["train_features"].std() + # data_dictionary["train_features"] = ( + # data_dictionary["train_features"] - train_mean + # ) / train_std + # data_dictionary["test_features"] = ( + # data_dictionary["test_features"] - train_mean + # ) / train_std + + # train_labels_std = data_dictionary["train_labels"].std() + # train_labels_mean = data_dictionary["train_labels"].mean() + # data_dictionary["train_labels"] = ( + # data_dictionary["train_labels"] - train_labels_mean + # ) / train_labels_std + # data_dictionary["test_labels"] = ( + # data_dictionary["test_labels"] - train_labels_mean + # ) / train_labels_std + + # for item in train_std.keys(): + # self.data[item + "_std"] = train_std[item] + # self.data[item + "_mean"] = train_mean[item] + + # self.data["labels_std"] = train_labels_std + # self.data["labels_mean"] = train_labels_mean + + # return data_dictionary + + # def standardize_data_from_metadata(self, df: DataFrame) -> DataFrame: + # """ + # Normalizes a set of data using the mean and standard deviation from + # the associated training data. + # :params: + # :df: Dataframe to be standardized + # """ + + # for item in df.keys(): + # df[item] = (df[item] - self.data[item + "_mean"]) / self.data[item + "_std"] + + # return df diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index d7bbc549a..68d21ecdc 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -158,12 +158,7 @@ class IFreqaiModel(ABC): else: self.model = dh.load_data(metadata['pair']) - # strategy_provided_features = self.dh.find_features(dataframe_train) - # # FIXME doesnt work with PCA - # if strategy_provided_features != self.dh.training_features_list: - # logger.info("User changed input features, retraining model.") - # self.model = self.train(dataframe_train, metadata) - # self.dh.save_data(self.model) + self.check_if_feature_list_matches_strategy(dataframe_train, dh) preds, do_preds = self.predict(dataframe_backtest, dh) @@ -220,16 +215,23 @@ class IFreqaiModel(ABC): self.model = dh.load_data(coin=metadata['pair']) - # FIXME - # strategy_provided_features = dh.find_features(dataframe) - # if strategy_provided_features != dh.training_features_list: - # self.train_model_in_series(new_trained_timerange, metadata, strategy) + self.check_if_feature_list_matches_strategy(dataframe, dh) preds, do_preds = self.predict(dataframe, dh) dh.append_predictions(preds, do_preds, len(dataframe)) return dh + def check_if_feature_list_matches_strategy(self, dataframe: DataFrame, + dh: FreqaiDataKitchen) -> None: + strategy_provided_features = dh.find_features(dataframe) + if strategy_provided_features != dh.training_features_list: + raise OperationalException("Trying to access pretrained model with `identifier` " + "but found different features furnished by current strategy." + "Change `identifer` to train from scratch, or ensure the" + "strategy is furnishing the same features as the pretrained" + "model") + def data_cleaning_train(self, dh: FreqaiDataKitchen) -> None: """ Base data cleaning method for train @@ -237,6 +239,7 @@ class IFreqaiModel(ABC): based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example of how outlier data points are dropped from the dataframe used for training. """ + if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): dh.principal_component_analysis() diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 73ea46032..3f70400d8 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -33,10 +33,6 @@ class CatboostPredictionModel(IFreqaiModel): / dataframe["close"] - 1 ) - dh.data["s_mean"] = dataframe["s"].mean() - dh.data["s_std"] = dataframe["s"].std() - - # logger.info("label mean", dh.data["s_mean"], "label std", dh.data["s_std"]) return dataframe["s"] @@ -68,8 +64,9 @@ class CatboostPredictionModel(IFreqaiModel): # split data into train/test data. data_dictionary = dh.make_train_test_datasets(features_filtered, labels_filtered) - # standardize all data based on train_dataset only - data_dictionary = dh.standardize_data(data_dictionary) + dh.fit_labels() # fit labels to a cauchy distribution so we know what to expect in strategy + # normalize all data based on train_dataset only + data_dictionary = dh.normalize_data(data_dictionary) # optional additional data cleaning/analysis self.data_cleaning_train(dh) @@ -128,7 +125,7 @@ class CatboostPredictionModel(IFreqaiModel): filtered_dataframe, _ = dh.filter_features( unfiltered_dataframe, original_feature_list, training_filter=False ) - filtered_dataframe = dh.standardize_data_from_metadata(filtered_dataframe) + filtered_dataframe = dh.normalize_data_from_metadata(filtered_dataframe) dh.data_dictionary["prediction_features"] = filtered_dataframe # optional additional data cleaning/analysis @@ -136,7 +133,7 @@ class CatboostPredictionModel(IFreqaiModel): predictions = self.model.predict(dh.data_dictionary["prediction_features"]) - # compute the non-standardized predictions + # compute the non-normalized predictions dh.predictions = (predictions + 1) * (dh.data["labels_max"] - dh.data["labels_min"]) / 2 + dh.data["labels_min"] diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index d2eb2c306..ed7c828cc 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -178,8 +178,8 @@ class FreqaiExampleStrategy(IStrategy): dataframe["target_std"], ) = self.model.bridge.start(dataframe, metadata, self) - dataframe["target_roi"] = dataframe["target_mean"] + dataframe["target_std"] * 1.5 - dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] * 1 + dataframe["target_roi"] = dataframe["target_mean"] + dataframe["target_std"] + dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: From 23c30dbc10703bda5b9a872d9c81ecf2155790c5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 27 May 2022 00:43:52 +0200 Subject: [PATCH 056/308] add error for user trying to backtest with backtest_period<1 --- freqtrade/freqai/data_kitchen.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index b5f1f6edb..1089797d1 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -19,6 +19,7 @@ from sklearn.model_selection import train_test_split from freqtrade.configuration import TimeRange from freqtrade.data.history import load_pair_history from freqtrade.data.history.history_utils import refresh_backtest_ohlcv_data +from freqtrade.exceptions import OperationalException from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.resolvers import ExchangeResolver from freqtrade.strategy.interface import IStrategy @@ -59,6 +60,11 @@ class FreqaiDataKitchen: self.pair = pair self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: + if config.get('freqai', {}).get('backtest_period') is not int: + raise OperationalException('backtest_period < 1,' + 'Can only backtest on full day increments' + 'backtest_period. Only live/dry mode' + 'allows fractions of days') self.full_timerange = self.create_fulltimerange(self.config["timerange"], self.freqai_config.get("train_period") ) From 8a501831d6626fd37302d156917bbd935c3d8531 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 27 May 2022 01:15:55 +0200 Subject: [PATCH 057/308] fix the error logic on previous commit --- freqtrade/freqai/data_kitchen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 1089797d1..63420a52b 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -60,7 +60,7 @@ class FreqaiDataKitchen: self.pair = pair self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: - if config.get('freqai', {}).get('backtest_period') is not int: + if config.get('freqai', {}).get('backtest_period') < 1: raise OperationalException('backtest_period < 1,' 'Can only backtest on full day increments' 'backtest_period. Only live/dry mode' From c080571b7a98ad3c29fd5c89ef229983040c2583 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 27 May 2022 12:23:32 +0200 Subject: [PATCH 058/308] help futures go dry/live with auto download feature --- docs/freqai.md | 2 +- freqtrade/freqai/data_kitchen.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 821f42258..78e25a234 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -400,7 +400,7 @@ The user can stratify the training/testing data using: } ``` -which will split the data chronolocially so that every X data points is a testing data point. In the +which will split the data chronologically so that every X data points is a testing data point. In the present example, the user is asking for every third data point in the dataframe to be used for testing, the other points are used for training. diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 63420a52b..45131f3d0 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -715,10 +715,9 @@ class FreqaiDataKitchen: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config, validate=False) - pairs = self.freqai_config.get('corr_pairlist', []) - if metadata['pair'] not in pairs: - pairs += metadata['pair'] # dont include pair twice - # timerange = TimeRange.parse_timerange(new_timerange) + pairs = copy.deepcopy(self.freqai_config.get('corr_pairlist', [])) + if str(metadata['pair']) not in pairs: + pairs.append(str(metadata['pair'])) refresh_backtest_ohlcv_data( exchange, pairs=pairs, timeframes=self.freqai_config.get('timeframes'), From 65fdebab75bd6238228620aa53172be01813d3fd Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 27 May 2022 13:01:33 +0200 Subject: [PATCH 059/308] let load_pairs_histories load futures candles in live --- freqtrade/freqai/data_kitchen.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 45131f3d0..5aa84620c 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -738,7 +738,9 @@ class FreqaiDataKitchen: for tf in self.freqai_config.get('timeframes'): base_dataframes[tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, - pair=metadata['pair'], timerange=timerange) + pair=metadata['pair'], timerange=timerange, + candle_type=self.config.get( + 'trading_mode', 'spot')) if pairs: for p in pairs: if metadata['pair'] in p: @@ -747,7 +749,9 @@ class FreqaiDataKitchen: corr_dataframes[p] = {} corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, - pair=p, timerange=timerange) + pair=p, timerange=timerange, + candle_type=self.config.get( + 'trading_mode', 'spot')) return corr_dataframes, base_dataframes From 891fb87712ae01adf2a578f457ff64251b4bcb4a Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 27 May 2022 13:38:22 +0200 Subject: [PATCH 060/308] give load_cached_data_for_updating the right flags to avoid redownloading data in dry/live --- freqtrade/freqai/data_kitchen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 5aa84620c..9866ee33a 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -669,7 +669,7 @@ class FreqaiDataKitchen: def check_if_new_training_required(self, trained_timestamp: int) -> Tuple[bool, TimeRange]: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() - trained_timerange = TimeRange() + trained_timerange = TimeRange('date', 'date') if trained_timestamp != 0: elapsed_time = (time - trained_timestamp) / SECONDS_IN_DAY retrain = elapsed_time > self.freqai_config.get('backtest_period') From b8f9c3557bd03a87217b12a6ba824e45e26fcea7 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 27 May 2022 13:56:34 +0200 Subject: [PATCH 061/308] dirty dirty, dont look here (hacking a flag to avoid reloading leverage_tiers in dry/live) --- freqtrade/exchange/exchange.py | 4 ++-- freqtrade/freqai/data_kitchen.py | 2 +- freqtrade/resolvers/exchange_resolver.py | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 65b9fb628..348f9c395 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -86,7 +86,7 @@ class Exchange: # TradingMode.SPOT always supported and not required in this list ] - def __init__(self, config: Dict[str, Any], validate: bool = True) -> None: + def __init__(self, config: Dict[str, Any], validate: bool = True, freqai: bool = False) -> None: """ Initializes this module with the given config, it does basic validation whether the specified exchange and pairs are valid. @@ -196,7 +196,7 @@ class Exchange: self.markets_refresh_interval: int = exchange_config.get( "markets_refresh_interval", 60) * 60 - if self.trading_mode != TradingMode.SPOT: + if self.trading_mode != TradingMode.SPOT and freqai is False: self.fill_leverage_tiers() self.additional_exchange_init() diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 9866ee33a..93e7b74ad 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -714,7 +714,7 @@ class FreqaiDataKitchen: def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict) -> None: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], - self.config, validate=False) + self.config, validate=False, freqai=True) pairs = copy.deepcopy(self.freqai_config.get('corr_pairlist', [])) if str(metadata['pair']) not in pairs: pairs.append(str(metadata['pair'])) diff --git a/freqtrade/resolvers/exchange_resolver.py b/freqtrade/resolvers/exchange_resolver.py index 4dfbf445b..c1ec8b69c 100644 --- a/freqtrade/resolvers/exchange_resolver.py +++ b/freqtrade/resolvers/exchange_resolver.py @@ -18,7 +18,8 @@ class ExchangeResolver(IResolver): object_type = Exchange @staticmethod - def load_exchange(exchange_name: str, config: dict, validate: bool = True) -> Exchange: + def load_exchange(exchange_name: str, config: dict, validate: bool = True, + freqai: bool = False) -> Exchange: """ Load the custom class from config parameter :param exchange_name: name of the Exchange to load @@ -31,7 +32,8 @@ class ExchangeResolver(IResolver): try: exchange = ExchangeResolver._load_exchange(exchange_name, kwargs={'config': config, - 'validate': validate}) + 'validate': validate, + 'freqai': freqai}) except ImportError: logger.info( f"No {exchange_name} specific subclass found. Using the generic class instead.") From c5a16e91fbb3052d01e4311ee72f739ba97fbf51 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 11:11:41 +0200 Subject: [PATCH 062/308] throw user error if user tries to load models but feeds the wrong features (while using PCA) --- docs/freqai.md | 2 ++ freqtrade/freqai/data_kitchen.py | 8 +++++++- freqtrade/freqai/freqai_interface.py | 10 +++++++--- .../prediction_models/CatboostPredictionModel.py | 5 +++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 78e25a234..57ff8f897 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -313,6 +313,8 @@ $$ W_i = \exp(\frac{-i}{\alpha*n}) $$ where $W_i$ is the weight of data point $i$ in a total set of $n$ data points._ +![weight-factor](assets/weights_factor.png) + Finally, `period` defines the offset used for the `labels`. In the present example, the user is asking for `labels` that are 24 candles in the future. diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 93e7b74ad..58b14b9f1 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -477,6 +477,11 @@ class FreqaiDataKitchen: index=self.data_dictionary["train_features"].index, ) + # keeping a copy of the non-transformed features so we can check for errors during + # model load from disk + self.data['training_features_list_raw'] = copy.deepcopy(self.training_features_list) + self.training_features_list = self.data_dictionary["train_features"].columns + self.data_dictionary["test_features"] = pd.DataFrame( data=test_components, columns=["PC" + str(i) for i in range(0, n_keep_components)], @@ -563,7 +568,8 @@ class FreqaiDataKitchen: def find_features(self, dataframe: DataFrame) -> list: column_names = dataframe.columns features = [c for c in column_names if '%' in c] - assert features, ("Could not find any features!") + if not features: + raise OperationalException("Could not find any features!") return features def check_if_pred_in_training_spaces(self) -> None: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 68d21ecdc..ab2d37753 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -225,7 +225,11 @@ class IFreqaiModel(ABC): def check_if_feature_list_matches_strategy(self, dataframe: DataFrame, dh: FreqaiDataKitchen) -> None: strategy_provided_features = dh.find_features(dataframe) - if strategy_provided_features != dh.training_features_list: + if dh.data['training_features_list_raw']: + feature_list = dh.data['training_features_list_raw'] + else: + feature_list = dh.training_features_list + if strategy_provided_features != feature_list: raise OperationalException("Trying to access pretrained model with `identifier` " "but found different features furnished by current strategy." "Change `identifer` to train from scratch, or ensure the" @@ -254,7 +258,7 @@ class IFreqaiModel(ABC): # if self.feature_parameters["remove_outliers"]: # dh.remove_outliers(predict=False) - def data_cleaning_predict(self, dh: FreqaiDataKitchen) -> None: + def data_cleaning_predict(self, dh: FreqaiDataKitchen, dataframe: DataFrame) -> None: """ Base data cleaning method for predict. These functions each modify dh.do_predict, which is a dataframe with equal length @@ -266,7 +270,7 @@ class IFreqaiModel(ABC): for buy signals. """ if self.freqai_info.get('feature_parameters', {}).get('principal_component_analysis'): - dh.pca_transform() + dh.pca_transform(dataframe) if self.freqai_info.get('feature_parameters', {}).get('use_SVM_to_remove_outliers'): dh.use_SVM_to_remove_outliers(predict=True) diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 3f70400d8..5147faf0c 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -71,7 +71,8 @@ class CatboostPredictionModel(IFreqaiModel): # optional additional data cleaning/analysis self.data_cleaning_train(dh) - logger.info(f'Training model on {len(dh.training_features_list)} features') + logger.info(f'Training model on {len(dh.data_dictionary["train_features"].columns)}' + 'features') logger.info(f'Training model on {len(data_dictionary["train_features"])} data points') model = self.fit(data_dictionary) @@ -129,7 +130,7 @@ class CatboostPredictionModel(IFreqaiModel): dh.data_dictionary["prediction_features"] = filtered_dataframe # optional additional data cleaning/analysis - self.data_cleaning_predict(dh) + self.data_cleaning_predict(dh, filtered_dataframe) predictions = self.model.predict(dh.data_dictionary["prediction_features"]) From 0bf915054d95f82bd5bb5f313a825d25c2ad0219 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 11:22:32 +0200 Subject: [PATCH 063/308] handle key check correctly --- freqtrade/freqai/freqai_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index ab2d37753..75c00988f 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -225,7 +225,7 @@ class IFreqaiModel(ABC): def check_if_feature_list_matches_strategy(self, dataframe: DataFrame, dh: FreqaiDataKitchen) -> None: strategy_provided_features = dh.find_features(dataframe) - if dh.data['training_features_list_raw']: + if 'training_features_list_raw' in dh.data: feature_list = dh.data['training_features_list_raw'] else: feature_list = dh.training_features_list From 7870a86e9acbc3962e63a2fbacef993ab00500d3 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 11:38:57 +0200 Subject: [PATCH 064/308] fix live retraining bug --- docs/assets/weights_factor.png | Bin 0 -> 129065 bytes freqtrade/freqai/data_kitchen.py | 2 +- freqtrade/freqai/freqai_interface.py | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 docs/assets/weights_factor.png diff --git a/docs/assets/weights_factor.png b/docs/assets/weights_factor.png new file mode 100644 index 0000000000000000000000000000000000000000..1171a49ba4d9300c6828b766fc8d80aecc907cf5 GIT binary patch literal 129065 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

%|IStn!TE@v9Zyy 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 literal 0 HcmV?d00001 diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 58b14b9f1..69a311925 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -675,7 +675,7 @@ class FreqaiDataKitchen: def check_if_new_training_required(self, trained_timestamp: int) -> Tuple[bool, TimeRange]: time = datetime.datetime.now(tz=datetime.timezone.utc).timestamp() - trained_timerange = TimeRange('date', 'date') + trained_timerange = TimeRange() if trained_timestamp != 0: elapsed_time = (time - trained_timestamp) / SECONDS_IN_DAY retrain = elapsed_time > self.freqai_config.get('backtest_period') diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 75c00988f..3e737e5e7 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -187,7 +187,8 @@ class IFreqaiModel(ABC): (model_filename, trained_timestamp, coin_first) = self.data_drawer.get_pair_dict_info(metadata) - + if self.training_on_separate_thread: + print('debug_here') if not self.training_on_separate_thread: file_exists = False From 2a4d1e2d64df6584b5c54849f33b96e49eb21e60 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 12:23:26 +0200 Subject: [PATCH 065/308] fix bug in setting new timerange for retraining --- freqtrade/freqai/data_kitchen.py | 2 +- freqtrade/freqai/freqai_interface.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 69a311925..629019549 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -681,7 +681,7 @@ class FreqaiDataKitchen: retrain = elapsed_time > self.freqai_config.get('backtest_period') if retrain: trained_timerange.startts = int(time - self.freqai_config.get( - 'backtest_period', 0) * SECONDS_IN_DAY) + 'train_period', 0) * SECONDS_IN_DAY) trained_timerange.stopts = int(time) else: # user passed no live_trained_timerange in config trained_timerange.startts = int(time - self.freqai_config.get('train_period') * diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 3e737e5e7..75c00988f 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -187,8 +187,7 @@ class IFreqaiModel(ABC): (model_filename, trained_timestamp, coin_first) = self.data_drawer.get_pair_dict_info(metadata) - if self.training_on_separate_thread: - print('debug_here') + if not self.training_on_separate_thread: file_exists = False From e54614fa2f190970234fcf7e4b67299c0eacbe38 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 14:55:07 +0200 Subject: [PATCH 066/308] remove remnants of single threaded version, ensure pair queue priority is checked before retraining --- freqtrade/freqai/freqai_interface.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 75c00988f..1952cd234 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -85,7 +85,7 @@ class IFreqaiModel(ABC): # determine what the current pair will do if self.live: if (not self.training_on_separate_thread and - self.data_drawer.training_queue == 1): + self.data_drawer.training_queue[metadata['pair']] == 1): self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) @@ -321,16 +321,26 @@ class IFreqaiModel(ABC): base_dataframes, metadata) - self.model = self.train(unfiltered_dataframe, metadata, dh) + try: + model = self.train(unfiltered_dataframe, metadata, dh) + except ValueError: + logger.warning('Value error encountered during training') + self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) + self.training_on_separate_thread = False + self.retrain = False + return self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts dh.set_new_model_names(metadata, new_trained_timerange) - self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) - dh.save_data(self.model, coin=metadata['pair']) + logger.info('Training queue' + f'{sorted(self.data_drawer.training_queue.items(), key=lambda item: item[1])}') + dh.save_data(model, coin=metadata['pair']) + self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) self.training_on_separate_thread = False self.retrain = False + return def train_model_in_series(self, new_trained_timerange: TimeRange, metadata: dict, strategy: IStrategy, dh: FreqaiDataKitchen): @@ -344,13 +354,13 @@ class IFreqaiModel(ABC): base_dataframes, metadata) - self.model = self.train(unfiltered_dataframe, metadata, dh) + model = self.train(unfiltered_dataframe, metadata, dh) self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts dh.set_new_model_names(metadata, new_trained_timerange) self.data_drawer.pair_dict[metadata['pair']]['first'] = False - dh.save_data(self.model, coin=metadata['pair']) + dh.save_data(model, coin=metadata['pair']) self.retrain = False # Methods which are overridden by user made prediction models. From 83dd45372356c62b17cd4789d377e2e25d7e1378 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 18:26:19 +0200 Subject: [PATCH 067/308] catch errors occuring on background thread, and make sure to keep the ball rolling. Improve pair retraining queue. --- freqtrade/freqai/data_drawer.py | 18 ++++++++--------- freqtrade/freqai/data_kitchen.py | 6 ++++-- freqtrade/freqai/freqai_interface.py | 29 ++++++++++++++++++---------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index a5d8a2123..477f45d84 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -28,7 +28,7 @@ class FreqaiDataDrawer: self.full_path = full_path self.load_drawer_from_disk() self.training_queue: Dict[str, int] = {} - self.create_training_queue(pair_whitelist) + # self.create_training_queue(pair_whitelist) def load_drawer_from_disk(self): exists = Path(self.full_path / str('pair_dictionary.json')).resolve().exists() @@ -58,7 +58,6 @@ class FreqaiDataDrawer: model_filename = self.pair_dict[metadata['pair']]['model_filename'] = '' coin_first = self.pair_dict[metadata['pair']]['first'] = True trained_timestamp = self.pair_dict[metadata['pair']]['trained_timestamp'] = 0 - self.pair_dict[metadata['pair']]['priority'] = 1 return model_filename, trained_timestamp, coin_first @@ -71,17 +70,16 @@ class FreqaiDataDrawer: self.pair_dict[metadata['pair']]['model_filename'] = '' self.pair_dict[metadata['pair']]['first'] = True self.pair_dict[metadata['pair']]['trained_timestamp'] = 0 - self.pair_dict[metadata['pair']]['priority'] = 1 + self.pair_dict[metadata['pair']]['priority'] = len(self.pair_dict) return - def create_training_queue(self, pairs: list) -> None: - for i, pair in enumerate(pairs): - self.training_queue[pair] = i + 1 + # def create_training_queue(self, pairs: list) -> None: + # for i, pair in enumerate(pairs): + # self.training_queue[pair] = i + 1 def pair_to_end_of_training_queue(self, pair: str) -> None: # march all pairs up in the queue - for p in self.training_queue: - self.training_queue[p] -= 1 - + for p in self.pair_dict: + self.pair_dict[p]['priority'] -= 1 # send pair to end of queue - self.training_queue[pair] = len(self.training_queue) + self.pair_dict[pair]['priority'] = len(self.pair_dict) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 629019549..a1bda34bf 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -717,10 +717,12 @@ class FreqaiDataKitchen: # enables persistence, but not fully implemented into save/load data yer # self.data['live_trained_timerange'] = str(int(trained_timerange.stopts)) - def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict) -> None: + def download_new_data_for_retraining(self, timerange: TimeRange, metadata: dict, + strategy: IStrategy) -> None: exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config, validate=False, freqai=True) + # exchange = strategy.dp._exchange # closes ccxt session pairs = copy.deepcopy(self.freqai_config.get('corr_pairlist', [])) if str(metadata['pair']) not in pairs: pairs.append(str(metadata['pair'])) @@ -766,7 +768,7 @@ class FreqaiDataKitchen: base_dataframes: dict, metadata: dict) -> DataFrame: - dataframe = base_dataframes[self.config['timeframe']] + dataframe = base_dataframes[self.config['timeframe']].copy() pairs = self.freqai_config.get("corr_pairlist", []) for tf in self.freqai_config.get("timeframes"): diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 1952cd234..dfd2f0bbd 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -85,7 +85,7 @@ class IFreqaiModel(ABC): # determine what the current pair will do if self.live: if (not self.training_on_separate_thread and - self.data_drawer.training_queue[metadata['pair']] == 1): + self.data_drawer.pair_dict[metadata['pair']]['priority'] == 1): self.dh = FreqaiDataKitchen(self.config, self.data_drawer, self.live, metadata["pair"]) @@ -313,13 +313,22 @@ class IFreqaiModel(ABC): strategy: IStrategy, dh: FreqaiDataKitchen): # with nostdout(): - dh.download_new_data_for_retraining(new_trained_timerange, metadata) + dh.download_new_data_for_retraining(new_trained_timerange, metadata, strategy) corr_dataframes, base_dataframes = dh.load_pairs_histories(new_trained_timerange, metadata) - unfiltered_dataframe = dh.use_strategy_to_populate_indicators(strategy, - corr_dataframes, - base_dataframes, - metadata) + + # protecting from common benign errors associated with grabbing new data from exchange: + try: + unfiltered_dataframe = dh.use_strategy_to_populate_indicators(strategy, + corr_dataframes, + base_dataframes, + metadata) + except Exception: + logger.warning('Mismatched sizes encountered in strategy') + self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) + self.training_on_separate_thread = False + self.retrain = False + return try: model = self.train(unfiltered_dataframe, metadata, dh) @@ -333,8 +342,8 @@ class IFreqaiModel(ABC): self.data_drawer.pair_dict[metadata['pair']][ 'trained_timestamp'] = new_trained_timerange.stopts dh.set_new_model_names(metadata, new_trained_timerange) - logger.info('Training queue' - f'{sorted(self.data_drawer.training_queue.items(), key=lambda item: item[1])}') + # logger.info('Training queue' + # f'{sorted(self.data_drawer.pair_dict.items(), key=lambda item: item[1])}') dh.save_data(model, coin=metadata['pair']) self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) @@ -345,7 +354,7 @@ class IFreqaiModel(ABC): def train_model_in_series(self, new_trained_timerange: TimeRange, metadata: dict, strategy: IStrategy, dh: FreqaiDataKitchen): - dh.download_new_data_for_retraining(new_trained_timerange, metadata) + dh.download_new_data_for_retraining(new_trained_timerange, metadata, strategy) corr_dataframes, base_dataframes = dh.load_pairs_histories(new_trained_timerange, metadata) @@ -363,7 +372,7 @@ class IFreqaiModel(ABC): dh.save_data(model, coin=metadata['pair']) self.retrain = False - # Methods which are overridden by user made prediction models. + # Following methods which are overridden by user made prediction models. # See freqai/prediction_models/CatboostPredictionModlel.py for an example. @abstractmethod From 4eb29c8810bad526f79206f2688eeaf7b5a2da1a Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 28 May 2022 18:34:26 +0200 Subject: [PATCH 068/308] Dont reset pair priority if it doesnt successfully train --- freqtrade/freqai/freqai_interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index dfd2f0bbd..ac0ad9d5a 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -325,7 +325,7 @@ class IFreqaiModel(ABC): metadata) except Exception: logger.warning('Mismatched sizes encountered in strategy') - self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) + # self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) self.training_on_separate_thread = False self.retrain = False return @@ -334,7 +334,7 @@ class IFreqaiModel(ABC): model = self.train(unfiltered_dataframe, metadata, dh) except ValueError: logger.warning('Value error encountered during training') - self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) + # self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) self.training_on_separate_thread = False self.retrain = False return From ce365eb9e3a12e83d21e696ff0c4c9033e7ce1a7 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 14:45:46 +0200 Subject: [PATCH 069/308] improve example strat so that it has dynamic buy and sell logic according to original prediction --- .gitignore | 3 +- .../config_freqai_futures.example.json | 93 ++++++++++++++++++ ...e.json => config_freqai_spot.example.json} | 17 ++-- freqtrade/freqai/freqai_interface.py | 1 + freqtrade/templates/FreqaiExampleStrategy.py | 98 ++++++++++++++++--- 5 files changed, 189 insertions(+), 23 deletions(-) create mode 100644 config_examples/config_freqai_futures.example.json rename config_examples/{config_freqai.example.json => config_freqai_spot.example.json} (89%) diff --git a/.gitignore b/.gitignore index dc87402b4..a066001db 100644 --- a/.gitignore +++ b/.gitignore @@ -109,4 +109,5 @@ target/ !config_examples/config_ftx.example.json !config_examples/config_full.example.json !config_examples/config_kraken.example.json -!config_examples/config_freqai.example.json +!config_examples/config_freqai_futures.example.json +!config_examples/config_freqai_spot.example.json diff --git a/config_examples/config_freqai_futures.example.json b/config_examples/config_freqai_futures.example.json new file mode 100644 index 000000000..cb545acdc --- /dev/null +++ b/config_examples/config_freqai_futures.example.json @@ -0,0 +1,93 @@ +{ + "trading_mode": "futures", + "margin_mode": "isolated", + "max_open_trades": 5, + "stake_currency": "USDT", + "stake_amount": 200, + "tradable_balance_ratio": 1, + "fiat_display_currency": "USD", + "dry_run": true, + "timeframe": "3m", + "dry_run_wallet": 1000, + "cancel_open_orders_on_exit": true, + "unfilledtimeout": { + "entry": 10, + "exit": 30 + }, + "exchange": { + "name": "okx", + "key": "", + "secret": "", + "ccxt_config": { + "enableRateLimit": true + }, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 200 + }, + "pair_whitelist": [ + "AGLD/USDT:USDT", + "1INCH/USDT:USDT", + "AAVE/USDT:USDT", + "ALGO/USDT:USDT", + "ALPHA/USDT:USDT", + "API3/USDT:USDT", + "AVAX/USDT:USDT", + "AXS/USDT:USDT", + "BCH/USDT:USDT" + ], + "pair_blacklist": [] + }, + "entry_pricing": { + "price_side": "same", + "use_order_book": true, + "order_book_top": 1, + "price_last_balance": 0.0, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "exit_pricing": { + "price_side": "other", + "use_order_book": true, + "order_book_top": 1 + }, + "pairlists": [ + { + "method": "StaticPairList" + } + ], + "freqai": { + "timeframes": [ + "3m", + "15m", + "1h" + ], + "train_period": 20, + "backtest_period": 2, + "identifier": "example", + "live_trained_timestamp": 0, + "corr_pairlist": [ + "BTC/USDT:USDT", + "ETH/USDT:USDT" + ], + "feature_parameters": { + "period": 20, + "shift": 2, + "DI_threshold": 0, + "weight_factor": 0.9, + "principal_component_analysis": false, + "use_SVM_to_remove_outliers": true, + "stratify": 0 + }, + "data_split_parameters": { + "test_size": 0.33, + "random_state": 1 + }, + "model_training_parameters": { + "n_estimators": 1000, + "task_type": "CPU" + } + } +} diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai_spot.example.json similarity index 89% rename from config_examples/config_freqai.example.json rename to config_examples/config_freqai_spot.example.json index b6c7ba7d8..e311fe280 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai_spot.example.json @@ -6,7 +6,7 @@ "fiat_display_currency": "USD", "dry_run": true, "timeframe": "5m", - "dry_run_wallet": 1000, + "dry_run_wallet": 4000, "cancel_open_orders_on_exit": true, "unfilledtimeout": { "entry": 10, @@ -51,7 +51,8 @@ "freqai": { "timeframes": [ "5m", - "15m" + "15m", + "4h" ], "train_period": 30, "backtest_period": 7, @@ -60,16 +61,18 @@ "corr_pairlist": [ "BTC/USDT", "ETH/USDT", - "DOT/USDT" + "DOT/USDT", + "MATIC/USDT", + "SOL/USDT" ], "feature_parameters": { - "period": 24, + "period": 20, "shift": 1, "DI_threshold": 0, "weight_factor": 0.9, "principal_component_analysis": false, - "use_SVM_to_remove_outliers": true, - "stratify": 3 + "use_SVM_to_remove_outliers": false, + "stratify": 0 }, "data_split_parameters": { "test_size": 0.33, @@ -77,8 +80,6 @@ }, "model_training_parameters": { "n_estimators": 1000, - "random_state": 1, - "learning_rate": 0.1, "task_type": "CPU" } }, diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index ac0ad9d5a..0d5b27385 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -56,6 +56,7 @@ class IFreqaiModel(ABC): self.set_full_path() self.data_drawer = FreqaiDataDrawer(Path(self.full_path), self.config['exchange']['pair_whitelist']) + self.lock = threading.Lock() def assert_config(self, config: Dict[str, Any]) -> None: diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index ed7c828cc..94fa0266d 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -7,8 +7,10 @@ import talib.abstract as ta from pandas import DataFrame from technical import qtpylib +from freqtrade.exchange import timeframe_to_prev_date from freqtrade.freqai.strategy_bridge import CustomModel -from freqtrade.strategy import merge_informative_pair +from freqtrade.persistence import Trade +from freqtrade.strategy import DecimalParameter, IntParameter, merge_informative_pair from freqtrade.strategy.interface import IStrategy @@ -46,6 +48,11 @@ class FreqaiExampleStrategy(IStrategy): stoploss = -0.05 use_sell_signal = True startup_candle_count: int = 300 + can_short = False + + linear_roi_offset = DecimalParameter(0.00, 0.02, default=0.005, space='sell', + optimize=False, load=True) + max_roi_time_long = IntParameter(0, 800, default=400, space='sell', optimize=False, load=True) def informative_pairs(self): whitelist_pairs = self.dp.current_whitelist() @@ -182,25 +189,88 @@ class FreqaiExampleStrategy(IStrategy): dataframe["sell_roi"] = dataframe["target_mean"] - dataframe["target_std"] return dataframe - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: - buy_conditions = [ - (dataframe["prediction"] > dataframe["target_roi"]) & (dataframe["do_predict"] == 1) + enter_long_conditions = [ + df['do_predict'] == 1, + df['prediction'] > df["target_roi"] ] - if buy_conditions: - dataframe.loc[reduce(lambda x, y: x | y, buy_conditions), "buy"] = 1 + if enter_long_conditions: + df.loc[reduce(lambda x, y: x & y, + enter_long_conditions), ["enter_long", "enter_tag"]] = (1, 'long') - return dataframe - - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - sell_conditions = [ - (dataframe["do_predict"] <= 0) + enter_short_conditions = [ + df['do_predict'] == 1, + df['prediction'] < df["sell_roi"] ] - if sell_conditions: - dataframe.loc[reduce(lambda x, y: x | y, sell_conditions), "sell"] = 1 - return dataframe + if enter_short_conditions: + df.loc[reduce(lambda x, y: x & y, + enter_short_conditions), ["enter_short", "enter_tag"]] = (1, 'short') + + return df + + def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + exit_long_conditions = [ + df['do_predict'] == 1, + df['prediction'] < df['sell_roi'] * 0.25 + ] + if exit_long_conditions: + df.loc[reduce(lambda x, y: x & y, exit_long_conditions), "exit_long"] = 1 + + exit_short_conditions = [ + df['do_predict'] == 1, + df['prediction'] > df['target_roi'] * 0.25 + ] + if exit_short_conditions: + df.loc[reduce(lambda x, y: x & y, exit_short_conditions), "exit_short"] = 1 + + return df def get_ticker_indicator(self): return int(self.config["timeframe"][:-1]) + + def custom_exit(self, pair: str, trade: Trade, current_time, current_rate, + current_profit, **kwargs): + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + + trade_date = timeframe_to_prev_date(self.config['timeframe'], trade.open_date_utc) + trade_candle = dataframe.loc[(dataframe['date'] == trade_date)] + + if trade_candle.empty: + return None + trade_candle = trade_candle.squeeze() + pair_dict = self.model.bridge.data_drawer.pair_dict + entry_tag = trade.enter_tag + + if 'prediction' + entry_tag not in pair_dict[pair]: + with self.model.bridge.lock: + self.model.bridge.data_drawer.pair_dict[pair][ + 'prediction' + entry_tag] = abs(trade_candle['prediction']) + self.model.bridge.data_drawer.save_drawer_to_disk() + else: + if pair_dict[pair]['prediction' + entry_tag] > 0: + roi_price = abs(trade_candle['prediction' + entry_tag]) + else: + with self.model.bridge.lock: + self.model.bridge.data_drawer.pair_dict[pair][ + 'prediction' + entry_tag] = abs(trade_candle['prediction']) + self.model.bridge.data_drawer.save_drawer_to_disk() + + roi_price = abs(trade_candle['prediction']) + roi_time = self.max_roi_time_long.value + + roi_decay = roi_price * (1 - ((current_time - trade.open_date_utc).seconds) / + (roi_time * 60)) + if roi_decay < 0: + roi_decay = self.linear_roi_offset.value + else: + roi_decay += self.linear_roi_offset.value + + if current_profit > roi_price: # roi_decay: + with self.model.bridge.lock: + self.model.bridge.data_drawer.pair_dict[pair]['prediction' + entry_tag] = 0 + self.model.bridge.data_drawer.save_drawer_to_disk() + return 'roi_custom_win' From fe36b08fcec9e2f4b52349e1aa6dbd4db0f3eaf7 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 16:26:34 +0200 Subject: [PATCH 070/308] fix key error in example strat --- freqtrade/templates/FreqaiExampleStrategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 94fa0266d..13df1f846 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -252,7 +252,7 @@ class FreqaiExampleStrategy(IStrategy): self.model.bridge.data_drawer.save_drawer_to_disk() else: if pair_dict[pair]['prediction' + entry_tag] > 0: - roi_price = abs(trade_candle['prediction' + entry_tag]) + roi_price = abs(trade_candle['prediction']) else: with self.model.bridge.lock: self.model.bridge.data_drawer.pair_dict[pair][ From 0aa71620553a8e72162939a2ccd7dc8eefe11fec Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 16:36:46 +0200 Subject: [PATCH 071/308] ensure the prediction is reset in the pair_dict after any trade exit, not just custom_exit --- freqtrade/templates/FreqaiExampleStrategy.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 13df1f846..ecda10919 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -269,8 +269,17 @@ class FreqaiExampleStrategy(IStrategy): else: roi_decay += self.linear_roi_offset.value - if current_profit > roi_price: # roi_decay: - with self.model.bridge.lock: - self.model.bridge.data_drawer.pair_dict[pair]['prediction' + entry_tag] = 0 - self.model.bridge.data_drawer.save_drawer_to_disk() + if current_profit > roi_price: return 'roi_custom_win' + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, exit_reason: str, + current_time, **kwargs) -> bool: + + entry_tag = trade.enter_tag + + with self.model.bridge.lock: + self.model.bridge.data_drawer.pair_dict[pair]['prediction' + entry_tag] = 0 + self.model.bridge.data_drawer.save_drawer_to_disk() + + return True From 4eb4753e20434ce8c4010f14f2e305dd44995a74 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 17:44:35 +0200 Subject: [PATCH 072/308] allow subdaily retraining for backtesting --- docs/freqai.md | 7 ++++--- freqtrade/freqai/data_kitchen.py | 22 +++++++++++++--------- freqtrade/freqai/freqai_interface.py | 3 ++- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 57ff8f897..d6998a8b6 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -280,9 +280,10 @@ freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example. By default, Freqai will not find find any existing models and will start by training a new one given the user configuration settings. Following training, it will use that model to predict for the duration of `backtest_period`. After a full `backtest_period` has elapsed, Freqai will auto retrain -a new model, and begin making predictions with the updated model. FreqAI in live mode permits -the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent -retraining. +a new model, and begin making predictions with the updated model. FreqAI backtesting and live both +permit the user to use fractional days (i.e. 0.1) in the `backtest_period`, which enables more frequent +retraining. But the user should be careful that using a fractional `backtest_period` with a large +`--timerange` in backtesting will result in a huge amount of required trainings/models. If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse the same `identifier` parameter diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index a1bda34bf..08a00c68d 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -60,11 +60,11 @@ class FreqaiDataKitchen: self.pair = pair self.svm_model: linear_model.SGDOneClassSVM = None if not self.live: - if config.get('freqai', {}).get('backtest_period') < 1: - raise OperationalException('backtest_period < 1,' - 'Can only backtest on full day increments' - 'backtest_period. Only live/dry mode' - 'allows fractions of days') + # if config.get('freqai', {}).get('backtest_period') < 1: + # raise OperationalException('backtest_period < 1,' + # 'Can only backtest on full day increments' + # 'backtest_period. Only live/dry mode' + # 'allows fractions of days') self.full_timerange = self.create_fulltimerange(self.config["timerange"], self.freqai_config.get("train_period") ) @@ -401,6 +401,8 @@ class FreqaiDataKitchen: tr_training_list = [] tr_backtesting_list = [] + tr_training_list_timerange = [] + tr_backtesting_list_timerange = [] first = True # within_config_timerange = True while True: @@ -412,6 +414,7 @@ class FreqaiDataKitchen: start = datetime.datetime.utcfromtimestamp(timerange_train.startts) stop = datetime.datetime.utcfromtimestamp(timerange_train.stopts) tr_training_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) + tr_training_list_timerange.append(copy.deepcopy(timerange_train)) # associated backtest period @@ -425,16 +428,17 @@ class FreqaiDataKitchen: start = datetime.datetime.utcfromtimestamp(timerange_backtest.startts) stop = datetime.datetime.utcfromtimestamp(timerange_backtest.stopts) tr_backtesting_list.append(start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d")) + tr_backtesting_list_timerange.append(copy.deepcopy(timerange_backtest)) # ensure we are predicting on exactly same amount of data as requested by user defined # --timerange if timerange_backtest.stopts == config_timerange.stopts: break - print(tr_training_list, tr_backtesting_list) - return tr_training_list, tr_backtesting_list + # print(tr_training_list, tr_backtesting_list) + return tr_training_list_timerange, tr_backtesting_list_timerange - def slice_dataframe(self, tr: str, df: DataFrame) -> DataFrame: + def slice_dataframe(self, timerange: TimeRange, df: DataFrame) -> DataFrame: """ Given a full dataframe, extract the user desired window :params: @@ -442,7 +446,7 @@ class FreqaiDataKitchen: :df: Dataframe containing all candles to run the entire backtest. Here it is sliced down to just the present training period. """ - timerange = TimeRange.parse_timerange(tr) + # timerange = TimeRange.parse_timerange(tr) start = datetime.datetime.fromtimestamp(timerange.startts, tz=datetime.timezone.utc) stop = datetime.datetime.fromtimestamp(timerange.stopts, tz=datetime.timezone.utc) df = df.loc[df["date"] >= start, :] diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 0d5b27385..db66ef033 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -142,10 +142,11 @@ class IFreqaiModel(ABC): gc.collect() dh.data = {} # clean the pair specific data between training window sliding self.training_timerange = tr_train + # self.training_timerange_timerange = tr_train dataframe_train = dh.slice_dataframe(tr_train, dataframe) dataframe_backtest = dh.slice_dataframe(tr_backtest, dataframe) logger.info("training %s for %s", metadata["pair"], tr_train) - trained_timestamp = TimeRange.parse_timerange(tr_train) + trained_timestamp = tr_train # TimeRange.parse_timerange(tr_train) dh.data_path = Path(dh.full_path / str("sub-train" + "-" + metadata['pair'].split("/")[0] + str(int(trained_timestamp.stopts)))) From cc6cae47ec53009922e941a6118cf555b0113ee6 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 19:49:43 +0200 Subject: [PATCH 073/308] allow pairs deeper in the queue to get trained if the higher priority pairs dont need training --- freqtrade/freqai/freqai_interface.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index db66ef033..90d96ad87 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -348,7 +348,8 @@ class IFreqaiModel(ABC): # f'{sorted(self.data_drawer.pair_dict.items(), key=lambda item: item[1])}') dh.save_data(model, coin=metadata['pair']) - self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) + if self.data_drawer.pair_dict[metadata['pair']['priority']] == 1: + self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) self.training_on_separate_thread = False self.retrain = False return From 3f722632788f13e471b9ed5fe4f0301f38634d8d Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 20:02:43 +0200 Subject: [PATCH 074/308] allow pairs deeper in the queue to get trained if the higher priority pairs dont need training --- freqtrade/freqai/freqai_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 90d96ad87..319240248 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -348,7 +348,7 @@ class IFreqaiModel(ABC): # f'{sorted(self.data_drawer.pair_dict.items(), key=lambda item: item[1])}') dh.save_data(model, coin=metadata['pair']) - if self.data_drawer.pair_dict[metadata['pair']['priority']] == 1: + if self.data_drawer.pair_dict[metadata['pair']]['priority'] == 1: self.data_drawer.pair_to_end_of_training_queue(metadata['pair']) self.training_on_separate_thread = False self.retrain = False From a79032bf75cf299c576ee7bf9f8cccbb29814c52 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 20:19:32 +0200 Subject: [PATCH 075/308] fixing bug in training queue --- freqtrade/freqai/freqai_interface.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 319240248..c09200a30 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -190,7 +190,8 @@ class IFreqaiModel(ABC): trained_timestamp, coin_first) = self.data_drawer.get_pair_dict_info(metadata) - if not self.training_on_separate_thread: + if (not self.training_on_separate_thread and + self.data_drawer.pair_dict[metadata['pair']]['priority'] == 1): file_exists = False if trained_timestamp != 0: # historical model available From d59eac3321f83301079b5a7326096f04ecc66212 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 29 May 2022 21:33:38 +0200 Subject: [PATCH 076/308] revert a79032b --- freqtrade/freqai/freqai_interface.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index c09200a30..4d02afb69 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -190,8 +190,7 @@ class IFreqaiModel(ABC): trained_timestamp, coin_first) = self.data_drawer.get_pair_dict_info(metadata) - if (not self.training_on_separate_thread and - self.data_drawer.pair_dict[metadata['pair']]['priority'] == 1): + if (not self.training_on_separate_thread): file_exists = False if trained_timestamp != 0: # historical model available From 2f1a2c1cd7651ab7f5e4bb16ffc4e8083824ca56 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 30 May 2022 02:12:31 +0200 Subject: [PATCH 077/308] allow users to store data in custom formats, update spot config to reflect better target horizon to training period ratio --- config_examples/config_freqai_spot.example.json | 10 ++++++---- freqtrade/freqai/data_kitchen.py | 6 +++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/config_examples/config_freqai_spot.example.json b/config_examples/config_freqai_spot.example.json index e311fe280..e730335e9 100644 --- a/config_examples/config_freqai_spot.example.json +++ b/config_examples/config_freqai_spot.example.json @@ -7,6 +7,7 @@ "dry_run": true, "timeframe": "5m", "dry_run_wallet": 4000, + "dataformat_ohlcv": "hdf5", "cancel_open_orders_on_exit": true, "unfilledtimeout": { "entry": 10, @@ -24,7 +25,8 @@ "rateLimit": 200 }, "pair_whitelist": [ - "BTC/USDT" + "BTC/USDT", + "ETH/USDT" ], "pair_blacklist": [] }, @@ -39,7 +41,7 @@ } }, "exit_pricing": { - "price_side": "same", + "price_side": "other", "use_order_book": true, "order_book_top": 1 }, @@ -54,7 +56,7 @@ "15m", "4h" ], - "train_period": 30, + "train_period": 60, "backtest_period": 7, "identifier": "example", "live_trained_timestamp": 0, @@ -66,7 +68,7 @@ "SOL/USDT" ], "feature_parameters": { - "period": 20, + "period": 500, "shift": 1, "DI_threshold": 0, "weight_factor": 0.9, diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 08a00c68d..5ab066bfd 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -735,7 +735,7 @@ class FreqaiDataKitchen: exchange, pairs=pairs, timeframes=self.freqai_config.get('timeframes'), datadir=self.config['datadir'], timerange=timerange, new_pairs_days=self.config['new_pairs_days'], - erase=False, data_format=self.config['dataformat_ohlcv'], + erase=False, data_format=self.config.get('dataformat_ohlcv', 'json'), trading_mode=self.config.get('trading_mode', 'spot'), prepend=self.config.get('prepend_data', False) ) @@ -751,6 +751,8 @@ class FreqaiDataKitchen: base_dataframes[tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, pair=metadata['pair'], timerange=timerange, + data_format=self.config.get( + 'dataformat_ohlcv', 'json'), candle_type=self.config.get( 'trading_mode', 'spot')) if pairs: @@ -762,6 +764,8 @@ class FreqaiDataKitchen: corr_dataframes[p][tf] = load_pair_history(datadir=self.config['datadir'], timeframe=tf, pair=p, timerange=timerange, + data_format=self.config.get( + 'dataformat_ohlcv', 'json'), candle_type=self.config.get( 'trading_mode', 'spot')) From a20651efd8f99bef142e1219b4c80d3f2f4283e2 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 30 May 2022 11:37:05 +0200 Subject: [PATCH 078/308] Increase performance by only predicting on most recent candle instead of full strat provided dataframe. Collect predictions and store them so that we can feed true predictions back to strategy (so that frequi isnt updating historic predictions based on newly trained models). --- freqtrade/freqai/data_drawer.py | 26 ++++++++++++++++++++++++++ freqtrade/freqai/data_kitchen.py | 2 +- freqtrade/freqai/freqai_interface.py | 12 ++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 477f45d84..6a5393cb8 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -1,4 +1,5 @@ +import copy import json import logging from pathlib import Path @@ -24,6 +25,7 @@ class FreqaiDataDrawer: self.pair_dict: Dict[str, Any] = {} # dictionary holding all actively inferenced models in memory given a model filename self.model_dictionary: Dict[str, Any] = {} + self.model_return_values: Dict[str, Any] = {} self.pair_data_dict: Dict[str, Any] = {} self.full_path = full_path self.load_drawer_from_disk() @@ -83,3 +85,27 @@ class FreqaiDataDrawer: self.pair_dict[p]['priority'] -= 1 # send pair to end of queue self.pair_dict[pair]['priority'] = len(self.pair_dict) + + def set_initial_return_values(self, pair, dh): + self.model_return_values[pair] = {} + self.model_return_values[pair]['predictions'] = dh.full_predictions + self.model_return_values[pair]['do_preds'] = dh.full_do_predict + self.model_return_values[pair]['target_mean'] = dh.full_target_mean + self.model_return_values[pair]['target_std'] = dh.full_target_std + + def append_model_predictions(self, pair, predictions, do_preds, + target_mean, target_std, dh) -> None: + + pred_store = self.model_return_values[pair]['predictions'] + do_pred_store = self.model_return_values[pair]['do_preds'] + tm_store = self.model_return_values[pair]['target_mean'] + ts_store = self.model_return_values[pair]['target_std'] + pred_store = np.append(pred_store[1:], predictions[-1]) + do_pred_store = np.append(do_pred_store[1:], do_preds[-1]) + tm_store = np.append(tm_store[1:], target_mean) + ts_store = np.append(ts_store[1:], target_std) + + dh.full_predictions = copy.deepcopy(pred_store) + dh.full_do_predict = copy.deepcopy(do_pred_store) + dh.full_target_mean = copy.deepcopy(tm_store) + dh.full_target_std = copy.deepcopy(ts_store) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 5ab066bfd..2b8306b5c 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -623,7 +623,7 @@ class FreqaiDataKitchen: Append backtest prediction from current backtest period to all previous periods """ - ones = np.ones(len_dataframe) + ones = np.ones(len(predictions)) target_mean, target_std = ones * self.data["target_mean"], ones * self.data["target_std"] self.full_predictions = np.append(self.full_predictions, predictions) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 4d02afb69..386fab9fc 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -219,8 +219,16 @@ class IFreqaiModel(ABC): self.check_if_feature_list_matches_strategy(dataframe, dh) - preds, do_preds = self.predict(dataframe, dh) - dh.append_predictions(preds, do_preds, len(dataframe)) + if metadata['pair'] not in self.data_drawer.model_return_values: + preds, do_preds = self.predict(dataframe, dh) + dh.append_predictions(preds, do_preds, len(dataframe)) + dh.fill_predictions(len(dataframe)) + self.data_drawer.set_initial_return_values(metadata['pair'], dh) + else: + preds, do_preds = self.predict(dataframe.iloc[-2:], dh) + self.data_drawer.append_model_predictions(metadata['pair'], preds, do_preds, + self.dh.data["target_mean"], + self.dh.data["target_std"], dh) return dh From e229902381ae21107cf379170ca92acb0cc841a2 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 30 May 2022 12:48:22 +0200 Subject: [PATCH 079/308] fix bug in previous commit --- freqtrade/freqai/data_drawer.py | 5 +++-- freqtrade/freqai/freqai_interface.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 6a5393cb8..5421db6cf 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -86,14 +86,15 @@ class FreqaiDataDrawer: # send pair to end of queue self.pair_dict[pair]['priority'] = len(self.pair_dict) - def set_initial_return_values(self, pair, dh): + def set_initial_return_values(self, pair: str, dh): + self.model_return_values[pair] = {} self.model_return_values[pair]['predictions'] = dh.full_predictions self.model_return_values[pair]['do_preds'] = dh.full_do_predict self.model_return_values[pair]['target_mean'] = dh.full_target_mean self.model_return_values[pair]['target_std'] = dh.full_target_std - def append_model_predictions(self, pair, predictions, do_preds, + def append_model_predictions(self, pair: str, predictions, do_preds, target_mean, target_std, dh) -> None: pred_store = self.model_return_values[pair]['predictions'] diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 386fab9fc..014b80208 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -227,8 +227,8 @@ class IFreqaiModel(ABC): else: preds, do_preds = self.predict(dataframe.iloc[-2:], dh) self.data_drawer.append_model_predictions(metadata['pair'], preds, do_preds, - self.dh.data["target_mean"], - self.dh.data["target_std"], dh) + dh.data["target_mean"], + dh.data["target_std"], dh) return dh From 5b4c649d434801af8485d36c68b89c31814db59f Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 30 May 2022 13:55:46 +0200 Subject: [PATCH 080/308] detect variable sized dataframes coming from strat, adjust our stored/returned data accordingly --- freqtrade/freqai/data_drawer.py | 48 ++++++++++++++++++++-------- freqtrade/freqai/freqai_interface.py | 3 +- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 5421db6cf..fc816ea48 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -95,18 +95,40 @@ class FreqaiDataDrawer: self.model_return_values[pair]['target_std'] = dh.full_target_std def append_model_predictions(self, pair: str, predictions, do_preds, - target_mean, target_std, dh) -> None: + target_mean, target_std, dh, len_df) -> None: - pred_store = self.model_return_values[pair]['predictions'] - do_pred_store = self.model_return_values[pair]['do_preds'] - tm_store = self.model_return_values[pair]['target_mean'] - ts_store = self.model_return_values[pair]['target_std'] - pred_store = np.append(pred_store[1:], predictions[-1]) - do_pred_store = np.append(do_pred_store[1:], do_preds[-1]) - tm_store = np.append(tm_store[1:], target_mean) - ts_store = np.append(ts_store[1:], target_std) + # strat seems to feed us variable sized dataframes - and since we are trying to build our + # own return array in the same shape, we need to figure out how the size has changed + # and adapt our stored/returned info accordingly. + length_difference = len(self.model_return_values[pair]['predictions']) - len_df + i = 0 - dh.full_predictions = copy.deepcopy(pred_store) - dh.full_do_predict = copy.deepcopy(do_pred_store) - dh.full_target_mean = copy.deepcopy(tm_store) - dh.full_target_std = copy.deepcopy(ts_store) + if length_difference == 0: + i = 1 + elif length_difference > 0: + i = length_difference + 1 + + self.model_return_values[pair]['predictions'] = np.append( + self.model_return_values[pair]['predictions'][i:], predictions[-1]) + self.model_return_values[pair]['do_preds'] = np.append( + self.model_return_values[pair]['do_preds'][i:], do_preds[-1]) + self.model_return_values[pair]['target_mean'] = np.append( + self.model_return_values[pair]['target_mean'][i:], target_mean) + self.model_return_values[pair]['target_std'] = np.append( + self.model_return_values[pair]['target_std'][i:], target_std) + + if length_difference < 0: + prepend = np.zeros(abs(length_difference) - 1) + self.model_return_values[pair]['predictions'] = np.insert( + self.model_return_values[pair]['predictions'], 0, prepend) + self.model_return_values[pair]['do_preds'] = np.insert( + self.model_return_values[pair]['do_preds'], 0, prepend) + self.model_return_values[pair]['target_mean'] = np.insert( + self.model_return_values[pair]['target_mean'], 0, prepend) + self.model_return_values[pair]['target_std'] = np.insert( + self.model_return_values[pair]['target_std'], 0, prepend) + + dh.full_predictions = copy.deepcopy(self.model_return_values[pair]['predictions']) + dh.full_do_predict = copy.deepcopy(self.model_return_values[pair]['do_preds']) + dh.full_target_mean = copy.deepcopy(self.model_return_values[pair]['target_mean']) + dh.full_target_std = copy.deepcopy(self.model_return_values[pair]['target_std']) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 014b80208..2831475bb 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -228,7 +228,8 @@ class IFreqaiModel(ABC): preds, do_preds = self.predict(dataframe.iloc[-2:], dh) self.data_drawer.append_model_predictions(metadata['pair'], preds, do_preds, dh.data["target_mean"], - dh.data["target_std"], dh) + dh.data["target_std"], dh, + len(dataframe)) return dh From 606f18e5c1c9043ba0954e215652e33e2413dc88 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 30 May 2022 21:35:48 +0200 Subject: [PATCH 081/308] Add follow_mode feature so that secondary bots can be launched with the same identifier and load models trained by the leader --- .../config_freqai_futures.example.json | 10 +++- .../config_freqai_spot.example.json | 2 +- docs/freqai.md | 20 ++++++- freqtrade/freqai/data_drawer.py | 58 +++++++++++++++++-- freqtrade/freqai/freqai_interface.py | 25 ++++++-- 5 files changed, 99 insertions(+), 16 deletions(-) diff --git a/config_examples/config_freqai_futures.example.json b/config_examples/config_freqai_futures.example.json index cb545acdc..5cd867e53 100644 --- a/config_examples/config_freqai_futures.example.json +++ b/config_examples/config_freqai_futures.example.json @@ -66,7 +66,7 @@ ], "train_period": 20, "backtest_period": 2, - "identifier": "example", + "identifier": "example2", "live_trained_timestamp": 0, "corr_pairlist": [ "BTC/USDT:USDT", @@ -86,8 +86,14 @@ "random_state": 1 }, "model_training_parameters": { - "n_estimators": 1000, + "n_estimators": 200, "task_type": "CPU" } + }, + "bot_name": "", + "force_entry_enable": true, + "initial_state": "running", + "internals": { + "process_throttle_secs": 5 } } diff --git a/config_examples/config_freqai_spot.example.json b/config_examples/config_freqai_spot.example.json index e730335e9..0b4d4e7c5 100644 --- a/config_examples/config_freqai_spot.example.json +++ b/config_examples/config_freqai_spot.example.json @@ -56,7 +56,7 @@ "15m", "4h" ], - "train_period": 60, + "train_period": 30, "backtest_period": 7, "identifier": "example", "live_trained_timestamp": 0, diff --git a/docs/freqai.md b/docs/freqai.md index d6998a8b6..c4ac30415 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -391,7 +391,7 @@ Freqai will train an SVM on the training data (or components if the user activat `principal_component_analysis`) and remove any data point that it deems to be sit beyond the feature space. -## Stratifying the data +### Stratifying the data The user can stratify the training/testing data using: @@ -403,10 +403,26 @@ The user can stratify the training/testing data using: } ``` -which will split the data chronologically so that every X data points is a testing data point. In the +which will split the data chronologically so that every Xth data points is a testing data point. In the present example, the user is asking for every third data point in the dataframe to be used for testing, the other points are used for training. +### Setting up a follower + +The user can define: + +```json + "freqai": { + "follow_mode": true, + "identifier": "example" + } +``` + +to indicate to the bot that it should not train models, but instead should look for models trained +by a leader with the same `identifier`. In this example, the user has a leader bot with the +`identifier: "example"` already running or launching simultaneously as the present follower. +The follower will load models created by the leader and inference them to obtain predictions. + - - ## Additional information ### Common pitfalls FreqAI cannot be combined with `VolumePairlists` (or any pairlist filter that adds and removes pairs dynamically). -This is for performance reasons - FreqAI relies on making quick predictions/retrains. To do this effectively, +This is for performance reasons - FreqAI relies on making quick predictions/retrains. To do this effectively, it needs to download all the training data at the beginning of a dry/live instance. FreqAI stores and appends -new candles automatically for future retrains. But this means that if new pairs arrive later in the dry run due +new candles automatically for future retrains. But this means that if new pairs arrive later in the dry run due to a volume pairlist, it will not have the data ready. FreqAI does work, however, with the `ShufflePairlist`. ### Feature normalization -The feature set created by the user is automatically normalized to the training -data only. This includes all test data and unseen prediction data (dry/live/backtest). +The feature set created by the user is automatically normalized to the training data only. +This includes all test data and unseen prediction data (dry/live/backtest). ### File structure -`user_data_dir/models/` contains all the data associated with the trainings and -backtests. This file structure is heavily controlled and read by the `FreqaiDataKitchen()` -and should thus not be modified. +`user_data_dir/models/` contains all the data associated with the trainings and backtests. +This file structure is heavily controlled and read by the `FreqaiDataKitchen()` +and should therefore not be modified. From 3acc86957016f9727c52d9a5ac5460204c43840b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 23 Jul 2022 12:42:24 +0200 Subject: [PATCH 176/308] improve the dataframe key description, update outdated parts of doc --- docs/freqai.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 1e597696a..04f442778 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -111,16 +111,17 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `learning_rate` | A common parameter among regressors which sets the boosting learning rate.
**Datatype:** float. | `n_jobs`, `thread_count`, `task_type` | Different libraries use different parameter names to control the number of threads used for parallel processing or whether or not it is a `task_type` of `gpu` or `cpu`.
**Datatype:** float. -### Return values for use in strategy -Here are the values you can expect to receive inside the dataframe returned by FreqAI: +### Important FreqAI dataframe key patterns +Here are the values the user can expect to include/use inside the typical strategy dataframe (`df[]`): -| Parameter | Description | +| DataFrame Key | Description | |------------|-------------| -| `&-s*` | user defined labels in the user made strategy. Anything prepended with `&` is treated as a training target inside FreqAI. These same dataframe columns names are fed back to the user as the predictions. For example, the user wishes to predict the price change in the next 40 candles (similar to `templates/FreqaiExampleStrategy.py`) by setting `&-s_close`. FreqAI makes the predictions and gives them back to the user under the same key (`&-s_close`) to be used in `populate_entry/exit_trend()`.
**Datatype:** depends on the output of the model. -| `&-s*_std/mean` | The standard deviation and mean values of the user defined labels during training (or live tracking with `fit_live_predictions_candles`). Commonly used to understand rarity of prediction (use the z-score as shown in `templates/FreqaiExampleStrategy.py` to evaluate how often a particular prediction was observed during training (or historically with `fit_live_predictions_candles`)
**Datatype:** float. -| `do_predict` | An indication of an outlier, this return value is integer between -1 and 2 which lets the user understand if the prediction is trustworthy or not. `do_predict==1` means the prediction is trustworthy. If the [Dissimilarity Index](#removing-outliers-with-the-dissimilarity-index) is above the user defined threshold, it will subtract 1 from `do_predict`. If `use_SVM_to_remove_outliers()` is active, then the Support Vector Machine (SVM) may also detect outliers in training and prediction data. In this case, the SVM will also subtract one from `do_predict`. A particular case is when `do_predict == 2`, it means that the model has expired due to `expired_hours`.
**Datatype:** integer between -1 and 2. -| `DI_values` | The raw Dissimilarity Index values to give the user a sense of confidence in the prediction. Lower DI means the data point is closer to the trained parameter space.
**Datatype:** float. +| `df['&*']` | Any dataframe column prepended with `&` in `populate_any_indicators()` is treated as a training target inside FreqAI (typically following the naming convention `&-s*`). These same dataframe columns names are fed back to the user as the predictions. For example, the user wishes to predict the price change in the next 40 candles (similar to `templates/FreqaiExampleStrategy.py`) by setting `df['&-s_close']`. FreqAI makes the predictions and gives them back to the user under the same key (`df['&-s_close']`) to be used in `populate_entry/exit_trend()`.
**Datatype:** depends on the output of the model. +| `df['&*_std/mean']` | The standard deviation and mean values of the user defined labels during training (or live tracking with `fit_live_predictions_candles`). Commonly used to understand rarity of prediction (use the z-score as shown in `templates/FreqaiExampleStrategy.py` to evaluate how often a particular prediction was observed during training (or historically with `fit_live_predictions_candles`)
**Datatype:** float. +| `df['do_predict']` | An indication of an outlier, this return value is integer between -1 and 2 which lets the user understand if the prediction is trustworthy or not. `do_predict==1` means the prediction is trustworthy. If the [Dissimilarity Index](#removing-outliers-with-the-dissimilarity-index) is above the user defined threshold, it will subtract 1 from `do_predict`. If `use_SVM_to_remove_outliers()` is active, then the Support Vector Machine (SVM) may also detect outliers in training and prediction data. In this case, the SVM will also subtract one from `do_predict`. A particular case is when `do_predict == 2`, it means that the model has expired due to `expired_hours`.
**Datatype:** integer between -1 and 2. +| `df['DI_values']` | The raw Dissimilarity Index values to give the user a sense of confidence in the prediction. Lower DI means the data point is closer to the trained parameter space.
**Datatype:** float. +| `df['%*']` | Any dataframe column prepended with `%` in `populate_any_indicators()` is treated as a training feature inside FreqAI. For example, the user can include the rsi in the training feature set (similar to `templates/FreqaiExampleStrategy.py`) by setting `df['%-rsi']`. See more details on how this is done [here](#building-the-feature-set). Note: since the number of features prepended with `%` can multiply very quickly (10s of thousands of features is easily engineered using the multiplictative functionality described in the `feature_parameters` table.) these features are removed from the dataframe upon return from FreqAI. If the user wishes to keep a particular type of feature for plotting purposes, you can prepend it with `%%`.
**Datatype:** depends on the output of the model. ### Example config file @@ -338,6 +339,9 @@ and adding this to the `train_period_days`. The units need to be in the base can !!! Note In dry/live, this is all precomputed and handled automatically. Thus, `startup_candle` has no influence on dry/live. +!!! Note + Although fractional `backtest_period_days` is allowed, the user should be ware that the `--timerange` is divided by this value to determine the number of models that FreqAI will need to train in order to backtest the full range. For example, if the user wants to set a `--timerange` of 10 days, and asks for a `backtest_period_days` of 0.1, FreqAI will need to train 100 models per pair to complete the full backtest. This is why it is physically impossible to truly backtest FreqAI adaptive training. The best way to fully test a model is to run it dry and let it constantly train. In this case, backtesting would take the exact same amount of time as a dry run. + ## Running Freqai ### Training and backtesting @@ -419,12 +423,7 @@ freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example. ``` By default, Freqai will not find find any existing models and will start by training a new one -given the user configuration settings. Following training, it will use that model to predict for the -duration of `backtest_period_days`. After a full `backtest_period_days` has elapsed, Freqai will auto retrain -a new model, and begin making predictions with the updated model. FreqAI backtesting and live both -permit the user to use fractional days (i.e. 0.1) in the `backtest_period_days`, which enables more frequent -retraining. But the user should be careful that using a fractional `backtest_period_days` with a large -`--timerange` in backtesting will result in a huge amount of required trainings/models. +given the user configuration settings. Following training, it will use that model to make predictions on incoming candles until a new model is available. New models are typically generated as often as possible, with FreqAI managing an internal queue of the pairs to try and keep all models equally "young." FreqAI will always use the newest trained model to make predictions on incoming live data. If users do not want FreqAI to retrain new models as often as possible, they can set `live_retrain_hours` to tell FreqAI to wait at least that number of hours before retraining a new model. Additionally, users can set `expired_hours` to tell FreqAI to avoid making predictions on models aged over this number of hours. If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse the same `identifier` parameter @@ -439,7 +438,6 @@ the same `identifier` parameter In this case, although Freqai will initiate with a pre-trained model, it will still check to see how much time has elapsed since the model was trained, and if a full `live_retrain_hours` has elapsed since the end of the loaded model, FreqAI will self retrain. -It is common to want constant retraining, in which case, the user should set `live_retrain_hours` to 0. ## Data analysis techniques From c2d6a0e891744791a9ad27db216bd141fd8e45d3 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 23 Jul 2022 13:04:06 +0200 Subject: [PATCH 177/308] add record of contribution to doc and source --- docs/freqai.md | 17 +++++++++++++++++ freqtrade/freqai/data_drawer.py | 20 +++++++++++++++++--- freqtrade/freqai/freqai_interface.py | 18 +++++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 04f442778..5072d3721 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -685,3 +685,20 @@ This includes all test data and unseen prediction data (dry/live/backtest). `user_data_dir/models/` contains all the data associated with the trainings and backtests. This file structure is heavily controlled and read by the `FreqaiDataKitchen()` and should therefore not be modified. + +## Credits +FreqAI was developed by a group of individuals who all contributed specific skillsets to the +project. + +Conception and software development: +Robert Caulk @robcaulk + +Theoretical brainstorming: +Elin Törnquist @thorntwig + +Code review, software architecture brainstorming: +@xmatthias + +Beta testing and bug reporting: +@bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm +Juha Nykänen @suikula, Wagner Costa @wagnercosta diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index b0493e766..baaa55c7e 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -13,9 +13,6 @@ from joblib.externals import cloudpickle from pandas import DataFrame -# from freqtrade.freqai.data_kitchen import FreqaiDataKitchen - - logger = logging.getLogger(__name__) @@ -25,6 +22,23 @@ class FreqaiDataDrawer: /loading to/from disk. This object remains persistent throughout live/dry, unlike FreqaiDataKitchen, which is reinstantiated for each coin. + + Record of contribution: + FreqAI was developed by a group of individuals who all contributed specific skillsets to the + project. + + Conception and software development: + Robert Caulk @robcaulk + + Theoretical brainstorming: + Elin Törnquist @thorntwig + + Code review, software architecture brainstorming: + @xmatthias + + Beta testing and bug reporting: + @bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm + Juha Nykänen @suikula, Wagner Costa @wagnercosta """ def __init__(self, full_path: Path, config: dict, follow_mode: bool = False): diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 55f5a03a0..5fa15ebf8 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -38,7 +38,23 @@ class IFreqaiModel(ABC): """ Class containing all tools for training and prediction in the strategy. Base*PredictionModels inherit from this class. - Author: Robert Caulk, rob.caulk@gmail.com + + Record of contribution: + FreqAI was developed by a group of individuals who all contributed specific skillsets to the + project. + + Conception and software development: + Robert Caulk @robcaulk + + Theoretical brainstorming: + Elin Törnquist @thorntwig + + Code review, software architecture brainstorming: + @xmatthias + + Beta testing and bug reporting: + @bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm + Juha Nykänen @suikula, Wagner Costa @wagnercosta """ def __init__(self, config: Dict[str, Any]) -> None: From a1cff377ec7b32046fbe254a29e5ef115c01e4a8 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 23 Jul 2022 13:32:04 +0200 Subject: [PATCH 178/308] add record of contribution to data_kitchen.py --- freqtrade/freqai/data_kitchen.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 4ba6badf9..9662f4f3a 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -35,7 +35,23 @@ class FreqaiDataKitchen: """ Class designed to analyze data for a single pair. Employed by the IFreqaiModel class. Functionalities include holding, saving, loading, and analyzing the data. - author: Robert Caulk, rob.caulk@gmail.com + + Record of contribution: + FreqAI was developed by a group of individuals who all contributed specific skillsets to the + project. + + Conception and software development: + Robert Caulk @robcaulk + + Theoretical brainstorming: + Elin Törnquist @thorntwig + + Code review, software architecture brainstorming: + @xmatthias + + Beta testing and bug reporting: + @bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm + Juha Nykänen @suikula, Wagner Costa @wagnercosta """ def __init__( From 50d630a1555a26251e162aab50102d491d5946d3 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 23 Jul 2022 13:35:44 +0200 Subject: [PATCH 179/308] remove unnecessary comments from data_drawer.py --- freqtrade/freqai/data_drawer.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index baaa55c7e..f9736a498 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -76,7 +76,7 @@ class FreqaiDataDrawer: :returns: exists: bool = whether or not the drawer was located """ - exists = self.pair_dictionary_path.is_file() # resolve().exists() + exists = self.pair_dictionary_path.is_file() if exists: with open(self.pair_dictionary_path, "r") as fp: self.pair_dict = json.load(fp) @@ -96,7 +96,7 @@ class FreqaiDataDrawer: :returns: exists: bool = whether or not the drawer was located """ - exists = self.historic_predictions_path.is_file() # resolve().exists() + exists = self.historic_predictions_path.is_file() if exists: with open(self.historic_predictions_path, "rb") as fp: self.historic_predictions = cloudpickle.load(fp) @@ -143,11 +143,7 @@ class FreqaiDataDrawer: whitelist_pairs = self.config.get("exchange", {}).get("pair_whitelist") - exists = ( - self.follower_dict_path.is_file() - # .resolve() - # .exists() - ) + exists = self.follower_dict_path.is_file() if exists: logger.info("Found an existing follower dictionary") From c91e23dc504e97e9d55b0e2f0636099cce378be2 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 23 Jul 2022 16:14:13 +0200 Subject: [PATCH 180/308] let user avoid normalizing labels --- freqtrade/freqai/data_kitchen.py | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 9662f4f3a..1c54a6375 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -356,7 +356,7 @@ class FreqaiDataKitchen: return self.data_dictionary - def normalize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: + def normalize_data(self, data_dictionary: Dict, do_labels: bool = True) -> Dict[Any, Any]: """ Normalize all data in the data_dictionary according to the training dataset :params: @@ -374,27 +374,28 @@ class FreqaiDataKitchen: 2 * (data_dictionary["test_features"] - train_min) / (train_max - train_min) - 1 ) - train_labels_max = data_dictionary["train_labels"].max() - train_labels_min = data_dictionary["train_labels"].min() - data_dictionary["train_labels"] = ( - 2 - * (data_dictionary["train_labels"] - train_labels_min) - / (train_labels_max - train_labels_min) - - 1 - ) - data_dictionary["test_labels"] = ( - 2 - * (data_dictionary["test_labels"] - train_labels_min) - / (train_labels_max - train_labels_min) - - 1 - ) - for item in train_max.keys(): self.data[item + "_max"] = train_max[item] self.data[item + "_min"] = train_min[item] - self.data["labels_max"] = train_labels_max.to_dict() - self.data["labels_min"] = train_labels_min.to_dict() + if do_labels: + train_labels_max = data_dictionary["train_labels"].max() + train_labels_min = data_dictionary["train_labels"].min() + data_dictionary["train_labels"] = ( + 2 + * (data_dictionary["train_labels"] - train_labels_min) + / (train_labels_max - train_labels_min) + - 1 + ) + data_dictionary["test_labels"] = ( + 2 + * (data_dictionary["test_labels"] - train_labels_min) + / (train_labels_max - train_labels_min) + - 1 + ) + + self.data["labels_max"] = train_labels_max.to_dict() + self.data["labels_min"] = train_labels_min.to_dict() return data_dictionary From 8fa6e8b4ba9edc8db557bba04adf9b0c6aa87741 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jul 2022 15:58:31 +0200 Subject: [PATCH 181/308] Remove freqAI model bridge in favor of `self.freqai` --- freqtrade/freqai/strategy_bridge.py | 12 -------- freqtrade/strategy/interface.py | 9 ++++++ freqtrade/templates/FreqaiExampleStrategy.py | 30 +++++++++----------- tests/strategy/strats/freqai_test_strat.py | 10 ++----- 4 files changed, 25 insertions(+), 36 deletions(-) delete mode 100644 freqtrade/freqai/strategy_bridge.py diff --git a/freqtrade/freqai/strategy_bridge.py b/freqtrade/freqai/strategy_bridge.py deleted file mode 100644 index bb43084a0..000000000 --- a/freqtrade/freqai/strategy_bridge.py +++ /dev/null @@ -1,12 +0,0 @@ -from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver - - -class CustomModel: - """ - A bridge between the user defined IFreqaiModel class - and the strategy. - """ - - def __init__(self, config): - - self.bridge = FreqaiModelResolver.load_freqaimodel(config) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index df73981bd..83d16b6f6 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -145,11 +145,20 @@ class IStrategy(ABC, HyperStrategyMixin): informative_data.candle_type = config['candle_type_def'] self._ft_informative.append((informative_data, cls_method)) + def load_freqAI_model(self) -> None: + if self.config.get('freqai', None): + # Import here to avoid importing this if freqAI is disabled + from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver + + self.freqai = FreqaiModelResolver.load_freqaimodel(self.config) + def ft_bot_start(self, **kwargs) -> None: """ Strategy init - runs after dataprovider has been added. Must call bot_start() """ + self.load_freqAI_model() + strategy_safe_wrapper(self.bot_start)() self.ft_load_hyper_params(self.config.get('runmode') == RunMode.HYPEROPT) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 402aa9d1c..86f141567 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -7,7 +7,6 @@ from pandas import DataFrame from technical import qtpylib from freqtrade.exchange import timeframe_to_prev_date -from freqtrade.freqai.strategy_bridge import CustomModel from freqtrade.persistence import Trade from freqtrade.strategy import DecimalParameter, IntParameter, merge_informative_pair from freqtrade.strategy.interface import IStrategy @@ -21,7 +20,7 @@ class FreqaiExampleStrategy(IStrategy): Example strategy showing how the user connects their own IFreqaiModel to the strategy. Namely, the user uses: self.model = CustomModel(self.config) - self.model.bridge.start(dataframe, metadata) + self.freqai.start(dataframe, metadata) to make predictions on their data. populate_any_indicators() automatically generates the variety of features indicated by the user in the @@ -67,9 +66,6 @@ class FreqaiExampleStrategy(IStrategy): informative_pairs.append((pair, tf)) return informative_pairs - def bot_start(self): - self.model = CustomModel(self.config) - def populate_any_indicators( self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False ): @@ -88,7 +84,7 @@ class FreqaiExampleStrategy(IStrategy): :coin: the name of the coin which will modify the feature names. """ - with self.model.bridge.lock: + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) @@ -180,7 +176,7 @@ class FreqaiExampleStrategy(IStrategy): # the target mean/std values for each of the labels created by user in # `populate_any_indicators()` for each training period. - dataframe = self.model.bridge.start(dataframe, metadata, self) + dataframe = self.freqai.start(dataframe, metadata, self) dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25 dataframe["sell_roi"] = dataframe["&-s_close_mean"] - dataframe["&-s_close_std"] * 1.25 @@ -234,9 +230,9 @@ class FreqaiExampleStrategy(IStrategy): follow_mode = self.config.get("freqai", {}).get("follow_mode", False) if not follow_mode: - pair_dict = self.model.bridge.dd.pair_dict + pair_dict = self.freqai.dd.pair_dict else: - pair_dict = self.model.bridge.dd.follower_dict + pair_dict = self.freqai.dd.follower_dict entry_tag = trade.enter_tag @@ -244,12 +240,12 @@ class FreqaiExampleStrategy(IStrategy): "prediction" + entry_tag not in pair_dict[pair] or pair_dict[pair]["prediction" + entry_tag] > 0 ): - with self.model.bridge.lock: + with self.freqai.lock: pair_dict[pair]["prediction" + entry_tag] = abs(trade_candle["&-s_close"]) if not follow_mode: - self.model.bridge.dd.save_drawer_to_disk() + self.freqai.dd.save_drawer_to_disk() else: - self.model.bridge.dd.save_follower_dict_to_disk() + self.freqai.dd.save_follower_dict_to_disk() roi_price = pair_dict[pair]["prediction" + entry_tag] roi_time = self.max_roi_time_long.value @@ -284,16 +280,16 @@ class FreqaiExampleStrategy(IStrategy): entry_tag = trade.enter_tag follow_mode = self.config.get("freqai", {}).get("follow_mode", False) if not follow_mode: - pair_dict = self.model.bridge.dd.pair_dict + pair_dict = self.freqai.dd.pair_dict else: - pair_dict = self.model.bridge.dd.follower_dict + pair_dict = self.freqai.dd.follower_dict - with self.model.bridge.lock: + with self.freqai.lock: pair_dict[pair]["prediction" + entry_tag] = 0 if not follow_mode: - self.model.bridge.dd.save_drawer_to_disk() + self.freqai.dd.save_drawer_to_disk() else: - self.model.bridge.dd.save_follower_dict_to_disk() + self.freqai.dd.save_follower_dict_to_disk() return True diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index 28e3dce54..221942bd3 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -5,7 +5,6 @@ import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.freqai.strategy_bridge import CustomModel from freqtrade.strategy import DecimalParameter, IntParameter, merge_informative_pair from freqtrade.strategy.interface import IStrategy @@ -18,7 +17,7 @@ class freqai_test_strat(IStrategy): Example strategy showing how the user connects their own IFreqaiModel to the strategy. Namely, the user uses: self.model = CustomModel(self.config) - self.model.bridge.start(dataframe, metadata) + self.freqai.start(dataframe, metadata) to make predictions on their data. populate_any_indicators() automatically generates the variety of features indicated by the user in the @@ -64,9 +63,6 @@ class freqai_test_strat(IStrategy): informative_pairs.append((pair, tf)) return informative_pairs - def bot_start(self): - self.model = CustomModel(self.config) - def populate_any_indicators( self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False ): @@ -85,7 +81,7 @@ class freqai_test_strat(IStrategy): :coin: the name of the coin which will modify the feature names. """ - with self.model.bridge.lock: + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) @@ -146,7 +142,7 @@ class freqai_test_strat(IStrategy): # the model will return 4 values, its prediction, an indication of whether or not the # prediction should be accepted, the target mean/std values from the labels used during # each training period. - dataframe = self.model.bridge.start(dataframe, metadata, self) + dataframe = self.freqai.start(dataframe, metadata, self) dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25 dataframe["sell_roi"] = dataframe["&-s_close_mean"] - dataframe["&-s_close_std"] * 1.25 From 62f7606d2c025e793aa24bd041a9d50a07bd0748 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jul 2022 16:05:25 +0200 Subject: [PATCH 182/308] Update tests to new variant --- tests/freqai/conftest.py | 2 +- tests/freqai/test_freqai_datakitchen.py | 8 ++++---- tests/freqai/test_freqai_interface.py | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index 549ba2663..1d98fd863 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -61,7 +61,7 @@ def get_patched_data_kitchen(mocker, freqaiconf): def get_patched_freqai_strategy(mocker, freqaiconf): strategy = StrategyResolver.load_strategy(freqaiconf) - strategy.bot_start() + strategy.ft_bot_start() return strategy diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index 1964d1423..d0d82b489 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -69,7 +69,7 @@ def test_update_historic_data(mocker, default_conf): strategy = get_patched_freqai_strategy(mocker, freqaiconf) exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") @@ -105,7 +105,7 @@ def test_load_all_pairs_histories(mocker, default_conf): strategy = get_patched_freqai_strategy(mocker, freqaiconf) exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") @@ -125,7 +125,7 @@ def test_get_base_and_corr_dataframes(mocker, default_conf): strategy = get_patched_freqai_strategy(mocker, freqaiconf) exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") @@ -153,7 +153,7 @@ def test_use_strategy_to_populate_indicators(mocker, default_conf): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 9219baee3..e812dd47e 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -21,7 +21,7 @@ def test_train_model_in_series_LightGBM(mocker, default_conf): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") @@ -113,7 +113,7 @@ def test_start_backtesting(mocker, default_conf): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = False freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") @@ -139,7 +139,7 @@ def test_start_backtesting_from_existing_folder(mocker, default_conf, caplog): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = False freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") @@ -162,7 +162,7 @@ def test_start_backtesting_from_existing_folder(mocker, default_conf, caplog): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = False freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") From 8a3cffcd1b80882d296c877d6b05198d3efacac5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jul 2022 16:06:46 +0200 Subject: [PATCH 183/308] Remove remaining CustomModel references --- docs/freqai.md | 12 ++++-------- freqtrade/templates/FreqaiExampleStrategy.py | 1 - tests/freqai/conftest.py | 6 +++--- tests/strategy/strats/freqai_test_strat.py | 1 - 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 5072d3721..48b8968a3 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -166,7 +166,7 @@ config setup includes: Features are added by the user inside the `populate_any_indicators()` method of the strategy by prepending indicators with `%` and labels are added by prepending `&`. There are some important components/structures that the user *must* include when building their feature set. -As shown below, `with self.model.bridge.lock:` must be used to ensure thread safety - especially when using third +As shown below, `with self.freqai.lock:` must be used to ensure thread safety - especially when using third party libraries for indicator construction such as TA-lib. Another structure to consider is the location of the labels at the bottom of the example function (below `if set_generalized_indicators:`). This is where the user will add single features and labels to their feature set to avoid duplication from @@ -191,7 +191,7 @@ various configuration parameters which multiply the feature set such as `include :coin: the name of the coin which will modify the feature names. """ - with self.model.bridge.lock: + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) @@ -370,7 +370,6 @@ for each pair, for each backtesting window within the bigger `--timerange`. The Freqai strategy requires the user to include the following lines of code in the strategy: ```python - from freqtrade.freqai.strategy_bridge import CustomModel def informative_pairs(self): whitelist_pairs = self.dp.current_whitelist() @@ -385,9 +384,6 @@ The Freqai strategy requires the user to include the following lines of code in informative_pairs.append((pair, tf)) return informative_pairs - def bot_start(self): - self.model = CustomModel(self.config) - def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: self.freqai_info = self.config["freqai"] @@ -400,7 +396,7 @@ The Freqai strategy requires the user to include the following lines of code in # the target mean/std values for each of the labels created by user in # `populate_any_indicators()` for each training period. - dataframe = self.model.bridge.start(dataframe, metadata, self) + dataframe = self.freqai.start(dataframe, metadata, self) return dataframe ``` @@ -648,7 +644,7 @@ below this value. An example usage in the strategy may look something like: dataframe["do_predict"], dataframe["target_upper_quantile"], dataframe["target_lower_quantile"], - ) = self.model.bridge.start(dataframe, metadata, self) + ) = self.freqai.start(dataframe, metadata, self) return dataframe diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 86f141567..b3c2cc8d7 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -19,7 +19,6 @@ class FreqaiExampleStrategy(IStrategy): """ Example strategy showing how the user connects their own IFreqaiModel to the strategy. Namely, the user uses: - self.model = CustomModel(self.config) self.freqai.start(dataframe, metadata) to make predictions on their data. populate_any_indicators() automatically diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index 1d98fd863..1d0ea0e54 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -76,7 +76,7 @@ def get_freqai_live_analyzed_dataframe(mocker, freqaiconf): strategy = get_patched_freqai_strategy(mocker, freqaiconf) exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") @@ -91,7 +91,7 @@ def get_freqai_analyzed_dataframe(mocker, freqaiconf): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") @@ -107,7 +107,7 @@ def get_ready_to_train(mocker, freqaiconf): exchange = get_patched_exchange(mocker, freqaiconf) strategy.dp = DataProvider(freqaiconf, exchange) strategy.freqai_info = freqaiconf.get("freqai", {}) - freqai = strategy.model.bridge + freqai = strategy.freqai freqai.live = True freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index 221942bd3..49f00d6e2 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -16,7 +16,6 @@ class freqai_test_strat(IStrategy): """ Example strategy showing how the user connects their own IFreqaiModel to the strategy. Namely, the user uses: - self.model = CustomModel(self.config) self.freqai.start(dataframe, metadata) to make predictions on their data. populate_any_indicators() automatically From 81c1aa3c13cdc674cb6e34f16287a2c83481a94b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jul 2022 16:14:11 +0200 Subject: [PATCH 184/308] Update imports in freqAI sample strategies --- freqtrade/templates/FreqaiExampleStrategy.py | 3 +-- tests/strategy/strats/freqai_test_strat.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index b3c2cc8d7..7008008a3 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -8,8 +8,7 @@ from technical import qtpylib from freqtrade.exchange import timeframe_to_prev_date from freqtrade.persistence import Trade -from freqtrade.strategy import DecimalParameter, IntParameter, merge_informative_pair -from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair logger = logging.getLogger(__name__) diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index 49f00d6e2..8679d4d74 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -5,8 +5,7 @@ import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.strategy import DecimalParameter, IntParameter, merge_informative_pair -from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair logger = logging.getLogger(__name__) From f3d46613ee501888defb30926cd1f1b3a610e93b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 23 Jul 2022 17:14:11 +0200 Subject: [PATCH 185/308] move prediction denormalization into datakitchen. remove duplicate associated code. avoid normalization/denormalization for string dtypes. --- freqtrade/freqai/data_kitchen.py | 37 +++++++++++++++---- freqtrade/freqai/freqai_interface.py | 8 +--- .../prediction_models/BaseRegressionModel.py | 7 +--- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 1c54a6375..3899c82df 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -356,7 +356,7 @@ class FreqaiDataKitchen: return self.data_dictionary - def normalize_data(self, data_dictionary: Dict, do_labels: bool = True) -> Dict[Any, Any]: + def normalize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: """ Normalize all data in the data_dictionary according to the training dataset :params: @@ -378,24 +378,26 @@ class FreqaiDataKitchen: self.data[item + "_max"] = train_max[item] self.data[item + "_min"] = train_min[item] - if do_labels: - train_labels_max = data_dictionary["train_labels"].max() - train_labels_min = data_dictionary["train_labels"].min() + for item in data_dictionary["train_labels"].keys(): + if data_dictionary["train_labels"][item].dtype == str: + continue + train_labels_max = data_dictionary["train_labels"][item].max() + train_labels_min = data_dictionary["train_labels"][item].min() data_dictionary["train_labels"] = ( 2 - * (data_dictionary["train_labels"] - train_labels_min) + * (data_dictionary["train_labels"][item] - train_labels_min) / (train_labels_max - train_labels_min) - 1 ) - data_dictionary["test_labels"] = ( + data_dictionary["test_labels"][item] = ( 2 * (data_dictionary["test_labels"] - train_labels_min) / (train_labels_max - train_labels_min) - 1 ) - self.data["labels_max"] = train_labels_max.to_dict() - self.data["labels_min"] = train_labels_min.to_dict() + self.data[f"{item}_max"] = train_labels_max # .to_dict() + self.data[f"{item}_min"] = train_labels_min # .to_dict() return data_dictionary @@ -417,6 +419,25 @@ class FreqaiDataKitchen: return df + def denormalize_labels_from_metadata(self, df: DataFrame) -> DataFrame: + """ + Normalize a set of data using the mean and standard deviation from + the associated training data. + :params: + :df: Dataframe of predictions to be denormalized + """ + + for label in self.label_list: + if df[label].dtype == str: + continue + df[label] = ( + (df[label] + 1) + * (self.data[f"{label}_max"] - self.data[f"{label}_min"]) + / 2 + ) + self.data[f"{label}_min"] + + return df + def split_timerange( self, tr: str, train_split: int = 28, bt_split: int = 7 ) -> Tuple[list, list]: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 5fa15ebf8..ac8cf6e60 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -501,12 +501,8 @@ class IFreqaiModel(ABC): ) -> None: trained_predictions = model.predict(df) pred_df = DataFrame(trained_predictions, columns=dk.label_list) - for label in dk.label_list: - pred_df[label] = ( - (pred_df[label] + 1) - * (dk.data["labels_max"][label] - dk.data["labels_min"][label]) - / 2 - ) + dk.data["labels_min"][label] + + pred_df = dk.denormalize_labels_from_metadata(pred_df) self.dd.historic_predictions[pair] = pd.DataFrame() self.dd.historic_predictions[pair] = copy.deepcopy(pred_df) diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index ffe30ef2a..2654b3726 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -107,11 +107,6 @@ class BaseRegressionModel(IFreqaiModel): predictions = self.model.predict(dk.data_dictionary["prediction_features"]) pred_df = DataFrame(predictions, columns=dk.label_list) - for label in dk.label_list: - pred_df[label] = ( - (pred_df[label] + 1) - * (dk.data["labels_max"][label] - dk.data["labels_min"][label]) - / 2 - ) + dk.data["labels_min"][label] + pred_df = dk.denormalize_labels_from_metadata(pred_df) return (pred_df, dk.do_predict) From 95f5218ceb49540f2f3110c907db1335d5085f52 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jul 2022 07:32:13 +0200 Subject: [PATCH 186/308] Reenable Catboost test (#7118) * Reenable Catboost test * Simplify freqAI tests, ensure they use a tempdir for modelstorage --- tests/freqai/conftest.py | 7 +- tests/freqai/test_freqai_datakitchen.py | 79 +++++++------- tests/freqai/test_freqai_interface.py | 130 ++++++++++-------------- 3 files changed, 96 insertions(+), 120 deletions(-) diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index 1d0ea0e54..ede991240 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -2,6 +2,8 @@ from copy import deepcopy from pathlib import Path from unittest.mock import MagicMock +import pytest + from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider from freqtrade.freqai.data_kitchen import FreqaiDataKitchen @@ -10,13 +12,14 @@ from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver from tests.conftest import get_patched_exchange -# @pytest.fixture(scope="function") -def freqai_conf(default_conf): +@pytest.fixture(scope="function") +def freqai_conf(default_conf, tmpdir): freqaiconf = deepcopy(default_conf) freqaiconf.update( { "datadir": Path(default_conf["datadir"]), "strategy": "freqai_test_strat", + "user_data_dir": Path(tmpdir), "strategy-path": "freqtrade/tests/strategy/strats", "freqaimodel": "LightGBMPredictionModel", "freqaimodel_path": "freqai/prediction_models", diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index d0d82b489..ee1d83982 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -1,6 +1,3 @@ -# from unittest.mock import MagicMock -# from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_edge -import copy import datetime import shutil from pathlib import Path @@ -13,7 +10,7 @@ from freqtrade.data.dataprovider import DataProvider from freqtrade.exceptions import OperationalException from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from tests.conftest import get_patched_exchange -from tests.freqai.conftest import freqai_conf, get_patched_data_kitchen, get_patched_freqai_strategy +from tests.freqai.conftest import get_patched_data_kitchen, get_patched_freqai_strategy @pytest.mark.parametrize( @@ -24,15 +21,15 @@ from tests.freqai.conftest import freqai_conf, get_patched_data_kitchen, get_pat ], ) def test_create_fulltimerange( - timerange, train_period_days, expected_result, default_conf, mocker, caplog + timerange, train_period_days, expected_result, freqai_conf, mocker, caplog ): - dk = get_patched_data_kitchen(mocker, freqai_conf(copy.deepcopy(default_conf))) + dk = get_patched_data_kitchen(mocker, freqai_conf) assert dk.create_fulltimerange(timerange, train_period_days) == expected_result shutil.rmtree(Path(dk.full_path)) -def test_create_fulltimerange_incorrect_backtest_period(mocker, default_conf): - dk = get_patched_data_kitchen(mocker, freqai_conf(copy.deepcopy(default_conf))) +def test_create_fulltimerange_incorrect_backtest_period(mocker, freqai_conf): + dk = get_patched_data_kitchen(mocker, freqai_conf) with pytest.raises(OperationalException, match=r"backtest_period_days must be an integer"): dk.create_fulltimerange("20220101-20220201", 0.5) with pytest.raises(OperationalException, match=r"backtest_period_days must be positive"): @@ -49,11 +46,10 @@ def test_create_fulltimerange_incorrect_backtest_period(mocker, default_conf): ], ) def test_split_timerange( - mocker, default_conf, timerange, train_period_days, backtest_period_days, expected_result + mocker, freqai_conf, timerange, train_period_days, backtest_period_days, expected_result ): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - freqaiconf.update({"timerange": "20220101-20220401"}) - dk = get_patched_data_kitchen(mocker, freqaiconf) + freqai_conf.update({"timerange": "20220101-20220401"}) + dk = get_patched_data_kitchen(mocker, freqai_conf) tr_list, bt_list = dk.split_timerange(timerange, train_period_days, backtest_period_days) assert len(tr_list) == len(bt_list) == expected_result @@ -64,14 +60,13 @@ def test_split_timerange( shutil.rmtree(Path(dk.full_path)) -def test_update_historic_data(mocker, default_conf): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) +def test_update_historic_data(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") freqai.dk.load_all_pair_histories(timerange) @@ -93,69 +88,65 @@ def test_update_historic_data(mocker, default_conf): (datetime.datetime.now(tz=datetime.timezone.utc).timestamp(), False), ], ) -def test_check_if_model_expired(mocker, default_conf, timestamp, expected): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - dk = get_patched_data_kitchen(mocker, freqaiconf) +def test_check_if_model_expired(mocker, freqai_conf, timestamp, expected): + dk = get_patched_data_kitchen(mocker, freqai_conf) assert dk.check_if_model_expired(timestamp) == expected shutil.rmtree(Path(dk.full_path)) -def test_load_all_pairs_histories(mocker, default_conf): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) +def test_load_all_pairs_histories(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") freqai.dk.load_all_pair_histories(timerange) assert len(freqai.dd.historic_data.keys()) == len( - freqaiconf.get("exchange", {}).get("pair_whitelist") + freqai_conf.get("exchange", {}).get("pair_whitelist") ) assert len(freqai.dd.historic_data["ADA/BTC"]) == len( - freqaiconf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") + freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") ) shutil.rmtree(Path(freqai.dk.full_path)) -def test_get_base_and_corr_dataframes(mocker, default_conf): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) +def test_get_base_and_corr_dataframes(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") freqai.dk.load_all_pair_histories(timerange) sub_timerange = TimeRange.parse_timerange("20180111-20180114") corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") num_tfs = len( - freqaiconf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") + freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") ) assert len(base_df.keys()) == num_tfs assert len(corr_df.keys()) == len( - freqaiconf.get("freqai", {}).get("feature_parameters", {}).get("include_corr_pairlist") + freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_corr_pairlist") ) assert len(corr_df["ADA/BTC"].keys()) == num_tfs shutil.rmtree(Path(freqai.dk.full_path)) -def test_use_strategy_to_populate_indicators(mocker, default_conf): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) - strategy.freqai_info = freqaiconf.get("freqai", {}) +def test_use_strategy_to_populate_indicators(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180114") freqai.dk.load_all_pair_histories(timerange) sub_timerange = TimeRange.parse_timerange("20180111-20180114") diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index e812dd47e..0bb2dac79 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -1,29 +1,29 @@ # from unittest.mock import MagicMock # from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_edge -import copy -# import platform +import platform import shutil from pathlib import Path from unittest.mock import MagicMock +import pytest + from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from tests.conftest import get_patched_exchange, log_has_re -from tests.freqai.conftest import freqai_conf, get_patched_freqai_strategy +from tests.freqai.conftest import get_patched_freqai_strategy -def test_train_model_in_series_LightGBM(mocker, default_conf): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - freqaiconf.update({"timerange": "20180110-20180130"}) +def test_train_model_in_series_LightGBM(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180110-20180130"}) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) - strategy.freqai_info = freqaiconf.get("freqai", {}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dk.load_all_pair_histories(timerange) @@ -58,64 +58,47 @@ def test_train_model_in_series_LightGBM(mocker, default_conf): shutil.rmtree(Path(freqai.dk.full_path)) -# FIXME: hits segfault -# @pytest.mark.skipif("arm" in platform.uname()[-1], reason="no ARM..") -# def test_train_model_in_series_Catboost(mocker, default_conf): -# freqaiconf = freqai_conf(copy.deepcopy(default_conf)) -# freqaiconf.update({"timerange": "20180110-20180130"}) -# freqaiconf.update({"freqaimodel": "CatboostPredictionModel"}) -# strategy = get_patched_freqai_strategy(mocker, freqaiconf) -# exchange = get_patched_exchange(mocker, freqaiconf) -# strategy.dp = DataProvider(freqaiconf, exchange) -# strategy.freqai_info = freqaiconf.get("freqai", {}) -# freqai = strategy.model.bridge -# freqai.live = True -# freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) -# timerange = TimeRange.parse_timerange("20180110-20180130") -# freqai.dk.load_all_pair_histories(timerange) +@pytest.mark.skipif("arm" in platform.uname()[-1], reason="no ARM for Catboost ...") +def test_train_model_in_series_Catboost(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180110-20180130"}) + freqai_conf.update({"freqaimodel": "CatboostPredictionModel"}) + del freqai_conf['freqai']['model_training_parameters']['verbosity'] + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) -# freqai.dd.pair_dict = MagicMock() + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + timerange = TimeRange.parse_timerange("20180110-20180130") + freqai.dk.load_all_pair_histories(timerange) -# data_load_timerange = TimeRange.parse_timerange("20180110-20180130") -# new_timerange = TimeRange.parse_timerange("20180120-20180130") + freqai.dd.pair_dict = MagicMock() -# freqai.train_model_in_series(new_timerange, "ADA/BTC", -# strategy, freqai.dk, data_load_timerange) + data_load_timerange = TimeRange.parse_timerange("20180110-20180130") + new_timerange = TimeRange.parse_timerange("20180120-20180130") -# assert ( -# Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_model.joblib")) -# .resolve() -# .exists() -# ) -# assert ( -# Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_metadata.json")) -# .resolve() -# .exists() -# ) -# assert ( -# Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_trained_df.pkl")) -# .resolve() -# .exists() -# ) -# assert ( -# Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_svm_model.joblib")) -# .resolve() -# .exists() -# ) + freqai.train_model_in_series(new_timerange, "ADA/BTC", + strategy, freqai.dk, data_load_timerange) -# shutil.rmtree(Path(freqai.dk.full_path)) + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").exists() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").exists() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").exists() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").exists() + + shutil.rmtree(Path(freqai.dk.full_path)) -def test_start_backtesting(mocker, default_conf): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - freqaiconf.update({"timerange": "20180120-20180130"}) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) - strategy.freqai_info = freqaiconf.get("freqai", {}) +def test_start_backtesting(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180120-20180130"}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dk.load_all_pair_histories(timerange) sub_timerange = TimeRange.parse_timerange("20180110-20180130") @@ -132,16 +115,15 @@ def test_start_backtesting(mocker, default_conf): shutil.rmtree(Path(freqai.dk.full_path)) -def test_start_backtesting_from_existing_folder(mocker, default_conf, caplog): - freqaiconf = freqai_conf(copy.deepcopy(default_conf)) - freqaiconf.update({"timerange": "20180120-20180130"}) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) - strategy.freqai_info = freqaiconf.get("freqai", {}) +def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): + freqai_conf.update({"timerange": "20180120-20180130"}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dk.load_all_pair_histories(timerange) sub_timerange = TimeRange.parse_timerange("20180110-20180130") @@ -157,14 +139,14 @@ def test_start_backtesting_from_existing_folder(mocker, default_conf, caplog): # without deleting the exiting folder structure, re-run - freqaiconf.update({"timerange": "20180120-20180130"}) - strategy = get_patched_freqai_strategy(mocker, freqaiconf) - exchange = get_patched_exchange(mocker, freqaiconf) - strategy.dp = DataProvider(freqaiconf, exchange) - strategy.freqai_info = freqaiconf.get("freqai", {}) + freqai_conf.update({"timerange": "20180120-20180130"}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqaiconf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dk.load_all_pair_histories(timerange) sub_timerange = TimeRange.parse_timerange("20180110-20180130") From fff39eff9edf8a33a094e78a4f0f6b68259b5ec8 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Sun, 24 Jul 2022 08:42:50 +0200 Subject: [PATCH 187/308] fix multitarget bug --- freqtrade/freqai/data_kitchen.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 3899c82df..569cc0c22 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -383,7 +383,7 @@ class FreqaiDataKitchen: continue train_labels_max = data_dictionary["train_labels"][item].max() train_labels_min = data_dictionary["train_labels"][item].min() - data_dictionary["train_labels"] = ( + data_dictionary["train_labels"][item] = ( 2 * (data_dictionary["train_labels"][item] - train_labels_min) / (train_labels_max - train_labels_min) @@ -391,14 +391,13 @@ class FreqaiDataKitchen: ) data_dictionary["test_labels"][item] = ( 2 - * (data_dictionary["test_labels"] - train_labels_min) + * (data_dictionary["test_labels"][item] - train_labels_min) / (train_labels_max - train_labels_min) - 1 ) self.data[f"{item}_max"] = train_labels_max # .to_dict() self.data[f"{item}_min"] = train_labels_min # .to_dict() - return data_dictionary def normalize_data_from_metadata(self, df: DataFrame) -> DataFrame: @@ -412,8 +411,8 @@ class FreqaiDataKitchen: for item in df.keys(): df[item] = ( 2 - * (df[item] - self.data[item + "_min"]) - / (self.data[item + "_max"] - self.data[item + "_min"]) + * (df[item] - self.data[f"{item}_min"]) + / (self.data[f"{item}_max"] - self.data[f"{item}_min"]) - 1 ) From 88e10f73065c53f847aa17a932c98d9239e5f505 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Sun, 24 Jul 2022 09:01:23 +0200 Subject: [PATCH 188/308] add exception for not passing timerange. Remove hard coded arguments for CatboostPredictionModels. Update docs --- docs/freqai.md | 2 +- freqtrade/freqai/data_kitchen.py | 3 +++ freqtrade/freqai/prediction_models/CatboostPredictionModel.py | 2 -- .../freqai/prediction_models/CatboostPredictionMultiModel.py | 3 --- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 48b8968a3..b2ee2407a 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -83,7 +83,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `backtest_period_days` | **Required.** Number of days to inference into the trained model before sliding the window and retraining. This can be fractional days, but beware that the user provided `timerange` will be divided by this number to yield the number of trainings necessary to complete the backtest.
**Datatype:** Float. | `live_retrain_hours` | Frequency of retraining during dry/live runs. Default set to 0, which means it will retrain as often as possible. **Datatype:** Float > 0. | `follow_mode` | If true, this instance of FreqAI will look for models associated with `identifier` and load those for inferencing. A `follower` will **not** train new models. `False` by default.
**Datatype:** boolean. -| `live_trained_timestamp` | Useful if user wants to start from models trained during a *backtest*. The timestamp can be located in the `user_data/models` backtesting folder. This is not a commonly used parameter, leave undefined for most applications.
**Datatype:** positive integer. +| `startup_candles` | Number of candles needed for *backtesting only* to ensure all indicators are non NaNs at the start of the first train period.
**Datatype:** positive integer. | `fit_live_predictions_candles` | Computes target (label) statistics from prediction data, instead of from the training data set. Number of candles is the number of historical candles it uses to generate the statistics.
**Datatype:** positive integer. | `purge_old_models` | Tell FreqAI to delete obsolete models. Otherwise, all historic models will remain on disk. Defaults to `False`.
**Datatype:** boolean. | `expiration_hours` | Ask FreqAI to avoid making predictions if a model is more than `expiration_hours` old. Defaults to 0 which means models never expire.
**Datatype:** positive integer. diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 569cc0c22..e732649ff 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -76,6 +76,9 @@ class FreqaiDataKitchen: self.keras = self.freqai_config.get("keras", False) self.set_all_pairs() if not self.live: + if not self.config["timerange"]: + raise OperationalException( + 'Please pass --timerange if you intend to use FreqAI for backtesting.') self.full_timerange = self.create_fulltimerange( self.config["timerange"], self.freqai_config.get("train_period_days") ) diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index fafb12abe..c69602025 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -38,8 +38,6 @@ class CatboostPredictionModel(BaseRegressionModel): model = CatBoostRegressor( allow_writing_files=False, - verbose=100, - early_stopping_rounds=400, **self.model_training_parameters, ) model.fit(X=train_data, eval_set=test_data) diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py index becfb43eb..1b91fe0c6 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py @@ -27,9 +27,6 @@ class CatboostPredictionMultiModel(BaseRegressionModel): cbr = CatBoostRegressor( allow_writing_files=False, - gpu_ram_part=0.5, - verbose=100, - early_stopping_rounds=400, **self.model_training_parameters, ) From 70b7a254afdd701a9dd2a2d35c65668abac6088e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jul 2022 16:51:48 +0200 Subject: [PATCH 189/308] Update some areas to use default docstring formatting --- docs/freqai.md | 11 ++- freqtrade/freqai/data_drawer.py | 22 +++--- freqtrade/freqai/freqai_interface.py | 75 +++++++++----------- freqtrade/strategy/interface.py | 11 ++- freqtrade/templates/FreqaiExampleStrategy.py | 11 ++- 5 files changed, 59 insertions(+), 71 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index b2ee2407a..4060b5394 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -183,12 +183,11 @@ various configuration parameters which multiply the feature set such as `include (see convention below). I.e. user should not prepend any supporting metrics (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the model. - :params: - :pair: pair to be used as informative - :df: strategy dataframe which will receive merges from informatives - :tf: timeframe of the dataframe which will modify the feature names - :informative: the dataframe associated with the informative pair - :coin: the name of the coin which will modify the feature names. + :param pair: pair to be used as informative + :param df: strategy dataframe which will receive merges from informatives + :param tf: timeframe of the dataframe which will modify the feature names + :param informative: the dataframe associated with the informative pair + :param coin: the name of the coin which will modify the feature names. """ with self.freqai.lock: diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index f9736a498..e18ecdbed 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -163,13 +163,12 @@ class FreqaiDataDrawer: Locate and load existing model metadata from persistent storage. If not located, create a new one and append the current pair to it and prepare it for its first training - :params: - metadata: dict = strategy furnished pair metadata - :returns: - model_filename: str = unique filename used for loading persistent objects from disk - trained_timestamp: int = the last time the coin was trained - coin_first: bool = If the coin is fresh without metadata - return_null_array: bool = Follower could not find pair metadata + :param pair: str: pair to lookup + :return: + model_filename: str = unique filename used for loading persistent objects from disk + trained_timestamp: int = the last time the coin was trained + coin_first: bool = If the coin is fresh without metadata + return_null_array: bool = Follower could not find pair metadata """ pair_in_dict = self.pair_dict.get(pair) data_path_set = self.pair_dict.get(pair, {}).get("data_path", None) @@ -277,13 +276,12 @@ class FreqaiDataDrawer: ) df = pd.concat([prepend_df, df], axis=0) - def attach_return_values_to_return_dataframe(self, pair: str, dataframe) -> DataFrame: + def attach_return_values_to_return_dataframe( + self, pair: str, dataframe: DataFrame) -> DataFrame: """ Attach the return values to the strat dataframe - :params: - dataframe: DataFrame = strat dataframe - :returns: - dataframe: DataFrame = strat dataframe with return values attached + :param dataframe: DataFrame = strategy dataframe + :return: DataFrame = strat dataframe with return values attached """ df = self.model_return_values[pair] to_keep = [col for col in dataframe.columns if not col.startswith("&")] diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index ac8cf6e60..b88923285 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -129,8 +129,7 @@ class IFreqaiModel(ABC): Function designed to constantly scan pairs for retraining on a separate thread (intracandle) to improve model youth. This function is agnostic to data preparation/collection/storage, it simply trains on what ever data is available in the self.dd. - :params: - strategy: IStrategy = The user defined strategy class + :param strategy: IStrategy = The user defined strategy class """ while 1: time.sleep(1) @@ -164,12 +163,11 @@ class IFreqaiModel(ABC): following the training window). FreqAI slides the window and sequentially builds the backtesting results before returning the concatenated results for the full backtesting period back to the strategy. - :params: - dataframe: DataFrame = strategy passed dataframe - metadata: Dict = pair metadata - dk: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only - :returns: - dk: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + :param dataframe: DataFrame = strategy passed dataframe + :param metadata: Dict = pair metadata + :param dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only + :return: + FreqaiDataKitchen = Data management/analysis tool associated to present pair only """ self.pair_it += 1 @@ -239,13 +237,12 @@ class IFreqaiModel(ABC): """ The main broad execution for dry/live. This function will check if a retraining should be performed, and if so, retrain and reset the model. - :params: - dataframe: DataFrame = strategy passed dataframe - metadata: Dict = pair metadata - strategy: IStrategy = currently employed strategy - dk: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + :param dataframe: DataFrame = strategy passed dataframe + :param metadata: Dict = pair metadata + :param strategy: IStrategy = currently employed strategy + dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only :returns: - dk: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only """ # update follower @@ -353,9 +350,9 @@ class IFreqaiModel(ABC): """ Ensure user is passing the proper feature set if they are reusing an `identifier` pointing to a folder holding existing models. - :params: - dataframe: DataFrame = strategy provided dataframe - dk: FreqaiDataKitchen = non-persistent data container/analyzer for current coin/bot loop + :param dataframe: DataFrame = strategy provided dataframe + :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: @@ -461,13 +458,14 @@ class IFreqaiModel(ABC): """ Retreive data and train model in single threaded mode (only used if model directory is empty upon startup for dry/live ) - :params: - new_trained_timerange: TimeRange = the timerange to train the model on - metadata: dict = strategy provided metadata - strategy: IStrategy = user defined strategy object - dk: FreqaiDataKitchen = non-persistent data container for current coin/loop - data_load_timerange: TimeRange = the amount of data to be loaded for populate_any_indicators - (larger than new_trained_timerange so that new_trained_timerange does not contain any NaNs) + :param new_trained_timerange: TimeRange = the timerange to train the model on + :param metadata: dict = strategy provided metadata + :param strategy: IStrategy = user defined strategy object + :param dk: FreqaiDataKitchen = non-persistent data container for current coin/loop + :param data_load_timerange: TimeRange = the amount of data to be loaded + for populate_any_indicators + (larger than new_trained_timerange so that + new_trained_timerange does not contain any NaNs) """ corr_dataframes, base_dataframes = dk.get_base_and_corr_dataframes( @@ -515,11 +513,9 @@ class IFreqaiModel(ABC): """ Filter the training data and train a model to it. Train makes heavy use of the datahandler for storing, saving, loading, and analyzing the data. - :params: - :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. - :returns: - :model: Trained model which can be used to inference (self.predict) + :param unfiltered_dataframe: Full dataframe for the current training period + :param metadata: pair metadata from strategy. + :return: Trained model which can be used to inference (self.predict) """ @abstractmethod @@ -528,9 +524,8 @@ class IFreqaiModel(ABC): Most regressors use the same function names and arguments e.g. user can drop in LGBMRegressor in place of CatBoostRegressor and all data management will be properly handled by Freqai. - :params: - data_dictionary: Dict = the dictionary constructed by DataHandler to hold - all the training and test data/labels. + :param data_dictionary: Dict = the dictionary constructed by DataHandler to hold + all the training and test data/labels. """ return @@ -541,9 +536,9 @@ class IFreqaiModel(ABC): ) -> Tuple[DataFrame, npt.ArrayLike]: """ Filter the prediction features data and predict with it. - :param: - unfiltered_dataframe: Full dataframe for the current backtest period. - dk: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only + :param unfiltered_dataframe: Full dataframe for the current backtest period. + :param dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only + :param first: boolean = whether this is the first prediction or not. :return: :predictions: np.array of predictions :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove @@ -554,12 +549,10 @@ class IFreqaiModel(ABC): def return_values(self, dataframe: DataFrame, dk: FreqaiDataKitchen) -> DataFrame: """ User defines the dataframe to be returned to strategy here. - :params: - dataframe: DataFrame = the full dataframe for the current prediction (live) - or --timerange (backtesting) - dk: FreqaiDataKitchen = Data management/analysis tool assoicated to present pair only - :returns: - dataframe: DataFrame = dataframe filled with user defined data + :param dataframe: DataFrame = the full dataframe for the current prediction (live) + or --timerange (backtesting) + :param dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only + :return: dataframe: DataFrame = dataframe filled with user defined data """ return diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 83d16b6f6..431e67a98 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -566,12 +566,11 @@ class IStrategy(ABC, HyperStrategyMixin): additional features here, but must follow the naming convention. This method is *only* used in FreqaiDataKitchen class and therefore it is only called if FreqAI is active. - :params: - :pair: pair to be used as informative - :df: strategy dataframe which will receive merges from informatives - :tf: timeframe of the dataframe which will modify the feature names - :informative: the dataframe associated with the informative pair - :coin: the name of the coin which will modify the feature names. + :param pair: pair to be used as informative + :param df: strategy dataframe which will receive merges from informatives + :param tf: timeframe of the dataframe which will modify the feature names + :param informative: the dataframe associated with the informative pair + :param coin: the name of the coin which will modify the feature names. """ return df diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 7008008a3..58eb47532 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -74,12 +74,11 @@ class FreqaiExampleStrategy(IStrategy): (see convention below). I.e. user should not prepend any supporting metrics (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the model. - :params: - :pair: pair to be used as informative - :df: strategy dataframe which will receive merges from informatives - :tf: timeframe of the dataframe which will modify the feature names - :informative: the dataframe associated with the informative pair - :coin: the name of the coin which will modify the feature names. + :param pair: pair to be used as informative + :param df: strategy dataframe which will receive merges from informatives + :param tf: timeframe of the dataframe which will modify the feature names + :param informative: the dataframe associated with the informative pair + :param coin: the name of the coin which will modify the feature names. """ with self.freqai.lock: From 1885deb632e52bcfb58c6e8bdb33178844477fd9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jul 2022 16:54:39 +0200 Subject: [PATCH 190/308] More docstring changes --- freqtrade/freqai/freqai_interface.py | 8 ++++---- freqtrade/freqai/prediction_models/BaseRegressionModel.py | 7 +++---- freqtrade/freqai/prediction_models/BaseTensorFlowModel.py | 5 ++--- .../freqai/prediction_models/CatboostPredictionModel.py | 5 ++--- .../prediction_models/CatboostPredictionMultiModel.py | 5 ++--- .../freqai/prediction_models/LightGBMPredictionModel.py | 5 ++--- .../prediction_models/LightGBMPredictionMultiModel.py | 5 ++--- 7 files changed, 17 insertions(+), 23 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index b88923285..f5a1d667c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -92,11 +92,11 @@ class IFreqaiModel(ABC): Entry point to the FreqaiModel from a specific pair, it will train a new model if necessary before making the prediction. - :params: - :dataframe: Full dataframe coming from strategy - it contains entire - backtesting timerange + additional historical data necessary to train + :param dataframe: Full dataframe coming from strategy - it contains entire + backtesting timerange + additional historical data necessary to train the model. - :metadata: pair metadata coming from strategy. + :param metadata: pair metadata coming from strategy. + :param strategy: Strategy to train on """ self.live = strategy.dp.runmode in (RunMode.DRY_RUN, RunMode.LIVE) diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index 2654b3726..c2fd53d0f 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -32,10 +32,9 @@ class BaseRegressionModel(IFreqaiModel): """ Filter the training data and train a model to it. Train makes heavy use of the datakitchen for storing, saving, loading, and analyzing the data. - :params: - :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. - :returns: + :param unfiltered_dataframe: Full dataframe for the current training period + :param metadata: pair metadata from strategy. + :return: :model: Trained model which can be used to inference (self.predict) """ diff --git a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py index 098ff24dd..268bb00c9 100644 --- a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py +++ b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py @@ -31,9 +31,8 @@ class BaseTensorFlowModel(IFreqaiModel): """ Filter the training data and train a model to it. Train makes heavy use of the datakitchen for storing, saving, loading, and analyzing the data. - :params: - :unfiltered_dataframe: Full dataframe for the current training period - :metadata: pair metadata from strategy. + :param unfiltered_dataframe: Full dataframe for the current training period + :param metadata: pair metadata from strategy. :returns: :model: Trained model which can be used to inference (self.predict) """ diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index c69602025..f41760472 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -19,9 +19,8 @@ class CatboostPredictionModel(BaseRegressionModel): def fit(self, data_dictionary: Dict) -> Any: """ User sets up the training and test data to fit their desired model here - :params: - :data_dictionary: the dictionary constructed by DataHandler to hold - all the training and test data/labels. + :param data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. """ train_data = Pool( diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py index 1b91fe0c6..17b5e6c68 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py @@ -20,9 +20,8 @@ class CatboostPredictionMultiModel(BaseRegressionModel): def fit(self, data_dictionary: Dict) -> Any: """ User sets up the training and test data to fit their desired model here - :params: - :data_dictionary: the dictionary constructed by DataHandler to hold - all the training and test data/labels. + :param data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. """ cbr = CatBoostRegressor( diff --git a/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py b/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py index 6a91837da..525566cf4 100644 --- a/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py +++ b/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py @@ -21,9 +21,8 @@ class LightGBMPredictionModel(BaseRegressionModel): Most regressors use the same function names and arguments e.g. user can drop in LGBMRegressor in place of CatBoostRegressor and all data management will be properly handled by Freqai. - :params: - :data_dictionary: the dictionary constructed by DataHandler to hold - all the training and test data/labels. + :param data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. """ eval_set = (data_dictionary["test_features"], data_dictionary["test_labels"]) diff --git a/freqtrade/freqai/prediction_models/LightGBMPredictionMultiModel.py b/freqtrade/freqai/prediction_models/LightGBMPredictionMultiModel.py index 89aad4323..4c51c9008 100644 --- a/freqtrade/freqai/prediction_models/LightGBMPredictionMultiModel.py +++ b/freqtrade/freqai/prediction_models/LightGBMPredictionMultiModel.py @@ -20,9 +20,8 @@ class LightGBMPredictionMultiModel(BaseRegressionModel): def fit(self, data_dictionary: Dict) -> Any: """ User sets up the training and test data to fit their desired model here - :params: - :data_dictionary: the dictionary constructed by DataHandler to hold - all the training and test data/labels. + :param data_dictionary: the dictionary constructed by DataHandler to hold + all the training and test data/labels. """ lgb = LGBMRegressor(**self.model_training_parameters) From 520ee3f7a1e8e741fd7ed23b08c5337520416351 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jul 2022 17:07:45 +0200 Subject: [PATCH 191/308] Convert freqAI into packages --- freqtrade/freqai/__init__.py | 0 freqtrade/freqai/prediction_models/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 freqtrade/freqai/__init__.py create mode 100644 freqtrade/freqai/prediction_models/__init__.py diff --git a/freqtrade/freqai/__init__.py b/freqtrade/freqai/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/freqtrade/freqai/prediction_models/__init__.py b/freqtrade/freqai/prediction_models/__init__.py new file mode 100644 index 000000000..e69de29bb From ab587747fb4f686f687306be40ad69918df0913c Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Sun, 24 Jul 2022 23:32:02 +0200 Subject: [PATCH 192/308] first fix for follower path bug --- freqtrade/freqai/data_drawer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index e18ecdbed..98fca339d 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -151,7 +151,7 @@ class FreqaiDataDrawer: for pair in whitelist_pairs: self.follower_dict[pair] = {} - with open(self.follow_path, "w") as fp: + with open(self.follow_path_dict, "w") as fp: json.dump(self.follower_dict, fp, default=self.np_encoder) def np_encoder(self, object): From c9d46a5237a251193390a4c511737741773f851c Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Mon, 25 Jul 2022 09:24:40 +0200 Subject: [PATCH 193/308] finish bringing follow_mode up to date --- freqtrade/freqai/data_drawer.py | 2 +- freqtrade/freqai/freqai_interface.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 98fca339d..8aca4b371 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -151,7 +151,7 @@ class FreqaiDataDrawer: for pair in whitelist_pairs: self.follower_dict[pair] = {} - with open(self.follow_path_dict, "w") as fp: + with open(self.follower_dict_path, "w") as fp: json.dump(self.follower_dict, fp, default=self.np_encoder) def np_encoder(self, object): diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index f5a1d667c..fc352ea8b 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -287,7 +287,7 @@ class IFreqaiModel(ABC): elif self.follow_mode: dk.set_paths(metadata["pair"], trained_timestamp) logger.info( - "FreqAI instance set to follow_mode, finding existing pair" + "FreqAI instance set to follow_mode, finding existing pair " f"using { self.identifier }" ) From 4abc26b582445d4c407327b77be9b8920812dbc6 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Mon, 25 Jul 2022 10:48:04 +0200 Subject: [PATCH 194/308] add test for follow_mode --- tests/freqai/test_freqai_interface.py | 73 +++++++++++++++++++-------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 0bb2dac79..ce1a52bbf 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -34,26 +34,10 @@ def test_train_model_in_series_LightGBM(mocker, freqai_conf): freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange) - assert ( - Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_model.joblib")) - .resolve() - .exists() - ) - assert ( - Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_metadata.json")) - .resolve() - .exists() - ) - assert ( - Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_trained_df.pkl")) - .resolve() - .exists() - ) - assert ( - Path(freqai.dk.data_path / str(freqai.dk.model_filename + "_svm_model.joblib")) - .resolve() - .exists() - ) + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").is_file() shutil.rmtree(Path(freqai.dk.full_path)) @@ -161,3 +145,52 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): ) shutil.rmtree(Path(freqai.dk.full_path)) + + +def test_follow_mode(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180110-20180130"}) + + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + timerange = TimeRange.parse_timerange("20180110-20180130") + freqai.dk.load_all_pair_histories(timerange) + + metadata = {"pair": "ADA/BTC"} + freqai.dd.set_pair_dict_info(metadata) + # freqai.dd.pair_dict = MagicMock() + + data_load_timerange = TimeRange.parse_timerange("20180110-20180130") + new_timerange = TimeRange.parse_timerange("20180120-20180130") + + freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange) + + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").is_file() + + # start the follower and ask it to predict on existing files + + freqai_conf.get("freqai", {}).update({"follow_mode": "true"}) + + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd, freqai.live) + timerange = TimeRange.parse_timerange("20180110-20180130") + freqai.dk.load_all_pair_histories(timerange) + + df = strategy.dp.get_pair_dataframe('ADA/BTC', '5m') + freqai.start_live(df, metadata, strategy, freqai.dk) + + assert len(freqai.dk.return_dataframe.index) == 5702 + + shutil.rmtree(Path(freqai.dk.full_path)) From 7b105532d13bd0edab34f5a1913a9cc22d3d08c2 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Mon, 25 Jul 2022 11:46:59 +0200 Subject: [PATCH 195/308] fix mypy error and add test for principal component analysis --- freqtrade/freqai/freqai_interface.py | 5 ++-- .../prediction_models/BaseRegressionModel.py | 7 ++--- tests/freqai/test_freqai_interface.py | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index fc352ea8b..c393420b5 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -65,7 +65,6 @@ class IFreqaiModel(ABC): self.data_split_parameters = config.get("freqai", {}).get("data_split_parameters") self.model_training_parameters = config.get("freqai", {}).get("model_training_parameters") self.feature_parameters = config.get("freqai", {}).get("feature_parameters") - self.model = None self.retrain = False self.first = True self.set_full_path() @@ -372,8 +371,8 @@ class IFreqaiModel(ABC): """ Base data cleaning method for train Any function inside this method should drop training data points from the filtered_dataframe - based on user decided logic. See FreqaiDataKitchen::remove_outliers() for an example - of how outlier data points are dropped from the dataframe used for training. + based on user decided logic. See FreqaiDataKitchen::use_SVM_to_remove_outliers() for an + example of how outlier data points are dropped from the dataframe used for training. """ if self.freqai_info.get("feature_parameters", {}).get( diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index c2fd53d0f..2db025fd6 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -1,6 +1,7 @@ import logging -from typing import Tuple +from typing import Any, Tuple +import numpy.typing as npt from pandas import DataFrame from freqtrade.freqai.data_kitchen import FreqaiDataKitchen @@ -28,7 +29,7 @@ class BaseRegressionModel(IFreqaiModel): def train( self, unfiltered_dataframe: DataFrame, pair: str, dk: FreqaiDataKitchen - ) -> Tuple[DataFrame, DataFrame]: + ) -> Any: """ Filter the training data and train a model to it. Train makes heavy use of the datakitchen for storing, saving, loading, and analyzing the data. @@ -83,7 +84,7 @@ class BaseRegressionModel(IFreqaiModel): def predict( self, unfiltered_dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = False - ) -> Tuple[DataFrame, DataFrame]: + ) -> Tuple[DataFrame, npt.ArrayLike]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index ce1a52bbf..6699ef563 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -194,3 +194,30 @@ def test_follow_mode(mocker, freqai_conf): assert len(freqai.dk.return_dataframe.index) == 5702 shutil.rmtree(Path(freqai.dk.full_path)) + + +def test_principal_component_analysis(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180110-20180130"}) + freqai_conf.get("freqai", {}).get("feature_parameters", {}).update( + {"princpial_component_analysis": "true"}) + + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + timerange = TimeRange.parse_timerange("20180110-20180130") + freqai.dk.load_all_pair_histories(timerange) + + freqai.dd.pair_dict = MagicMock() + + data_load_timerange = TimeRange.parse_timerange("20180110-20180130") + new_timerange = TimeRange.parse_timerange("20180120-20180130") + + freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange) + + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_pca_object.pkl") + + shutil.rmtree(Path(freqai.dk.full_path)) From 897f18a8c87c4d7d350757782be21f6b5caeb5de Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Mon, 25 Jul 2022 15:07:09 +0200 Subject: [PATCH 196/308] ensure proper integer type casting for timestamps. Add check test for backtesting subdaily time periods --- freqtrade/freqai/data_kitchen.py | 4 ++-- freqtrade/freqai/freqai_interface.py | 5 +++-- tests/freqai/test_freqai_interface.py | 28 ++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 80c037a3d..5ca64e504 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -909,10 +909,10 @@ class FreqaiDataKitchen: coin, _ = pair.split("/") self.data_path = Path( self.full_path - / str("sub-train" + "-" + pair.split("/")[0] + "_" + str(int(trained_timerange.stopts))) + / f"sub-train-{pair.split('/')[0]}_{int(trained_timerange.stopts)}" ) - self.model_filename = "cb_" + coin.lower() + "_" + str(int(trained_timerange.stopts)) + self.model_filename = f"cb_{coin.lower()}_{int(trained_timerange.stopts)}" def download_all_data_for_training(self, timerange: TimeRange) -> None: """ diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index c393420b5..a8527f9e1 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -210,11 +210,12 @@ class IFreqaiModel(ABC): ) ) if not self.model_exists( - metadata["pair"], dk, trained_timestamp=trained_timestamp.stopts + metadata["pair"], dk, trained_timestamp=int(trained_timestamp.stopts) ): dk.find_features(dataframe_train) self.model = self.train(dataframe_train, metadata["pair"], dk) - self.dd.pair_dict[metadata["pair"]]["trained_timestamp"] = trained_timestamp.stopts + self.dd.pair_dict[metadata["pair"]]["trained_timestamp"] = int( + trained_timestamp.stopts) dk.set_new_model_names(metadata["pair"], trained_timestamp) dk.save_data(self.model, metadata["pair"]) else: diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 6699ef563..e4df8772c 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -90,7 +90,7 @@ def test_start_backtesting(mocker, freqai_conf): df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") - metadata = {"pair": "ADA/BTC"} + metadata = {"pair": "LTC/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()] @@ -99,6 +99,32 @@ def test_start_backtesting(mocker, freqai_conf): shutil.rmtree(Path(freqai.dk.full_path)) +def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180120-20180124"}) + freqai_conf.get("freqai", {}).update({"backtest_period_days": 0.5}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = False + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + timerange = TimeRange.parse_timerange("20180110-20180130") + freqai.dk.load_all_pair_histories(timerange) + sub_timerange = TimeRange.parse_timerange("20180110-20180130") + corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") + + df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") + + metadata = {"pair": "LTC/BTC"} + freqai.start_backtesting(df, metadata, freqai.dk) + model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()] + pytest.set_trace() + assert len(model_folders) == 8 + + shutil.rmtree(Path(freqai.dk.full_path)) + + def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): freqai_conf.update({"timerange": "20180120-20180130"}) strategy = get_patched_freqai_strategy(mocker, freqai_conf) From 55cf378ec2cc69d3123febb0cb78781307d38ffc Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 25 Jul 2022 17:13:24 +0200 Subject: [PATCH 197/308] remove leftover breakpoint from test file --- tests/freqai/test_freqai_interface.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index e4df8772c..f368ebe1d 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -119,7 +119,6 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): metadata = {"pair": "LTC/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()] - pytest.set_trace() assert len(model_folders) == 8 shutil.rmtree(Path(freqai.dk.full_path)) From 56b17e6f3cc8e8286a582be2bf57db1c59af3725 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 25 Jul 2022 19:40:13 +0200 Subject: [PATCH 198/308] allow user to pass test_size = 0 and avoid using eval sets in prediction models --- freqtrade/freqai/data_kitchen.py | 80 +++++++++++-------- .../CatboostPredictionModel.py | 17 ++-- .../CatboostPredictionMultiModel.py | 8 +- .../LightGBMPredictionModel.py | 6 +- 4 files changed, 67 insertions(+), 44 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 5ca64e504..1b0ef7f33 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -243,20 +243,28 @@ class FreqaiDataKitchen: else: stratification = None - ( - train_features, - test_features, - train_labels, - test_labels, - train_weights, - test_weights, - ) = train_test_split( - filtered_dataframe[: filtered_dataframe.shape[0]], - labels, - weights, - stratify=stratification, - **self.config["freqai"]["data_split_parameters"], - ) + if self.freqai_config.get('data_split_parameters', {}).get('test_size', 0.1) != 0: + ( + train_features, + test_features, + train_labels, + test_labels, + train_weights, + test_weights, + ) = train_test_split( + filtered_dataframe[: filtered_dataframe.shape[0]], + labels, + weights, + stratify=stratification, + **self.config["freqai"]["data_split_parameters"], + ) + else: + test_labels = np.zeros(2) + test_features = pd.DataFrame() + test_weights = np.zeros(2) + train_features = filtered_dataframe + train_labels = labels + train_weights = weights return self.build_data_dictionary( train_features, test_features, train_labels, test_labels, train_weights, test_weights @@ -392,12 +400,13 @@ class FreqaiDataKitchen: / (train_labels_max - train_labels_min) - 1 ) - data_dictionary["test_labels"][item] = ( - 2 - * (data_dictionary["test_labels"][item] - train_labels_min) - / (train_labels_max - train_labels_min) - - 1 - ) + if self.freqai_config.get('data_split_parameters', {}).get('test_size', 0.1) != 0: + data_dictionary["test_labels"][item] = ( + 2 + * (data_dictionary["test_labels"][item] - train_labels_min) + / (train_labels_max - train_labels_min) + - 1 + ) self.data[f"{item}_max"] = train_labels_max # .to_dict() self.data[f"{item}_min"] = train_labels_min # .to_dict() @@ -555,11 +564,12 @@ class FreqaiDataKitchen: self.data["training_features_list_raw"] = copy.deepcopy(self.training_features_list) self.training_features_list = self.data_dictionary["train_features"].columns - self.data_dictionary["test_features"] = pd.DataFrame( - data=test_components, - columns=["PC" + str(i) for i in range(0, n_keep_components)], - index=self.data_dictionary["test_features"].index, - ) + if self.freqai_config.get('data_split_parameters', {}).get('test_size', 0.1) != 0: + self.data_dictionary["test_features"] = pd.DataFrame( + data=test_components, + columns=["PC" + str(i) for i in range(0, n_keep_components)], + index=self.data_dictionary["test_features"].index, + ) self.data["n_kept_components"] = n_keep_components self.pca = pca2 @@ -652,15 +662,17 @@ class FreqaiDataKitchen: ) # same for test data - y_pred = self.svm_model.predict(self.data_dictionary["test_features"]) - dropped_points = np.where(y_pred == -1, 0, y_pred) - self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ - (y_pred == 1) - ] - self.data_dictionary["test_labels"] = self.data_dictionary["test_labels"][(y_pred == 1)] - self.data_dictionary["test_weights"] = self.data_dictionary["test_weights"][ - (y_pred == 1) - ] + if self.freqai_config.get('data_split_parameters', {}).get('test_size', 0.1) != 0: + y_pred = self.svm_model.predict(self.data_dictionary["test_features"]) + dropped_points = np.where(y_pred == -1, 0, y_pred) + self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ + (y_pred == 1) + ] + self.data_dictionary["test_labels"] = self.data_dictionary["test_labels"][( + y_pred == 1)] + self.data_dictionary["test_weights"] = self.data_dictionary["test_weights"][ + (y_pred == 1) + ] logger.info( f"svm_remove_outliers() tossed {len(y_pred) - dropped_points.sum()}" diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index f41760472..56b84c08d 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -28,17 +28,22 @@ class CatboostPredictionModel(BaseRegressionModel): label=data_dictionary["train_labels"], weight=data_dictionary["train_weights"], ) - - test_data = Pool( - data=data_dictionary["test_features"], - label=data_dictionary["test_labels"], - weight=data_dictionary["test_weights"], - ) + if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) == 0: + test_data = None + else: + test_data = Pool( + data=data_dictionary["test_features"], + label=data_dictionary["test_labels"], + weight=data_dictionary["test_weights"], + ) model = CatBoostRegressor( allow_writing_files=False, **self.model_training_parameters, ) + + if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) == 0: + test_data = None model.fit(X=train_data, eval_set=test_data) return model diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py index 17b5e6c68..35a93e808 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionMultiModel.py @@ -36,7 +36,9 @@ class CatboostPredictionMultiModel(BaseRegressionModel): model = MultiOutputRegressor(estimator=cbr) model.fit(X=X, y=y, sample_weight=sample_weight) # , eval_set=eval_set) - train_score = model.score(X, y) - test_score = model.score(*eval_set) - logger.info(f"Train score {train_score}, Test score {test_score}") + + if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) != 0: + train_score = model.score(X, y) + test_score = model.score(*eval_set) + logger.info(f"Train score {train_score}, Test score {test_score}") return model diff --git a/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py b/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py index 525566cf4..c94bc5698 100644 --- a/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py +++ b/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py @@ -25,11 +25,15 @@ class LightGBMPredictionModel(BaseRegressionModel): all the training and test data/labels. """ - eval_set = (data_dictionary["test_features"], data_dictionary["test_labels"]) + if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) == 0: + eval_set = None + else: + eval_set = (data_dictionary["test_features"], data_dictionary["test_labels"]) X = data_dictionary["train_features"] y = data_dictionary["train_labels"] model = LGBMRegressor(**self.model_training_parameters) + model.fit(X=X, y=y, eval_set=eval_set) return model From e213d0ad55db09d83a172019234398b64469de6f Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 26 Jul 2022 10:24:14 +0200 Subject: [PATCH 199/308] isolate data_drawer functions from data_kitchen, accommodate tests, add new test --- freqtrade/freqai/data_drawer.py | 222 ++++++++++++++++- freqtrade/freqai/data_kitchen.py | 234 +----------------- freqtrade/freqai/freqai_interface.py | 36 ++- .../prediction_models/BaseRegressionModel.py | 9 +- .../prediction_models/BaseTensorFlowModel.py | 10 +- tests/freqai/conftest.py | 12 +- tests/freqai/test_freqai_datadrawer.py | 95 +++++++ tests/freqai/test_freqai_datakitchen.py | 92 +------ tests/freqai/test_freqai_interface.py | 77 ++++-- tests/rpc/test_rpc_apiserver.py | 1 + .../strats/freqai_test_multimodel_strat.py | 188 ++++++++++++++ tests/strategy/test_strategy_loading.py | 6 +- 12 files changed, 606 insertions(+), 376 deletions(-) create mode 100644 tests/freqai/test_freqai_datadrawer.py create mode 100644 tests/strategy/strats/freqai_test_multimodel_strat.py diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 8aca4b371..e1fc28d92 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -7,11 +7,17 @@ import threading from pathlib import Path from typing import Any, Dict, Tuple +import numpy.typing as npt import numpy as np import pandas as pd from joblib.externals import cloudpickle from pandas import DataFrame - +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen +from joblib import dump, load +from freqtrade.strategy.interface import IStrategy +from freqtrade.exceptions import OperationalException +from freqtrade.data.history import load_pair_history +from freqtrade.configuration import TimeRange logger = logging.getLogger(__name__) @@ -214,7 +220,8 @@ class FreqaiDataDrawer: # send pair to end of queue self.pair_dict[pair]["priority"] = len(self.pair_dict) - def set_initial_return_values(self, pair: str, dk, pred_df, do_preds) -> None: + def set_initial_return_values(self, pair: str, dk: FreqaiDataKitchen, + pred_df: DataFrame, do_preds: npt.ArrayLike) -> None: """ Set the initial return values to a persistent dataframe. This avoids needing to repredict on historical candles, and also stores historical predictions despite retrainings (so stored @@ -351,6 +358,217 @@ class FreqaiDataDrawer: if self.config.get("freqai", {}).get("purge_old_models", False): self.purge_old_models() + # Functions pulled back from FreqaiDataKitchen because they relied on DataDrawer + + def save_data(self, model: Any, coin: str, dk: FreqaiDataKitchen) -> None: + """ + Saves all data associated with a model for a single sub-train time range + :params: + :model: User trained model which can be reused for inferencing to generate + predictions + """ + + if not dk.data_path.is_dir(): + dk.data_path.mkdir(parents=True, exist_ok=True) + + save_path = Path(dk.data_path) + + # Save the trained model + if not dk.keras: + dump(model, save_path / f"{dk.model_filename}_model.joblib") + else: + model.save(save_path / f"{dk.model_filename}_model.h5") + + if dk.svm_model is not None: + dump(dk.svm_model, save_path / str(dk.model_filename + "_svm_model.joblib")) + + 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["label_list"] = dk.label_list + # store the metadata + with open(save_path / str(dk.model_filename + "_metadata.json"), "w") as fp: + json.dump(dk.data, fp, default=dk.np_encoder) + + # save the train data to file so we can check preds for area of applicability later + dk.data_dictionary["train_features"].to_pickle( + save_path / str(dk.model_filename + "_trained_df.pkl") + ) + + if self.freqai_info.get("feature_parameters", {}).get("principal_component_analysis"): + cloudpickle.dump( + dk.pca, open(dk.data_path / str(dk.model_filename + "_pca_object.pkl"), "wb") + ) + + # if self.live: + self.model_dictionary[dk.model_filename] = model + self.pair_dict[coin]["model_filename"] = dk.model_filename + self.pair_dict[coin]["data_path"] = str(dk.data_path) + self.save_drawer_to_disk() + + return + + def load_data(self, coin: str, dk: FreqaiDataKitchen) -> Any: + """ + loads all data required to make a prediction on a sub-train time range + :returns: + :model: User trained model which can be inferenced for new predictions + """ + + if not self.pair_dict[coin]["model_filename"]: + return None + + if dk.live: + dk.model_filename = self.pair_dict[coin]["model_filename"] + dk.data_path = Path(self.pair_dict[coin]["data_path"]) + if self.freqai_info.get("follow_mode", False): + # follower can be on a different system which is rsynced to the leader: + dk.data_path = Path( + self.config["user_data_dir"] + / "models" + / dk.data_path.parts[-2] + / dk.data_path.parts[-1] + ) + + with open(dk.data_path / str(dk.model_filename + "_metadata.json"), "r") as fp: + dk.data = json.load(fp) + dk.training_features_list = dk.data["training_features_list"] + dk.label_list = dk.data["label_list"] + + dk.data_dictionary["train_features"] = pd.read_pickle( + dk.data_path / str(dk.model_filename + "_trained_df.pkl") + ) + + # try to access model in memory instead of loading object from disk to save time + if dk.live and dk.model_filename in self.model_dictionary: + model = self.model_dictionary[dk.model_filename] + elif not dk.keras: + model = load(dk.data_path / str(dk.model_filename + "_model.joblib")) + else: + from tensorflow import keras + + model = keras.models.load_model(dk.data_path / str(dk.model_filename + "_model.h5")) + + if Path(dk.data_path / str(dk.model_filename + "_svm_model.joblib")).resolve().exists(): + dk.svm_model = load(dk.data_path / str(dk.model_filename + "_svm_model.joblib")) + + if not model: + raise OperationalException( + f"Unable to load model, ensure model exists at " f"{dk.data_path} " + ) + + if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]: + dk.pca = cloudpickle.load( + open(dk.data_path / str(dk.model_filename + "_pca_object.pkl"), "rb") + ) + + return model + + def update_historic_data(self, strategy: IStrategy, dk: FreqaiDataKitchen) -> None: + """ + Append new candles to our stores historic data (in memory) so that + we do not need to load candle history from disk and we dont need to + pinging exchange multiple times for the same candle. + :params: + dataframe: DataFrame = strategy provided dataframe + """ + feat_params = self.freqai_info.get("feature_parameters", {}) + with self.history_lock: + history_data = self.historic_data + + for pair in dk.all_pairs: + for tf in feat_params.get("include_timeframes"): + + # check if newest candle is already appended + df_dp = strategy.dp.get_pair_dataframe(pair, tf) + if len(df_dp.index) == 0: + continue + if str(history_data[pair][tf].iloc[-1]["date"]) == str( + df_dp.iloc[-1:]["date"].iloc[-1] + ): + continue + + try: + index = ( + df_dp.loc[ + df_dp["date"] == history_data[pair][tf].iloc[-1]["date"] + ].index[0] + + 1 + ) + except IndexError: + logger.warning( + f"Unable to update pair history for {pair}. " + "If this does not resolve itself after 1 additional candle, " + "please report the error to #freqai discord channel" + ) + return + + history_data[pair][tf] = pd.concat( + [ + history_data[pair][tf], + strategy.dp.get_pair_dataframe(pair, tf).iloc[index:], + ], + ignore_index=True, + axis=0, + ) + + def load_all_pair_histories(self, timerange: TimeRange, dk: FreqaiDataKitchen) -> None: + """ + Load pair histories for all whitelist and corr_pairlist pairs. + Only called once upon startup of bot. + :params: + timerange: TimeRange = full timerange required to populate all indicators + for training according to user defined train_period_days + """ + history_data = self.historic_data + + for pair in dk.all_pairs: + if pair not in history_data: + history_data[pair] = {} + for tf in self.freqai_info.get("feature_parameters", {}).get("include_timeframes"): + history_data[pair][tf] = load_pair_history( + datadir=self.config["datadir"], + timeframe=tf, + pair=pair, + timerange=timerange, + data_format=self.config.get("dataformat_ohlcv", "json"), + candle_type=self.config.get("trading_mode", "spot"), + ) + + def get_base_and_corr_dataframes( + self, timerange: TimeRange, pair: str, dk: FreqaiDataKitchen + ) -> Tuple[Dict[Any, Any], Dict[Any, Any]]: + """ + Searches through our historic_data in memory and returns the dataframes relevant + to the present pair. + :params: + timerange: TimeRange = full timerange required to populate all indicators + for training according to user defined train_period_days + metadata: dict = strategy furnished pair metadata + """ + + with self.history_lock: + corr_dataframes: Dict[Any, Any] = {} + base_dataframes: Dict[Any, Any] = {} + historic_data = self.historic_data + pairs = self.freqai_info.get("feature_parameters", {}).get( + "include_corr_pairlist", [] + ) + + for tf in self.freqai_info.get("feature_parameters", {}).get("include_timeframes"): + base_dataframes[tf] = dk.slice_dataframe(timerange, historic_data[pair][tf]) + if pairs: + for p in pairs: + if pair in p: + continue # dont repeat anything from whitelist + if p not in corr_dataframes: + corr_dataframes[p] = {} + corr_dataframes[p][tf] = dk.slice_dataframe( + timerange, historic_data[p][tf] + ) + + return corr_dataframes, base_dataframes + # to be used if we want to send predictions directly to the follower instead of forcing # follower to load models and inference # def save_model_return_values_to_disk(self) -> None: diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 1b0ef7f33..f16e169b9 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -1,6 +1,5 @@ import copy import datetime -import json import logging import shutil from pathlib import Path @@ -9,18 +8,14 @@ from typing import Any, Dict, List, Tuple import numpy as np import numpy.typing as npt import pandas as pd -from joblib import dump, load # , Parallel, delayed # used for auto distribution assignment -from joblib.externals import cloudpickle from pandas import DataFrame from sklearn import linear_model from sklearn.metrics.pairwise import pairwise_distances from sklearn.model_selection import train_test_split from freqtrade.configuration import TimeRange -from freqtrade.data.history import load_pair_history from freqtrade.data.history.history_utils import refresh_backtest_ohlcv_data from freqtrade.exceptions import OperationalException -from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.resolvers import ExchangeResolver from freqtrade.strategy.interface import IStrategy @@ -57,7 +52,6 @@ class FreqaiDataKitchen: def __init__( self, config: Dict[str, Any], - data_drawer: FreqaiDataDrawer, live: bool = False, pair: str = "", ): @@ -69,6 +63,7 @@ class FreqaiDataKitchen: self.append_df: DataFrame = DataFrame() self.data_path = Path() self.label_list: List = [] + self.training_features_list: List = [] self.model_filename: str = "" self.live = live self.pair = pair @@ -89,8 +84,6 @@ class FreqaiDataKitchen: config["freqai"]["backtest_period_days"], ) - self.dd = data_drawer - def set_paths( self, pair: str, @@ -113,110 +106,6 @@ class FreqaiDataKitchen: return - def save_data(self, model: Any, coin: str = "", label=None) -> None: - """ - Saves all data associated with a model for a single sub-train time range - :params: - :model: User trained model which can be reused for inferencing to generate - predictions - """ - - if not self.data_path.is_dir(): - self.data_path.mkdir(parents=True, exist_ok=True) - - save_path = Path(self.data_path) - - # Save the trained model - if not self.keras: - dump(model, save_path / f"{self.model_filename}_model.joblib") - else: - model.save(save_path / f"{self.model_filename}_model.h5") - - if self.svm_model is not None: - dump(self.svm_model, save_path / str(self.model_filename + "_svm_model.joblib")) - - self.data["data_path"] = str(self.data_path) - self.data["model_filename"] = str(self.model_filename) - self.data["training_features_list"] = list(self.data_dictionary["train_features"].columns) - self.data["label_list"] = self.label_list - # store the metadata - with open(save_path / str(self.model_filename + "_metadata.json"), "w") as fp: - json.dump(self.data, fp, default=self.np_encoder) - - # save the train data to file so we can check preds for area of applicability later - self.data_dictionary["train_features"].to_pickle( - save_path / str(self.model_filename + "_trained_df.pkl") - ) - - if self.freqai_config.get("feature_parameters", {}).get("principal_component_analysis"): - cloudpickle.dump( - self.pca, open(self.data_path / str(self.model_filename + "_pca_object.pkl"), "wb") - ) - - # if self.live: - self.dd.model_dictionary[self.model_filename] = model - self.dd.pair_dict[coin]["model_filename"] = self.model_filename - self.dd.pair_dict[coin]["data_path"] = str(self.data_path) - self.dd.save_drawer_to_disk() - - return - - def load_data(self, coin: str = "") -> Any: - """ - loads all data required to make a prediction on a sub-train time range - :returns: - :model: User trained model which can be inferenced for new predictions - """ - - if not self.dd.pair_dict[coin]["model_filename"]: - return None - - if self.live: - self.model_filename = self.dd.pair_dict[coin]["model_filename"] - self.data_path = Path(self.dd.pair_dict[coin]["data_path"]) - if self.freqai_config.get("follow_mode", False): - # follower can be on a different system which is rsynced to the leader: - self.data_path = Path( - self.config["user_data_dir"] - / "models" - / self.data_path.parts[-2] - / self.data_path.parts[-1] - ) - - with open(self.data_path / str(self.model_filename + "_metadata.json"), "r") as fp: - self.data = json.load(fp) - self.training_features_list = self.data["training_features_list"] - self.label_list = self.data["label_list"] - - self.data_dictionary["train_features"] = pd.read_pickle( - self.data_path / str(self.model_filename + "_trained_df.pkl") - ) - - # try to access model in memory instead of loading object from disk to save time - if self.live and self.model_filename in self.dd.model_dictionary: - model = self.dd.model_dictionary[self.model_filename] - elif not self.keras: - model = load(self.data_path / str(self.model_filename + "_model.joblib")) - else: - from tensorflow import keras - - model = keras.models.load_model(self.data_path / str(self.model_filename + "_model.h5")) - - if Path(self.data_path / str(self.model_filename + "_svm_model.joblib")).resolve().exists(): - self.svm_model = load(self.data_path / str(self.model_filename + "_svm_model.joblib")) - - if not model: - raise OperationalException( - f"Unable to load model, ensure model exists at " f"{self.data_path} " - ) - - if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]: - self.pca = cloudpickle.load( - open(self.data_path / str(self.model_filename + "_pca_object.pkl"), "rb") - ) - - return model - def make_train_test_datasets( self, filtered_dataframe: DataFrame, labels: DataFrame ) -> Dict[Any, Any]: @@ -953,56 +842,6 @@ class FreqaiDataKitchen: prepend=self.config.get("prepend_data", False), ) - def update_historic_data(self, strategy: IStrategy) -> None: - """ - Append new candles to our stores historic data (in memory) so that - we do not need to load candle history from disk and we dont need to - pinging exchange multiple times for the same candle. - :params: - dataframe: DataFrame = strategy provided dataframe - """ - feat_params = self.freqai_config.get("feature_parameters", {}) - with self.dd.history_lock: - history_data = self.dd.historic_data - - for pair in self.all_pairs: - for tf in feat_params.get("include_timeframes"): - - # check if newest candle is already appended - df_dp = strategy.dp.get_pair_dataframe(pair, tf) - if len(df_dp.index) == 0: - continue - if str(history_data[pair][tf].iloc[-1]["date"]) == str( - df_dp.iloc[-1:]["date"].iloc[-1] - ): - continue - - try: - index = ( - df_dp.loc[ - df_dp["date"] == history_data[pair][tf].iloc[-1]["date"] - ].index[0] - + 1 - ) - except IndexError: - logger.warning( - f"Unable to update pair history for {pair}. " - "If this does not resolve itself after 1 additional candle, " - "please report the error to #freqai discord channel" - ) - return - - history_data[pair][tf] = pd.concat( - [ - history_data[pair][tf], - strategy.dp.get_pair_dataframe(pair, tf).iloc[index:], - ], - ignore_index=True, - axis=0, - ) - - # logger.info(f'Length of history data {len(history_data[pair][tf])}') - def set_all_pairs(self) -> None: self.all_pairs = copy.deepcopy( @@ -1012,63 +851,6 @@ class FreqaiDataKitchen: if pair not in self.all_pairs: self.all_pairs.append(pair) - def load_all_pair_histories(self, timerange: TimeRange) -> None: - """ - Load pair histories for all whitelist and corr_pairlist pairs. - Only called once upon startup of bot. - :params: - timerange: TimeRange = full timerange required to populate all indicators - for training according to user defined train_period_days - """ - history_data = self.dd.historic_data - - for pair in self.all_pairs: - if pair not in history_data: - history_data[pair] = {} - for tf in self.freqai_config.get("feature_parameters", {}).get("include_timeframes"): - history_data[pair][tf] = load_pair_history( - datadir=self.config["datadir"], - timeframe=tf, - pair=pair, - timerange=timerange, - data_format=self.config.get("dataformat_ohlcv", "json"), - candle_type=self.config.get("trading_mode", "spot"), - ) - - def get_base_and_corr_dataframes( - self, timerange: TimeRange, pair: str - ) -> Tuple[Dict[Any, Any], Dict[Any, Any]]: - """ - Searches through our historic_data in memory and returns the dataframes relevant - to the present pair. - :params: - timerange: TimeRange = full timerange required to populate all indicators - for training according to user defined train_period_days - metadata: dict = strategy furnished pair metadata - """ - - with self.dd.history_lock: - corr_dataframes: Dict[Any, Any] = {} - base_dataframes: Dict[Any, Any] = {} - historic_data = self.dd.historic_data - pairs = self.freqai_config.get("feature_parameters", {}).get( - "include_corr_pairlist", [] - ) - - for tf in self.freqai_config.get("feature_parameters", {}).get("include_timeframes"): - base_dataframes[tf] = self.slice_dataframe(timerange, historic_data[pair][tf]) - if pairs: - for p in pairs: - if pair in p: - continue # dont repeat anything from whitelist - if p not in corr_dataframes: - corr_dataframes[p] = {} - corr_dataframes[p][tf] = self.slice_dataframe( - timerange, historic_data[p][tf] - ) - - return corr_dataframes, base_dataframes - def use_strategy_to_populate_indicators( self, strategy: IStrategy, @@ -1134,20 +916,6 @@ class FreqaiDataKitchen: return dataframe - def fit_live_predictions(self) -> None: - """ - Fit the labels with a gaussian distribution - """ - import scipy as spy - - num_candles = self.freqai_config.get("fit_live_predictions_candles", 100) - self.data["labels_mean"], self.data["labels_std"] = {}, {} - for label in self.label_list: - f = spy.stats.norm.fit(self.dd.historic_predictions[self.pair][label].tail(num_candles)) - self.data["labels_mean"][label], self.data["labels_std"][label] = f[0], f[1] - - return - def fit_labels(self) -> None: """ Fit the labels with a gaussian distribution diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index a8527f9e1..6edb6b78f 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -102,7 +102,7 @@ class IFreqaiModel(ABC): self.dd.set_pair_dict_info(metadata) if self.live: - self.dk = FreqaiDataKitchen(self.config, self.dd, self.live, metadata["pair"]) + self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"]) dk = self.start_live(dataframe, metadata, strategy, self.dk) # For backtesting, each pair enters and then gets trained for each window along the @@ -111,7 +111,7 @@ class IFreqaiModel(ABC): # FreqAI slides the window and sequentially builds the backtesting results before returning # the concatenated results for the full backtesting period back to the strategy. elif not self.follow_mode: - self.dk = FreqaiDataKitchen(self.config, self.dd, self.live, metadata["pair"]) + self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"]) logger.info(f"Training {len(self.dk.training_timeranges)} timeranges") dataframe = self.dk.use_strategy_to_populate_indicators( @@ -138,7 +138,7 @@ class IFreqaiModel(ABC): if self.dd.pair_dict[pair]["priority"] != 1: continue - dk = FreqaiDataKitchen(self.config, self.dd, self.live, pair) + dk = FreqaiDataKitchen(self.config, self.live, pair) dk.set_paths(pair, trained_timestamp) ( retrain, @@ -217,9 +217,9 @@ class IFreqaiModel(ABC): self.dd.pair_dict[metadata["pair"]]["trained_timestamp"] = int( trained_timestamp.stopts) dk.set_new_model_names(metadata["pair"], trained_timestamp) - dk.save_data(self.model, metadata["pair"]) + self.dd.save_data(self.model, metadata["pair"], dk) else: - self.model = dk.load_data(metadata["pair"]) + self.model = self.dd.load_data(metadata["pair"], dk) self.check_if_feature_list_matches_strategy(dataframe_train, dk) @@ -260,7 +260,7 @@ class IFreqaiModel(ABC): # append the historic data once per round if self.dd.historic_data: - dk.update_historic_data(strategy) + self.dd.update_historic_data(strategy, dk) logger.debug(f'Updating historic data on pair {metadata["pair"]}') if not self.follow_mode: @@ -278,7 +278,7 @@ class IFreqaiModel(ABC): "data saved" ) dk.download_all_data_for_training(data_load_timerange) - dk.load_all_pair_histories(data_load_timerange) + self.dd.load_all_pair_histories(data_load_timerange, dk) if not self.scanning: self.scanning = True @@ -292,7 +292,7 @@ class IFreqaiModel(ABC): ) # load the model and associated data into the data kitchen - self.model = dk.load_data(coin=metadata["pair"]) + self.model = self.dd.load_data(metadata["pair"], dk) dataframe = self.dk.use_strategy_to_populate_indicators( strategy, prediction_dataframe=dataframe, pair=metadata["pair"] @@ -468,8 +468,8 @@ class IFreqaiModel(ABC): new_trained_timerange does not contain any NaNs) """ - corr_dataframes, base_dataframes = dk.get_base_and_corr_dataframes( - data_load_timerange, pair + corr_dataframes, base_dataframes = self.dd.get_base_and_corr_dataframes( + data_load_timerange, pair, dk ) unfiltered_dataframe = dk.use_strategy_to_populate_indicators( @@ -489,7 +489,7 @@ class IFreqaiModel(ABC): if self.dd.pair_dict[pair]["priority"] == 1 and self.scanning: with self.lock: self.dd.pair_to_end_of_training_queue(pair) - dk.save_data(model, coin=pair) + self.dd.save_data(model, pair, dk) if self.freqai_info.get("purge_old_models", False): self.dd.purge_old_models() @@ -505,6 +505,20 @@ class IFreqaiModel(ABC): self.dd.historic_predictions[pair] = pd.DataFrame() self.dd.historic_predictions[pair] = copy.deepcopy(pred_df) + def fit_live_predictions(self, dk: FreqaiDataKitchen) -> None: + """ + Fit the labels with a gaussian distribution + """ + import scipy as spy + + num_candles = self.freqai_info.get("fit_live_predictions_candles", 100) + dk.data["labels_mean"], dk.data["labels_std"] = {}, {} + for label in dk.label_list: + f = spy.stats.norm.fit(self.dd.historic_predictions[dk.pair][label].tail(num_candles)) + dk.data["labels_mean"][label], dk.data["labels_std"][label] = f[0], f[1] + + return + # Following methods which are overridden by user made prediction models. # See freqai/prediction_models/CatboostPredictionModlel.py for an example. diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index 2db025fd6..611b5fb04 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -55,8 +55,6 @@ class BaseRegressionModel(IFreqaiModel): f"{end_date}--------------------") # split data into train/test data. data_dictionary = dk.make_train_test_datasets(features_filtered, labels_filtered) - if not self.freqai_info.get('fit_live_predictions', 0): - dk.fit_labels() # normalize all data based on train_dataset only data_dictionary = dk.normalize_data(data_dictionary) @@ -73,8 +71,11 @@ class BaseRegressionModel(IFreqaiModel): if pair not in self.dd.historic_predictions: self.set_initial_historic_predictions( data_dictionary['train_features'], model, dk, pair) - elif self.freqai_info.get('fit_live_predictions_candles', 0): - dk.fit_live_predictions() + + if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: + self.fit_live_predictions(dk) + else: + dk.fit_labels() self.dd.save_historic_predictions_to_disk() diff --git a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py index 268bb00c9..d14ac0eee 100644 --- a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py +++ b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py @@ -49,8 +49,7 @@ class BaseTensorFlowModel(IFreqaiModel): # split data into train/test data. data_dictionary = dk.make_train_test_datasets(features_filtered, labels_filtered) - if not self.freqai_info.get('fit_live_predictions', 0): - dk.fit_labels() + # normalize all data based on train_dataset only data_dictionary = dk.normalize_data(data_dictionary) @@ -67,8 +66,11 @@ class BaseTensorFlowModel(IFreqaiModel): if pair not in self.dd.historic_predictions: self.set_initial_historic_predictions( data_dictionary['train_features'], model, dk, pair) - elif self.freqai_info.get('fit_live_predictions_candles', 0): - dk.fit_live_predictions() + + if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: + self.fit_live_predictions(dk) + else: + dk.fit_labels() self.dd.save_historic_predictions_to_disk() diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index ede991240..c039222c0 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -1,12 +1,12 @@ from copy import deepcopy from pathlib import Path -from unittest.mock import MagicMock import pytest from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider from freqtrade.freqai.data_kitchen import FreqaiDataKitchen +from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.resolvers import StrategyResolver from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver from tests.conftest import get_patched_exchange @@ -57,11 +57,17 @@ def freqai_conf(default_conf, tmpdir): def get_patched_data_kitchen(mocker, freqaiconf): - dd = mocker.patch('freqtrade.freqai.data_drawer', MagicMock()) - dk = FreqaiDataKitchen(freqaiconf, dd) + # dd = mocker.patch('freqtrade.freqai.data_drawer', MagicMock()) + dk = FreqaiDataKitchen(freqaiconf) return dk +def get_patched_data_drawer(mocker, freqaiconf): + # dd = mocker.patch('freqtrade.freqai.data_drawer', MagicMock()) + dd = FreqaiDataDrawer(freqaiconf) + return dd + + def get_patched_freqai_strategy(mocker, freqaiconf): strategy = StrategyResolver.load_strategy(freqaiconf) strategy.ft_bot_start() diff --git a/tests/freqai/test_freqai_datadrawer.py b/tests/freqai/test_freqai_datadrawer.py new file mode 100644 index 000000000..81503cf15 --- /dev/null +++ b/tests/freqai/test_freqai_datadrawer.py @@ -0,0 +1,95 @@ + +import shutil +from pathlib import Path + +from freqtrade.configuration import TimeRange +from freqtrade.data.dataprovider import DataProvider +# from freqtrade.freqai.data_drawer import FreqaiDataDrawer +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen +from tests.conftest import get_patched_exchange +from tests.freqai.conftest import get_patched_freqai_strategy + + +def test_update_historic_data(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf) + timerange = TimeRange.parse_timerange("20180110-20180114") + + freqai.dd.load_all_pair_histories(timerange, freqai.dk) + historic_candles = len(freqai.dd.historic_data["ADA/BTC"]["5m"]) + dp_candles = len(strategy.dp.get_pair_dataframe("ADA/BTC", "5m")) + candle_difference = dp_candles - historic_candles + freqai.dd.update_historic_data(strategy, freqai.dk) + + updated_historic_candles = len(freqai.dd.historic_data["ADA/BTC"]["5m"]) + + assert updated_historic_candles - historic_candles == candle_difference + shutil.rmtree(Path(freqai.dk.full_path)) + + +def test_load_all_pairs_histories(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf) + timerange = TimeRange.parse_timerange("20180110-20180114") + freqai.dd.load_all_pair_histories(timerange, freqai.dk) + + assert len(freqai.dd.historic_data.keys()) == len( + freqai_conf.get("exchange", {}).get("pair_whitelist") + ) + assert len(freqai.dd.historic_data["ADA/BTC"]) == len( + freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") + ) + shutil.rmtree(Path(freqai.dk.full_path)) + + +def test_get_base_and_corr_dataframes(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf) + timerange = TimeRange.parse_timerange("20180110-20180114") + freqai.dd.load_all_pair_histories(timerange, freqai.dk) + sub_timerange = TimeRange.parse_timerange("20180111-20180114") + corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + + num_tfs = len( + freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") + ) + + assert len(base_df.keys()) == num_tfs + + assert len(corr_df.keys()) == len( + freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_corr_pairlist") + ) + + assert len(corr_df["ADA/BTC"].keys()) == num_tfs + shutil.rmtree(Path(freqai.dk.full_path)) + + +def test_use_strategy_to_populate_indicators(mocker, freqai_conf): + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf) + timerange = TimeRange.parse_timerange("20180110-20180114") + freqai.dd.load_all_pair_histories(timerange, freqai.dk) + sub_timerange = TimeRange.parse_timerange("20180111-20180114") + corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + + df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, 'LTC/BTC') + + assert len(df.columns) == 45 + shutil.rmtree(Path(freqai.dk.full_path)) diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index ee1d83982..9f2a2f71e 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -4,13 +4,8 @@ from pathlib import Path import pytest -from freqtrade.configuration import TimeRange -from freqtrade.data.dataprovider import DataProvider -# from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.exceptions import OperationalException -from freqtrade.freqai.data_kitchen import FreqaiDataKitchen -from tests.conftest import get_patched_exchange -from tests.freqai.conftest import get_patched_data_kitchen, get_patched_freqai_strategy +from tests.freqai.conftest import get_patched_data_kitchen @pytest.mark.parametrize( @@ -60,27 +55,6 @@ def test_split_timerange( shutil.rmtree(Path(dk.full_path)) -def test_update_historic_data(mocker, freqai_conf): - strategy = get_patched_freqai_strategy(mocker, freqai_conf) - exchange = get_patched_exchange(mocker, freqai_conf) - strategy.dp = DataProvider(freqai_conf, exchange) - freqai = strategy.freqai - freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) - timerange = TimeRange.parse_timerange("20180110-20180114") - - freqai.dk.load_all_pair_histories(timerange) - historic_candles = len(freqai.dd.historic_data["ADA/BTC"]["5m"]) - dp_candles = len(strategy.dp.get_pair_dataframe("ADA/BTC", "5m")) - candle_difference = dp_candles - historic_candles - freqai.dk.update_historic_data(strategy) - - updated_historic_candles = len(freqai.dd.historic_data["ADA/BTC"]["5m"]) - - assert updated_historic_candles - historic_candles == candle_difference - shutil.rmtree(Path(freqai.dk.full_path)) - - @pytest.mark.parametrize( "timestamp, expected", [ @@ -92,67 +66,3 @@ def test_check_if_model_expired(mocker, freqai_conf, timestamp, expected): dk = get_patched_data_kitchen(mocker, freqai_conf) assert dk.check_if_model_expired(timestamp) == expected shutil.rmtree(Path(dk.full_path)) - - -def test_load_all_pairs_histories(mocker, freqai_conf): - strategy = get_patched_freqai_strategy(mocker, freqai_conf) - exchange = get_patched_exchange(mocker, freqai_conf) - strategy.dp = DataProvider(freqai_conf, exchange) - freqai = strategy.freqai - freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) - timerange = TimeRange.parse_timerange("20180110-20180114") - freqai.dk.load_all_pair_histories(timerange) - - assert len(freqai.dd.historic_data.keys()) == len( - freqai_conf.get("exchange", {}).get("pair_whitelist") - ) - assert len(freqai.dd.historic_data["ADA/BTC"]) == len( - freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") - ) - shutil.rmtree(Path(freqai.dk.full_path)) - - -def test_get_base_and_corr_dataframes(mocker, freqai_conf): - strategy = get_patched_freqai_strategy(mocker, freqai_conf) - exchange = get_patched_exchange(mocker, freqai_conf) - strategy.dp = DataProvider(freqai_conf, exchange) - freqai = strategy.freqai - freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) - timerange = TimeRange.parse_timerange("20180110-20180114") - freqai.dk.load_all_pair_histories(timerange) - sub_timerange = TimeRange.parse_timerange("20180111-20180114") - corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") - - num_tfs = len( - freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_timeframes") - ) - - assert len(base_df.keys()) == num_tfs - - assert len(corr_df.keys()) == len( - freqai_conf.get("freqai", {}).get("feature_parameters", {}).get("include_corr_pairlist") - ) - - assert len(corr_df["ADA/BTC"].keys()) == num_tfs - shutil.rmtree(Path(freqai.dk.full_path)) - - -def test_use_strategy_to_populate_indicators(mocker, freqai_conf): - strategy = get_patched_freqai_strategy(mocker, freqai_conf) - exchange = get_patched_exchange(mocker, freqai_conf) - strategy.dp = DataProvider(freqai_conf, exchange) - strategy.freqai_info = freqai_conf.get("freqai", {}) - freqai = strategy.freqai - freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) - timerange = TimeRange.parse_timerange("20180110-20180114") - freqai.dk.load_all_pair_histories(timerange) - sub_timerange = TimeRange.parse_timerange("20180111-20180114") - corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") - - df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, 'LTC/BTC') - - assert len(df.columns) == 45 - shutil.rmtree(Path(freqai.dk.full_path)) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index f368ebe1d..c4302e756 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -1,5 +1,3 @@ -# from unittest.mock import MagicMock -# from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_edge import platform import shutil from pathlib import Path @@ -23,9 +21,9 @@ def test_train_model_in_series_LightGBM(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) freqai.dd.pair_dict = MagicMock() @@ -42,6 +40,36 @@ def test_train_model_in_series_LightGBM(mocker, freqai_conf): shutil.rmtree(Path(freqai.dk.full_path)) +def test_train_model_in_series_LightGBMMultiModel(mocker, freqai_conf): + freqai_conf.update({"timerange": "20180110-20180130"}) + freqai_conf.update({"strategy": "freqai_test_multimodel_strat"}) + freqai_conf.update({"freqaimodel": "LightGBMPredictionMultiModel"}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) + exchange = get_patched_exchange(mocker, freqai_conf) + strategy.dp = DataProvider(freqai_conf, exchange) + strategy.freqai_info = freqai_conf.get("freqai", {}) + freqai = strategy.freqai + freqai.live = True + freqai.dk = FreqaiDataKitchen(freqai_conf) + timerange = TimeRange.parse_timerange("20180110-20180130") + freqai.dd.load_all_pair_histories(timerange, freqai.dk) + + freqai.dd.pair_dict = MagicMock() + + data_load_timerange = TimeRange.parse_timerange("20180110-20180130") + new_timerange = TimeRange.parse_timerange("20180120-20180130") + + freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange) + + assert len(freqai.dk.label_list) == 2 + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").is_file() + assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").is_file() + + shutil.rmtree(Path(freqai.dk.full_path)) + + @pytest.mark.skipif("arm" in platform.uname()[-1], reason="no ARM for Catboost ...") def test_train_model_in_series_Catboost(mocker, freqai_conf): freqai_conf.update({"timerange": "20180110-20180130"}) @@ -54,9 +82,9 @@ def test_train_model_in_series_Catboost(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) freqai.dd.pair_dict = MagicMock() @@ -82,11 +110,11 @@ def test_start_backtesting(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") + corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") @@ -108,11 +136,11 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") + corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") @@ -132,11 +160,11 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") + corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") @@ -155,11 +183,11 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = False - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dk.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC") + corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") freqai.start_backtesting(df, metadata, freqai.dk) @@ -181,13 +209,12 @@ def test_follow_mode(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) metadata = {"pair": "ADA/BTC"} freqai.dd.set_pair_dict_info(metadata) - # freqai.dd.pair_dict = MagicMock() data_load_timerange = TimeRange.parse_timerange("20180110-20180130") new_timerange = TimeRange.parse_timerange("20180120-20180130") @@ -209,9 +236,9 @@ def test_follow_mode(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd, freqai.live) + freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.live) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) df = strategy.dp.get_pair_dataframe('ADA/BTC', '5m') freqai.start_live(df, metadata, strategy, freqai.dk) @@ -232,9 +259,9 @@ def test_principal_component_analysis(mocker, freqai_conf): strategy.freqai_info = freqai_conf.get("freqai", {}) freqai = strategy.freqai freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.dd) + freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dk.load_all_pair_histories(timerange) + freqai.dd.load_all_pair_histories(timerange, freqai.dk) freqai.dd.pair_dict = MagicMock() diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 86fe0bf03..3afdd5245 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1404,6 +1404,7 @@ def test_api_strategies(botclient): 'StrategyTestV3', 'StrategyTestV3Analysis', 'StrategyTestV3Futures', + 'freqai_test_multimodel_strat', 'freqai_test_strat' ]} diff --git a/tests/strategy/strats/freqai_test_multimodel_strat.py b/tests/strategy/strats/freqai_test_multimodel_strat.py new file mode 100644 index 000000000..9652e816b --- /dev/null +++ b/tests/strategy/strats/freqai_test_multimodel_strat.py @@ -0,0 +1,188 @@ +import logging +from functools import reduce + +import pandas as pd +import talib.abstract as ta +from pandas import DataFrame + +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair + + +logger = logging.getLogger(__name__) + + +class freqai_test_multimodel_strat(IStrategy): + """ + Example strategy showing how the user connects their own + IFreqaiModel to the strategy. Namely, the user uses: + self.freqai.start(dataframe, metadata) + + to make predictions on their data. populate_any_indicators() automatically + generates the variety of features indicated by the user in the + canonical freqtrade configuration file under config['freqai']. + """ + + minimal_roi = {"0": 0.1, "240": -1} + + plot_config = { + "main_plot": {}, + "subplots": { + "prediction": {"prediction": {"color": "blue"}}, + "target_roi": { + "target_roi": {"color": "brown"}, + }, + "do_predict": { + "do_predict": {"color": "brown"}, + }, + }, + } + + process_only_new_candles = True + stoploss = -0.05 + use_exit_signal = True + startup_candle_count: int = 300 + can_short = False + + linear_roi_offset = DecimalParameter( + 0.00, 0.02, default=0.005, space="sell", optimize=False, load=True + ) + max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True) + + def informative_pairs(self): + whitelist_pairs = self.dp.current_whitelist() + corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"] + informative_pairs = [] + for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]: + for pair in whitelist_pairs: + informative_pairs.append((pair, tf)) + for pair in corr_pairs: + if pair in whitelist_pairs: + continue # avoid duplication + informative_pairs.append((pair, tf)) + return informative_pairs + + def populate_any_indicators( + self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False + ): + """ + Function designed to automatically generate, name and merge features + from user indicated timeframes in the configuration file. User controls the indicators + passed to the training/prediction by prepending indicators with `'%-' + coin ` + (see convention below). I.e. user should not prepend any supporting metrics + (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the + model. + :params: + :pair: pair to be used as informative + :df: strategy dataframe which will receive merges from informatives + :tf: timeframe of the dataframe which will modify the feature names + :informative: the dataframe associated with the informative pair + :coin: the name of the coin which will modify the feature names. + """ + + with self.freqai.lock: + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) + + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + + informative[f"%-{coin}pct-change"] = informative["close"].pct_change() + informative[f"%-{coin}raw_volume"] = informative["volume"] + informative[f"%-{coin}raw_price"] = informative["close"] + + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) + + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) + + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) + + df["&-s_range"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .max() + - + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .min() + ) + + return df + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + self.freqai_info = self.config["freqai"] + + # All indicators must be populated by populate_any_indicators() for live functionality + # to work correctly. + # the model will return 4 values, its prediction, an indication of whether or not the + # prediction should be accepted, the target mean/std values from the labels used during + # each training period. + dataframe = self.freqai.start(dataframe, metadata, self) + + dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25 + dataframe["sell_roi"] = dataframe["&-s_close_mean"] - dataframe["&-s_close_std"] * 1.25 + return dataframe + + def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + + enter_long_conditions = [df["do_predict"] == 1, df["&-s_close"] > df["target_roi"]] + + if enter_long_conditions: + df.loc[ + reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"] + ] = (1, "long") + + enter_short_conditions = [df["do_predict"] == 1, df["&-s_close"] < df["sell_roi"]] + + if enter_short_conditions: + df.loc[ + reduce(lambda x, y: x & y, enter_short_conditions), ["enter_short", "enter_tag"] + ] = (1, "short") + + return df + + def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + exit_long_conditions = [df["do_predict"] == 1, df["&-s_close"] < df["sell_roi"] * 0.25] + if exit_long_conditions: + df.loc[reduce(lambda x, y: x & y, exit_long_conditions), "exit_long"] = 1 + + exit_short_conditions = [df["do_predict"] == 1, df["&-s_close"] > df["target_roi"] * 0.25] + if exit_short_conditions: + df.loc[reduce(lambda x, y: x & y, exit_short_conditions), "exit_short"] = 1 + + return df diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index aaad26e5b..5b6f15d11 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -34,7 +34,7 @@ def test_search_all_strategies_no_failed(): directory = Path(__file__).parent / "strats" strategies = StrategyResolver.search_all_objects(directory, enum_failed=False) assert isinstance(strategies, list) - assert len(strategies) == 8 + assert len(strategies) == 9 assert isinstance(strategies[0], dict) @@ -42,10 +42,10 @@ def test_search_all_strategies_with_failed(): directory = Path(__file__).parent / "strats" strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) assert isinstance(strategies, list) - assert len(strategies) == 9 + assert len(strategies) == 10 # with enum_failed=True search_all_objects() shall find 2 good strategies # and 1 which fails to load - assert len([x for x in strategies if x['class'] is not None]) == 8 + assert len([x for x in strategies if x['class'] is not None]) == 9 assert len([x for x in strategies if x['class'] is None]) == 1 From fb4e8430cd5677864b83b855517dd5bf546397c5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 26 Jul 2022 10:51:39 +0200 Subject: [PATCH 200/308] isort auto import sorting --- freqtrade/freqai/data_drawer.py | 14 ++++++++------ tests/freqai/conftest.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index e1fc28d92..89708fd3e 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -7,17 +7,19 @@ import threading from pathlib import Path from typing import Any, Dict, Tuple -import numpy.typing as npt import numpy as np +import numpy.typing as npt import pandas as pd +from joblib import dump, load from joblib.externals import cloudpickle from pandas import DataFrame -from freqtrade.freqai.data_kitchen import FreqaiDataKitchen -from joblib import dump, load -from freqtrade.strategy.interface import IStrategy -from freqtrade.exceptions import OperationalException -from freqtrade.data.history import load_pair_history + from freqtrade.configuration import TimeRange +from freqtrade.data.history import load_pair_history +from freqtrade.exceptions import OperationalException +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen +from freqtrade.strategy.interface import IStrategy + logger = logging.getLogger(__name__) diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index c039222c0..ff70a40a4 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -5,8 +5,8 @@ import pytest from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider -from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.freqai.data_drawer import FreqaiDataDrawer +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.resolvers import StrategyResolver from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver from tests.conftest import get_patched_exchange From ad25a4cb5642b44225c40ec6f7feec277dc6da7f Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 26 Jul 2022 15:58:40 +0200 Subject: [PATCH 201/308] reduce number of pair_dict lookups, remove coin_first --- freqtrade/freqai/data_drawer.py | 25 ++++++++++++------------- freqtrade/freqai/freqai_interface.py | 6 +++--- tests/freqai/test_freqai_datadrawer.py | 1 - 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 89708fd3e..8c26d01b0 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -166,7 +166,7 @@ class FreqaiDataDrawer: if isinstance(object, np.generic): return object.item() - def get_pair_dict_info(self, pair: str) -> Tuple[str, int, bool, bool]: + def get_pair_dict_info(self, pair: str) -> Tuple[str, int, bool]: """ Locate and load existing model metadata from persistent storage. If not located, create a new one and append the current pair to it and prepare it for its first @@ -175,23 +175,20 @@ class FreqaiDataDrawer: :return: model_filename: str = unique filename used for loading persistent objects from disk trained_timestamp: int = the last time the coin was trained - coin_first: bool = If the coin is fresh without metadata return_null_array: bool = Follower could not find pair metadata """ - pair_in_dict = self.pair_dict.get(pair) + pair_dict = self.pair_dict.get(pair) data_path_set = self.pair_dict.get(pair, {}).get("data_path", None) return_null_array = False - if pair_in_dict: - model_filename = self.pair_dict[pair]["model_filename"] - trained_timestamp = self.pair_dict[pair]["trained_timestamp"] - coin_first = self.pair_dict[pair]["first"] + if pair_dict: + model_filename = pair_dict["model_filename"] + trained_timestamp = pair_dict["trained_timestamp"] elif not self.follow_mode: - self.pair_dict[pair] = {} - model_filename = self.pair_dict[pair]["model_filename"] = "" - coin_first = self.pair_dict[pair]["first"] = True - trained_timestamp = self.pair_dict[pair]["trained_timestamp"] = 0 - self.pair_dict[pair]["priority"] = len(self.pair_dict) + pair_dict = self.pair_dict[pair] = {} + model_filename = pair_dict["model_filename"] = "" + trained_timestamp = pair_dict["trained_timestamp"] = 0 + pair_dict["priority"] = len(self.pair_dict) if not data_path_set and self.follow_mode: logger.warning( @@ -199,9 +196,11 @@ class FreqaiDataDrawer: f"pair_dictionary at path {self.full_path}, sending null values " "back to strategy." ) + trained_timestamp = 0 + model_filename = '' return_null_array = True - return model_filename, trained_timestamp, coin_first, return_null_array + return model_filename, trained_timestamp, return_null_array def set_pair_dict_info(self, metadata: dict) -> None: pair_in_dict = self.pair_dict.get(metadata["pair"]) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 6edb6b78f..5eecffd9c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -134,7 +134,7 @@ class IFreqaiModel(ABC): time.sleep(1) for pair in self.config.get("exchange", {}).get("pair_whitelist"): - (_, trained_timestamp, _, _) = self.dd.get_pair_dict_info(pair) + (_, trained_timestamp, _) = self.dd.get_pair_dict_info(pair) if self.dd.pair_dict[pair]["priority"] != 1: continue @@ -177,7 +177,7 @@ class IFreqaiModel(ABC): # following tr_train. Both of these windows slide through the # entire backtest for tr_train, tr_backtest in zip(dk.training_timeranges, dk.backtesting_timeranges): - (_, _, _, _) = self.dd.get_pair_dict_info(metadata["pair"]) + (_, _, _) = self.dd.get_pair_dict_info(metadata["pair"]) train_it += 1 total_trains = len(dk.backtesting_timeranges) gc.collect() @@ -250,7 +250,7 @@ class IFreqaiModel(ABC): self.dd.update_follower_metadata() # get the model metadata associated with the current pair - (_, trained_timestamp, _, return_null_array) = self.dd.get_pair_dict_info(metadata["pair"]) + (_, trained_timestamp, return_null_array) = self.dd.get_pair_dict_info(metadata["pair"]) # if the metadata doesnt exist, the follower returns null arrays to strategy if self.follow_mode and return_null_array: diff --git a/tests/freqai/test_freqai_datadrawer.py b/tests/freqai/test_freqai_datadrawer.py index 81503cf15..a6df60e61 100644 --- a/tests/freqai/test_freqai_datadrawer.py +++ b/tests/freqai/test_freqai_datadrawer.py @@ -4,7 +4,6 @@ from pathlib import Path from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider -# from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from tests.conftest import get_patched_exchange from tests.freqai.conftest import get_patched_freqai_strategy From 3f149c40673871c6056b97f02c89c97f7eaf7f8b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 26 Jul 2022 16:01:54 +0200 Subject: [PATCH 202/308] fix return type in BaseTensorFlowModel --- freqtrade/freqai/prediction_models/BaseTensorFlowModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py index d14ac0eee..bfbd5aa46 100644 --- a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py +++ b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py @@ -1,5 +1,5 @@ import logging -from typing import Tuple +from typing import Any from pandas import DataFrame @@ -27,7 +27,7 @@ class BaseTensorFlowModel(IFreqaiModel): def train( self, unfiltered_dataframe: DataFrame, pair: str, dk: FreqaiDataKitchen - ) -> Tuple[DataFrame, DataFrame]: + ) -> Any: """ Filter the training data and train a model to it. Train makes heavy use of the datakitchen for storing, saving, loading, and analyzing the data. From 324e54c0159aa823167d90eb639ba8ba0b9aaa4d Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 26 Jul 2022 17:29:29 +0200 Subject: [PATCH 203/308] fix possible memory leak associated with Catboost Pool object --- freqtrade/freqai/freqai_interface.py | 6 +++--- .../freqai/prediction_models/BaseRegressionModel.py | 2 +- .../freqai/prediction_models/BaseTensorFlowModel.py | 2 +- .../freqai/prediction_models/CatboostPredictionModel.py | 9 ++++++--- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 5eecffd9c..4bee3fefd 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -120,7 +120,8 @@ class IFreqaiModel(ABC): dk = self.start_backtesting(dataframe, metadata, self.dk) dataframe = dk.remove_features_from_df(dk.return_dataframe) - return self.return_values(dataframe, dk) + del dk + return self.return_values(dataframe) @threaded def start_scanning(self, strategy: IStrategy) -> None: @@ -560,12 +561,11 @@ class IFreqaiModel(ABC): """ @abstractmethod - def return_values(self, dataframe: DataFrame, dk: FreqaiDataKitchen) -> DataFrame: + def return_values(self, dataframe: DataFrame) -> DataFrame: """ User defines the dataframe to be returned to strategy here. :param dataframe: DataFrame = the full dataframe for the current prediction (live) or --timerange (backtesting) - :param dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only :return: dataframe: DataFrame = dataframe filled with user defined data """ diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index 611b5fb04..2baec9fc3 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -18,7 +18,7 @@ class BaseRegressionModel(IFreqaiModel): such as prediction_models/CatboostPredictionModel.py for guidance. """ - def return_values(self, dataframe: DataFrame, dk: FreqaiDataKitchen) -> DataFrame: + def return_values(self, dataframe: DataFrame) -> DataFrame: """ User uses this function to add any additional return values to the dataframe. e.g. diff --git a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py index bfbd5aa46..d94378494 100644 --- a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py +++ b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py @@ -16,7 +16,7 @@ class BaseTensorFlowModel(IFreqaiModel): User *must* inherit from this class and set fit() and predict(). """ - def return_values(self, dataframe: DataFrame, dk: FreqaiDataKitchen) -> DataFrame: + def return_values(self, dataframe: DataFrame) -> DataFrame: """ User uses this function to add any additional return values to the dataframe. e.g. diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 56b84c08d..884933803 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -1,6 +1,6 @@ import logging from typing import Any, Dict - +import gc from catboost import CatBoostRegressor, Pool from freqtrade.freqai.prediction_models.BaseRegressionModel import BaseRegressionModel @@ -42,8 +42,11 @@ class CatboostPredictionModel(BaseRegressionModel): **self.model_training_parameters, ) - if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) == 0: - test_data = None model.fit(X=train_data, eval_set=test_data) + # some evidence that catboost pools have memory leaks: + # https://github.com/catboost/catboost/issues/1835 + del train_data, test_data + gc.collect() + return model From bc760b7eb236cc2fbec745c2f628755f33c2899d Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 26 Jul 2022 19:41:49 +0200 Subject: [PATCH 204/308] Simplify small segment in datadrawer --- freqtrade/freqai/data_drawer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 8c26d01b0..5562ffba0 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -63,7 +63,7 @@ class FreqaiDataDrawer: self.historic_predictions: Dict[str, Any] = {} self.follower_dict: Dict[str, Any] = {} self.full_path = full_path - self.follower_name = self.config.get("bot_name", "follower1") + self.follower_name: str = self.config.get("bot_name", "follower1") self.follower_dict_path = Path( self.full_path / f"follower_dictionary-{self.follower_name}.json" ) @@ -159,8 +159,7 @@ class FreqaiDataDrawer: for pair in whitelist_pairs: self.follower_dict[pair] = {} - with open(self.follower_dict_path, "w") as fp: - json.dump(self.follower_dict, fp, default=self.np_encoder) + self.save_follower_dict_to_disk() def np_encoder(self, object): if isinstance(object, np.generic): From f31106dc6196107f9eaad6b841ab1f5d698c2eeb Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 27 Jul 2022 07:27:24 +0200 Subject: [PATCH 205/308] Minor comment fixes --- freqtrade/freqai/data_drawer.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 5562ffba0..4f3c0062f 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -81,8 +81,7 @@ class FreqaiDataDrawer: """ Locate and load a previously saved data drawer full of all pair model metadata in present model folder. - :returns: - exists: bool = whether or not the drawer was located + :return: bool - whether or not the drawer was located """ exists = self.pair_dictionary_path.is_file() if exists: @@ -101,8 +100,7 @@ class FreqaiDataDrawer: def load_historic_predictions_from_disk(self): """ Locate and load a previously saved historic predictions. - :returns: - exists: bool = whether or not the drawer was located + :return: bool - whether or not the drawer was located """ exists = self.historic_predictions_path.is_file() if exists: @@ -422,7 +420,7 @@ class FreqaiDataDrawer: dk.model_filename = self.pair_dict[coin]["model_filename"] dk.data_path = Path(self.pair_dict[coin]["data_path"]) if self.freqai_info.get("follow_mode", False): - # follower can be on a different system which is rsynced to the leader: + # follower can be on a different system which is rsynced from the leader: dk.data_path = Path( self.config["user_data_dir"] / "models" From a2a0d35a24ebc55fa6be095d72dd8e59f1aea796 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 28 Jul 2022 07:07:40 +0200 Subject: [PATCH 206/308] Update missing typehints --- freqtrade/freqai/data_drawer.py | 9 +++++---- freqtrade/freqai/freqai_interface.py | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 4f3c0062f..4d37ef8c1 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -8,10 +8,10 @@ from pathlib import Path from typing import Any, Dict, Tuple import numpy as np -import numpy.typing as npt import pandas as pd from joblib import dump, load from joblib.externals import cloudpickle +from numpy.typing import ArrayLike from pandas import DataFrame from freqtrade.configuration import TimeRange @@ -219,7 +219,7 @@ class FreqaiDataDrawer: self.pair_dict[pair]["priority"] = len(self.pair_dict) def set_initial_return_values(self, pair: str, dk: FreqaiDataKitchen, - pred_df: DataFrame, do_preds: npt.ArrayLike) -> None: + pred_df: DataFrame, do_preds: ArrayLike) -> None: """ Set the initial return values to a persistent dataframe. This avoids needing to repredict on historical candles, and also stores historical predictions despite retrainings (so stored @@ -238,7 +238,8 @@ class FreqaiDataDrawer: mrv_df["do_predict"] = do_preds - def append_model_predictions(self, pair: str, predictions, do_preds, dk, len_df) -> None: + def append_model_predictions(self, pair: str, predictions: DataFrame, do_preds: ArrayLike, + dk: FreqaiDataKitchen, len_df: int) -> None: # strat seems to feed us variable sized dataframes - and since we are trying to build our # own return array in the same shape, we need to figure out how the size has changed @@ -293,7 +294,7 @@ class FreqaiDataDrawer: dataframe = pd.concat([dataframe[to_keep], df], axis=1) return dataframe - def return_null_values_to_strategy(self, dataframe: DataFrame, dk) -> None: + def return_null_values_to_strategy(self, dataframe: DataFrame, dk: FreqaiDataKitchen) -> None: """ Build 0 filled dataframe to return to strategy """ diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 4bee3fefd..4c74be7ab 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -11,8 +11,8 @@ from pathlib import Path from typing import Any, Dict, Tuple import numpy as np -import numpy.typing as npt import pandas as pd +from numpy.typing import ArrayLike from pandas import DataFrame from freqtrade.configuration import TimeRange @@ -548,7 +548,7 @@ class IFreqaiModel(ABC): @abstractmethod def predict( self, dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = True - ) -> Tuple[DataFrame, npt.ArrayLike]: + ) -> Tuple[DataFrame, ArrayLike]: """ Filter the prediction features data and predict with it. :param unfiltered_dataframe: Full dataframe for the current backtest period. From efbd83c56db75a1d904cd115549a385c474ea374 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 28 Jul 2022 07:24:30 +0200 Subject: [PATCH 207/308] Small type and typo fixes in freqai_interface --- freqtrade/freqai/freqai_interface.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 4c74be7ab..ec69a78c4 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -61,19 +61,21 @@ class IFreqaiModel(ABC): self.config = config self.assert_config(self.config) - self.freqai_info = config["freqai"] - self.data_split_parameters = config.get("freqai", {}).get("data_split_parameters") - self.model_training_parameters = config.get("freqai", {}).get("model_training_parameters") + self.freqai_info: Dict[str, Any] = config["freqai"] + self.data_split_parameters: Dict[str, Any] = config.get("freqai", {}).get( + "data_split_parameters", {}) + self.model_training_parameters: Dict[str, Any] = config.get("freqai", {}).get( + "model_training_parameters", {}) self.feature_parameters = config.get("freqai", {}).get("feature_parameters") self.retrain = False self.first = True self.set_full_path() - self.follow_mode = self.freqai_info.get("follow_mode", False) + self.follow_mode: bool = self.freqai_info.get("follow_mode", False) self.dd = FreqaiDataDrawer(Path(self.full_path), self.config, self.follow_mode) self.lock = threading.Lock() - self.identifier = self.freqai_info.get("identifier", "no_id_provided") + self.identifier: str = self.freqai_info.get("identifier", "no_id_provided") self.scanning = False - self.keras = self.freqai_info.get("keras", False) + self.keras: bool = self.freqai_info.get("keras", False) if self.keras and self.freqai_info.get("feature_parameters", {}).get("DI_threshold", 0): self.freqai_info["feature_parameters"]["DI_threshold"] = 0 logger.warning("DI threshold is not configured for Keras models yet. Deactivating.") @@ -253,7 +255,7 @@ class IFreqaiModel(ABC): # get the model metadata associated with the current pair (_, trained_timestamp, return_null_array) = self.dd.get_pair_dict_info(metadata["pair"]) - # if the metadata doesnt exist, the follower returns null arrays to strategy + # if the metadata doesn't exist, the follower returns null arrays to strategy if self.follow_mode and return_null_array: logger.info("Returning null array from follower to strategy") self.dd.return_null_values_to_strategy(dataframe, dk) @@ -364,7 +366,7 @@ class IFreqaiModel(ABC): raise OperationalException( "Trying to access pretrained model with `identifier` " "but found different features furnished by current strategy." - "Change `identifer` to train from scratch, or ensure the" + "Change `identifier` to train from scratch, or ensure the" "strategy is furnishing the same features as the pretrained" "model" ) @@ -457,7 +459,7 @@ class IFreqaiModel(ABC): data_load_timerange: TimeRange, ): """ - Retreive data and train model in single threaded mode (only used if model directory is empty + Retrieve data and train model in single threaded mode (only used if model directory is empty upon startup for dry/live ) :param new_trained_timerange: TimeRange = the timerange to train the model on :param metadata: dict = strategy provided metadata From c84d54b35ec455e02818bca592ce80c98a89d756 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 29 Jul 2022 08:12:50 +0200 Subject: [PATCH 208/308] Fix typing issue, avoid using .get() when unnecessary, convert to fstrings --- freqtrade/freqai/data_drawer.py | 45 ++++++++++--------- freqtrade/freqai/data_kitchen.py | 28 ++++++------ freqtrade/freqai/freqai_interface.py | 34 +++++++------- .../prediction_models/BaseRegressionModel.py | 4 +- .../CatboostPredictionModel.py | 3 +- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 4d37ef8c1..97cf7607a 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -11,7 +11,7 @@ import numpy as np import pandas as pd from joblib import dump, load from joblib.externals import cloudpickle -from numpy.typing import ArrayLike +from numpy.typing import ArrayLike, NDArray from pandas import DataFrame from freqtrade.configuration import TimeRange @@ -233,12 +233,13 @@ class FreqaiDataDrawer: mrv_df[f"{label}_mean"] = dk.data["labels_mean"][label] mrv_df[f"{label}_std"] = dk.data["labels_std"][label] - if self.freqai_info.get("feature_parameters", {}).get("DI_threshold", 0) > 0: + if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: mrv_df["DI_values"] = dk.DI_values mrv_df["do_predict"] = do_preds - def append_model_predictions(self, pair: str, predictions: DataFrame, do_preds: ArrayLike, + def append_model_predictions(self, pair: str, predictions: DataFrame, + do_preds: NDArray[np.int_], dk: FreqaiDataKitchen, len_df: int) -> None: # strat seems to feed us variable sized dataframes - and since we are trying to build our @@ -266,10 +267,10 @@ class FreqaiDataDrawer: df[label].iloc[-1] = predictions[label].iloc[-1] df[f"{label}_mean"].iloc[-1] = dk.data["labels_mean"][label] df[f"{label}_std"].iloc[-1] = dk.data["labels_std"][label] - # df['prediction'].iloc[-1] = predictions[-1] + df["do_predict"].iloc[-1] = do_preds[-1] - if self.freqai_info.get("feature_parameters", {}).get("DI_threshold", 0) > 0: + if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: df["DI_values"].iloc[-1] = dk.DI_values[-1] # append the new predictions to persistent storage @@ -309,7 +310,7 @@ class FreqaiDataDrawer: # dataframe['prediction'] = 0 dataframe["do_predict"] = 0 - if self.freqai_info.get("feature_parameters", {}).get("DI_threshold", 0) > 0: + if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: dataframe["DI_value"] = 0 dk.return_dataframe = dataframe @@ -379,24 +380,24 @@ class FreqaiDataDrawer: model.save(save_path / f"{dk.model_filename}_model.h5") if dk.svm_model is not None: - dump(dk.svm_model, save_path / str(dk.model_filename + "_svm_model.joblib")) + dump(dk.svm_model, save_path / f"{dk.model_filename}_svm_model.joblib") 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["label_list"] = dk.label_list # store the metadata - with open(save_path / str(dk.model_filename + "_metadata.json"), "w") as fp: + with open(save_path / f"{dk.model_filename}_metadata.json", "w") as fp: json.dump(dk.data, fp, default=dk.np_encoder) # save the train data to file so we can check preds for area of applicability later dk.data_dictionary["train_features"].to_pickle( - save_path / str(dk.model_filename + "_trained_df.pkl") + save_path / f"{dk.model_filename}_trained_df.pkl" ) - if self.freqai_info.get("feature_parameters", {}).get("principal_component_analysis"): + if self.freqai_info["feature_parameters"].get("principal_component_analysis"): cloudpickle.dump( - dk.pca, open(dk.data_path / str(dk.model_filename + "_pca_object.pkl"), "wb") + dk.pca, open(dk.data_path / f"{dk.model_filename}_pca_object.pkl", "wb") ) # if self.live: @@ -429,27 +430,27 @@ class FreqaiDataDrawer: / dk.data_path.parts[-1] ) - with open(dk.data_path / str(dk.model_filename + "_metadata.json"), "r") as fp: + with open(dk.data_path / f"{dk.model_filename}_metadata.json", "r") as fp: dk.data = json.load(fp) dk.training_features_list = dk.data["training_features_list"] dk.label_list = dk.data["label_list"] dk.data_dictionary["train_features"] = pd.read_pickle( - dk.data_path / str(dk.model_filename + "_trained_df.pkl") + dk.data_path / f"{dk.model_filename}_trained_df.pkl" ) # try to access model in memory instead of loading object from disk to save time if dk.live and dk.model_filename in self.model_dictionary: model = self.model_dictionary[dk.model_filename] elif not dk.keras: - model = load(dk.data_path / str(dk.model_filename + "_model.joblib")) + model = load(dk.data_path / f"{dk.model_filename}_model.joblib") else: from tensorflow import keras - model = keras.models.load_model(dk.data_path / str(dk.model_filename + "_model.h5")) + model = keras.models.load_model(dk.data_path / f"{dk.model_filename}_model.h5") - if Path(dk.data_path / str(dk.model_filename + "_svm_model.joblib")).resolve().exists(): - dk.svm_model = load(dk.data_path / str(dk.model_filename + "_svm_model.joblib")) + if Path(dk.data_path / f"{dk.model_filename}_svm_model.joblib").is_file(): + dk.svm_model = load(dk.data_path / f"{dk.model_filename}_svm_model.joblib") if not model: raise OperationalException( @@ -458,7 +459,7 @@ class FreqaiDataDrawer: if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]: dk.pca = cloudpickle.load( - open(dk.data_path / str(dk.model_filename + "_pca_object.pkl"), "rb") + open(dk.data_path / f"{dk.model_filename}_pca_object.pkl", "rb") ) return model @@ -471,7 +472,7 @@ class FreqaiDataDrawer: :params: dataframe: DataFrame = strategy provided dataframe """ - feat_params = self.freqai_info.get("feature_parameters", {}) + feat_params = self.freqai_info["feature_parameters"] with self.history_lock: history_data = self.historic_data @@ -524,7 +525,7 @@ class FreqaiDataDrawer: for pair in dk.all_pairs: if pair not in history_data: history_data[pair] = {} - for tf in self.freqai_info.get("feature_parameters", {}).get("include_timeframes"): + for tf in self.freqai_info["feature_parameters"].get("include_timeframes"): history_data[pair][tf] = load_pair_history( datadir=self.config["datadir"], timeframe=tf, @@ -550,11 +551,11 @@ class FreqaiDataDrawer: corr_dataframes: Dict[Any, Any] = {} base_dataframes: Dict[Any, Any] = {} historic_data = self.historic_data - pairs = self.freqai_info.get("feature_parameters", {}).get( + pairs = self.freqai_info["feature_parameters"].get( "include_corr_pairlist", [] ) - for tf in self.freqai_info.get("feature_parameters", {}).get("include_timeframes"): + for tf in self.freqai_info["feature_parameters"].get("include_timeframes"): base_dataframes[tf] = dk.slice_dataframe(timerange, historic_data[pair][tf]) if pairs: for p in pairs: diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index f16e169b9..b5a3295b5 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -116,7 +116,7 @@ class FreqaiDataKitchen: :filtered_dataframe: cleaned dataframe ready to be split. :labels: cleaned labels ready to be split. """ - feat_dict = self.freqai_config.get("feature_parameters", {}) + feat_dict = self.freqai_config["feature_parameters"] weights: npt.ArrayLike if feat_dict.get("weight_factor", 0) > 0: @@ -515,7 +515,9 @@ class FreqaiDataKitchen: return if predict: - assert self.svm_model, "No svm model available for outlier removal" + if not self.svm_model: + logger.warning("No svm model available for outlier removal") + return y_pred = self.svm_model.predict(self.data_dictionary["prediction_features"]) do_predict = np.where(y_pred == -1, 0, y_pred) @@ -528,7 +530,7 @@ class FreqaiDataKitchen: else: # use SGDOneClassSVM to increase speed? - nu = self.freqai_config.get("feature_parameters", {}).get("svm_nu", 0.2) + nu = self.freqai_config["feature_parameters"].get("svm_nu", 0.2) self.svm_model = linear_model.SGDOneClassSVM(nu=nu).fit( self.data_dictionary["train_features"] ) @@ -551,7 +553,7 @@ class FreqaiDataKitchen: ) # same for test data - if self.freqai_config.get('data_split_parameters', {}).get('test_size', 0.1) != 0: + if self.freqai_config['data_split_parameters'].get('test_size', 0.1) != 0: y_pred = self.svm_model.predict(self.data_dictionary["test_features"]) dropped_points = np.where(y_pred == -1, 0, y_pred) self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ @@ -605,7 +607,7 @@ class FreqaiDataKitchen: self.DI_values = distance.min(axis=0) / self.data["avg_mean_dist"] do_predict = np.where( - self.DI_values < self.freqai_config.get("feature_parameters", {}).get("DI_threshold"), + self.DI_values < self.freqai_config["feature_parameters"]["DI_threshold"], 1, 0, ) @@ -640,7 +642,7 @@ class FreqaiDataKitchen: self.append_df[f"{label}_std"] = self.data["labels_std"][label] self.append_df["do_predict"] = do_predict - if self.freqai_config.get("feature_parameters", {}).get("DI_threshold", 0) > 0: + if self.freqai_config["feature_parameters"].get("DI_threshold", 0) > 0: self.append_df["DI_values"] = self.DI_values if self.full_df.empty: @@ -701,7 +703,7 @@ class FreqaiDataKitchen: full_timerange = start.strftime("%Y%m%d") + "-" + stop.strftime("%Y%m%d") self.full_path = Path( - self.config["user_data_dir"] / "models" / str(self.freqai_config.get("identifier")) + self.config["user_data_dir"] / "models" / f"{self.freqai_config['identifier']}" ) config_path = Path(self.config["config_files"][0]) @@ -741,10 +743,10 @@ class FreqaiDataKitchen: data_load_timerange = TimeRange() # find the max indicator length required - max_timeframe_chars = self.freqai_config.get("feature_parameters", {}).get( + max_timeframe_chars = self.freqai_config["feature_parameters"].get( "include_timeframes" )[-1] - max_period = self.freqai_config.get("feature_parameters", {}).get( + max_period = self.freqai_config["feature_parameters"].get( "indicator_max_period_candles", 50 ) additional_seconds = 0 @@ -832,7 +834,7 @@ class FreqaiDataKitchen: refresh_backtest_ohlcv_data( exchange, pairs=self.all_pairs, - timeframes=self.freqai_config.get("feature_parameters", {}).get("include_timeframes"), + timeframes=self.freqai_config["feature_parameters"].get("include_timeframes"), datadir=self.config["datadir"], timerange=timerange, new_pairs_days=new_pairs_days, @@ -845,7 +847,7 @@ class FreqaiDataKitchen: def set_all_pairs(self) -> None: self.all_pairs = copy.deepcopy( - self.freqai_config.get("feature_parameters", {}).get("include_corr_pairlist", []) + self.freqai_config["feature_parameters"].get("include_corr_pairlist", []) ) for pair in self.config.get("exchange", "").get("pair_whitelist"): if pair not in self.all_pairs: @@ -876,8 +878,8 @@ class FreqaiDataKitchen: # for prediction dataframe creation, we let dataprovider handle everything in the strategy # so we create empty dictionaries, which allows us to pass None to # `populate_any_indicators()`. Signaling we want the dp to give us the live dataframe. - tfs = self.freqai_config.get("feature_parameters", {}).get("include_timeframes") - pairs = self.freqai_config.get("feature_parameters", {}).get("include_corr_pairlist", []) + tfs = self.freqai_config["feature_parameters"].get("include_timeframes") + pairs = self.freqai_config["feature_parameters"].get("include_corr_pairlist", []) if not prediction_dataframe.empty: dataframe = prediction_dataframe.copy() for tf in tfs: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index ec69a78c4..47aeb32e4 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -12,7 +12,7 @@ from typing import Any, Dict, Tuple import numpy as np import pandas as pd -from numpy.typing import ArrayLike +from numpy.typing import NDArray from pandas import DataFrame from freqtrade.configuration import TimeRange @@ -204,14 +204,9 @@ class IFreqaiModel(ABC): dk.data_path = Path( dk.full_path - / str( - "sub-train" - + "-" - + metadata["pair"].split("/")[0] - + "_" - + str(int(trained_timestamp.stopts)) + / + f"sub-train-{metadata['pair'].split('/')[0]}_{int(trained_timestamp.stopts)}" ) - ) if not self.model_exists( metadata["pair"], dk, trained_timestamp=int(trained_timestamp.stopts) ): @@ -331,7 +326,8 @@ class IFreqaiModel(ABC): return elif self.dk.check_if_model_expired(trained_timestamp): pred_df = DataFrame(np.zeros((2, len(dk.label_list))), columns=dk.label_list) - do_preds, dk.DI_values = np.ones(2) * 2, np.zeros(2) + do_preds = np.ones(2, dtype=np.int_) * 2 + dk.DI_values = np.zeros(2) logger.warning( f"Model expired for {pair}, returning null values to strategy. Strategy " "construction should take care to consider this event with " @@ -379,15 +375,15 @@ class IFreqaiModel(ABC): example of how outlier data points are dropped from the dataframe used for training. """ - if self.freqai_info.get("feature_parameters", {}).get( + if self.freqai_info["feature_parameters"].get( "principal_component_analysis", False ): dk.principal_component_analysis() - if self.freqai_info.get("feature_parameters", {}).get("use_SVM_to_remove_outliers", False): + if self.freqai_info["feature_parameters"].get("use_SVM_to_remove_outliers", False): dk.use_SVM_to_remove_outliers(predict=False) - if self.freqai_info.get("feature_parameters", {}).get("DI_threshold", 0): + if self.freqai_info["feature_parameters"].get("DI_threshold", 0): dk.data["avg_mean_dist"] = dk.compute_distances() def data_cleaning_predict(self, dk: FreqaiDataKitchen, dataframe: DataFrame) -> None: @@ -401,15 +397,15 @@ class IFreqaiModel(ABC): of how the do_predict vector is modified. do_predict is ultimately passed back to strategy for buy signals. """ - if self.freqai_info.get("feature_parameters", {}).get( + if self.freqai_info["feature_parameters"].get( "principal_component_analysis", False ): dk.pca_transform(dataframe) - if self.freqai_info.get("feature_parameters", {}).get("use_SVM_to_remove_outliers", False): + if self.freqai_info["feature_parameters"].get("use_SVM_to_remove_outliers", False): dk.use_SVM_to_remove_outliers(predict=True) - if self.freqai_info.get("feature_parameters", {}).get("DI_threshold", 0): + if self.freqai_info["feature_parameters"].get("DI_threshold", 0): dk.check_if_pred_in_training_spaces() def model_exists( @@ -430,9 +426,9 @@ class IFreqaiModel(ABC): coin, _ = pair.split("/") if not self.live: - dk.model_filename = model_filename = "cb_" + coin.lower() + "_" + str(trained_timestamp) + dk.model_filename = model_filename = f"cb_{coin.lower()}_{trained_timestamp}" - path_to_modelfile = Path(dk.data_path / str(model_filename + "_model.joblib")) + path_to_modelfile = Path(dk.data_path / f"{model_filename}_model.joblib") file_exists = path_to_modelfile.is_file() if file_exists and not scanning: logger.info("Found model at %s", dk.data_path / dk.model_filename) @@ -442,7 +438,7 @@ class IFreqaiModel(ABC): def set_full_path(self) -> None: self.full_path = Path( - self.config["user_data_dir"] / "models" / str(self.freqai_info.get("identifier")) + self.config["user_data_dir"] / "models" / f"{self.freqai_info['identifier']}" ) self.full_path.mkdir(parents=True, exist_ok=True) shutil.copy( @@ -550,7 +546,7 @@ class IFreqaiModel(ABC): @abstractmethod def predict( self, dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = True - ) -> Tuple[DataFrame, ArrayLike]: + ) -> Tuple[DataFrame, NDArray[np.int_]]: """ Filter the prediction features data and predict with it. :param unfiltered_dataframe: Full dataframe for the current backtest period. diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index 2baec9fc3..85d7ae1ee 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -3,7 +3,7 @@ from typing import Any, Tuple import numpy.typing as npt from pandas import DataFrame - +import numpy as np from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.freqai.freqai_interface import IFreqaiModel @@ -85,7 +85,7 @@ class BaseRegressionModel(IFreqaiModel): def predict( self, unfiltered_dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = False - ) -> Tuple[DataFrame, npt.ArrayLike]: + ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: """ Filter the prediction features data and predict with it. :param: unfiltered_dataframe: Full dataframe for the current backtest period. diff --git a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py index 884933803..9731e0c01 100644 --- a/freqtrade/freqai/prediction_models/CatboostPredictionModel.py +++ b/freqtrade/freqai/prediction_models/CatboostPredictionModel.py @@ -1,6 +1,7 @@ +import gc import logging from typing import Any, Dict -import gc + from catboost import CatBoostRegressor, Pool from freqtrade.freqai.prediction_models.BaseRegressionModel import BaseRegressionModel From 59624181bd1005feb93e822e0fffddf0644fec44 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 29 Jul 2022 08:23:44 +0200 Subject: [PATCH 209/308] isort BaseRegressionModel imports --- freqtrade/freqai/prediction_models/BaseRegressionModel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index 85d7ae1ee..1901c18fe 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -1,9 +1,10 @@ import logging from typing import Any, Tuple +import numpy as np import numpy.typing as npt from pandas import DataFrame -import numpy as np + from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.freqai.freqai_interface import IFreqaiModel From 08d3ac7ef821e42e428d8250c279fb00c8da553e Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 29 Jul 2022 08:49:35 +0200 Subject: [PATCH 210/308] add keras and conv_width to schema and documentation --- docs/freqai.md | 3 +++ freqtrade/constants.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/docs/freqai.md b/docs/freqai.md index 4060b5394..3c04d5b31 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -110,6 +110,9 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `n_estimators` | A common parameter among regressors which sets the number of boosted trees to fit
**Datatype:** integer. | `learning_rate` | A common parameter among regressors which sets the boosting learning rate.
**Datatype:** float. | `n_jobs`, `thread_count`, `task_type` | Different libraries use different parameter names to control the number of threads used for parallel processing or whether or not it is a `task_type` of `gpu` or `cpu`.
**Datatype:** float. +| | **Extraneous parameters** +| `keras` | If your model makes use of keras (typical of Tensorflow based prediction models), activate this flag so that the model save/loading follows keras standards. Default value `false`
**Datatype:** boolean. +| `conv_width` | The width of a convolutional neural network input tensor. This replaces the need for `shift` by feeding in historical data points as the second dimension of the tensor. Technically, this parameter can also be used for regressors, but it only adds computational overhead and does not change the model training/prediction. Default value, 2
**Datatype:** integer. ### Important FreqAI dataframe key patterns diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 90c87809b..0134dafc0 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -481,6 +481,8 @@ CONF_SCHEMA = { "freqai": { "type": "object", "properties": { + "keras": {"type": "boolean", "default": False}, + "conv_width": {"type": "integer", "default": 2}, "train_period_days": {"type": "integer", "default": 0}, "backtest_period_days": {"type": "float", "default": 7}, "identifier": {"type": "str", "default": "example"}, From f22b14078259aea39ba6731091538dc307fccc30 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 29 Jul 2022 17:27:35 +0200 Subject: [PATCH 211/308] fix backtesting bug, undo move of label stat calc, fix example strat exit logic --- freqtrade/freqai/data_kitchen.py | 18 +++++++++--------- freqtrade/freqai/freqai_interface.py | 3 --- .../prediction_models/BaseRegressionModel.py | 4 ++-- freqtrade/templates/FreqaiExampleStrategy.py | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index b5a3295b5..788572ba6 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -635,20 +635,20 @@ class FreqaiDataKitchen: Append backtest prediction from current backtest period to all previous periods """ - self.append_df = DataFrame() + append_df = DataFrame() for label in self.label_list: - self.append_df[label] = predictions[label] - self.append_df[f"{label}_mean"] = self.data["labels_mean"][label] - self.append_df[f"{label}_std"] = self.data["labels_std"][label] + append_df[label] = predictions[label] + append_df[f"{label}_mean"] = self.data["labels_mean"][label] + append_df[f"{label}_std"] = self.data["labels_std"][label] - self.append_df["do_predict"] = do_predict + append_df["do_predict"] = do_predict if self.freqai_config["feature_parameters"].get("DI_threshold", 0) > 0: - self.append_df["DI_values"] = self.DI_values + append_df["DI_values"] = self.DI_values if self.full_df.empty: - self.full_df = self.append_df + self.full_df = append_df else: - self.full_df = pd.concat([self.full_df, self.append_df], axis=0) + self.full_df = pd.concat([self.full_df, append_df], axis=0) return @@ -668,7 +668,7 @@ class FreqaiDataKitchen: to_keep = [col for col in dataframe.columns if not col.startswith("&")] self.return_dataframe = pd.concat([dataframe[to_keep], self.full_df], axis=1) - self.append_df = DataFrame() + # self.append_df = DataFrame() self.full_df = DataFrame() return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 47aeb32e4..3b97637a8 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -1,7 +1,6 @@ # import contextlib import copy import datetime -import gc import logging import shutil import threading @@ -183,8 +182,6 @@ class IFreqaiModel(ABC): (_, _, _) = self.dd.get_pair_dict_info(metadata["pair"]) train_it += 1 total_trains = len(dk.backtesting_timeranges) - gc.collect() - dk.data = {} # clean the pair specific data between training window sliding self.training_timerange = tr_train dataframe_train = dk.slice_dataframe(tr_train, dataframe) dataframe_backtest = dk.slice_dataframe(tr_backtest, dataframe) diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index 1901c18fe..112e48183 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -56,6 +56,8 @@ class BaseRegressionModel(IFreqaiModel): f"{end_date}--------------------") # split data into train/test data. data_dictionary = dk.make_train_test_datasets(features_filtered, labels_filtered) + if not self.freqai_info.get('fit_live_predictions', 0) or not self.live: + dk.fit_labels() # normalize all data based on train_dataset only data_dictionary = dk.normalize_data(data_dictionary) @@ -75,8 +77,6 @@ class BaseRegressionModel(IFreqaiModel): if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: self.fit_live_predictions(dk) - else: - dk.fit_labels() self.dd.save_historic_predictions_to_disk() diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 58eb47532..1196405ab 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -235,7 +235,7 @@ class FreqaiExampleStrategy(IStrategy): if ( "prediction" + entry_tag not in pair_dict[pair] - or pair_dict[pair]["prediction" + entry_tag] > 0 + or pair_dict[pair]["prediction" + entry_tag] == 0 ): with self.freqai.lock: pair_dict[pair]["prediction" + entry_tag] = abs(trade_candle["&-s_close"]) From dd8288c090a7abb0c6e503e80bdfd7c2220decca Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 30 Jul 2022 13:40:05 +0200 Subject: [PATCH 212/308] expose full parameter set for SVM outlier detection. Set default shuffle to false to improve reproducibility --- docs/freqai.md | 2 +- freqtrade/freqai/data_kitchen.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 3c04d5b31..c4d0ad0f8 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -97,7 +97,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `weight_factor` | Used to set weights for training data points according to their recency, see details and a figure of how it works [here](##controlling-the-model-learning-process).
**Datatype:** positive float (typically below 1). | `principal_component_analysis` | Ask FreqAI to automatically reduce the dimensionality of the data set using PCA.
**Datatype:** boolean. | `use_SVM_to_remove_outliers` | Ask FreqAI to train a support vector machine to detect and remove outliers from the training data set as well as from incoming data points.
**Datatype:** boolean. -| `svm_nu` | The `nu` parameter for the support vector machine. *Very* broadly, this is the percentage of data points that should be considered outliers.
**Datatype:** float between 0 and 1. +| `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. E.g. `nu` *Very* broadly, is the percentage of data points that should be considered outliers. `shuffle` is by default false to maintain reprodicibility. But these and all others can be added/changed in this dictionary.
**Datatype:** dictionary. | `stratify_training_data` | This value is used to indicate the stratification of the data. e.g. 2 would set every 2nd data point into a separate dataset to be pulled from during training/testing.
**Datatype:** positive integer. | `indicator_max_period_candles` | The maximum *period* used in `populate_any_indicators()` for indicator creation. FreqAI uses this information in combination with the maximum timeframe to calculate how many data points it should download so that the first data point does not have a NaN
**Datatype:** positive integer. | `indicator_periods_candles` | A list of integers used to duplicate all indicators according to a set of periods and add them to the feature set.
**Datatype:** list of positive integers. diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 788572ba6..4a936475a 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -530,8 +530,9 @@ class FreqaiDataKitchen: else: # use SGDOneClassSVM to increase speed? - nu = self.freqai_config["feature_parameters"].get("svm_nu", 0.2) - self.svm_model = linear_model.SGDOneClassSVM(nu=nu).fit( + svm_params = self.freqai_config["feature_parameters"].get( + "svm_params", {"shuffle": False, "nu": 0.1}) + self.svm_model = linear_model.SGDOneClassSVM(**svm_params).fit( self.data_dictionary["train_features"] ) y_pred = self.svm_model.predict(self.data_dictionary["train_features"]) From c2eaa3d2cde4db76111d93f9a1281676838861e0 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Sat, 30 Jul 2022 18:51:00 +0200 Subject: [PATCH 213/308] add image of algorithmic overview to doc --- docs/assets/freqai_algo.png | Bin 0 -> 335507 bytes docs/freqai.md | 18 ++++++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) create mode 100644 docs/assets/freqai_algo.png diff --git a/docs/assets/freqai_algo.png b/docs/assets/freqai_algo.png new file mode 100644 index 0000000000000000000000000000000000000000..39fb898558b638c4703c67a406fbc2cead95728f GIT binary patch literal 335507 zcmbTeby!qUyElv=prk>kL3eiu2oeI)-QCU5h=?>ONVl|fcO%{1Lr9l24E3$i=Q-y+ z|9;nHz@9yOR^IEre=)%y}7M6#n>SOK4g`o05MCfi zy%kY*OWs?AXveHyw;o{!3L=YW2L*+A+BqB+Sy-5M#AcglSZG3<{*wR+#ny}exdVPB$nvEK>i@k-8T~Qe|MML1;tx&95t09U zX;SnP*8lryFF)tuJ#+p)4S4ys>TA0H|Go4x;34V%`TR!;jQ>BIq(0${3h#g?Ei)2F zz+B?NmnW-Ctn5g{W)<+C|26K$D#4;klhFOC=%b^OvL9Mx+(VX@^~9n<4V_cJ!XS#) z;1`eCB(#ju9M6}ZYqbUz2TBQP9zXosM(OC7|MYQzQc8X!Q)SYb`STMP2ybi@Sn|HO1r1!<`y^l5TAtJJ z-@(5K`#Ur@1$mQ}=@b`^{!D1~LthhmL+1Sq*K%8p;%Q8?V}`5g zB75=QIXEEwJ873{b?zrrrW_;p+70=HI%Yj-VlT;*EfkPH9~5uvDyN*F;!Swyr1FA? zMx`>oFe^|F#D_m3FX)Cm5)7tq`1kKP6P8sJd{0Fu2m*=-(eVF{<|jN5@AP7+H|RCC)|M|L5WVeOH=;6>GiWEquD_W=yp}#Sik{y+Yt6S=`MsWZw5=IOy>u9y60O2{s`)=H`vc!x z4r;V9(yj*!Qg7cr?2aH6E0|neU2Q+z9xp2&!|Yq%+>B06elIGD=;PyKY--Bpy!GMy zU{R~12_L(j(`t&vX0B3;Z=?Ngmt>y6QKtL1DSrCUG=l!7@vr2xz@@RHd#*U_ZZ_X# z3IAzVoW_W{UyE8F-Ir_LG^cq#lFh*T*kz-A$g}k|@oR@?2e*NVRhutYM4PWCProTC z1*K3@jW4+d=_1~z)7^x(NU-sXuk>S91&Vot`KV&0L&*wopSPqw0SFEN31bEE4){gh5r_MR= z6GV-Te>d&rEL|VA40n_JYQMG-mVEa7`E02HQb{w+QWlb}9S{((x73t$wmS_Sb2zUm z%%9G}J6f?I(IEds$4>sS_;uqJZ!;~Lc(3z~KuqF7q1TUMx;kf?FJZ>GrfBTC8bXg` ztWGSwg|VZ#yovt2yTOpNMl-siM}5H3kkn7|ag?2(WoI3$@OmN*dgocLsj9+|SRJ}6 zLR*ODiN}qN%0w3QVA{>H03+P`DYJ~cIkpsuMI+aO=0S#`Nz1O0P!BvLTB zbmrGH_FbCN^L+1Hx)|=~z(A<#T%o7ME$mF-e8#B83;W8sAXL7l9-)@YdHEtz?g7hL z6ItcC&4&XAUcxJ{vjN+i>d(<6Nm92tYz4If8+d5iJG1P+6Q;61VL@7S*x9!@I-|iL z9!C&kw0!OPg*0ukKmU<0oaBLR$@q+8q)c;c zdyYjzkZ_vhMmU2dr)&LLSHb92TJeap`Wn$;;NLNHtL>Q}dfDmSy||d-xsNdE zc|oU*0YRHX5!V(}l1fcRt!it7u`DTwGZ}h+lyEejDsG8(sZ+V(!OqheUX5>Vf+rDk zw>2!1xz3S@VZZ!KAamMBmMA6Fwy^0P_vzIHd2frk-rFHLpQP3Hv4cqy9Eg;yCRxiV zRB|MTB{9;nJ&awR0GTA6=Ht0GG3+*%{~Di!*`v(3Atn>Im{HqYXsqBjfVDOy7F?PA|Fsoo%S}!pa%#ZOsq5O-JkHH=$)qoMg@; zc$QMlv2@%){}#1tl&;hx2R*m7aBlTl`lo(?#C2IM@Jmi zGhcmfVcY16ak%8hdT?3KyqPZ6>EF*(Euf^N3;^fl z@yUtBcusiR`Kk?FObD3pZM|u84w@KguurP1t2t~J;tLBIM8(98&d+mHi!>!{C@CnG z4-e%vHHjECE7LtM4r(|hHPzLFT3Un+3=DX9c$Rl}3l6OcRExsSTU_^v;+S+qGe<|7 zJRyl(HkPG21(W6WE22Yb!gi;3ht#{%C7Tye-Zh0b|& z-U!QNTpBkSOBP9-BNrjsGbJ)b&Ml|!7V1L_il3DWB7RipM=>x^s`Aab@GL=9^Jy_X zHf5-Tu6MEIZ^0HE=-&AwSWXV9v{dk0j1oeo4oE|I>{IqSN$Ldu9<6VyqCu9o+Wdrw z$nsA`e%pPT4=k9u`SO!Sh3ROeh0;`s-f+dRQ2)+k0U?L^SD%)J1#Q!z|s z9)A7`wm5mN;~qckFBjO7-|GCFw*Mk1nKBewG9oKirb3#jmLfTVT9~oV(8VPzJKrh z6^hU6y!9l7&js;Kk?P4o!(qAAG}DsX8fJ2G^5voLy^NzH8!@*n2O6SsCls3IezL)8 z(uc$6y!8gmlU?%_RUj6r;oZ#@ibx<>{i&V@ykO!JSdCD&x3@9Kg^~{z8!8;vrLApj zjxH`X*W>i41O!M%il}H7(`1vlMl-|$=`Id!XX~7(#lB#)wf`Wx>r`R;isQx>p>yBR z-pKj-w1m^*uq#;B0J3zhqxe-VD4~7eg^RN6sNND?m|He=e(lr5kh*|R;IJ-eY=6No z7`af02%={u3%8h-EIp|$rQ6fr`0}Td#>dK*L|l-Jj&uoJJRP9=9tXOh*=tADnCAo(WoYU-7Et!z7h>pwAK>%v+9mE^a3H{uIF&3?2Oi|F&ufV=n z7qx6)D$P{ZmTyd>0D^IO z#@*?7rmxaU#;yXYVQIUrd18O2{_tB}VwqRjANN<(las9yzg0>XaUj2GdJfMBFKfQR zmuzbPzyQT7QSKzAeC2YZ?g(kChhAWv4J2_#iUne^>bD{wbVZU6qcbO9r2IQ5V*&yKJPxZ5!Lk6Wdptu7 z_2%|Ae6FUv{1rcc5-Gnci)*2SU(fH~#u4Pga?oaPOkIe*{R?X9z`-PLc8Ars&z?Oy zEuaG*E$`vMcYSd&S&Ti`c0`4JDiWayprk?>NyGryldom=;>!{RJt7i0^+S z^zR^I)@fWJ)VlMq*=x!m+|<0Y7yMvhj}?hmwauA9+u&O-+L=u;7VXq4sXBU5wt?YU zjd|^Z+3D-~koIV{cA_Fv#}`|oX@ZQOdc42~q|UQ9gYKe36#5o65p?WnAaVX8XE(T& zKpKY9`aF~Ua=R!qi@Kmk`Df4jUZeeRd@0!;gN{wJAZ+>9phW@g7*MIfgiBMi4j6_> zamM|*{oU0H+jcKq;XcC~^u=yB_8;a5atb2f=7VIUZpxQ=z)O6XMXRq}jccyO)r;eYLzK%#*^@bjv>S8f=owRf`X#g@G*1V^~Z{qw{_9s9|t(LQkHa#+8bu|d*sbZ-wN zrRk&QvsY^-d>EFUC5I$t{ZS`3&NlTzG+9g|rCw7Hz$t5V9w`=om(NUlq;Vr~NWffu z6NBs<@uOSa&YQUV9&LRZ63Kqu{Zin{fO!DN)Hrvu%<|5`wYYY`NsmCth#b$r^T%nv zt7ce{hkafAyI~Is{7FLA55Jb#2Vb+1pt zkA5`sL{w9mZzFcY?X>V+gGEs((;*>w-tXhY7g7F7v;*{=lidN;ku~WV!9R`@5i$F| zDo6ON%6H!FBD~#ek&`z6>66xVD_9Ddp3HxAOa075l8(1eTUi?StYL!Fjr`^OYsuQE zFzE!D2u1OZgR?EJ0%OE>kP&{xixF`(#NzFxL-Cpkog38oa}6UY%UyLicl>dGEm+2^ zf{*m#)`N<=ML=eu?jac7JVnQ&Q=2zwkovV%8-mY+{XLr#Q74_rVI5;b&nh)1+ygGd z&Nn8;P6V3n6)fFVz2wp1g;LNCyrk|FgsgTx*7ew?1m)@nx)|*S*P`}Ye}Dh0Vc$Ek zG$HTP2Z4ql2Q>f%FoQ<<=WLlc#IK2oA(}-SAb6o%H{Zc_t!GO8O!{MwPKJe{s?dHE zT)H18{y0{4_O*WImd@$vI6`()gi?n!iK!y3?qpu4(+8*s=;-LC z!>NOyY`xkoX>mL5rKaCElazeq;NYOHNi>X-#^>_W=NC%rCuHH5sumpUCC=ass<_UjpEz=+yKqx66#}*F6DP)) zKj^^->a*%B?jqc`LXSrY3+d<{S{d0%Z5o6-FcEq64k|>aX01+CKRR}r1l5TCa9_b` z(%2`pX7bPe6`Y&rZ%-BnkZx`#d4(3ZQt?bs5k7J44o*5B9G)!c|Tpj}|t)&9~MNThr1mD=hC= z6;~_Vx0CK94u!cJKH8knWq_(E7ug)of&Mqo=!M3nq zvga#nzEoSGZ%|2E+CGW+KE+S%>b@5+wD)rU7!}!N*U`1~Dd3uFN9~b$Rq5Kb3`0tp z-n1#QUqpz&wFY_WO)2%YFS_Bc8k*I-BYzzx7EG#JU`*Kt3-417fLZb`9rCR)5#n zPUD@Uic`3ebnW#^#No@0uo36_~5c##fzgPNx(y(S`p6$6|Q>p!8JLHR(ma z4ik!#a%y0)u*JW-yu`5*`tzEdG7bdI<0IindrK`IaESDlX=HVpji)Ct2`UWUo;=b$7EO+n+O|0UR7LfHjM<*q6a)zqkqy-H?q`8* zpY`5*nNu4F?gdTw>ecvbA$ulHS=Zvb+IArw#uV+*_Ao8?bmzh&!HI%wX=&N=Tr3L- zF%OI7)r*~K?mZb0n*xRTew`U{=Rs#l17YVB+S0GQ>^K(9AX$eEi{YQJ-wE;k3T7Tw z{91$_=Hiyaxu%A>b_vcOPzV-DL{R9;Qk^RcfSNoL>gyT5SHPz>xK#J<@e+~T#cWF6 zWY4$VZoAU6tES7LUFmyl&xA%{rXsB0GwtKGZqw}*@lFN4FKJRA`_6MREtpm9TH>467e31rvSp z(0%QZ!{#%BQ{SfTGgEw=ShS(rLo|Bt=}}utnXX%biF7W>LSF&U7i3e@c&#L*cs0q+ zX7fUsTg<%iITdo}TAv$~(Qex(PHb3}1P^f#R+%ZDIk80qfhSm2#>Z)>q+`gALti84 zm{xAKHc)Tf81g$tsa*Pc`c>v(q+XhRx{Du4`F6v(PR=K1*KsNqX<%y;A)U|t3VGFzR)d<#z{KPi$godK2GfMo4qNV* z%&R?*(yvl*@|c+O5Yj);^pVcc3KfGK3RWoriY|SS$iot`00xQ5awQaM_4d0@8ZO9@ zIu;g^0fv<9vOD!HK||3<|8#3KjEEC$q=@edfFK`ea4?9u2DSwD=WB9HOTT8mi&V{D zOgskx^Q0Y}SsD6R22;7v>zV+a`o7~{c4259iR(D4TV7j;L~G@RxfnVA#yx9@$!0F= zzJDr0Ew`(2U&G?rb(m+>>x0yYQ};^Vg3Q#-mZUB==X%@otIyN?M?A}8+t+cErBr1I~%F_c~Z=@ag6%B#`3bEzssn8Ms^i1 z784gw?aUSu_s>GaW-m+bp95a0w}p`+&_PC=_ueI_S9O+CUixl}nZ*>*DY4zDX(dFB zOIBV=jr>z9J7vVli=-yydNon?EwX7LYMzyQ8ZG7x+oXxEW0)SP3pjn9HTCH%+?gPm zNxhng<5tBSM*Huswyl1JlIubUV$Jt<#u%3R_Rm8i*>elw55?|aWC*mqR3$Jvgo(j#%^StJ8Q6#%+PZP)dLxRnZ2DE!!_&h z!+D+UdmnkG5=_J4q%Y4|1g<%L=X*!HSsuPEByoQJ{EPQwWH(pX)V*4+tQ3p$A2V;a zgG(GueBqA%#>l(Fi{HJA&$s`)-~F-wg&zQ*anu*@Cvq|Pt4;-U^lat(AImCi;v#Of zATBh1?Wun}Z*Q?P5R{E{`rx^i8Zp%^>$589!JJ&z48{qa)6fDWg)doSp0@b@W<}X4 z$VO@yU1Lkf8FJ*5aP-2VB?@pnK}6Gy?oP0?UA2Sr=hSjrElldAt>z6?Rh*9>KZd1| zl90snI#FpB;Ry>1%cTlP+1s;7N!5#x+F%a3(aSwhiIvD~829F3MMW8IP@yGL{6 z#k{DwHfOq?G<#YIr;&Rpw-m{})**T>LyVru_eijt(`2!I{L(IRwD3_XKP z=~Z@O$%~lddbJZ(9dkpU8c8^%SQBdFh!_N`SwFA&2COd4NC{iD6f(g?B-d6URo8WpZu{3$3btI>0|-e`-4W~c`_{5QSs-Y|ZtX0cChGI)eAr#8 z$JN2d-coGD$&G+*7rl`7e*&f}(~9Z>*)pv-#=9CQXV4>|5B`PL8ad9wOR_3(^jgY>F(I*4~Z0+M`86 zsc4aK^WXEW`bk9vn53z;;n3;L+EcA3i@KvlTpzNx##Hj1CMi%TcFpdQoW1h}1BL&r zEy$}8G}pGYSq4T$;CmOfJ9W&;TzD}b)+r=6=QWyrI1-E{O9_@&kgi$@y&kvzj30i@ zIdNFy-Q~l9OytqL)N3xD2xucv(mktZj{;+GL^elYVowKnAd7E=5*J^>Lop9*v?(|K za@7h*aE7>+`4r%s3!2EZwDkg$9bYhwZZ3}`=FJA;{i>=~UJTAvS-BrJUD!h)n^n`g zYrWKIS?TE?0nD!KyJ_c_l(bz*sG*_pdvn*6SuTkS)6UK=(>nxRMs4zkc<9!6E;dLm zelNHAfBy32csn<(-0R8_5Nt9vwu`5~N>Y-OPc2gWG|P=2gS>#VZr=y~dh`9=wWXlh zcDh)cLHLoS+VNF*>gtQ+I%=-*7kH{jL!7WV6ql|o<`Kki~C_A=X|wW zK6Yc#j$uP;W7Wk+Q%$=`3$``|=zPD833LN(`k4^xADlZvwRo>4Ca(fW7!&>WbmV># zM#k1(;5$g+zaLP`pKZ~^r?3)k&Aho#ve{O4){~vgX+`{lwA+o(d;%JW*vx89XsLaRrQ`vbI={x#M!`>wVP4*het2t%Q6%3* z`;WT(vLu>_pX}nx7wRR8jAW=g%w>ZE%nN#8S-Du&T#Vo@UAwXql5C8d+cGXF&nGzF zwZ#*V{fWw-$iYR2WyLeof_)ZMMVcv4cmnyjVZhwX8RKI@9ibd1X|4OqqX@J1INj~Z zqlBq24c52!PMXRn{Cd1WY!s6d86G~N!w*JaqZ?E;p63=pV8c9u;um4_!4K&Xaqr$? zy7WcmjyK`nI{W~f_)sum+-aJK;h_v`u$6Xi*g+z|73P*kRc6>{FxQ}?aX%4#m|glI|DuIZeXz)2pp*)Byq~ zwE?Yhyqire?QY;OPn{4wT4z$-?qA&G$~j z*9Pzn@*Q8qkt3B9{~RBSX4E!qr&?H8SkIOR0L~n$&|)_YKz57KAL0QP^|qlRskUo_ z`>1ZqEw9_R&I;by>6=*j$#Zw;hc{Jl9^P_(;r1vo+77+8x7+LdB>c|cQ2S`WR2CPd zPb>E4y8V@XSldU4Lw)kVckQA5V5(KaS4S(`S)IG8Bgz~fbi5uf2)x(RDhf_0*9?!< z_g(y%e2lWx&yV-wC7l>~=jCR1fAS2DY3btJ(6b`dQ2)?yAzwFb^~Ae)814YgRP6Ju zS`*x?qB;eRS_1o55s<*UBHzVGieRBq=NrtGFH&)(6 zyV_E`HNi>Aj5<(W@wT83=2NZ=$vkzvKpR7#)E%C-hvPMRFJ|B|ep)cO^r?a@m&*oj^7?W<&qE-w2DW zA2_@Oge5|4)lVBol*WX13^j86)gh{{IO(04aR-EKzfXiPZffIte~iY8({>+M$d*XZ z9)yNM7^9KDg@#JvZxEwQ729BCva~#5cVf>>*!vZNnh+Xlp{Ii%rkUNfFqe#?(~q5q zkBWZaM&-55qmU5I>&eS{+TUDA|I@%IgpC5%L;=Q+PK>VjdW^P*Hoa7NE~D`W;vWm~ z;ZLhM9>esHm(9^QC{Sn=P;%3yd&QM-vKY7{vYS%$*HZ+!`|$jj7{MWQdjXPT)ACX` zF9q+c!XKY5NYiXO0960go;N|Kgw$}_DzMbG{D;CJigUtfL~JAhYU^K8sdJGU4rzJY z{qFe&NM&c~or{~fG;wQF}wD}SQMEDrO7LiuT>xl|Q3LT##)cdUmIF7a3UZ(;#L?Be&u z0~e$9`@W<&Qs2;lYkb1CDY{vS#iu#NGAf zlg_(HQBm=t-q{mSGN&n-Nv0TeRLahMoCQCf$Y8qgT! z)>9%I#av8ewlk4Ggp^s#qhjMTp(Uy*QP6MENge8^znK^q2CwvYdHArc3Zb#l-xQr! zL*|O-_9n;XNwuw6YCe3(o7zHMmL=Do@Jfhoh?Ndd;QFXY7Uw~E$Xk<~FeOgPHM>#t z)4Z^}IPUqkxM-fUNMQ-)#17C61*-{WP_Dm1Fw*{k9!Y-QL3KO zY3(Z{x98uqt*ut~&0^Jh@)?>KiTD%~nc$X)T?V{Gl<#6ckHJ!()f{osR`Q4#&(^K; z*h3)?n{D@lBD%Y8e+;y(5(8i&kCO6->y2y*zJ=8zDL?6A@)iReXPU!inquVTNvMA} zS46%eKafX}cpW}8Yi{|RYlj3dfQXAH@&KK~y4!r%jh9-?q3%-PKZPtl{6vNyJ#~&d zU;1`nc&rGoj76op^=%TwDH~}EWt93x^Ug`vK!Yu_r9-L6oNcB;dJxYTzjXhXxArZ2 zd`<^3`|i#-tQGzH&0uW|t|H(vc%^Yc-QK^ab>x(JY^FSVgq!t@0ZS5h1Ale2qPcm* z#iWp=h~Uz}4#jICX`+;4b(s1I$h8W5QJmauo&Xh1Y?7(WU**RFDMX!1_R&kaT-Acd zn3$A&d_*4$)JmQa5lI6EJ|+U<;<64z2yjpgvgF>a|AGe)nn1Lb0CEugk3c43XlFM( zS)hhFMr&eXQf4|xq*-Gt>*mIzSrnU>M|1n8PBcTm=j%(5fbWD-9YR~ubelW~Pk#YC z&JPLo89siXbT%8$Jy_EAE-sW*R9|{}B>mUGVelX*DCh-fO?Vd%vnPn_>R?ml%BPv0 z?M$M~gOo=D=silB&NX9-3E!BSQh^^66`mN6=g10N{f>qyOWQRbp+r;38qSuRXg7IG z>O=ieu>k|y-s(qLQ6(rSXfgQ{_wMfQ_xiSJ*5P6UzMdYG?xKi~QMWN3=tH0}PHNR- zZQoBRZ~?(?IbFkDcYCRq0r2S6z3IVZqnPT9veo*g0MO z8S1DJSX=S9w#I>T>BEqXrht}EMTm&t2r`N4xo-FNA=B8|`niD97HeYo=@@prnya1# zeLlb9lHi{9_bz&F#>h{}KZ~fG>7-HBNW5s|&x)LBu9_Q_aC7t6epM;YmwYlPHtf%fQIa>=K8tT|>aw_##=e`LvyO02xAL2b)(OBI-QOnt1g+TEf z&=3M8+~wuv7V0Vpzu}RQ*g(=#X$NhV-Xs)oW1*HyenCSM1lNA(w;?Whoybzjrw$O? zHHu6Z*C%%Y!Qm!|=owPcRHr+Wq4GjkpCg6u;sJH`2UMt~=A*BGP;q;v?6px>SleWk z@mEu@44wDqVxGR1fCuEei`+?r)qJ z7#V397_xw1#rbe41xSs61m&zPw6*n3V`F1!S=mb(nx3tN3bSF;-Kiq4lR<8HN(A<5 zTAZ#&aGlfU@mi#?Vy;{Yot`H-IXO_hw#Bm=UH*=ihfAe^5(2&lDP>}}E|h3+;0)o# zl4s=6TK5S!B~C!v#SUPtYTLy==9U{ndtG*R_Nii>P=9}6dP_66wHL53yWMIZ291g2iJJA`=KN<=EsRV`B5@`0S2`c|l%X_I^HQ z(3UeL)#&oX=0R;KbNzx)0eZ;EB>|bWDTcS(b$?0ku8J+Z%z}djlfV{PK=Qdm=dNYI{ z#T3Mqak24YBD%c@)<-*E%aNPVkI}++Bxd+D6BlY`5>o2Ts;ZN}9sYdShLF=djbz1- zK6DU42l>@kx2OPX{SGu_Ts$!^THKG`c_uJB+jUp~3e&Hc=eR(XcK$$l-jr&K-DhSI3XbXq3Lpt9b`OxkLZ|M}u;9Q;krKmaInk*Jtm67WGG3DP{4G4Zo@UUF@1 zqUY(bP`%WXUl!HxM{&$~s(uTkd$#xyyNK_4Z@O@5ihPLI3(9G=pB$54yl0tt2c1^D z_$X1tsv(oXMw=o2U{(5)9PTaS8QH27qrA>C#c5iP<3*?df&aat&PO(o7Fi{Ayg%4v z?;?)WJv)2w^j{%+DCt4@vQvlC{n!}nA8p3XoskSApo^nqW&QT&kNwV6kyZJn!~NZD zo!1o`$i6>+{`{fA)yB)q3&DJ@k`}1+fNDND86z~E%W@(JpsUXa34;~$vz#`EfGA9u z3dC`^@Cw}bRzd>gPu+llW?^SH0xB4gP_6FlgcKCeqXo3u`w+nX#Zi+pnf@n)hx(AXpH%J)fO;HVi}r7%3rx@ zsiI%+ekvK_4;10bh)C+MS=FPY!zP+`jFznWSf!KR3rwE;V0 z_Fn6S2=&?{z+-cHV~pEbRFxiuvVXMIZ``{ky0Cl)1kUR_qr{+ymLPv_VdUd+^60tl zVV1AWj&Hq_p%P7QwfK|g-wknYdZh#sK1O<#BEQ1FN~{P@#I6731L

`jI=0OPvGE+XkyM4LCk);n#?DXb_ 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�c(Y`HV;wnHG(YD?dc> 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

ytnY64L#I7zshZtDH3t~T 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 z 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%0AP3q`gg*t0bir_>^ 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ɱ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 **Datatype:** positive float (typically below 1). | `principal_component_analysis` | Ask FreqAI to automatically reduce the dimensionality of the data set using PCA.
**Datatype:** boolean. | `use_SVM_to_remove_outliers` | Ask FreqAI to train a support vector machine to detect and remove outliers from the training data set as well as from incoming data points.
**Datatype:** boolean. -| `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. E.g. `nu` *Very* broadly, is the percentage of data points that should be considered outliers. `shuffle` is by default false to maintain reprodicibility. But these and all others can be added/changed in this dictionary.
**Datatype:** dictionary. +| `svm_nu` | The `nu` parameter for the support vector machine. *Very* broadly, this is the percentage of data points that should be considered outliers.
**Datatype:** float between 0 and 1. | `stratify_training_data` | This value is used to indicate the stratification of the data. e.g. 2 would set every 2nd data point into a separate dataset to be pulled from during training/testing.
**Datatype:** positive integer. | `indicator_max_period_candles` | The maximum *period* used in `populate_any_indicators()` for indicator creation. FreqAI uses this information in combination with the maximum timeframe to calculate how many data points it should download so that the first data point does not have a NaN
**Datatype:** positive integer. | `indicator_periods_candles` | A list of integers used to duplicate all indicators according to a set of periods and add them to the feature set.
**Datatype:** list of positive integers. @@ -110,9 +111,6 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `n_estimators` | A common parameter among regressors which sets the number of boosted trees to fit
**Datatype:** integer. | `learning_rate` | A common parameter among regressors which sets the boosting learning rate.
**Datatype:** float. | `n_jobs`, `thread_count`, `task_type` | Different libraries use different parameter names to control the number of threads used for parallel processing or whether or not it is a `task_type` of `gpu` or `cpu`.
**Datatype:** float. -| | **Extraneous parameters** -| `keras` | If your model makes use of keras (typical of Tensorflow based prediction models), activate this flag so that the model save/loading follows keras standards. Default value `false`
**Datatype:** boolean. -| `conv_width` | The width of a convolutional neural network input tensor. This replaces the need for `shift` by feeding in historical data points as the second dimension of the tensor. Technically, this parameter can also be used for regressors, but it only adds computational overhead and does not change the model training/prediction. Default value, 2
**Datatype:** integer. ### Important FreqAI dataframe key patterns From e6ebc0443ee3d738b29f78ec41f2c8d1c9e82127 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 31 Jul 2022 13:08:43 +0200 Subject: [PATCH 214/308] make single generalized config for freqai. update docs to reflect that. --- .gitignore | 3 +- ...xample.json => config_freqai.example.json} | 6 +- .../config_freqai_spot.example.json | 96 ------------------- docs/freqai.md | 9 +- 4 files changed, 9 insertions(+), 105 deletions(-) rename config_examples/{config_freqai_futures.example.json => config_freqai.example.json} (94%) delete mode 100644 config_examples/config_freqai_spot.example.json diff --git a/.gitignore b/.gitignore index 4498e42ac..73a11b47c 100644 --- a/.gitignore +++ b/.gitignore @@ -111,5 +111,4 @@ target/ !config_examples/config_ftx.example.json !config_examples/config_full.example.json !config_examples/config_kraken.example.json -!config_examples/config_freqai_futures.example.json -!config_examples/config_freqai_spot.example.json +!config_examples/config_freqai.example.json diff --git a/config_examples/config_freqai_futures.example.json b/config_examples/config_freqai.example.json similarity index 94% rename from config_examples/config_freqai_futures.example.json rename to config_examples/config_freqai.example.json index 60e1cce82..e9fc50a4a 100644 --- a/config_examples/config_freqai_futures.example.json +++ b/config_examples/config_freqai.example.json @@ -57,8 +57,7 @@ "train_period_days": 15, "backtest_period_days": 7, "live_retrain_hours": 0, - "identifier": "uniqe-id6", - "live_trained_timestamp": 0, + "identifier": "uniqe-id", "feature_parameters": { "include_timeframes": [ "3m", @@ -84,8 +83,7 @@ "random_state": 1 }, "model_training_parameters": { - "n_estimators": 1000, - "task_type": "CPU" + "n_estimators": 1000 } }, "bot_name": "", diff --git a/config_examples/config_freqai_spot.example.json b/config_examples/config_freqai_spot.example.json deleted file mode 100644 index 1ea6ddecb..000000000 --- a/config_examples/config_freqai_spot.example.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "max_open_trades": 1, - "stake_currency": "USDT", - "stake_amount": 900, - "tradable_balance_ratio": 1, - "fiat_display_currency": "USD", - "dry_run": true, - "timeframe": "5m", - "dry_run_wallet": 4000, - "dataformat_ohlcv": "json", - "cancel_open_orders_on_exit": true, - "unfilledtimeout": { - "entry": 10, - "exit": 30 - }, - "exchange": { - "name": "binance", - "key": "", - "secret": "", - "ccxt_config": { - "enableRateLimit": true - }, - "ccxt_async_config": { - "enableRateLimit": true, - "rateLimit": 200 - }, - "pair_whitelist": [ - "BTC/USDT", - "ETH/USDT" - ], - "pair_blacklist": [] - }, - "entry_pricing": { - "price_side": "same", - "use_order_book": true, - "order_book_top": 1, - "price_last_balance": 0.0, - "check_depth_of_market": { - "enabled": false, - "bids_to_ask_delta": 1 - } - }, - "exit_pricing": { - "price_side": "other", - "use_order_book": true, - "order_book_top": 1 - }, - "pairlists": [ - { - "method": "StaticPairList" - } - ], - "freqai": { - "startup_candles": 10000, - - "train_period_days": 30, - "backtest_period_days": 7, - "live_retrain_hours": 1, - "identifier": "example", - "live_trained_timestamp": 0, - "feature_parameters": { - "include_timeframes": [ - "5m", - "15m", - "4h" - ], - "include_corr_pairlist": [ - "BTC/USDT", - "ETH/USDT" - ], - "label_period_candles": 500, - "include_shifted_candles": 1, - "DI_threshold": 0, - "weight_factor": 0.9, - "principal_component_analysis": false, - "use_SVM_to_remove_outliers": false, - "stratify_training_data": 0, - "indicator_max_period_candles": 50, - "indicator_periods_candles": [10, 20] - }, - "data_split_parameters": { - "test_size": 0.33, - "random_state": 1 - }, - "model_training_parameters": { - "n_estimators": 1000, - "task_type": "CPU" - } - }, - "bot_name": "", - "initial_state": "running", - "forcebuy_enable": false, - "internals": { - "process_throttle_secs": 5 - } -} diff --git a/docs/freqai.md b/docs/freqai.md index bffa12e5d..de321b787 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -60,7 +60,7 @@ pip install -r requirements-freqai.txt An example strategy, an example prediction model, and example config can all be found in `freqtrade/templates/FreqaiExampleStrategy.py`, `freqtrade/freqai/prediction_models/LightGBMPredictionModel.py`, -`config_examples/config_freqai_futures.example.json`, respectively. +`config_examples/config_freqai.example.json`, respectively. Assuming the user has downloaded the necessary data, Freqai can be executed from these templates with: @@ -98,7 +98,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `weight_factor` | Used to set weights for training data points according to their recency, see details and a figure of how it works [here](##controlling-the-model-learning-process).
**Datatype:** positive float (typically below 1). | `principal_component_analysis` | Ask FreqAI to automatically reduce the dimensionality of the data set using PCA.
**Datatype:** boolean. | `use_SVM_to_remove_outliers` | Ask FreqAI to train a support vector machine to detect and remove outliers from the training data set as well as from incoming data points.
**Datatype:** boolean. -| `svm_nu` | The `nu` parameter for the support vector machine. *Very* broadly, this is the percentage of data points that should be considered outliers.
**Datatype:** float between 0 and 1. +| `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. E.g. `nu` *Very* broadly, is the percentage of data points that should be considered outliers. `shuffle` is by default false to maintain reprodicibility. But these and all others can be added/changed in this dictionary.
**Datatype:** dictionary. | `stratify_training_data` | This value is used to indicate the stratification of the data. e.g. 2 would set every 2nd data point into a separate dataset to be pulled from during training/testing.
**Datatype:** positive integer. | `indicator_max_period_candles` | The maximum *period* used in `populate_any_indicators()` for indicator creation. FreqAI uses this information in combination with the maximum timeframe to calculate how many data points it should download so that the first data point does not have a NaN
**Datatype:** positive integer. | `indicator_periods_candles` | A list of integers used to duplicate all indicators according to a set of periods and add them to the feature set.
**Datatype:** list of positive integers. @@ -111,6 +111,9 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `n_estimators` | A common parameter among regressors which sets the number of boosted trees to fit
**Datatype:** integer. | `learning_rate` | A common parameter among regressors which sets the boosting learning rate.
**Datatype:** float. | `n_jobs`, `thread_count`, `task_type` | Different libraries use different parameter names to control the number of threads used for parallel processing or whether or not it is a `task_type` of `gpu` or `cpu`.
**Datatype:** float. +| | **Extraneous parameters** +| `keras` | If your model makes use of keras (typical of Tensorflow based prediction models), activate this flag so that the model save/loading follows keras standards. Default value `false`
**Datatype:** boolean. +| `conv_width` | The width of a convolutional neural network input tensor. This replaces the need for `shift` by feeding in historical data points as the second dimension of the tensor. Technically, this parameter can also be used for regressors, but it only adds computational overhead and does not change the model training/prediction. Default value, 2
**Datatype:** integer. ### Important FreqAI dataframe key patterns @@ -349,7 +352,7 @@ and adding this to the `train_period_days`. The units need to be in the base can The freqai training/backtesting module can be executed with the following command: ```bash -freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai_futures.example.json --freqaimodel LightGBMPredictionModel --timerange 20210501-20210701 +freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel LightGBMPredictionModel --timerange 20210501-20210701 ``` If this command has never been executed with the existing config file, then it will train a new model From 61693f6c8bfc5c3e7eb4dc345fea4534ea5edb0a Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 31 Jul 2022 13:20:11 +0200 Subject: [PATCH 215/308] fix tests after changing config_example file --- tests/freqai/conftest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index ff70a40a4..ecd8b2d57 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -49,7 +49,7 @@ def freqai_conf(default_conf, tmpdir): "data_split_parameters": {"test_size": 0.33, "random_state": 1}, "model_training_parameters": {"n_estimators": 100, "verbosity": 0}, }, - "config_files": [Path('config_examples', 'config_freqai_futures.example.json')] + "config_files": [Path('config_examples', 'config_freqai.example.json')] } ) freqaiconf['exchange'].update({'pair_whitelist': ['ADA/BTC', 'DASH/BTC', 'ETH/BTC', 'LTC/BTC']}) @@ -57,7 +57,6 @@ def freqai_conf(default_conf, tmpdir): def get_patched_data_kitchen(mocker, freqaiconf): - # dd = mocker.patch('freqtrade.freqai.data_drawer', MagicMock()) dk = FreqaiDataKitchen(freqaiconf) return dk From cbb05354a8968c10bfcb5944db2c5fa13eb6fd5b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jul 2022 15:10:01 +0200 Subject: [PATCH 216/308] Add install variant for freqai --- requirements-freqai.txt | 1 - setup.py | 10 +++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/requirements-freqai.txt b/requirements-freqai.txt index c3aa2e4db..060a5219d 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -3,7 +3,6 @@ # Required for freqai scikit-learn==1.1.1 -scikit-optimize==0.9.0 joblib==1.1.0 catboost==1.0.4 lightgbm==3.3.2 diff --git a/setup.py b/setup.py index 7aa56bf81..33e35c5ab 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,13 @@ hyperopt = [ 'progressbar2', ] +freqai = [ + 'scikit-learn', + 'joblib', + 'catboost', + 'lightgbm', +] + develop = [ 'coveralls', 'flake8', @@ -31,7 +38,7 @@ jupyter = [ 'nbconvert', ] -all_extra = plot + develop + jupyter + hyperopt +all_extra = plot + develop + jupyter + hyperopt + freqai setup( tests_require=[ @@ -79,6 +86,7 @@ setup( 'plot': plot, 'jupyter': jupyter, 'hyperopt': hyperopt, + 'freqai': freqai, 'all': all_extra, }, ) From 659870312df456036372a3afa7825220292a3229 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jul 2022 15:23:27 +0200 Subject: [PATCH 217/308] Use JSON Schema validation for freaAI schema validation --- freqtrade/configuration/config_validation.py | 17 ------------ freqtrade/constants.py | 29 +++++++++----------- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index 5d9667196..ee846e7e6 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -85,7 +85,6 @@ def validate_config_consistency(conf: Dict[str, Any], preliminary: bool = False) _validate_unlimited_amount(conf) _validate_ask_orderbook(conf) validate_migrated_strategy_settings(conf) - _validate_freqai(conf) # validate configuration before returning logger.info('Validating configuration ...') @@ -164,22 +163,6 @@ def _validate_edge(conf: Dict[str, Any]) -> None: ) -def _validate_freqai(conf: Dict[str, Any]) -> None: - """ - Freqai param validator - """ - - if not conf.get('freqai', {}): - return - - for param in constants.SCHEMA_FREQAI_REQUIRED: - if param not in conf.get('freqai', {}): - if param not in conf.get('freqai', {}).get('feature_parameters', {}): - raise OperationalException( - f'{param} not found in Freqai config' - ) - - def _validate_whitelist(conf: Dict[str, Any]) -> None: """ Dynamic whitelist does not require pair_whitelist to be set - however StaticWhitelist does. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 0134dafc0..af2e4748a 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -241,6 +241,7 @@ CONF_SCHEMA = { }, 'exchange': {'$ref': '#/definitions/exchange'}, 'edge': {'$ref': '#/definitions/edge'}, + 'freqai': {'$ref': '#/definitions/freqai'}, 'experimental': { 'type': 'object', 'properties': { @@ -484,20 +485,21 @@ CONF_SCHEMA = { "keras": {"type": "boolean", "default": False}, "conv_width": {"type": "integer", "default": 2}, "train_period_days": {"type": "integer", "default": 0}, - "backtest_period_days": {"type": "float", "default": 7}, - "identifier": {"type": "str", "default": "example"}, + "backtest_period_days": {"type": "number", "default": 7}, + "identifier": {"type": "string", "default": "example"}, "feature_parameters": { "type": "object", "properties": { - "include_corr_pairlist": {"type": "list"}, - "include_timeframes": {"type": "list"}, + "include_corr_pairlist": {"type": "array"}, + "include_timeframes": {"type": "array"}, "label_period_candles": {"type": "integer"}, "include_shifted_candles": {"type": "integer", "default": 0}, - "DI_threshold": {"type": "float", "default": 0}, + "DI_threshold": {"type": "number", "default": 0}, "weight_factor": {"type": "number", "default": 0}, "principal_component_analysis": {"type": "boolean", "default": False}, "use_SVM_to_remove_outliers": {"type": "boolean", "default": False}, }, + "required": ["include_timeframes", "include_corr_pairlist", ] }, "data_split_parameters": { "type": "object", @@ -516,6 +518,12 @@ CONF_SCHEMA = { }, }, }, + "required": ["train_period_days", + "backtest_period_days", + "identifier", + "feature_parameters", + "data_split_parameters", + "model_training_parameters"] }, }, } @@ -560,17 +568,6 @@ SCHEMA_MINIMAL_REQUIRED = [ 'dataformat_trades', ] -SCHEMA_FREQAI_REQUIRED = [ - 'include_timeframes', - 'train_period_days', - 'backtest_period_days', - 'identifier', - 'include_corr_pairlist', - 'feature_parameters', - 'data_split_parameters', - 'model_training_parameters' -] - CANCEL_REASON = { "TIMEOUT": "cancelled due to timeout", "PARTIALLY_FILLED_KEEP_OPEN": "partially filled - keeping order open", From 153336d4241b79c8c9195ca19124fe6be56cfb29 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 31 Jul 2022 15:45:15 +0200 Subject: [PATCH 218/308] move corr_pairlist expansion to after expand_pairlist() --- freqtrade/plugins/pairlist/pairlist_helpers.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/freqtrade/plugins/pairlist/pairlist_helpers.py b/freqtrade/plugins/pairlist/pairlist_helpers.py index ee17c1be9..a07a0f783 100644 --- a/freqtrade/plugins/pairlist/pairlist_helpers.py +++ b/freqtrade/plugins/pairlist/pairlist_helpers.py @@ -43,12 +43,10 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], def dynamic_expand_pairlist(config: dict, markets: list) -> List[str]: + expanded_pairs = expand_pairlist(config['pairs'], markets) if config.get('freqai', {}): corr_pairlist = config['freqai']['feature_parameters']['include_corr_pairlist'] - full_pairs = config['pairs'] + [pair for pair in corr_pairlist - if pair not in config['pairs']] - expanded_pairs = expand_pairlist(full_pairs, markets) - else: - expanded_pairs = expand_pairlist(config['pairs'], markets) + expanded_pairs += [pair for pair in corr_pairlist + if pair not in config['pairs']] return expanded_pairs From d830105605863c2c88839d7df864c35b6db7de4f Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 31 Jul 2022 17:05:29 +0200 Subject: [PATCH 219/308] *BREAKING CHANGE* remove unnecessary arguments from populate_any_indicators(), accommodate tests --- freqtrade/freqai/data_kitchen.py | 13 +++----- freqtrade/strategy/interface.py | 5 ++- freqtrade/templates/FreqaiExampleStrategy.py | 31 +++++++++++++------ .../strats/freqai_test_multimodel_strat.py | 4 ++- tests/strategy/strats/freqai_test_strat.py | 4 ++- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 4a936475a..aedf01d11 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -892,29 +892,26 @@ class FreqaiDataKitchen: else: dataframe = base_dataframes[self.config["timeframe"]].copy() - sgi = True + sgi = False for tf in tfs: + if tf == tfs[-1]: + sgi = True # doing this last allows user to use all tf raw prices in labels dataframe = strategy.populate_any_indicators( - pair, pair, dataframe.copy(), tf, informative=base_dataframes[tf], - coin=pair.split("/")[0] + "-", - set_generalized_indicators=sgi, + set_generalized_indicators=sgi ) - sgi = False if pairs: for i in pairs: if pair in i: continue # dont repeat anything from whitelist dataframe = strategy.populate_any_indicators( - pair, i, dataframe.copy(), tf, - informative=corr_dataframes[i][tf], - coin=i.split("/")[0] + "-", + informative=corr_dataframes[i][tf] ) return dataframe diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 431e67a98..be6447811 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -557,8 +557,8 @@ class IStrategy(ABC, HyperStrategyMixin): """ return None - def populate_any_indicators(self, basepair: str, pair: str, df: DataFrame, tf: str, - informative: DataFrame = None, coin: str = "", + def populate_any_indicators(self, pair: str, df: DataFrame, tf: str, + informative: DataFrame = None, set_generalized_indicators: bool = False) -> DataFrame: """ Function designed to automatically generate, name and merge features @@ -570,7 +570,6 @@ class IStrategy(ABC, HyperStrategyMixin): :param df: strategy dataframe which will receive merges from informatives :param tf: timeframe of the dataframe which will modify the feature names :param informative: the dataframe associated with the informative pair - :param coin: the name of the coin which will modify the feature names. """ return df diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 1196405ab..90343cc80 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -65,7 +65,7 @@ class FreqaiExampleStrategy(IStrategy): return informative_pairs def populate_any_indicators( - self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False + self, pair, df, tf, informative=None, set_generalized_indicators=False ): """ Function designed to automatically generate, name and merge features @@ -78,9 +78,10 @@ class FreqaiExampleStrategy(IStrategy): :param df: strategy dataframe which will receive merges from informatives :param tf: timeframe of the dataframe which will modify the feature names :param informative: the dataframe associated with the informative pair - :param coin: the name of the coin which will modify the feature names. """ + coin = pair.split('/')[0] + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) @@ -92,11 +93,8 @@ class FreqaiExampleStrategy(IStrategy): informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - informative[f"{coin}20sma-period_{t}"] = ta.SMA(informative, timeperiod=t) - informative[f"{coin}21ema-period_{t}"] = ta.EMA(informative, timeperiod=t) - informative[f"%-{coin}close_over_20sma-period_{t}"] = ( - informative["close"] / informative[f"{coin}20sma-period_{t}"] - ) + informative[f"{coin}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) + informative[f"{coin}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) @@ -148,8 +146,6 @@ class FreqaiExampleStrategy(IStrategy): df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py df["&-s_close"] = ( df["close"] .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) @@ -159,6 +155,23 @@ class FreqaiExampleStrategy(IStrategy): - 1 ) + # If user wishes to use multiple targets, they can add more by + # appending more columns with '&'. User should keep in mind that multi targets + # requires a multioutput prediction model such as + # templates/CatboostPredictionMultiModel.py, + + # df["&-s_range"] = ( + # df["close"] + # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + # .max() + # - + # df["close"] + # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + # .min() + # ) + return df def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/strats/freqai_test_multimodel_strat.py b/tests/strategy/strats/freqai_test_multimodel_strat.py index 9652e816b..e58086757 100644 --- a/tests/strategy/strats/freqai_test_multimodel_strat.py +++ b/tests/strategy/strats/freqai_test_multimodel_strat.py @@ -62,7 +62,7 @@ class freqai_test_multimodel_strat(IStrategy): return informative_pairs def populate_any_indicators( - self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False + self, pair, df, tf, informative=None, set_generalized_indicators=False ): """ Function designed to automatically generate, name and merge features @@ -79,6 +79,8 @@ class freqai_test_multimodel_strat(IStrategy): :coin: the name of the coin which will modify the feature names. """ + coin = pair.split('/')[0] + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index 8679d4d74..8288228d1 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -62,7 +62,7 @@ class freqai_test_strat(IStrategy): return informative_pairs def populate_any_indicators( - self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False + self, pair, df, tf, informative=None, set_generalized_indicators=False ): """ Function designed to automatically generate, name and merge features @@ -79,6 +79,8 @@ class freqai_test_strat(IStrategy): :coin: the name of the coin which will modify the feature names. """ + coin = pair.split('/')[0] + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) From 4e68626bcbced4ac2d7e6a41b6e330802b6bf097 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 31 Jul 2022 17:51:19 +0200 Subject: [PATCH 220/308] ensure convolutional window is prepended for frequi consistency --- freqtrade/freqai/data_drawer.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 97cf7607a..6844af0ec 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -238,6 +238,15 @@ class FreqaiDataDrawer: mrv_df["do_predict"] = do_preds + # for keras type models, the conv_window needs to be prepended so + # viewing is correct in frequi + if self.freqai_info.get('keras', False): + n_lost_points = self.freqai_info.get('conv_width', 2) + zeros_df = DataFrame(np.zeros((n_lost_points, len(mrv_df.columns))), + columns=mrv_df.columns) + self.model_return_values[pair] = pd.concat( + [zeros_df, mrv_df], axis=0, ignore_index=True) + def append_model_predictions(self, pair: str, predictions: DataFrame, do_preds: NDArray[np.int_], dk: FreqaiDataKitchen, len_df: int) -> None: From 946d4c7cfcc645f3061b714d6b3579bdb68c820d Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 31 Jul 2022 18:39:46 +0200 Subject: [PATCH 221/308] fix trailing whitespace for flake8 --- freqtrade/freqai/data_drawer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 6844af0ec..f14277bed 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -238,7 +238,7 @@ class FreqaiDataDrawer: mrv_df["do_predict"] = do_preds - # for keras type models, the conv_window needs to be prepended so + # for keras type models, the conv_window needs to be prepended so # viewing is correct in frequi if self.freqai_info.get('keras', False): n_lost_points = self.freqai_info.get('conv_width', 2) From 3013282dbf83ee06985478cfcf8866b633c5af53 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 1 Aug 2022 05:39:38 +0200 Subject: [PATCH 222/308] remove non-catboost stuff from schema --- freqtrade/constants.py | 11 +++++++---- freqtrade/templates/FreqaiExampleStrategy.py | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index af2e4748a..d1a009ece 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -498,6 +498,12 @@ CONF_SCHEMA = { "weight_factor": {"type": "number", "default": 0}, "principal_component_analysis": {"type": "boolean", "default": False}, "use_SVM_to_remove_outliers": {"type": "boolean", "default": False}, + "svm_params": {"type": "object", + "properties": { + "shuffle": {"type": "boolean", "default": False}, + "nu": {"type": "number", "default": 0.1} + }, + } }, "required": ["include_timeframes", "include_corr_pairlist", ] }, @@ -511,10 +517,7 @@ CONF_SCHEMA = { "model_training_parameters": { "type": "object", "properties": { - "n_estimators": {"type": "integer", "default": 2000}, - "random_state": {"type": "integer", "default": 1}, - "learning_rate": {"type": "number", "default": 0.02}, - "task_type": {"type": "string", "default": "CPU"}, + "n_estimators": {"type": "integer", "default": 1000} }, }, }, diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 90343cc80..4f632f907 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -93,8 +93,8 @@ class FreqaiExampleStrategy(IStrategy): informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - informative[f"{coin}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) - informative[f"{coin}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) + informative[f"%-{coin}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) + informative[f"%-{coin}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) From 895ebbfd1836b3d9964b70422ba221aa084df2f3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Aug 2022 07:32:25 +0000 Subject: [PATCH 223/308] Exclude aarch64 from catboost requirements --- docs/freqai.md | 3 +++ requirements-freqai.txt | 2 +- setup.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index de321b787..adf64dd07 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -56,6 +56,9 @@ Use `pip` to install the prerequisites with: pip install -r requirements-freqai.txt ``` +!!! Note + Catboost will not be installed on arm devices (raspberry, Mac M1, ARM based VPS, ...), since Catboost does not provide wheels for this platform. + ## Running from the example files An example strategy, an example prediction model, and example config can all be found in diff --git a/requirements-freqai.txt b/requirements-freqai.txt index 060a5219d..e4f4a7c17 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -4,5 +4,5 @@ # Required for freqai scikit-learn==1.1.1 joblib==1.1.0 -catboost==1.0.4 +catboost==1.0.4; platform_machine != 'aarch64' lightgbm==3.3.2 diff --git a/setup.py b/setup.py index 33e35c5ab..dfadbdefa 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ hyperopt = [ freqai = [ 'scikit-learn', 'joblib', - 'catboost', + 'catboost; platform_machine != "aarch64"', 'lightgbm', ] From 95d3009a9531c99802cfa5ce3c9c46ff8010d633 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 2 Aug 2022 20:14:02 +0200 Subject: [PATCH 224/308] give user ability to analyze live trade dataframe inside custom prediction model. Add documentation to explain new functionality --- docs/freqai.md | 40 ++++++++++++++++ freqtrade/freqai/data_drawer.py | 22 +++++++-- freqtrade/freqai/data_kitchen.py | 30 ++++++++++-- freqtrade/freqai/freqai_interface.py | 68 ++++++++++++++++++++++++++-- 4 files changed, 147 insertions(+), 13 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index adf64dd07..0a07f45ef 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -619,6 +619,46 @@ If the user sets this value, FreqAI will initially use the predictions from the and then subsequently begin introducing real prediction data as it is generated. FreqAI will save this historical data to be reloaded if the user stops and restarts with the same `identifier`. +## Extra returns per train + +Users may find that there are some important metrics that they'd like to return to the strategy at the end of each retrain. +Users can include these metrics by assigining them to `dk.data['extra_returns_per_train']['my_new_value'] = XYZ` inside their custom prediction +model class. FreqAI takes the `my_new_value` assigned in this dictionary and expands it to fit the return dataframe to the strategy. +The user can then use the value in the strategy with `dataframe['my_new_value']`. An example of how this is already used in FreqAI is +the `&*_mean` and `&*_std` values, which indicate the mean and standard deviation of that particular label during the most recent training. +Another example is shown below if the user wants to use live metrics from the trade databse. + +The user needs to set the standard dictionary in the config so FreqAI can return proper dataframe shapes: + +```json + "freqai": { + "extra_returns_per_train": {"total_profit": 4} + } +``` + +These values will likely be overridden by the user prediction model, but in the case where the user model has yet to set them, or needs +a default initial value - this is the value that will be returned. + +## Analyzing the trade live database + +Users can analyze the live trade database by calling `analyze_trade_database()` in their custom prediction model. FreqAI already has the +database setup in a pandas dataframe and ready to be analyzed. Here is an example usecase: + +```python + def analyze_trade_database(self, dk: FreqaiDataKitchen, pair: str) -> None: + """ + User analyzes the trade database here and returns summary stats which will be passed back + to the strategy for reinforcement learning or for additional adaptive metrics for use + in entry/exit signals. Store these metrics in dk.data['extra_returns_per_train'] and + they will format themselves into the dataframe as an additional column in the user + strategy. User has access to the current trade database in dk.trade_database_df. + """ + total_profit = dk.trade_database_df['close_profit_abs'].sum() + dk.data['extra_returns_per_train']['total_profit'] = total_profit + + return +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FreqAI + + + + + + + + + + + + + + + diff --git a/docs/assets/freqai_logo_no_md.svg b/docs/assets/freqai_logo_no_md.svg deleted file mode 100644 index 62c32217f..000000000 --- a/docs/assets/freqai_logo_no_md.svg +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - FreqAI - - - - - - - - - - - - - diff --git a/docs/freqai.md b/docs/freqai.md index b3682127c..9b2377557 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -1,21 +1,37 @@ -![freqai-logo](assets/freqai_logo_no_md.svg) +![freqai-logo](assets/freqai_doc_logo.svg) # FreqAI -FreqAI is a module designed to automate a variety of tasks associated with -training a predictive model to provide signals based on input features. +FreqAI is a module designed to automate a variety of tasks associated with training a predictive model to generate market forecasts given a set of input features. Among the the features included: -* Create large rich feature sets (10k+ features) based on simple user created strategies. -* Sweep model training and backtesting to simulate consistent model retraining through time. -* Remove outliers automatically from training and prediction sets using a Dissimilarity Index and Support Vector Machines. -* Reduce the dimensionality of the data with Principal Component Analysis. -* Store models to disk to make reloading from a crash fast and easy (and purge obsolete files automatically for sustained dry/live runs). -* Normalize the data automatically in a smart and statistically safe way. -* Automated data download and data handling. -* Clean the incoming data of NaNs in a safe way before training and prediction. -* Retrain live automatically so that the model self-adapts to the market in an unsupervised manner. +* **Self-adaptive retraining**: automatically retrain models during live deployments to self-adapt to the market in an unsupervised manner. +* **Rapid feature engineering**: create large rich feature sets (10k+ features) based on simple user created strategies. +* **High performance**: adaptive retraining occurs on separate thread (or on GPU if available) from inferencing and bot trade operations. Keep newest models and data in memory for rapid inferencing. +* **Realistic backtesting**: emulate self-adaptive retraining with backtesting module that automates past retraining. +* **Modifiable**: use the generalized and robust architecture for incorporating any machine learning library/method available in Python. Seven examples available. +* **Smart outlier removal**: remove outliers automatically from training and prediction sets using a variety of outlier detection techniques. +* **Crash resilience**: automatic model storage to disk to make reloading from a crash fast and easy (and purge obsolete files automatically for sustained dry/live runs). +* **Automated data normalization**: automatically normalize the data automatically in a smart and statistically safe way. +* **Automatic data download**: automatically compute the data download timerange and downloads data accordingly (in live deployments). +* **Clean the incoming data of NaNs in a safe way before training and prediction. +* **Dimensionality reduction**: reduce the size of the training data via Principal Component Analysis. +* **Deploy bot fleets**: set one bot to train models while a fleet of other bots inference into the models and handle trades. + +## Quick start + +The easiest way to quickly test FreqAI is to run it in dry run with the following command + +```bash +freqtrade trade --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates +``` + +where the user will see the boot-up process of auto-data downloading, followed by simultaneous training and trading. + +The example strategy, example prediction model, and example config can all be found in +`freqtrade/templates/FreqaiExampleStrategy.py`, `freqtrade/freqai/prediction_models/LightGBMRegressor.py`, +`config_examples/config_freqai.example.json`, respectively. ## General approach @@ -30,7 +46,7 @@ An overview of the algorithm is shown here to help users understand the data pro ## Background and vocabulary **Features** are the quantities with which a model is trained. $X_i$ represents the -vector of all features for a single candle. In Freqai, the user +vector of all features for a single candle. In FreqAI, the user builds the features from anything they can construct in the strategy. **Labels** are the target values with which the weights inside a model are trained @@ -50,7 +66,7 @@ directly influence nodal weights within the model. ## Install prerequisites -Use `pip` to install the prerequisites with: +The normal Freqtrade install process will ask the user if they wish to install `FreqAI` dependencies. The user should reply "yes" to this question if they wish to use FreqAI. If the user did not reply yes, they can manually install these dependencies after the install with: ``` bash pip install -r requirements-freqai.txt @@ -59,18 +75,6 @@ pip install -r requirements-freqai.txt !!! Note Catboost will not be installed on arm devices (raspberry, Mac M1, ARM based VPS, ...), since Catboost does not provide wheels for this platform. -## Running from the example files - -An example strategy, an example prediction model, and example config can all be found in -`freqtrade/templates/FreqaiExampleStrategy.py`, `freqtrade/freqai/prediction_models/LightGBMRegressor.py`, -`config_examples/config_freqai.example.json`, respectively. - -Assuming the user has downloaded the necessary data, Freqai can be executed from these templates with: - -```bash -freqtrade backtesting --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates --timerange 20220101-20220201 -``` - ## Configuring the bot ### Parameter table @@ -92,13 +96,13 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `purge_old_models` | Tell FreqAI to delete obsolete models. Otherwise, all historic models will remain on disk. Defaults to `False`.
**Datatype:** boolean. | `expiration_hours` | Ask FreqAI to avoid making predictions if a model is more than `expiration_hours` old. Defaults to 0 which means models never expire.
**Datatype:** positive integer. | | **Feature Parameters** -| `feature_parameters` | A dictionary containing the parameters used to engineer the feature set. Details and examples shown [here](#building-the-feature-set)
**Datatype:** dictionary. +| `feature_parameters` | A dictionary containing the parameters used to engineer the feature set. Details and examples shown [here](#feature-engineering)
**Datatype:** dictionary. | `include_corr_pairlist` | A list of correlated coins that FreqAI will add as additional features to all `pair_whitelist` coins. All indicators set in `populate_any_indicators` will be created for each coin in this list, and that set of features is added to the base asset feature set.
**Datatype:** list of assets (strings). | `include_timeframes` | A list of timeframes that all indicators in `populate_any_indicators` will be created for and added as features to the base asset feature set.
**Datatype:** list of timeframes (strings). | `label_period_candles` | Number of candles into the future that the labels are created for. This is used in `populate_any_indicators`, refer to `templates/FreqaiExampleStrategy.py` for detailed usage. The user can create custom labels, making use of this parameter not.
**Datatype:** positive integer. | `include_shifted_candles` | Parameter used to add a sense of temporal recency to flattened regression type input data. `include_shifted_candles` takes all features, duplicates and shifts them by the number indicated by user.
**Datatype:** positive integer. | `DI_threshold` | Activates the Dissimilarity Index for outlier detection when above 0, explained more [here](#removing-outliers-with-the-dissimilarity-index).
**Datatype:** positive float (typically below 1). -| `weight_factor` | Used to set weights for training data points according to their recency, see details and a figure of how it works [here](##controlling-the-model-learning-process).
**Datatype:** positive float (typically below 1). +| `weight_factor` | Used to set weights for training data points according to their recency, see details and a figure of how it works [here](#controlling-the-model-learning-process).
**Datatype:** positive float (typically below 1). | `principal_component_analysis` | Ask FreqAI to automatically reduce the dimensionality of the data set using PCA.
**Datatype:** boolean. | `use_SVM_to_remove_outliers` | Ask FreqAI to train a support vector machine to detect and remove outliers from the training data set as well as from incoming data points.
**Datatype:** boolean. | `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. E.g. `nu` *Very* broadly, is the percentage of data points that should be considered outliers. `shuffle` is by default false to maintain reprodicibility. But these and all others can be added/changed in this dictionary.
**Datatype:** dictionary. @@ -133,8 +137,8 @@ Here are the values the user can expect to include/use inside the typical strate ### Example config file -The user interface is isolated to the typical config file. A typical Freqai -config setup includes: +The user interface is isolated to the typical config file. A typical FreqAI +config setup could include: ```json "freqai": { @@ -169,7 +173,7 @@ config setup includes: } ``` -### Building the feature set +### Feature engineering Features are added by the user inside the `populate_any_indicators()` method of the strategy by prepending indicators with `%` and labels are added by prepending `&`. @@ -182,7 +186,7 @@ various configuration parameters which multiply the feature set such as `include ```python def populate_any_indicators( - self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False + self, pair, df, tf, informative=None, set_generalized_indicators=False ): """ Function designed to automatically generate, name and merge features @@ -198,6 +202,8 @@ various configuration parameters which multiply the feature set such as `include :param coin: the name of the coin which will modify the feature names. """ + coint = pair.split('/')[0] + with self.freqai.lock: if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) @@ -265,7 +271,7 @@ various configuration parameters which multiply the feature set such as `include return df ``` -The user of the present example does not want to pass the `bb_lowerband` as a feature to the model, +The user of the present example does not wish to pass the `bb_lowerband` as a feature to the model, and has therefore not prepended it with `%`. The user does, however, wish to pass `bb_width` to the model for training/prediction and has therefore prepended it with `%`. @@ -313,7 +319,7 @@ set will include all the features from `populate_any_indicators` on all the `inc `include_shifted_candles` is another user controlled parameter which indicates the number of previous candles to include in the present feature set. In other words, `include_shifted_candles: 2`, tells -Freqai to include the the past 2 candles for each of the features included in the dataset. +FreqAI to include the the past 2 candles for each of the features included in the dataset. In total, the number of features the present user has created is: @@ -326,12 +332,12 @@ Users define the backtesting timerange with the typical `--timerange` parameter configuration file. `train_period_days` is the duration of the sliding training window, while `backtest_period_days` is the sliding backtesting window, both in number of days (`backtest_period_days` can be a float to indicate sub daily retraining in live/dry mode). In the present example, -the user is asking Freqai to use a training period of 30 days and backtest the subsequent 7 days. +the user is asking FreqAI to use a training period of 30 days and backtest the subsequent 7 days. This means that if the user sets `--timerange 20210501-20210701`, -Freqai will train 8 separate models (because the full range comprises 8 weeks), +FreqAI will train 8 separate models (because the full range comprises 8 weeks), and then backtest the subsequent week associated with each of the 8 training data set timerange months. Users can think of this as a "sliding window" which -emulates Freqai retraining itself once per week in live using the previous +emulates FreqAI retraining itself once per week in live using the previous month of data. In live, the required training data is automatically computed and downloaded. However, in backtesting @@ -349,16 +355,18 @@ and adding this to the `train_period_days`. The units need to be in the base can !!! Note Although fractional `backtest_period_days` is allowed, the user should be ware that the `--timerange` is divided by this value to determine the number of models that FreqAI will need to train in order to backtest the full range. For example, if the user wants to set a `--timerange` of 10 days, and asks for a `backtest_period_days` of 0.1, FreqAI will need to train 100 models per pair to complete the full backtest. This is why it is physically impossible to truly backtest FreqAI adaptive training. The best way to fully test a model is to run it dry and let it constantly train. In this case, backtesting would take the exact same amount of time as a dry run. -## Running Freqai +## Running FreqAI -### Training and backtesting +### Backtesting -The freqai training/backtesting module can be executed with the following command: +The FreqAI backtesting module can be executed with the following command: ```bash freqtrade backtesting --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel LightGBMRegressor --timerange 20210501-20210701 ``` +Backtesting mode requires the user to have the data pre-downloaded (unlike dry/live, where FreqAI automatically downloads the necessary data). The user should be careful to consider that the range of the downloaded data is more than the backtesting range. This is because FreqAI needs data prior to the desired backtesting range in order to train a model to be ready to make predictions on the first candle of the user set backtesting range. More details on how to calculate the data download timerange can be found [here](#deciding-the-sliding-training-window-and-backtesting-duration). + If this command has never been executed with the existing config file, then it will train a new model for each pair, for each backtesting window within the bigger `--timerange`. @@ -374,7 +382,7 @@ for each pair, for each backtesting window within the bigger `--timerange`. ### Building a freqai strategy -The Freqai strategy requires the user to include the following lines of code in the strategy: +The FreqAI strategy requires the user to include the following lines of code in the strategy: ```python @@ -419,21 +427,16 @@ FreqAI includes a the `CatboostClassifier` via the flag `--freqaimodel CatboostC df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') ``` -### Building an IFreqaiModel - -FreqAI has multiple example prediction model based libraries such as `Catboost` regression (`freqai/prediction_models/CatboostRegressor.py`) and `LightGBM` regression. -However, users can customize and create their own prediction models using the `IFreqaiModel` class. -Users are encouraged to inherit `train()` and `predict()` to let them customize various aspects of their training procedures. ### Running the model live -Freqai can be run dry/live using the following command +FreqAI can be run dry/live using the following command ```bash -freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel ExamplePredictionModel +freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel LightGBMRegressor ``` -By default, Freqai will not find find any existing models and will start by training a new one +By default, FreqAI will not find find any existing models and will start by training a new one given the user configuration settings. Following training, it will use that model to make predictions on incoming candles until a new model is available. New models are typically generated as often as possible, with FreqAI managing an internal queue of the pairs to try and keep all models equally "young." FreqAI will always use the newest trained model to make predictions on incoming live data. If users do not want FreqAI to retrain new models as often as possible, they can set `live_retrain_hours` to tell FreqAI to wait at least that number of hours before retraining a new model. Additionally, users can set `expired_hours` to tell FreqAI to avoid making predictions on models aged over this number of hours. If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse @@ -446,7 +449,7 @@ the same `identifier` parameter } ``` -In this case, although Freqai will initiate with a +In this case, although FreqAI will initiate with a pre-trained model, it will still check to see how much time has elapsed since the model was trained, and if a full `live_retrain_hours` has elapsed since the end of the loaded model, FreqAI will self retrain. @@ -473,7 +476,7 @@ the user is asking for `labels` that are 24 candles in the future. ### Removing outliers with the Dissimilarity Index The Dissimilarity Index (DI) aims to quantify the uncertainty associated with each -prediction by the model. To do so, Freqai measures the distance between each training +prediction by the model. To do so, FreqAI measures the distance between each training data point and all other training data points: $$ d_{ab} = \sqrt{\sum_{j=1}^p(X_{a,j}-X_{b,j})^2} $$ @@ -679,6 +682,11 @@ database setup in a pandas dataframe and ready to be analyzed. Here is an exampl return ``` +## Building an IFreqaiModel + +FreqAI has multiple example prediction model based libraries such as `Catboost` regression (`freqai/prediction_models/CatboostRegressor.py`) and `LightGBM` regression. +However, users can customize and create their own prediction models using the `IFreqaiModel` class. +Users are encouraged to inherit `train()` and `predict()` to let them customize various aspects of their training procedures. - ## Additional information ### Common pitfalls diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index adfd68c84..5e64d165d 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -2,9 +2,8 @@ import copy import datetime import logging import shutil -import sqlite3 from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Tuple import numpy as np import numpy.typing as npt @@ -88,20 +87,6 @@ class FreqaiDataKitchen: config["freqai"]["backtest_period_days"], ) - self.database_path: Optional[Path] = None - - if self.live: - db_url = self.config.get('db_url', None) - self.database_path = Path(db_url) - if 'sqlite' not in self.database_path.parts[0]: - self.database_path = None - logger.warning('FreqAI database analyzer only available for sqlite dbs. ' - ' FreqAI will still run, but user cannot use database analyzer.') - else: - self.database_name = Path(*self.database_path.parts[1:]) - - self.trade_database_df: DataFrame = pd.DataFrame() - self.data['extra_returns_per_train'] = self.freqai_config.get('extra_returns_per_train', {}) self.thread_count = self.freqai_config.get("data_kitchen_thread_count", -1) self.train_dates: DataFrame = pd.DataFrame() @@ -1007,13 +992,6 @@ class FreqaiDataKitchen: f = spy.stats.norm.fit(self.data_dictionary["train_labels"][label]) self.data["labels_mean"][label], self.data["labels_std"][label] = f[0], f[1] - # KEEPME incase we want to let user start to grab quantiles. - # upper_q = spy.stats.norm.ppf(self.freqai_config['feature_parameters'][ - # 'target_quantile'], *f) - # lower_q = spy.stats.norm.ppf(1 - self.freqai_config['feature_parameters'][ - # 'target_quantile'], *f) - # self.data["upper_quantile"] = upper_q - # self.data["lower_quantile"] = lower_q return def remove_features_from_df(self, dataframe: DataFrame) -> DataFrame: @@ -1025,181 +1003,3 @@ class FreqaiDataKitchen: col for col in dataframe.columns if not col.startswith("%") or col.startswith("%%") ] return dataframe[to_keep] - - def get_current_trade_database(self) -> None: - - if self.database_path is None: - logger.warning('No trade database found. Skipping analysis.') - return - - data = sqlite3.connect(self.database_name) - query = data.execute("SELECT * From trades") - cols = [column[0] for column in query.description] - df = pd.DataFrame.from_records(data=query.fetchall(), columns=cols) - self.trade_database_df = df.dropna(subset='close_date') - data.close() - - def np_encoder(self, object): - if isinstance(object, np.generic): - return object.item() - - # Functions containing useful data manipulation examples. but not actively in use. - - # Possibly phasing these outlier removal methods below out in favor of - # use_SVM_to_remove_outliers (computationally more efficient and apparently higher performance). - # But these have good data manipulation examples, so keep them commented here for now. - - # def determine_statistical_distributions(self) -> None: - # from fitter import Fitter - - # logger.info('Determining best model for all features, may take some time') - - # def compute_quantiles(ft): - # f = Fitter(self.data_dictionary["train_features"][ft], - # distributions=['gamma', 'cauchy', 'laplace', - # 'beta', 'uniform', 'lognorm']) - # f.fit() - # # f.summary() - # dist = list(f.get_best().items())[0][0] - # params = f.get_best()[dist] - # upper_q = getattr(spy.stats, list(f.get_best().items())[0][0]).ppf(0.999, **params) - # lower_q = getattr(spy.stats, list(f.get_best().items())[0][0]).ppf(0.001, **params) - - # return ft, upper_q, lower_q, dist - - # quantiles_tuple = Parallel(n_jobs=-1)( - # delayed(compute_quantiles)(ft) for ft in self.data_dictionary[ - # 'train_features'].columns) - - # df = pd.DataFrame(quantiles_tuple, columns=['features', 'upper_quantiles', - # 'lower_quantiles', 'dist']) - # self.data_dictionary['upper_quantiles'] = df['upper_quantiles'] - # self.data_dictionary['lower_quantiles'] = df['lower_quantiles'] - - # return - - # def remove_outliers(self, predict: bool) -> None: - # """ - # Remove data that looks like an outlier based on the distribution of each - # variable. - # :params: - # :predict: boolean which tells the function if this is prediction data or - # training data coming in. - # """ - - # lower_quantile = self.data_dictionary["lower_quantiles"].to_numpy() - # upper_quantile = self.data_dictionary["upper_quantiles"].to_numpy() - - # if predict: - - # df = self.data_dictionary["prediction_features"][ - # (self.data_dictionary["prediction_features"] < upper_quantile) - # & (self.data_dictionary["prediction_features"] > lower_quantile) - # ] - # drop_index = pd.isnull(df).any(1) - # self.data_dictionary["prediction_features"].fillna(0, inplace=True) - # drop_index = ~drop_index - # do_predict = np.array(drop_index.replace(True, 1).replace(False, 0)) - - # logger.info( - # "remove_outliers() tossed %s predictions", - # len(do_predict) - do_predict.sum(), - # ) - # self.do_predict += do_predict - # self.do_predict -= 1 - - # else: - - # filter_train_df = self.data_dictionary["train_features"][ - # (self.data_dictionary["train_features"] < upper_quantile) - # & (self.data_dictionary["train_features"] > lower_quantile) - # ] - # drop_index = pd.isnull(filter_train_df).any(1) - # drop_index = drop_index.replace(True, 1).replace(False, 0) - # self.data_dictionary["train_features"] = self.data_dictionary["train_features"][ - # (drop_index == 0) - # ] - # self.data_dictionary["train_labels"] = self.data_dictionary["train_labels"][ - # (drop_index == 0) - # ] - # self.data_dictionary["train_weights"] = self.data_dictionary["train_weights"][ - # (drop_index == 0) - # ] - - # logger.info( - # f'remove_outliers() tossed {drop_index.sum()}' - # f' training points from {len(filter_train_df)}' - # ) - - # # do the same for the test data - # filter_test_df = self.data_dictionary["test_features"][ - # (self.data_dictionary["test_features"] < upper_quantile) - # & (self.data_dictionary["test_features"] > lower_quantile) - # ] - # drop_index = pd.isnull(filter_test_df).any(1) - # drop_index = drop_index.replace(True, 1).replace(False, 0) - # self.data_dictionary["test_labels"] = self.data_dictionary["test_labels"][ - # (drop_index == 0) - # ] - # self.data_dictionary["test_features"] = self.data_dictionary["test_features"][ - # (drop_index == 0) - # ] - # self.data_dictionary["test_weights"] = self.data_dictionary["test_weights"][ - # (drop_index == 0) - # ] - - # logger.info( - # f'remove_outliers() tossed {drop_index.sum()}' - # f' test points from {len(filter_test_df)}' - # ) - - # return - - # def standardize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: - # """ - # standardize all data in the data_dictionary according to the training dataset - # :params: - # :data_dictionary: dictionary containing the cleaned and split training/test data/labels - # :returns: - # :data_dictionary: updated dictionary with standardized values. - # """ - # # standardize the data by training stats - # train_mean = data_dictionary["train_features"].mean() - # train_std = data_dictionary["train_features"].std() - # data_dictionary["train_features"] = ( - # data_dictionary["train_features"] - train_mean - # ) / train_std - # data_dictionary["test_features"] = ( - # data_dictionary["test_features"] - train_mean - # ) / train_std - - # train_labels_std = data_dictionary["train_labels"].std() - # train_labels_mean = data_dictionary["train_labels"].mean() - # data_dictionary["train_labels"] = ( - # data_dictionary["train_labels"] - train_labels_mean - # ) / train_labels_std - # data_dictionary["test_labels"] = ( - # data_dictionary["test_labels"] - train_labels_mean - # ) / train_labels_std - - # for item in train_std.keys(): - # self.data[item + "_std"] = train_std[item] - # self.data[item + "_mean"] = train_mean[item] - - # self.data["labels_std"] = train_labels_std - # self.data["labels_mean"] = train_labels_mean - - # return data_dictionary - - # def standardize_data_from_metadata(self, df: DataFrame) -> DataFrame: - # """ - # Normalizes a set of data using the mean and standard deviation from - # the associated training data. - # :params: - # :df: Dataframe to be standardized - # """ - - # for item in df.keys(): - # df[item] = (df[item] - self.data[item + "_mean"]) / self.data[item + "_std"] - - # return df diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 833fb50d6..0c32a625d 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -491,9 +491,6 @@ class IFreqaiModel(ABC): model = self.train(unfiltered_dataframe, pair, dk) - dk.get_current_trade_database() - self.analyze_trade_database(dk, pair) - self.dd.pair_dict[pair]["trained_timestamp"] = new_trained_timerange.stopts dk.set_new_model_names(pair, new_trained_timerange) self.dd.pair_dict[pair]["first"] = False @@ -612,20 +609,3 @@ class IFreqaiModel(ABC): :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove data (NaNs) or felt uncertain about data (i.e. SVM and/or DI index) """ - - def analyze_trade_database(self, dk: FreqaiDataKitchen, pair: str) -> None: - """ - User analyzes the trade database here and returns summary stats which will be passed back - to the strategy for reinforcement learning or for additional adaptive metrics for use - in entry/exit signals. Store these metrics in dk.data['extra_returns_per_train'] and - they will format themselves into the dataframe as an additional column in the user - strategy. User has access to the current trade database in dk.trade_database_df. - """ - # if dk.trade_database_df.empty: - # logger.warning(f'No trades found for {pair} to analyze DB') - # return - - # total_profit = dk.trade_database_df['close_profit_abs'].sum() - # dk.data['extra_returns_per_train']['total_profit'] = total_profit - - return From fb4b73ce8961dd9db34ad5b94d7484ca80ffc06b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 12 Aug 2022 12:03:44 +0200 Subject: [PATCH 258/308] ensure dates are saved --- freqtrade/freqai/data_kitchen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 5e64d165d..0cff9c90e 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -202,7 +202,7 @@ class FreqaiDataKitchen: labels = unfiltered_dataframe.filter(label_list, axis=1) drop_index_labels = pd.isnull(labels).any(1) drop_index_labels = drop_index_labels.replace(True, 1).replace(False, 0) - dates = unfiltered_dataframe.filter('date', axis=1) + dates = unfiltered_dataframe['date'] filtered_dataframe = filtered_dataframe[ (drop_index == 0) & (drop_index_labels == 0) ] # dropping values From 923f73a5161dd861be3ae2885856a0b0ac54b640 Mon Sep 17 00:00:00 2001 From: ecoppen <51025241+ecoppen@users.noreply.github.com> Date: Fri, 12 Aug 2022 19:56:46 +0100 Subject: [PATCH 259/308] nobase -> baseonly --- freqtrade/rpc/telegram.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index c3b41a907..88222608e 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1371,7 +1371,7 @@ class Telegram(RPCHandler): if context.args: if "sorted" in context.args: whitelist['whitelist'] = sorted(whitelist['whitelist']) - if "nobase" in context.args: + if "baseonly" in context.args: whitelist['whitelist'] = [pair.split("/")[0] for pair in whitelist['whitelist']] message = f"Using whitelist `{whitelist['method']}` with {whitelist['length']} pairs\n" @@ -1493,8 +1493,8 @@ class Telegram(RPCHandler): "*/fx |all:* `Alias to /forceexit`\n" f"{force_enter_text if self._config.get('force_entry_enable', False) else ''}" "*/delete :* `Instantly delete the given trade in the database`\n" - "*/whitelist [sorted] [nobase]:* `Show current whitelist. Optionally in " - "order and/or without the base currency.`\n" + "*/whitelist [sorted] [baseonly]:* `Show current whitelist. Optionally in " + "order and/or only displaying the base currency of each pairing.`\n" "*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " "to the blacklist.` \n" "*/blacklist_delete [pairs]| /bl_delete [pairs]:* " From ccc0ad6f642aa875c06bc39bb34a646c07cddb10 Mon Sep 17 00:00:00 2001 From: ecoppen <51025241+ecoppen@users.noreply.github.com> Date: Fri, 12 Aug 2022 19:58:41 +0100 Subject: [PATCH 260/308] fix - reload whitelist Should fix the issue, if not I'll move development to a different computer and get local testing running properly. --- tests/rpc/test_rpc_telegram.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 8049a10e9..cd26e744f 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1461,21 +1461,25 @@ def test_whitelist_static(default_conf, update, mocker) -> None: context = MagicMock() context.args = ['sorted'] msg_mock.reset_mock() + telegram._whitelist(update=update, context=MagicMock()) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH/BTC, LTC/BTC, NEO/BTC, XRP/BTC`" in sorted(msg_mock.call_args_list[0][0][0])) context = MagicMock() - context.args = ['nobase'] + context.args = ['baseonly'] msg_mock.reset_mock() + telegram._whitelist(update=update, context=MagicMock()) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH, LTC, XRP, NEO`" in msg_mock.call_args_list[0][0][0]) context = MagicMock() - context.args = ['nobase', 'sorted'] + context.args = ['baseonly', 'sorted'] msg_mock.reset_mock() + telegram._whitelist(update=update, context=MagicMock()) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH, LTC, NEO, XRP`" in msg_mock.call_args_list[0][0][0]) + def test_whitelist_dynamic(default_conf, update, mocker) -> None: mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) default_conf['pairlists'] = [{'method': 'VolumePairList', @@ -1491,21 +1495,25 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None: context = MagicMock() context.args = ['sorted'] msg_mock.reset_mock() + telegram._whitelist(update=update, context=MagicMock()) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH/BTC, LTC/BTC, NEO/BTC, XRP/BTC`" in sorted(msg_mock.call_args_list[0][0][0])) context = MagicMock() - context.args = ['nobase'] + context.args = ['baseonly'] msg_mock.reset_mock() + telegram._whitelist(update=update, context=MagicMock()) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH, LTC, XRP, NEO`" in msg_mock.call_args_list[0][0][0]) context = MagicMock() - context.args = ['nobase', 'sorted'] + context.args = ['baseonly', 'sorted'] msg_mock.reset_mock() + telegram._whitelist(update=update, context=MagicMock()) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH, LTC, NEO, XRP`" in msg_mock.call_args_list[0][0][0]) + def test_blacklist_static(default_conf, update, mocker) -> None: telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) From 2312b86a66bbe31a1aa28e52e82b74db77bbdbbc Mon Sep 17 00:00:00 2001 From: ecoppen <51025241+ecoppen@users.noreply.github.com> Date: Fri, 12 Aug 2022 19:59:08 +0100 Subject: [PATCH 261/308] Update telegram-usage.md Add the optional arguments to the documentation. --- docs/telegram-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index a690e18b9..add889681 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -187,7 +187,7 @@ official commands. You can ask at any moment for help with `/help`. | `/stats` | Shows Wins / losses by Exit reason as well as Avg. holding durations for buys and sells | `/exits` | Shows Wins / losses by Exit reason as well as Avg. holding durations for buys and sells | `/entries` | Shows Wins / losses by Exit reason as well as Avg. holding durations for buys and sells -| `/whitelist` | Show the current whitelist +| `/whitelist [sorted] [baseonly]` | Show the current whitelist. Optionally display in alphabetical order and/or with just the base currency of each pairing. | `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist. | `/edge` | Show validated pairs by Edge if it is enabled. | `/help` | Show help message From f6545ebdb8a82cedce065779873d395631aff07f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:10:03 +0200 Subject: [PATCH 262/308] Disallow backtesting with --strategy-list for now. --- freqtrade/optimize/backtesting.py | 3 +++ tests/freqai/test_freqai_backtsting.py | 33 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/freqai/test_freqai_backtsting.py diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 86c1822f7..c00f30686 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -89,6 +89,9 @@ class Backtesting: self.dataprovider = DataProvider(self.config, self.exchange) if self.config.get('strategy_list'): + if self.config.get('freqai'): + raise OperationalException( + "You can't use strategy_list and freqai at the same time.") for strat in list(self.config['strategy_list']): stratconf = deepcopy(self.config) stratconf['strategy'] = strat diff --git a/tests/freqai/test_freqai_backtsting.py b/tests/freqai/test_freqai_backtsting.py new file mode 100644 index 000000000..bb0a71e2c --- /dev/null +++ b/tests/freqai/test_freqai_backtsting.py @@ -0,0 +1,33 @@ +from pathlib import Path +from unittest.mock import PropertyMock + +import pytest + +from freqtrade.commands.optimize_commands import start_backtesting +from freqtrade.exceptions import OperationalException +from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, patch_exchange, + patched_configuration_load_config_file) + + +def test_backtest_start_backtest_list_freqai(freqai_conf, mocker, testdatadir): + # Tests detail-data loading + patch_exchange(mocker) + + mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['HULUMULU/USDT', 'XRP/USDT'])) + # mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock) + + patched_configuration_load_config_file(mocker, freqai_conf) + + args = [ + 'backtesting', + '--config', 'config.json', + '--datadir', str(testdatadir), + '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'), + '--timeframe', '1h', + '--strategy-list', CURRENT_TEST_STRATEGY + ] + args = get_args(args) + with pytest.raises(OperationalException, + match=r"You can't use strategy_list and freqai at the same time\."): + start_backtesting(args) From 49989012abae22740a6a65ccc5ba2685c036aa91 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:20:58 +0200 Subject: [PATCH 263/308] Bump catboost requirement to latest --- requirements-freqai.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-freqai.txt b/requirements-freqai.txt index 5e67a5539..26e4617af 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -4,5 +4,5 @@ # Required for freqai scikit-learn==1.1.2 joblib==1.1.0 -catboost==1.0.4; platform_machine != 'aarch64' +catboost==1.0.6; platform_machine != 'aarch64' lightgbm==3.3.2 From 3b827ee60a6f9194c825a7ee472bfbc4815e4fe6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:24:04 +0200 Subject: [PATCH 264/308] Add "freqai.enabled" flag to disable freqAI via config flag aligns with how other optional modules work in freqtrade. --- config_examples/config_freqai.example.json | 1 + freqtrade/constants.py | 16 ++++++++++------ freqtrade/optimize/backtesting.py | 4 ++-- freqtrade/plugins/pairlist/pairlist_helpers.py | 2 +- freqtrade/strategy/interface.py | 2 +- tests/freqai/conftest.py | 1 + 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index e9fc50a4a..aeb1cb13d 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -52,6 +52,7 @@ } ], "freqai": { + "enabled": true, "startup_candles": 10000, "purge_old_models": true, "train_period_days": 15, diff --git a/freqtrade/constants.py b/freqtrade/constants.py index b5d6b4b8e..ddbc84fa9 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -486,6 +486,7 @@ CONF_SCHEMA = { "freqai": { "type": "object", "properties": { + "enabled": {"type": "boolean", "default": False}, "keras": {"type": "boolean", "default": False}, "conv_width": {"type": "integer", "default": 2}, "train_period_days": {"type": "integer", "default": 0}, @@ -525,12 +526,15 @@ CONF_SCHEMA = { }, }, }, - "required": ["train_period_days", - "backtest_period_days", - "identifier", - "feature_parameters", - "data_split_parameters", - "model_training_parameters"] + "required": [ + "enabled", + "train_period_days", + "backtest_period_days", + "identifier", + "feature_parameters", + "data_split_parameters", + "model_training_parameters" + ] }, }, } diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index c00f30686..7691b96f1 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -89,7 +89,7 @@ class Backtesting: self.dataprovider = DataProvider(self.config, self.exchange) if self.config.get('strategy_list'): - if self.config.get('freqai'): + if self.config.get('freqai', {}).get('enabled', False): raise OperationalException( "You can't use strategy_list and freqai at the same time.") for strat in list(self.config['strategy_list']): @@ -210,7 +210,7 @@ class Backtesting: """ self.progress.init_step(BacktestState.DATALOAD, 1) - if self.config.get('freqai') is not None: + if self.config.get('freqai', {}).get('enabled', False): startup_candles = int(self.config.get('freqai', {}).get('startup_candles', 0)) if not startup_candles: raise OperationalException('FreqAI backtesting module requires user set ' diff --git a/freqtrade/plugins/pairlist/pairlist_helpers.py b/freqtrade/plugins/pairlist/pairlist_helpers.py index a07a0f783..f1eca6df0 100644 --- a/freqtrade/plugins/pairlist/pairlist_helpers.py +++ b/freqtrade/plugins/pairlist/pairlist_helpers.py @@ -44,7 +44,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], def dynamic_expand_pairlist(config: dict, markets: list) -> List[str]: expanded_pairs = expand_pairlist(config['pairs'], markets) - if config.get('freqai', {}): + if config.get('freqai', {}).get('enabled', False): corr_pairlist = config['freqai']['feature_parameters']['include_corr_pairlist'] expanded_pairs += [pair for pair in corr_pairlist if pair not in config['pairs']] diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index cda8a1cbc..d10699e3b 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -146,7 +146,7 @@ class IStrategy(ABC, HyperStrategyMixin): self._ft_informative.append((informative_data, cls_method)) def load_freqAI_model(self) -> None: - if self.config.get('freqai', None): + if self.config.get('freqai', {}).get('enabled', False): # Import here to avoid importing this if freqAI is disabled from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index ee02cc097..63f3ef2c7 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -17,6 +17,7 @@ def freqai_conf(default_conf, tmpdir): freqaiconf = deepcopy(default_conf) freqaiconf.update( { + "enabled": True, "datadir": Path(default_conf["datadir"]), "strategy": "freqai_test_strat", "user_data_dir": Path(tmpdir), From 3918f4abbd7ed975e113477f09bd231ceb8f2fab Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:27:56 +0200 Subject: [PATCH 265/308] Simplify strategy interface by removing explicit self.freqai_info assignment --- docs/freqai.md | 2 -- freqtrade/strategy/interface.py | 1 + freqtrade/templates/FreqaiExampleStrategy.py | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index c495ba24b..eb76ab1a4 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -401,8 +401,6 @@ The FreqAI strategy requires the user to include the following lines of code in def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - self.freqai_info = self.config["freqai"] - # All indicators must be populated by populate_any_indicators() for live functionality # to work correctly. diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index d10699e3b..760d852c4 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -151,6 +151,7 @@ class IStrategy(ABC, HyperStrategyMixin): from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver self.freqai = FreqaiModelResolver.load_freqaimodel(self.config) + self.freqai_info = self.config["freqai"] def ft_bot_start(self, **kwargs) -> None: """ diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 01f947a6a..d8584d5f9 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -180,8 +180,6 @@ class FreqaiExampleStrategy(IStrategy): def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - self.freqai_info = self.config["freqai"] - # All indicators must be populated by populate_any_indicators() for live functionality # to work correctly. From c190d57f1a67ffd3a6735365bbe3ee592c445a6e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:48:59 +0200 Subject: [PATCH 266/308] Test populate_any_indicator interface --- tests/strategy/test_interface.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 4257b2cf9..8b4ba5f03 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -290,6 +290,18 @@ def test_advise_all_indicators(default_conf, testdatadir) -> None: assert len(processed['UNITTEST/BTC']) == 102 # partial candle was removed +def test_populate_any_indicators(default_conf, testdatadir) -> None: + strategy = StrategyResolver.load_strategy(default_conf) + + timerange = TimeRange.parse_timerange('1510694220-1510700340') + data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange, + fill_up_missing=True) + processed = strategy.populate_any_indicators('UNITTEST/BTC', data, '5m') + assert processed == data + assert id(processed) == id(data) + assert len(processed['UNITTEST/BTC']) == 102 # partial candle was removed + + def test_advise_all_indicators_copy(mocker, default_conf, testdatadir) -> None: strategy = StrategyResolver.load_strategy(default_conf) aimock = mocker.patch('freqtrade.strategy.interface.IStrategy.advise_indicators') From b682fc446e10c3df0aee91776df7a6e0ccebf851 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:53:18 +0200 Subject: [PATCH 267/308] Graciously fail if strategy has freqAI code, but freqAI is not enabled. --- freqtrade/strategy/interface.py | 7 +++++++ tests/strategy/test_interface.py | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 760d852c4..45609beaa 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -152,6 +152,13 @@ class IStrategy(ABC, HyperStrategyMixin): self.freqai = FreqaiModelResolver.load_freqaimodel(self.config) self.freqai_info = self.config["freqai"] + else: + # Gracious failures if freqAI is disabled but "start" is called. + class DummyClass(): + def start(self, *args, **kwargs): + raise OperationalException( + 'freqAI is not enabled. Please enable it in your config to use this strategy.') + self.freqai = DummyClass() # type: ignore def ft_bot_start(self, **kwargs) -> None: """ diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 8b4ba5f03..83f7d19b7 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -302,6 +302,13 @@ def test_populate_any_indicators(default_conf, testdatadir) -> None: assert len(processed['UNITTEST/BTC']) == 102 # partial candle was removed +def test_freqai_not_initialized(default_conf) -> None: + strategy = StrategyResolver.load_strategy(default_conf) + strategy.ft_bot_start() + with pytest.raises(OperationalException, match=r'freqAI is not enabled\.'): + strategy.freqai.start() + + def test_advise_all_indicators_copy(mocker, default_conf, testdatadir) -> None: strategy = StrategyResolver.load_strategy(default_conf) aimock = mocker.patch('freqtrade.strategy.interface.IStrategy.advise_indicators') From 1ac6ec1446a02a30d0a840e2181fcd2dcf6de932 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 09:56:21 +0200 Subject: [PATCH 268/308] Fix failing test... --- tests/freqai/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index 63f3ef2c7..6ace13677 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -17,7 +17,6 @@ def freqai_conf(default_conf, tmpdir): freqaiconf = deepcopy(default_conf) freqaiconf.update( { - "enabled": True, "datadir": Path(default_conf["datadir"]), "strategy": "freqai_test_strat", "user_data_dir": Path(tmpdir), @@ -26,6 +25,7 @@ def freqai_conf(default_conf, tmpdir): "freqaimodel_path": "freqai/prediction_models", "timerange": "20180110-20180115", "freqai": { + "enabled": True, "startup_candles": 10000, "purge_old_models": True, "train_period_days": 5, From 5aaab75d1cf177e10cd4ee0bd575084f9a6a2910 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 10:18:57 +0200 Subject: [PATCH 269/308] Add test for dynamic_pairlist_expand --- freqtrade/plugins/pairlist/pairlist_helpers.py | 4 ++-- freqtrade/strategy/interface.py | 3 ++- tests/plugins/test_pairlist.py | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/freqtrade/plugins/pairlist/pairlist_helpers.py b/freqtrade/plugins/pairlist/pairlist_helpers.py index f1eca6df0..0cec734fb 100644 --- a/freqtrade/plugins/pairlist/pairlist_helpers.py +++ b/freqtrade/plugins/pairlist/pairlist_helpers.py @@ -1,5 +1,5 @@ import re -from typing import List +from typing import Any, Dict, List def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], @@ -42,7 +42,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], return result -def dynamic_expand_pairlist(config: dict, markets: list) -> List[str]: +def dynamic_expand_pairlist(config: Dict[str, Any], markets: List[str]) -> List[str]: expanded_pairs = expand_pairlist(config['pairs'], markets) if config.get('freqai', {}).get('enabled', False): corr_pairlist = config['freqai']['feature_parameters']['include_corr_pairlist'] diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 45609beaa..f41369189 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -157,7 +157,8 @@ class IStrategy(ABC, HyperStrategyMixin): class DummyClass(): def start(self, *args, **kwargs): raise OperationalException( - 'freqAI is not enabled. Please enable it in your config to use this strategy.') + 'freqAI is not enabled. ' + 'Please enable it in your config to use this strategy.') self.freqai = DummyClass() # type: ignore def ft_bot_start(self, **kwargs) -> None: diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index c56f405e2..d3d08dc8c 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -12,7 +12,7 @@ from freqtrade.constants import AVAILABLE_PAIRLISTS from freqtrade.enums import CandleType, RunMode from freqtrade.exceptions import OperationalException from freqtrade.persistence import Trade -from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist +from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist, expand_pairlist from freqtrade.plugins.pairlistmanager import PairListManager from freqtrade.resolvers import PairListResolver from tests.conftest import (create_mock_trades_usdt, get_patched_exchange, get_patched_freqtradebot, @@ -1282,6 +1282,22 @@ def test_expand_pairlist(wildcardlist, pairs, expected): expand_pairlist(wildcardlist, pairs) else: assert sorted(expand_pairlist(wildcardlist, pairs)) == sorted(expected) + conf = { + 'pairs': wildcardlist, + 'freqai': { + "enabled": True, + "feature_parameters": { + "include_corr_pairlist": [ + "BTC/USDT:USDT", + "XRP/BUSD", + ] + } + } + } + assert sorted(dynamic_expand_pairlist(conf, pairs)) == sorted(expected + [ + "BTC/USDT:USDT", + "XRP/BUSD", + ]) @pytest.mark.parametrize('wildcardlist,pairs,expected', [ From 0b92c30abd3ec1262b15ecfce1a6b2cbea0e5d6b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 10:19:46 +0200 Subject: [PATCH 270/308] Fix typo in test file --- .../{test_freqai_backtsting.py => test_freqai_backtesting.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/freqai/{test_freqai_backtsting.py => test_freqai_backtesting.py} (100%) diff --git a/tests/freqai/test_freqai_backtsting.py b/tests/freqai/test_freqai_backtesting.py similarity index 100% rename from tests/freqai/test_freqai_backtsting.py rename to tests/freqai/test_freqai_backtesting.py From 82ac8cb41ff400e45306f3e6fbaf9fd1ebf9638d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 10:48:57 +0200 Subject: [PATCH 271/308] Add freqai backtesting_load test --- tests/freqai/test_freqai_backtesting.py | 32 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/freqai/test_freqai_backtesting.py b/tests/freqai/test_freqai_backtesting.py index bb0a71e2c..a92742b86 100644 --- a/tests/freqai/test_freqai_backtesting.py +++ b/tests/freqai/test_freqai_backtesting.py @@ -1,16 +1,18 @@ +from copy import deepcopy +from datetime import datetime, timezone from pathlib import Path -from unittest.mock import PropertyMock +from unittest.mock import MagicMock, PropertyMock import pytest from freqtrade.commands.optimize_commands import start_backtesting from freqtrade.exceptions import OperationalException -from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, patch_exchange, +from freqtrade.optimize.backtesting import Backtesting +from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, log_has_re, patch_exchange, patched_configuration_load_config_file) -def test_backtest_start_backtest_list_freqai(freqai_conf, mocker, testdatadir): - # Tests detail-data loading +def test_freqai_backtest_start_backtest_list(freqai_conf, mocker, testdatadir): patch_exchange(mocker) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', @@ -31,3 +33,25 @@ def test_backtest_start_backtest_list_freqai(freqai_conf, mocker, testdatadir): with pytest.raises(OperationalException, match=r"You can't use strategy_list and freqai at the same time\."): start_backtesting(args) + + +def test_freqai_backtest_load_data(freqai_conf, mocker, caplog): + patch_exchange(mocker) + + now = datetime.now(timezone.utc) + mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['HULUMULU/USDT', 'XRP/USDT'])) + mocker.patch('freqtrade.optimize.backtesting.history.load_data') + mocker.patch('freqtrade.optimize.backtesting.history.get_timerange', return_value=(now, now)) + backtesting = Backtesting(deepcopy(freqai_conf)) + backtesting.load_bt_data() + + assert log_has_re('Increasing startup_candle_count for freqai to.*', caplog) + + del freqai_conf['freqai']['startup_candles'] + backtesting = Backtesting(freqai_conf) + with pytest.raises(OperationalException, + match=r'FreqAI backtesting module.*startup_candles in config.'): + backtesting.load_bt_data() + + Backtesting.cleanup() From d36da95941e497492420d1dfe3c0db5c0d9db528 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 11:07:58 +0200 Subject: [PATCH 272/308] Fix bad import --- tests/freqai/test_freqai_backtesting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/freqai/test_freqai_backtesting.py b/tests/freqai/test_freqai_backtesting.py index a92742b86..273791609 100644 --- a/tests/freqai/test_freqai_backtesting.py +++ b/tests/freqai/test_freqai_backtesting.py @@ -1,7 +1,7 @@ from copy import deepcopy from datetime import datetime, timezone from pathlib import Path -from unittest.mock import MagicMock, PropertyMock +from unittest.mock import PropertyMock import pytest From e09fbe9e53b23b54ad1ee1b9c65535cf0f2f4915 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 11:17:22 +0200 Subject: [PATCH 273/308] Improve test resiliance --- tests/test_freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index fb5fd38d8..eb4804167 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3451,7 +3451,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( trade.stop_loss = 2.0 * 1.01 if is_short else 2.0 * 0.99 freqtrade.execute_trade_exit( - trade=trade, limit=(ticker_usdt_sell_up if is_short else ticker_usdt_sell_down())['bid'], + trade=trade, limit=trade.stop_loss, exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)) assert rpc_mock.call_count == 2 From 7c18ec4053f3f3f44a2acfa0ac7a87e4f36e38d9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 11:24:55 +0200 Subject: [PATCH 274/308] Add missing key to "full" config sample --- config_examples/config_full.example.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config_examples/config_full.example.json b/config_examples/config_full.example.json index e2e9a16fd..f076ffaf1 100644 --- a/config_examples/config_full.example.json +++ b/config_examples/config_full.example.json @@ -5,6 +5,7 @@ "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", "amount_reserve_percent": 0.05, + "available_capital": 1000, "amend_last_stake_amount": false, "last_stake_amount_min_ratio": 0.5, "dry_run": true, From 7075b00e201e0d6dc331ecd3478780035f540374 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 11:37:23 +0200 Subject: [PATCH 275/308] Remove odd dry run stoploss behavior closes #7208 --- freqtrade/freqtradebot.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 0dbeb2e44..95f884056 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1475,12 +1475,6 @@ class FreqtradeBot(LoggingMixin): ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS, ExitType.LIQUIDATION): exit_type = 'stoploss' - # if stoploss is on exchange and we are on dry_run mode, - # we consider the sell price stop price - if (self.config['dry_run'] and exit_type == 'stoploss' - and self.strategy.order_types['stoploss_on_exchange']): - limit = trade.stoploss_or_liquidation - # set custom_exit_price if available proposed_limit_rate = limit current_profit = trade.calc_profit_ratio(limit) From 61acbf21d0372a87401884fdbfa03c8a16a6264e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 15:46:06 +0200 Subject: [PATCH 276/308] Fix broken telegram tests --- tests/rpc/test_rpc_telegram.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index cd26e744f..a30115bd9 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1461,21 +1461,21 @@ def test_whitelist_static(default_conf, update, mocker) -> None: context = MagicMock() context.args = ['sorted'] msg_mock.reset_mock() - telegram._whitelist(update=update, context=MagicMock()) + telegram._whitelist(update=update, context=context) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" - "`ETH/BTC, LTC/BTC, NEO/BTC, XRP/BTC`" in sorted(msg_mock.call_args_list[0][0][0])) + "`ETH/BTC, LTC/BTC, NEO/BTC, XRP/BTC`" in msg_mock.call_args_list[0][0][0]) context = MagicMock() context.args = ['baseonly'] msg_mock.reset_mock() - telegram._whitelist(update=update, context=MagicMock()) + telegram._whitelist(update=update, context=context) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH, LTC, XRP, NEO`" in msg_mock.call_args_list[0][0][0]) context = MagicMock() context.args = ['baseonly', 'sorted'] msg_mock.reset_mock() - telegram._whitelist(update=update, context=MagicMock()) + telegram._whitelist(update=update, context=context) assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" "`ETH, LTC, NEO, XRP`" in msg_mock.call_args_list[0][0][0]) @@ -1495,22 +1495,22 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None: context = MagicMock() context.args = ['sorted'] msg_mock.reset_mock() - telegram._whitelist(update=update, context=MagicMock()) - assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" - "`ETH/BTC, LTC/BTC, NEO/BTC, XRP/BTC`" in sorted(msg_mock.call_args_list[0][0][0])) + telegram._whitelist(update=update, context=context) + assert ("Using whitelist `['VolumePairList']` with 4 pairs\n" + "`ETH/BTC, LTC/BTC, NEO/BTC, XRP/BTC`" in msg_mock.call_args_list[0][0][0]) context = MagicMock() context.args = ['baseonly'] msg_mock.reset_mock() - telegram._whitelist(update=update, context=MagicMock()) - assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" + telegram._whitelist(update=update, context=context) + assert ("Using whitelist `['VolumePairList']` with 4 pairs\n" "`ETH, LTC, XRP, NEO`" in msg_mock.call_args_list[0][0][0]) context = MagicMock() context.args = ['baseonly', 'sorted'] msg_mock.reset_mock() - telegram._whitelist(update=update, context=MagicMock()) - assert ("Using whitelist `['StaticPairList']` with 4 pairs\n" + telegram._whitelist(update=update, context=context) + assert ("Using whitelist `['VolumePairList']` with 4 pairs\n" "`ETH, LTC, NEO, XRP`" in msg_mock.call_args_list[0][0][0]) From 23cc21ce59093df511f6fcc89ae22ec0ab5829cb Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 9 Aug 2022 17:31:38 +0200 Subject: [PATCH 277/308] add predict_proba to base classifier, improve historic predictions handling --- freqtrade/freqai/data_drawer.py | 10 +++-- freqtrade/freqai/data_kitchen.py | 11 +++++ .../prediction_models/CatboostClassifier.py | 41 +++++++++++++++++-- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index ec49c7050..0dacd4ee7 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -358,10 +358,12 @@ class FreqaiDataDrawer: dk.find_features(dataframe) - if self.freqai_info.get('predict_proba', []): - full_labels = dk.label_list + self.freqai_info['predict_proba'] - else: - full_labels = dk.label_list + added_labels = [] + if dk.unique_classes: + for label in dk.unique_classes: + added_labels += dk.unique_classes[label] + + full_labels = dk.label_list + added_labels for label in full_labels: dataframe[label] = 0 diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 0cff9c90e..3eb89ce6d 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -90,6 +90,7 @@ class FreqaiDataKitchen: self.data['extra_returns_per_train'] = self.freqai_config.get('extra_returns_per_train', {}) self.thread_count = self.freqai_config.get("data_kitchen_thread_count", -1) self.train_dates: DataFrame = pd.DataFrame() + self.unique_classes: Dict[str, list] = {} def set_paths( self, @@ -977,6 +978,8 @@ class FreqaiDataKitchen: informative=corr_dataframes[i][tf] ) + self.get_unique_classes_from_labels(dataframe) + return dataframe def fit_labels(self) -> None: @@ -1003,3 +1006,11 @@ class FreqaiDataKitchen: col for col in dataframe.columns if not col.startswith("%") or col.startswith("%%") ] return dataframe[to_keep] + + def get_unique_classes_from_labels(self, dataframe: DataFrame) -> None: + + self.find_features(dataframe) + + for key in self.label_list: + if dataframe[key].dtype == object: + self.unique_classes[key] = dataframe[key].dropna().unique() diff --git a/freqtrade/freqai/prediction_models/CatboostClassifier.py b/freqtrade/freqai/prediction_models/CatboostClassifier.py index ac1386eee..7a4b06557 100644 --- a/freqtrade/freqai/prediction_models/CatboostClassifier.py +++ b/freqtrade/freqai/prediction_models/CatboostClassifier.py @@ -1,10 +1,12 @@ import logging -from typing import Any, Dict - +from typing import Any, Dict, Tuple +import pandas as pd +from pandas import DataFrame from catboost import CatBoostClassifier, Pool - +import numpy.typing as npt +import numpy as np from freqtrade.freqai.prediction_models.BaseRegressionModel import BaseRegressionModel - +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen logger = logging.getLogger(__name__) @@ -39,3 +41,34 @@ class CatboostClassifier(BaseRegressionModel): cbr.fit(train_data) return cbr + + def predict( + self, unfiltered_dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = False + ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: + """ + Filter the prediction features data and predict with it. + :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :return: + :pred_df: dataframe containing the predictions + :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove + data (NaNs) or felt uncertain about data (PCA and DI index) + """ + + dk.find_features(unfiltered_dataframe) + filtered_dataframe, _ = dk.filter_features( + unfiltered_dataframe, dk.training_features_list, training_filter=False + ) + filtered_dataframe = dk.normalize_data_from_metadata(filtered_dataframe) + dk.data_dictionary["prediction_features"] = filtered_dataframe + + self.data_cleaning_predict(dk, filtered_dataframe) + + predictions = self.model.predict(dk.data_dictionary["prediction_features"]) + pred_df = DataFrame(predictions, columns=dk.label_list) + + predictions_prob = self.model.predict_proba(dk.data_dictionary["prediction_features"]) + pred_df_prob = DataFrame(predictions_prob, columns=self.model.classes_) + + pred_df = pd.concat([pred_df, pred_df_prob], axis=1) + + return (pred_df, dk.do_predict) From b1b76a2dbede53ad6d00fc3c2f06c10176f7cdda Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 10 Aug 2022 15:16:50 +0200 Subject: [PATCH 278/308] debug classifier with predict proba --- freqtrade/freqai/data_drawer.py | 7 +------ freqtrade/freqai/data_kitchen.py | 11 ++++++++++- freqtrade/freqai/freqai_interface.py | 18 ++++++++++-------- .../prediction_models/BaseRegressionModel.py | 9 --------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 0dacd4ee7..db1206a39 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -358,12 +358,7 @@ class FreqaiDataDrawer: dk.find_features(dataframe) - added_labels = [] - if dk.unique_classes: - for label in dk.unique_classes: - added_labels += dk.unique_classes[label] - - full_labels = dk.label_list + added_labels + full_labels = dk.label_list + dk.unique_class_list for label in full_labels: dataframe[label] = 0 diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 3eb89ce6d..2ba8c5ecf 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -91,6 +91,7 @@ class FreqaiDataKitchen: self.thread_count = self.freqai_config.get("data_kitchen_thread_count", -1) self.train_dates: DataFrame = pd.DataFrame() self.unique_classes: Dict[str, list] = {} + self.unique_class_list: list = [] def set_paths( self, @@ -338,7 +339,7 @@ class FreqaiDataKitchen: """ for label in df.columns: - if df[label].dtype == object: + if df[label].dtype == object or label in self.unique_class_list: continue df[label] = ( (df[label] + 1) @@ -995,6 +996,10 @@ class FreqaiDataKitchen: f = spy.stats.norm.fit(self.data_dictionary["train_labels"][label]) self.data["labels_mean"][label], self.data["labels_std"][label] = f[0], f[1] + # incase targets are classifications + for label in self.unique_class_list: + self.data["labels_mean"][label], self.data["labels_std"][label] = 0, 0 + return def remove_features_from_df(self, dataframe: DataFrame) -> DataFrame: @@ -1014,3 +1019,7 @@ class FreqaiDataKitchen: for key in self.label_list: if dataframe[key].dtype == object: self.unique_classes[key] = dataframe[key].dropna().unique() + + if self.unique_classes: + for label in self.unique_classes: + self.unique_class_list += list(self.unique_classes[label]) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 0c32a625d..e7dd6c714 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -320,6 +320,8 @@ class IFreqaiModel(ABC): # allows FreqUI to show full return values. pred_df, do_preds = self.predict(dataframe, dk) self.dd.set_initial_return_values(pair, dk, pred_df, do_preds) + if pair not in self.dd.historic_predictions: + self.set_initial_historic_predictions(pred_df, dk, pair) dk.return_dataframe = self.dd.attach_return_values_to_return_dataframe(pair, dataframe) return elif self.dk.check_if_model_expired(trained_timestamp): @@ -336,6 +338,9 @@ class IFreqaiModel(ABC): # historical accuracy reasons. pred_df, do_preds = self.predict(dataframe.iloc[-self.CONV_WIDTH:], dk, first=False) + self.dd.save_historic_predictions_to_disk() + if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: + self.fit_live_predictions(dk) self.dd.append_model_predictions(pair, pred_df, do_preds, dk, len(dataframe)) dk.return_dataframe = self.dd.attach_return_values_to_return_dataframe(pair, dataframe) @@ -503,7 +508,7 @@ class IFreqaiModel(ABC): self.dd.purge_old_models() def set_initial_historic_predictions( - self, df: DataFrame, model: Any, dk: FreqaiDataKitchen, pair: str + self, pred_df: DataFrame, dk: FreqaiDataKitchen, pair: str ) -> None: """ This function is called only if the datadrawer failed to load an @@ -528,12 +533,6 @@ class IFreqaiModel(ABC): :param: dk: FreqaiDataKitchen = object containing methods for data analysis :param: pair: str = current pair """ - num_candles = self.freqai_info.get('fit_live_predictions_candles', 600) - if not num_candles: - num_candles = 600 - df_tail = df.tail(num_candles) - trained_predictions = model.predict(df_tail) - pred_df = DataFrame(trained_predictions, columns=dk.label_list) pred_df = dk.denormalize_labels_from_metadata(pred_df) @@ -560,9 +559,12 @@ class IFreqaiModel(ABC): """ import scipy as spy + # add classes from classifier label types if used + full_labels = dk.label_list + dk.unique_class_list + num_candles = self.freqai_info.get("fit_live_predictions_candles", 100) dk.data["labels_mean"], dk.data["labels_std"] = {}, {} - for label in dk.label_list: + for label in full_labels: if self.dd.historic_predictions[dk.pair][label].dtype == object: continue f = spy.stats.norm.fit(self.dd.historic_predictions[dk.pair][label].tail(num_candles)) diff --git a/freqtrade/freqai/prediction_models/BaseRegressionModel.py b/freqtrade/freqai/prediction_models/BaseRegressionModel.py index a3bd82a8f..2ef175a2e 100644 --- a/freqtrade/freqai/prediction_models/BaseRegressionModel.py +++ b/freqtrade/freqai/prediction_models/BaseRegressionModel.py @@ -62,15 +62,6 @@ class BaseRegressionModel(IFreqaiModel): model = self.fit(data_dictionary) - if pair not in self.dd.historic_predictions: - self.set_initial_historic_predictions( - data_dictionary['train_features'], model, dk, pair) - - if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: - self.fit_live_predictions(dk) - - self.dd.save_historic_predictions_to_disk() - logger.info(f"--------------------done training {pair}--------------------") return model From 1f192be43bd448172f0eecb5cf5c0b1109f1b40a Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 10 Aug 2022 17:30:57 +0200 Subject: [PATCH 279/308] avoid denormalizing labels twice --- freqtrade/freqai/freqai_interface.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index e7dd6c714..d8356702c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -534,8 +534,6 @@ class IFreqaiModel(ABC): :param: pair: str = current pair """ - pred_df = dk.denormalize_labels_from_metadata(pred_df) - self.dd.historic_predictions[pair] = pred_df hist_preds_df = self.dd.historic_predictions[pair] From 7d448fd4ac44b724d4f54fd0c85032242a517639 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Wed, 10 Aug 2022 19:44:22 +0200 Subject: [PATCH 280/308] allow fit_live_predictions access to current pair --- freqtrade/freqai/freqai_interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index d8356702c..502d5ac34 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -340,7 +340,7 @@ class IFreqaiModel(ABC): self.dd.save_historic_predictions_to_disk() if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: - self.fit_live_predictions(dk) + self.fit_live_predictions(dk, pair) self.dd.append_model_predictions(pair, pred_df, do_preds, dk, len(dataframe)) dk.return_dataframe = self.dd.attach_return_values_to_return_dataframe(pair, dataframe) @@ -551,7 +551,7 @@ class IFreqaiModel(ABC): for return_str in dk.data['extra_returns_per_train']: hist_preds_df[return_str] = 0 - def fit_live_predictions(self, dk: FreqaiDataKitchen) -> None: + def fit_live_predictions(self, dk: FreqaiDataKitchen, pair: str) -> None: """ Fit the labels with a gaussian distribution """ From 3e38c1b0bd80498f0e6c7a03727653e24a148db6 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 12 Aug 2022 13:13:08 +0200 Subject: [PATCH 281/308] take dynamic sized tail off historic_predictions as return dataframe to strategy. --- freqtrade/freqai/data_drawer.py | 114 ++++++++++++++------------- freqtrade/freqai/freqai_interface.py | 12 ++- 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index db1206a39..0644ddbc9 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -241,48 +241,48 @@ class FreqaiDataDrawer: """ # dynamic df returned to strategy and plotted in frequi - mrv_df = self.model_return_values[pair] = pd.DataFrame() + # mrv_df = self.model_return_values[pair] = pd.DataFrame() # if user reused `identifier` in config and has historical predictions collected, load them # so that frequi remains uninterrupted after a crash hist_df = self.historic_predictions - if pair in hist_df: - len_diff = len(hist_df[pair].index) - len(pred_df.index) - if len_diff < 0: - df_concat = pd.concat([pred_df.iloc[:abs(len_diff)], hist_df[pair]], - ignore_index=True, keys=hist_df[pair].keys()) - else: - df_concat = hist_df[pair].tail(len(pred_df.index)).reset_index(drop=True) - df_concat = df_concat.fillna(0) - self.model_return_values[pair] = df_concat - logger.info(f'Setting initial FreqUI plots from historical data for {pair}.') - + # if pair in hist_df: + len_diff = len(hist_df[pair].index) - len(pred_df.index) + if len_diff < 0: + df_concat = pd.concat([pred_df.iloc[:abs(len_diff)], hist_df[pair]], + ignore_index=True, keys=hist_df[pair].keys()) else: - for label in pred_df.columns: - mrv_df[label] = pred_df[label] - if mrv_df[label].dtype == object: - continue - mrv_df[f"{label}_mean"] = dk.data["labels_mean"][label] - mrv_df[f"{label}_std"] = dk.data["labels_std"][label] + df_concat = hist_df[pair].tail(len(pred_df.index)).reset_index(drop=True) + df_concat = df_concat.fillna(0) + self.model_return_values[pair] = df_concat + logger.info(f'Setting initial FreqUI plots from historical data for {pair}.') - if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: - mrv_df["DI_values"] = dk.DI_values + # else: + # for label in pred_df.columns: + # mrv_df[label] = pred_df[label] + # if mrv_df[label].dtype == object: + # continue + # mrv_df[f"{label}_mean"] = dk.data["labels_mean"][label] + # mrv_df[f"{label}_std"] = dk.data["labels_std"][label] - mrv_df["do_predict"] = do_preds + # if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: + # mrv_df["DI_values"] = dk.DI_values - if dk.data['extra_returns_per_train']: - rets = dk.data['extra_returns_per_train'] - for return_str in rets: - mrv_df[return_str] = rets[return_str] + # mrv_df["do_predict"] = do_preds - # for keras type models, the conv_window needs to be prepended so - # viewing is correct in frequi - if self.freqai_info.get('keras', False): - n_lost_points = self.freqai_info.get('conv_width', 2) - zeros_df = DataFrame(np.zeros((n_lost_points, len(mrv_df.columns))), - columns=mrv_df.columns) - self.model_return_values[pair] = pd.concat( - [zeros_df, mrv_df], axis=0, ignore_index=True) + # if dk.data['extra_returns_per_train']: + # rets = dk.data['extra_returns_per_train'] + # for return_str in rets: + # mrv_df[return_str] = rets[return_str] + + # # for keras type models, the conv_window needs to be prepended so + # # viewing is correct in frequi + # if self.freqai_info.get('keras', False): + # n_lost_points = self.freqai_info.get('conv_width', 2) + # zeros_df = DataFrame(np.zeros((n_lost_points, len(mrv_df.columns))), + # columns=mrv_df.columns) + # self.model_return_values[pair] = pd.concat( + # [zeros_df, mrv_df], axis=0, ignore_index=True) def append_model_predictions(self, pair: str, predictions: DataFrame, do_preds: NDArray[np.int_], @@ -292,23 +292,23 @@ class FreqaiDataDrawer: # own return array in the same shape, we need to figure out how the size has changed # and adapt our stored/returned info accordingly. - length_difference = len(self.model_return_values[pair]) - len_df - i = 0 + # length_difference = len(self.model_return_values[pair]) - len_df + # i = 0 - if length_difference == 0: - i = 1 - elif length_difference > 0: - i = length_difference + 1 + # if length_difference == 0: + # i = 1 + # elif length_difference > 0: + # i = length_difference + 1 - df = self.model_return_values[pair] = self.model_return_values[pair].shift(-i) + # df = self.model_return_values[pair] = self.model_return_values[pair].shift(-i) - if pair in self.historic_predictions: - hp_df = self.historic_predictions[pair] - # here are some pandas hula hoops to accommodate the possibility of a series - # or dataframe depending number of labels requested by user - nan_df = pd.DataFrame(np.nan, index=hp_df.index[-2:] + 2, columns=hp_df.columns) - hp_df = pd.concat([hp_df, nan_df], ignore_index=True, axis=0) - self.historic_predictions[pair] = hp_df[:-1] + # if pair in self.historic_predictions: + df = self.historic_predictions[pair] + # here are some pandas hula hoops to accommodate the possibility of a series + # or dataframe depending number of labels requested by user + nan_df = pd.DataFrame(np.nan, index=df.index[-2:] + 2, columns=df.columns) + df = pd.concat([df, nan_df], ignore_index=True, axis=0) + df = self.historic_predictions[pair] = df[:-1] # incase user adds additional "predictions" e.g. predict_proba output: for label in predictions.columns: @@ -328,16 +328,18 @@ class FreqaiDataDrawer: for return_str in rets: df[return_str].iloc[-1] = rets[return_str] - # append the new predictions to persistent storage - if pair in self.historic_predictions: - for key in df.keys(): - self.historic_predictions[pair][key].iloc[-1] = df[key].iloc[-1] + self.model_return_values[pair] = df.tail(len_df).reset_index(drop=True) - if length_difference < 0: - prepend_df = pd.DataFrame( - np.zeros((abs(length_difference) - 1, len(df.columns))), columns=df.columns - ) - df = pd.concat([prepend_df, df], axis=0) + # # append the new predictions to persistent storage + # if pair in self.historic_predictions: + # for key in df.keys(): + # self.historic_predictions[pair][key].iloc[-1] = df[key].iloc[-1] + + # if length_difference < 0: + # prepend_df = pd.DataFrame( + # np.zeros((abs(length_difference) - 1, len(df.columns))), columns=df.columns + # ) + # df = pd.concat([prepend_df, df], axis=0) def attach_return_values_to_return_dataframe( self, pair: str, dataframe: DataFrame) -> DataFrame: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 502d5ac34..4306b4879 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -319,9 +319,10 @@ class IFreqaiModel(ABC): # first predictions are made on entire historical candle set coming from strategy. This # allows FreqUI to show full return values. pred_df, do_preds = self.predict(dataframe, dk) - self.dd.set_initial_return_values(pair, dk, pred_df, do_preds) if pair not in self.dd.historic_predictions: self.set_initial_historic_predictions(pred_df, dk, pair) + self.dd.set_initial_return_values(pair, dk, pred_df, do_preds) + dk.return_dataframe = self.dd.attach_return_values_to_return_dataframe(pair, dataframe) return elif self.dk.check_if_model_expired(trained_timestamp): @@ -551,6 +552,15 @@ class IFreqaiModel(ABC): for return_str in dk.data['extra_returns_per_train']: hist_preds_df[return_str] = 0 + # # for keras type models, the conv_window needs to be prepended so + # # viewing is correct in frequi + if self.freqai_info.get('keras', False): + n_lost_points = self.freqai_info.get('conv_width', 2) + zeros_df = DataFrame(np.zeros((n_lost_points, len(hist_preds_df.columns))), + columns=hist_preds_df.columns) + self.model_return_values[pair] = pd.concat( + [zeros_df, hist_preds_df], axis=0, ignore_index=True) + def fit_live_predictions(self, dk: FreqaiDataKitchen, pair: str) -> None: """ Fit the labels with a gaussian distribution From 31be707cc838433ddd35a8c4d404e725c9e4274a Mon Sep 17 00:00:00 2001 From: robcaulk Date: Fri, 12 Aug 2022 16:12:28 +0200 Subject: [PATCH 282/308] clean up code, add docstrings --- freqtrade/freqai/data_drawer.py | 86 ++++++---------------------- freqtrade/freqai/freqai_interface.py | 4 +- 2 files changed, 19 insertions(+), 71 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 0644ddbc9..02ef156bd 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -232,85 +232,43 @@ class FreqaiDataDrawer: # send pair to end of queue self.pair_dict[pair]["priority"] = len(self.pair_dict) - def set_initial_return_values(self, pair: str, dk: FreqaiDataKitchen, - pred_df: DataFrame, do_preds: ArrayLike) -> None: + def set_initial_return_values(self, pair: str, pred_df: DataFrame) -> None: """ - Set the initial return values to a persistent dataframe. This avoids needing to repredict on - historical candles, and also stores historical predictions despite retrainings (so stored - predictions are true predictions, not just inferencing on trained data) + Set the initial return values to the historical predictions dataframe. This avoids needing + to repredict on historical candles, and also stores historical predictions despite + retrainings (so stored predictions are true predictions, not just inferencing on trained + data) """ - # dynamic df returned to strategy and plotted in frequi - # mrv_df = self.model_return_values[pair] = pd.DataFrame() - - # if user reused `identifier` in config and has historical predictions collected, load them - # so that frequi remains uninterrupted after a crash hist_df = self.historic_predictions - # if pair in hist_df: len_diff = len(hist_df[pair].index) - len(pred_df.index) if len_diff < 0: df_concat = pd.concat([pred_df.iloc[:abs(len_diff)], hist_df[pair]], - ignore_index=True, keys=hist_df[pair].keys()) + ignore_index=True, keys=hist_df[pair].keys()) else: df_concat = hist_df[pair].tail(len(pred_df.index)).reset_index(drop=True) df_concat = df_concat.fillna(0) self.model_return_values[pair] = df_concat - logger.info(f'Setting initial FreqUI plots from historical data for {pair}.') - - # else: - # for label in pred_df.columns: - # mrv_df[label] = pred_df[label] - # if mrv_df[label].dtype == object: - # continue - # mrv_df[f"{label}_mean"] = dk.data["labels_mean"][label] - # mrv_df[f"{label}_std"] = dk.data["labels_std"][label] - - # if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: - # mrv_df["DI_values"] = dk.DI_values - - # mrv_df["do_predict"] = do_preds - - # if dk.data['extra_returns_per_train']: - # rets = dk.data['extra_returns_per_train'] - # for return_str in rets: - # mrv_df[return_str] = rets[return_str] - - # # for keras type models, the conv_window needs to be prepended so - # # viewing is correct in frequi - # if self.freqai_info.get('keras', False): - # n_lost_points = self.freqai_info.get('conv_width', 2) - # zeros_df = DataFrame(np.zeros((n_lost_points, len(mrv_df.columns))), - # columns=mrv_df.columns) - # self.model_return_values[pair] = pd.concat( - # [zeros_df, mrv_df], axis=0, ignore_index=True) def append_model_predictions(self, pair: str, predictions: DataFrame, do_preds: NDArray[np.int_], dk: FreqaiDataKitchen, len_df: int) -> None: - - # strat seems to feed us variable sized dataframes - and since we are trying to build our - # own return array in the same shape, we need to figure out how the size has changed - # and adapt our stored/returned info accordingly. - - # length_difference = len(self.model_return_values[pair]) - len_df - # i = 0 - - # if length_difference == 0: - # i = 1 - # elif length_difference > 0: - # i = length_difference + 1 - - # df = self.model_return_values[pair] = self.model_return_values[pair].shift(-i) - - # if pair in self.historic_predictions: + """ + Append model predictions to historic predictions dataframe, then set the + strategy return dataframe to the tail of the historic predictions. The length of + the tail is equivalent to the length of the dataframe that entered FreqAI from + the strategy originally. Doing this allows FreqUI to always display the correct + historic predictions. + """ df = self.historic_predictions[pair] + # here are some pandas hula hoops to accommodate the possibility of a series # or dataframe depending number of labels requested by user nan_df = pd.DataFrame(np.nan, index=df.index[-2:] + 2, columns=df.columns) df = pd.concat([df, nan_df], ignore_index=True, axis=0) df = self.historic_predictions[pair] = df[:-1] - # incase user adds additional "predictions" e.g. predict_proba output: + # model outputs and associated statistics for label in predictions.columns: df[label].iloc[-1] = predictions[label].iloc[-1] if df[label].dtype == object: @@ -318,11 +276,12 @@ class FreqaiDataDrawer: df[f"{label}_mean"].iloc[-1] = dk.data["labels_mean"][label] df[f"{label}_std"].iloc[-1] = dk.data["labels_std"][label] + # outlier indicators df["do_predict"].iloc[-1] = do_preds[-1] - if self.freqai_info["feature_parameters"].get("DI_threshold", 0) > 0: df["DI_values"].iloc[-1] = dk.DI_values[-1] + # extra values the user added within custom prediction model if dk.data['extra_returns_per_train']: rets = dk.data['extra_returns_per_train'] for return_str in rets: @@ -330,17 +289,6 @@ class FreqaiDataDrawer: self.model_return_values[pair] = df.tail(len_df).reset_index(drop=True) - # # append the new predictions to persistent storage - # if pair in self.historic_predictions: - # for key in df.keys(): - # self.historic_predictions[pair][key].iloc[-1] = df[key].iloc[-1] - - # if length_difference < 0: - # prepend_df = pd.DataFrame( - # np.zeros((abs(length_difference) - 1, len(df.columns))), columns=df.columns - # ) - # df = pd.concat([prepend_df, df], axis=0) - def attach_return_values_to_return_dataframe( self, pair: str, dataframe: DataFrame) -> DataFrame: """ diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 4306b4879..374fcea2f 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -321,7 +321,7 @@ class IFreqaiModel(ABC): pred_df, do_preds = self.predict(dataframe, dk) if pair not in self.dd.historic_predictions: self.set_initial_historic_predictions(pred_df, dk, pair) - self.dd.set_initial_return_values(pair, dk, pred_df, do_preds) + self.dd.set_initial_return_values(pair, pred_df) dk.return_dataframe = self.dd.attach_return_values_to_return_dataframe(pair, dataframe) return @@ -558,7 +558,7 @@ class IFreqaiModel(ABC): n_lost_points = self.freqai_info.get('conv_width', 2) zeros_df = DataFrame(np.zeros((n_lost_points, len(hist_preds_df.columns))), columns=hist_preds_df.columns) - self.model_return_values[pair] = pd.concat( + self.dd.historic_predictions[pair] = pd.concat( [zeros_df, hist_preds_df], axis=0, ignore_index=True) def fit_live_predictions(self, dk: FreqaiDataKitchen, pair: str) -> None: From 58de20af0f1226dd5b3985d16d72bd979ec9fcf5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 13 Aug 2022 20:07:31 +0200 Subject: [PATCH 283/308] make BaseClassifierModel. Add predict_proba to lightgbm --- freqtrade/freqai/data_drawer.py | 2 +- .../prediction_models/BaseClassifierModel.py | 99 +++++++++++++++++++ .../prediction_models/CatboostClassifier.py | 45 ++------- .../prediction_models/LightGBMClassifier.py | 4 +- 4 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 freqtrade/freqai/prediction_models/BaseClassifierModel.py diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 02ef156bd..4ba55a0ec 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -12,7 +12,7 @@ import pandas as pd import rapidjson from joblib import dump, load from joblib.externals import cloudpickle -from numpy.typing import ArrayLike, NDArray +from numpy.typing import NDArray from pandas import DataFrame from freqtrade.configuration import TimeRange diff --git a/freqtrade/freqai/prediction_models/BaseClassifierModel.py b/freqtrade/freqai/prediction_models/BaseClassifierModel.py new file mode 100644 index 000000000..2edbf3b51 --- /dev/null +++ b/freqtrade/freqai/prediction_models/BaseClassifierModel.py @@ -0,0 +1,99 @@ +import logging +from typing import Any, Tuple + +import numpy as np +import numpy.typing as npt +import pandas as pd +from pandas import DataFrame + +from freqtrade.freqai.data_kitchen import FreqaiDataKitchen +from freqtrade.freqai.freqai_interface import IFreqaiModel + + +logger = logging.getLogger(__name__) + + +class BaseClassifierModel(IFreqaiModel): + """ + Base class for regression type models (e.g. Catboost, LightGBM, XGboost etc.). + User *must* inherit from this class and set fit() and predict(). See example scripts + such as prediction_models/CatboostPredictionModel.py for guidance. + """ + + def train( + self, unfiltered_dataframe: DataFrame, pair: str, dk: FreqaiDataKitchen + ) -> Any: + """ + Filter the training data and train a model to it. Train makes heavy use of the datakitchen + for storing, saving, loading, and analyzing the data. + :param unfiltered_dataframe: Full dataframe for the current training period + :param metadata: pair metadata from strategy. + :return: + :model: Trained model which can be used to inference (self.predict) + """ + + logger.info("-------------------- Starting training " f"{pair} --------------------") + + # filter the features requested by user in the configuration file and elegantly handle NaNs + features_filtered, labels_filtered = dk.filter_features( + unfiltered_dataframe, + dk.training_features_list, + dk.label_list, + training_filter=True, + ) + + start_date = unfiltered_dataframe["date"].iloc[0].strftime("%Y-%m-%d") + end_date = unfiltered_dataframe["date"].iloc[-1].strftime("%Y-%m-%d") + logger.info(f"-------------------- Training on data from {start_date} to " + f"{end_date}--------------------") + # split data into train/test data. + data_dictionary = dk.make_train_test_datasets(features_filtered, labels_filtered) + if not self.freqai_info.get('fit_live_predictions', 0) or not self.live: + dk.fit_labels() + # normalize all data based on train_dataset only + data_dictionary = dk.normalize_data(data_dictionary) + + # optional additional data cleaning/analysis + self.data_cleaning_train(dk) + + logger.info( + f'Training model on {len(dk.data_dictionary["train_features"].columns)}' " features" + ) + logger.info(f'Training model on {len(data_dictionary["train_features"])} data points') + + model = self.fit(data_dictionary) + + logger.info(f"--------------------done training {pair}--------------------") + + return model + + def predict( + self, unfiltered_dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = False + ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: + """ + Filter the prediction features data and predict with it. + :param: unfiltered_dataframe: Full dataframe for the current backtest period. + :return: + :pred_df: dataframe containing the predictions + :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove + data (NaNs) or felt uncertain about data (PCA and DI index) + """ + + dk.find_features(unfiltered_dataframe) + filtered_dataframe, _ = dk.filter_features( + unfiltered_dataframe, dk.training_features_list, training_filter=False + ) + filtered_dataframe = dk.normalize_data_from_metadata(filtered_dataframe) + dk.data_dictionary["prediction_features"] = filtered_dataframe + + self.data_cleaning_predict(dk, filtered_dataframe) + + predictions = self.model.predict(dk.data_dictionary["prediction_features"]) + pred_df = DataFrame(predictions, columns=dk.label_list) + + predictions_prob = self.model.predict_proba(dk.data_dictionary["prediction_features"]) + pred_df_prob = DataFrame(predictions_prob, columns=self.model.classes_) + + pred_df = pd.concat([pred_df, pred_df_prob], axis=1) + + return (pred_df, dk.do_predict) diff --git a/freqtrade/freqai/prediction_models/CatboostClassifier.py b/freqtrade/freqai/prediction_models/CatboostClassifier.py index 7a4b06557..b88b28b25 100644 --- a/freqtrade/freqai/prediction_models/CatboostClassifier.py +++ b/freqtrade/freqai/prediction_models/CatboostClassifier.py @@ -1,17 +1,15 @@ import logging -from typing import Any, Dict, Tuple -import pandas as pd -from pandas import DataFrame +from typing import Any, Dict + from catboost import CatBoostClassifier, Pool -import numpy.typing as npt -import numpy as np -from freqtrade.freqai.prediction_models.BaseRegressionModel import BaseRegressionModel -from freqtrade.freqai.data_kitchen import FreqaiDataKitchen + +from freqtrade.freqai.prediction_models.BaseClassifierModel import BaseClassifierModel + logger = logging.getLogger(__name__) -class CatboostClassifier(BaseRegressionModel): +class CatboostClassifier(BaseClassifierModel): """ User created prediction model. The class needs to override three necessary functions, predict(), train(), fit(). The class inherits ModelHandler which @@ -41,34 +39,3 @@ class CatboostClassifier(BaseRegressionModel): cbr.fit(train_data) return cbr - - def predict( - self, unfiltered_dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = False - ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: - """ - Filter the prediction features data and predict with it. - :param: unfiltered_dataframe: Full dataframe for the current backtest period. - :return: - :pred_df: dataframe containing the predictions - :do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove - data (NaNs) or felt uncertain about data (PCA and DI index) - """ - - dk.find_features(unfiltered_dataframe) - filtered_dataframe, _ = dk.filter_features( - unfiltered_dataframe, dk.training_features_list, training_filter=False - ) - filtered_dataframe = dk.normalize_data_from_metadata(filtered_dataframe) - dk.data_dictionary["prediction_features"] = filtered_dataframe - - self.data_cleaning_predict(dk, filtered_dataframe) - - predictions = self.model.predict(dk.data_dictionary["prediction_features"]) - pred_df = DataFrame(predictions, columns=dk.label_list) - - predictions_prob = self.model.predict_proba(dk.data_dictionary["prediction_features"]) - pred_df_prob = DataFrame(predictions_prob, columns=self.model.classes_) - - pred_df = pd.concat([pred_df, pred_df_prob], axis=1) - - return (pred_df, dk.do_predict) diff --git a/freqtrade/freqai/prediction_models/LightGBMClassifier.py b/freqtrade/freqai/prediction_models/LightGBMClassifier.py index 782dbce35..bafb16a39 100644 --- a/freqtrade/freqai/prediction_models/LightGBMClassifier.py +++ b/freqtrade/freqai/prediction_models/LightGBMClassifier.py @@ -3,13 +3,13 @@ from typing import Any, Dict from lightgbm import LGBMClassifier -from freqtrade.freqai.prediction_models.BaseRegressionModel import BaseRegressionModel +from freqtrade.freqai.prediction_models.BaseClassifierModel import BaseClassifierModel logger = logging.getLogger(__name__) -class LightGBMClassifier(BaseRegressionModel): +class LightGBMClassifier(BaseClassifierModel): """ User created prediction model. The class needs to override three necessary functions, predict(), train(), fit(). The class inherits ModelHandler which From 8d9284a524a15cbce39eb3b82df53b1e21c3c3a6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Aug 2022 20:16:36 +0200 Subject: [PATCH 284/308] Fix docs edit button --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index a43322f78..45f9aba27 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,6 +1,7 @@ site_name: Freqtrade site_url: https://www.freqtrade.io/ repo_url: https://github.com/freqtrade/freqtrade +edit_uri: edit/develop/docs/ use_directory_urls: True nav: - Home: index.md From c9c128f78137e69d55c8d8c1ab42869eeb218af8 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Sun, 14 Aug 2022 02:49:01 +0200 Subject: [PATCH 285/308] finalize logo, improve doc, improve algo overview, fix base tensorflowmodel for mypy --- docs/assets/freqai_algo.png | Bin 335507 -> 1018784 bytes docs/assets/freqai_doc_logo.svg | 531 +++++++----------- docs/freqai.md | 81 ++- .../prediction_models/BaseTensorFlowModel.py | 22 +- 4 files changed, 290 insertions(+), 344 deletions(-) diff --git a/docs/assets/freqai_algo.png b/docs/assets/freqai_algo.png index 39fb898558b638c4703c67a406fbc2cead95728f..13813e129b09e392826b7326c6df73b781967d31 100644 GIT binary patch literal 1018784 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

6ToLyn&M`dx8qSX z2iVQ%32-nrf@=GwE+&~iH<*j?yV2Iz;q4y+Za|^e)+m&a$me(P7cb2ONZ6qH26A5q zNn{B{PjnID`Tx&2B$SVr4swx^NaPR1og@JF;tPN!4Z!3{&RvO*WL#W#OvGLJj9`A?! zet>`jv;H0){D6TN0nT(wKtblnSj*zK#eqf#k}pC4dsI?U z(OKA`qNI!kV3Q?~YH+aHQDB!I9v<4y{on&dC+nl6wzjtYOf3gEe(BKA&%p4yi}78nCD5K90G`~gahQi#Z!V0 zt65}!`fKT=_t-ryM9@JiCg688dOQ^op#Z5j{CydZUxSnS?JAJpn<)3On>UImBtDD< z0{K{*TJW;|f~>rDFzGFMi2>v=5*UX(2fl)|r`wAyEgT$7U^fIr?wFt-i3a%mui;?= zK>6wfkLLqC)G-&f1!gtF!BU6v73U^kYRIWfDJ?Axm1_{M>zEw_Xr_E>xgtaWZIzdi zxd(JS%zL|Y^}5-zK!WX@La$vYg#yBXdbq^dN5%5(-@>%&J#5tqB;`? zs?t*Fxjdf0Doh(x4i%3}1|v-SmiSp-*b}BdPn9*@L$>PBs47m)^VML0a5I~FS`s0nI{a^$ae;hei zVkho{cKB;}3N8y0MhKWH<>aa2attp60Zcce={;L(D=;LNM>M%;e;4)PHn)Cfd*k)Q zW0RHcUK07d#gIFimF`4Y@a39ijzDd0u$C$apPU30bu`9-5 ztJZD%=`M`>A>-inT(*qPIQDdAqAP}UrH$6Gf6YBjwZHSR&Fa~lkNTBz3Yg8PyXhHp zWCaGgUtFuMrHbp(GzC99eDnRR;B|e1jHsu-bBn@`9bTv`o7C||zrBh}nHwH6M;O=E)+TTt{Oli)%lU!ekQ-+s^(3|PS!j)$jB-4#4uF06%dYDz-Ws={f{d>Q- zvSP^OkuP}tM^1HgLtr|@A=#87eU)LETG=q#G>)_-~@-Sfq;TTpbeyz-A;U?l2*JLCQ2uGkQj4Yt<-g3Wl2H2BZ0W(gFQ zae%FK_r`f-{*_qwhJPH~-Yv-G!14EWmP85S|)N_E*!9s!O2(-S40gWnj2>>g~UcCh_BTx$q ziDJODwJk2vK`u<-e2fHOixpVL0FGRI`8+UP4V=>svjT7oH1p8&Z1kj{f|0F#Ypj$A zfIk-(e$es>3?qa#XJ7&G9=PWzsi~dxxxnm!`#3Zifn(Sj{5{CV0xUx!Ae;$=8L;aV z$LL4`ln*RjPS_FPLi$-IG>w407!<4o*|-At*A8%1kcnzKm%;t!=4RU7 zPKN|2CfDa3;@PVll4&WPnKo%>f>AXaR9jy=Ig0U0;fj|mJ z0{sGbx)@+y1@{Ac6d<8gg)~ZFC8vdT2L?RBUCzG=G?Xb>&?u2B=B;wG{rlZ34+NM_ ztV&5&S^!9U57yS!_Pf#FQ`-(4;TOOXw?%JvNlfFdka}+BV-ul2Xjvz1n@K>$&!J4o zqMFeG-bVMWQI;D}u7OgN2QU$e$Ft#x<{Bn7Fpv^~E&=S4IK|Q4@L15oZ%;_{D@{4N zZh$zx8rW8<&V#MI%|C147YUgi9?ttNz5|~%G(Q2n7a~qU-doVzd=C}%jo8A#Hi30_ zJm5rG17vSmf|(f&ES2Pd_u|vN`?@tY%8-{Wa7I)B_O$5{??Bs72y6kC>E0~4i4Z<~ zxN~TsFeL~K=vkCOqFumLjqU61RapcA@&8fvmQhhaZM*OwNOwpoNF!Ym0z;RCG$LJs zG)PGd(kUGx-60@Icek|C-Q8Vh&+~ro_nh;?wOB4>0%!00z7if~@HT-3&q>bOngvj2 zcJg;8IRqw{Y>5~ECa6~Ehxh<2ILYPoxYE2Xg^iYOB$bO%CHMu0;|H$~mv5`|#SN9F zH#JM%@6+$rp{mHQp74NGSekaCQTsPNxTujJQ}tftfWlMM)|Zck_z*E`1-pb2vF07V z+F%ZFkzJw}}DN@eEZyfjJ;%{cW~s-58@rb0t5U zN*=8^`kIvJfv9>J(Kj(lFAMqp0-R0B?&2r1U92lO$aI|UfVLq9STln5U z<+b15WL31kB-dl`;*qo9b7i&|v?q{1PY1 zB>Sf`QupI=sku^G-pgY{*tTJv-_+=b#BuA#&FJFt%`czH_VbP7lu(sSi9#{F>eSR% zrL>kE&jjTK7O;>`leV+m#3Sf;qz2Vo2Ox7HBqM!en3#WyG$o9@nli68N1#)#hAj)} zyp|1lF*25_7-mspH3b+=XS)+9z8u&md7qcx%+JofwymKXJg;jet5cHe_3V{jv>Kx} zx%IbZJB&5zfBR!^(@P&Fl5s&$(QuOI#+L5t5kQEkqNSvmj1POCK3hh*_i@a-%XN$` z)~;}9!hX!vQne%2y5*PhILpki+wJ%6;Kg-*ycvi2KCg&b#!r^wC`}q(ua*y&7*-?i zo~mwqIj(PfWKQ8MjipZ%mM%Sgt(%OTm`SZJR6p{M^448$2CxXCu9&HX$T- zQERF9eVVIX@GA;w59knIzu>aSE1G*X@(H7|2kDtX#*FM6m$YU`KB!_V!QWsvx1Q=n z9icoK6a2LOjdWY_r#=5w52449EC&1*f~Va9tj8sAxCV}fMZORoX?csX)ZI0~{9n-| z9HtWmAx|S9l!L&X_+2cgMGUfxg$1L&$3CxrU|{lr84uSRPQdw0Rx)?|E!JxK$G{5y z?@H!9KvEClsDiT*v_T^H6e0;rbfuBLkL;g+zbK$%_HNp z6q3<{B-=fib1~w#7aQG{(DWlVTy#V*tf5Z>qJCpDgfL07%3YgqG zw6LeD+Tdbi4LU2pG9pp+>90^iF@T+#A8xGHXS58w;)^`9?bK!?XoVXna-6Ll!Sgi` zNauIR3W|C4aI?$4{*)B(RVPLIUkod4z(BBa1vsKkIJgLMWFof| zf`j!SBL2Jaqf#UmQ=hEd5IDY%Km}09sdxao5kLw7ato3jcr3?|(mhW?_!mKoTBud1 zN#&U$81GEPf_)9~IJ3%*JuZ>U{>cET0^@~K9?qf8 z`A*RrCP4GFgEK}|dfuu!eU}woXX=patQbgCKp;=|9s3SuR(3WX0XZVGKM`8TROHCxAY?itEQsx59qX=JFid)OcooLCf$eSZYV&?FxiPRcML;bARz+MC zx+(B2xDHQ$T6vZIMk#M99bNX3fkMK8mF~9WriJR(Jm)?tgcw&UM}l@U2LHH#l}qJo z?B?8gf!cQqKfGB|+I=Njm95Z|9BkVk^2qddZsudieS9Mkf7S2Jo*>sAXEly`*PC=l ze@JYqhAy~M&hrg+X~D`m-abu}`*9z>+h<~`Ks`bgoRLDyb`!#uh$~+B?Ug{n2l*Q) zodg%}S6UH~7h%uXpGcKwb-k-oH9L?5Wsc%RGM#g%qp$#DOs);&nCeP{Np+gzmq-TQ zkq6QUvRMW6I44W109Z^ocPeCoKeB{`h z#0WE!U}uh@uH~TFN--f}?nc7Aj%;3D&|$gElZ~M{v3$($Bk{DhH{hnEto8Kj;_5jk z8V{AW=2d{0TJkV560mPIvIJF=L?AyAk)`w-gLNh=on`Eg7rsAwI2RA^#dnG_SD#)o zJ8o^=bSh>XxlZ3wJO~NvpNi*Ze6OIf%A*=M=wyx(Ri1(Bn8h*qx-puV?qs| zNmSFS;$f61DnV=QtyP?rI&{>oFe04ED|J<`r})#I-6aAHP|d!k>4a zI_MVOJ0AC@0_t?VWBt+JJd^lu;>$ENbdr++`faWKcF+X5nR^uo~ki7%;e zru4mVy(N#XmPe&^ey!Key{b14$*0VufBo=>!&@#YuRi%YTWn@_)8Iu;@y#Poo>FQk zpc#w-y#~UU)B^io0BQV#fIAsE?3!YW7rEDn-uAyl%+)2$^ftT>jIxUC5j{sT(2K(U z_QJ-&IzH)`BYHZ7)aS>@3j&%x&oh2rud$el z8zB5e8X#$k&YoUg@GwC5J_C+zyh+#nnfNSQ5dSBptDEx6u;5W5q*R8Fh@G-Uj8zKn#^Bq{{icSFsQsG_#oI5GI@z1k# z+s;iCT2Ov#4ZYc-!6OFa9Jos05LV&NNSOgtQbxuE>>dywI06NKJH~Ruv;+}a!IM^- zE6fAItsvKl1Sk_wT2lud08LEDraNVl3It*~MQ>!l0Y2ISgLQUyKY_q$YPckKJ6{-P za80$^{o`aCgcX1jQyk=Qbt#d81H2=N(?oTy9O6^)K^i<5_gw=Cy7J$SG1$?W`P=@X^o1y$s%5YYzECNLtwY+ zP`~AcH!{H&DL7dI;rKMcShiUNB+xH``Z&Q%0OXekfGovTAfATIxpZ}Q*18fI`J8&= z>nbI-TRPe~A*2dP2eY6L49dzort{fMNaC6h5D=6bb$sFRD5+y?N7KJNT)blz4^Tnb;+oOc`~Q) zX`FDe0EzS6Iw5&P`KPghkWXO&4Pc>q0+xrl78oT2monYZvIU=LtRVhgSB_v>>Hg~z z%K(6H${x%ys?uTt1Zs7ChCREj_{z*rH*hi}I9otb-Z%Z7c1*AEwx^K%Oa*VPS0e%A-MG&e5mp6B6CzZ(qSm`Dmk zDW~1uprF{TRWxv#JqAB+H>I^eZG}Hm%^{NZ=tS^NGFPNOP{8?}V*L^q2~VCF&E+*V zfizd2{m_Q6Q-_)(aSJ>Zlnf-%-}eDd$TUIe(3O~jRp}LBUFBejg`Wsa zGcB8+cot^(DP?T+q`QQaX_PgSh0-hTlaF39Y<@a85baHI?7^P*_KqaIA6{kOwZt@c z4;(5O#a>ObZ-d-51Nvt%I=u{GDdNH|*d!B!=d;Buf=Tmp44RF>A7Ls6;r_s8!8lCf z*L~aaD`=}^s@I)1S>y%l0aLZu@sGS%6QWzS)a<{K7$z))-@-D(D+qDDYSk^FZ~gAc zNFNKk4D{^k?n5IxCuHz7-MqA?nBNfoZGhzn2 zZ>ttEV$P@#83#yjN*oR97$X(;zkc5x38EbsN?UWU zNbjxMIh4LF)KE~{S25`^ZIFI`Hk9}CF|d5s){kDKz&75}=k76?u}4;~h;x(>LUYom zL7hI3#}qWEt~DtC@8^Yrd&>hAQ={Ex^9B}9PwkXfm=e}QHm_+=Si2dU{J$dxWzEBrIfZd z3BVyj!JwH9KJP%wX&2acaeUks90JWW|H0-naQZ{Y=Kmkf?;0HT+XdomRhiFyU#oWg zuxmz}V7V&zdxUy}{3vsu8XN6{ZrZ5S+`OYTx6r&lN3IvXj);f|ub|A=&Ii-$7C_UD zJ;3Y+$5bMnE6o3df`?@?!=~V;l0!j;ON(Lm=ZX9Yk z%Gx|f=>`c22{pRXpr9Zc4vu%Ui1W=}$hI2{yq| zECaN#jkX`bO93Zlpt#Ech>|sH`F&yn4pFtZbQ&3K^`F{!KuShD3ApDNV`FKZC|)Z~ zc+NQp&c&MqsMlRD0r%MN0c06qjOZ-o24r~$paFb=Hpz_zcD|!wHW>!b!~q}{ygFzEL~A*~z?&j}4Umjn z`R>i5(^Ivf@#Lgs8_)5vM4&2*b5aiZh~s-ko0vn3cw|kmpN$D&CjdJRUgCRwL#WDO3SuD@^WOWbfQ2H*4M@)kTmPrsY7ZgGE+CM#= z5|HB%2=nAm@zcq(Yjr=WdE140B3F~S-FK-o?1;&M#8&?Z6-(YXNYi3{3e2oC{)_IA z0yPj(hh-+yCUR;hn!u`gzH)5Mt#OUP_-7SPLTEpRG)OWe96J>+Zokqh%9$FTepB(m z(%$0WBVAfj^qNA9Ga<*hw&T3Q#p&%`a{PVX$AXlv{0?iiZSTgY5gj+t=`Y^$()KCG zGz5px-*$u&s^D{HWewxf9RtzNaXKldnk*2=5|{le$xl#z`LM531AJ$|4@12%)D1&{ zrNB?qJku~BLUJZK%e=|We)J%Jteml%<80Ud5#xCMVRD`t%_y<(dF$1O?|GLfRXW=o zasR6YXq11VuF8@$5m7_87UH3bf=5el<`|ofj@nKR`y&|;rpFe!+7A22jA<%TgJFWOu9ZjrR@sGDH=J@AX3e%F2 z{b;8r*;R(rseaxrssnA>L4HG0WOW5~1cKBXy{QlUf|Zu}G3Cxp{qam;T*L8gnH@oK zCw#UGtvgj#BX?Ei<|p-3S+SDn^P0zju+hmRT~&cXP232x_W^@S3TqFOof*}><|nL* z#+>x-M;_t~O>Byd!40lBKo=oyXsCpQjGVjZExppO{=6$LD-w|oA-I3Zxf4RgIbrzg zubY9s-^&M{Yf;zg0K4x}cg}jGEPFi!RxKy0pk93cqNj7Nt7O&{xEgVN9g*`aT4eR9 zy!5Bg3JGYuB6~V{%1)b^_A>h9c-*o37voxcax}Pzv|@UK5Dc-gz{y*;7vuiw_`z$g z$%%Yu%@ol1U(?IVW+^?d4S`$4eWZ*t!rvfJY>RdS2yVTzq`$ zyS|(+Cr&)_5}^5EA%-dut`)UMa6_m|7P;S2z9-zZ@l&_6U&6PDHi-$elJx-eOqtJp^Cl161+O-l=<3P)77OvL zB5wG=AgA%f)zI)idRo8^gj%ucRQj~EoNqc{%O@ev+1)G2%UAro1c*xTD!@!vz!wTC zucg32Ia-!}d%6sgUzatErNP{-_IGjFK101wb*jmurdE0p_fIqsk(&NVCIajuWX>)C zwp&sI3eeHYY<~IHm~O%$>iZ>tC@ZSHfuDIm!O8(xQiyHEDX_4-18lImbCFhAnwF`p zNsNCyc+-G%RNfdsGkmHn>Hl&<&S=eZ^08&WOwR#ywdD=1Ai@-WEqTNNLDfsteh5gG zRW6&A$N9O@rYv&Z8K-U@0N`jUE-uv+pdu4dY%T<9XL!Ete{h~S4?rKN4S{!YyJ`+4 z!adRPkJ@PBmb2tt8)4z~=7k&6`6 zk@>UZ_vTPrkDrL|#)#02U1-aKt7JLmFN5VWcMzW;PMKw?bK6pLtQ>alyT_2nkQckO zmO|$m$DunOxyCC#Mqt*bTVTO78x=yhqx4)IdI?kb`*td~`Tl!M;5;!8CZhpL$z#&D zU=xp{A*W@x&AMd9XM|4_C&&9Aeu;ih!Xt7b&^URfxd$b8!cfDu>xh$>wda%DA8_U6BDBh7k*&Es3F!h%R=M{o za#!`M_~NB$d^*J(>r&&}*ZaqPzmyF-f7bnmpWmTg-I8boeQ9T}6p{6ARLWqtL##iw zo6u)ntR>VZNaw;LWzwQ>*M<#1*-xCry%ssuPg%T0RUZ8RFV&Hau%pm34#vlZ@OZ2m={*6e2x*_>EFiVTFp?oYHfpL zxyD!%?x808iB1fPS3Ut=+cgHO`=W{@@_!y`r?gqLDa zloPOAk^0XEp`PxiMHdn~4ESCO=^ba^WzGzOk*Edo*0{r^turK@a+_aPYrfl_o}1^Q z=fOjQ=zht1isy3=dyH^*`e<@*uxo$Pi5C466CxE#D7Ihk4CpZOM%A(x7Fqrl@x9sO zOv+ao!|a}4YF*CJHA}QZ<~>|i9;s;@cGl$9rN{xB=awgl)~M5hpi^ZV^lBJdhNDld z?x#S(QJHCp8$z8woYLKWzDv}i@l%%+n6{n`qx7pGIUV9QT6Q4sL4Vkqcre;57b5~-oEM5~hL}LS(AK{`VCs&Hv^f;< ztmH$OcP9ZSC@L%W*u=J8tS6F*q>vt*C%L-1p|-Qo2e<)J*+g073DK(^9Q~b+jJyG( zwPZO;vS&B;JtQjx_`l4?rLE^1(GuD9+kwdfmoN^)NGc3eFz-^`brFNr)#Qt~DMYu_ zltS1OsR!iq^bs)FKg_-F?Chjwd;JXhCnW?T{61_lHpG(W*@=MY^ODa`)ntD2D3*$! zgai)ekhPLn8VE&hJC&_an@2J1tEaE7Iajnl8Cg2{6!4$*1o?l~6VwQyK}MXzUk_Wi z1(}UsJEZH&5BG?~w9DSNpU!TAJM!Jg@D|i=I?+~u{F}5%$LQAQ$(qgZvo_%BP|H&g z12#87m%U&uefM>hV$=VMc@4nX(Q~%(h5S+J^T8avIK#KB%&y4vW>DIk!5rxR0iP*T zm!Jw}`M%EXlLdS)Cjf42d;#7SHJ22~+{OE@sDlI*FwXNt?CVsm4GHkL`?p(Mf>PDP zcfc|K-WftbR_yc#ysbov*|DA7vwctO3PSq8lD>~I)0MZ?Ldhn_M zwH|lsb-U&o1mfLg0P)Z?hURue^6|4V+~>x?) zS4MrqB=~WSV@yDls^7==&xy|Af+)XC^zO)PDM$2LDx5<{;Hexpt&1pP@@vai_}oA< z@7wfPLp-eIu0Q5L^2_*K9&+HGX`5PadyI`j_SzyiSm1y*Uc*W=a|T1h`6TTFH{Z1~ zec|yuKhpKWALD>E%|frQ3E3L8j>&l;rUX^rG9Y5jY-ECX@>Prdn*xZA03&ZMm-hT) zIO#wJqt+3{dNO+Ci(0YJgg<>6lx>+|GBd9(oR?X5oO);_aif z+c}x|JM&o_7;kGLIm8vCr3SK;XR@z}@>WA$kKX zNuNGe{&64U-!ol^dDk?Uyf8P+l9}wMDoUwsKpj{1n=O>Y;b}oh0qyV4yx@ z3k$77@Oim&p!l=F9y3h&uqQ8!p$nUo@Ij=x;CoBKt8ROH3T3Vj{EJBS(NoV0C}jqf)K#9&_tf zWTwUj$G~7wy_=J6pWsQoIsG+|cL3$ZV6rd<-l@6CW!gN`gLFz#QgClmbnqN`NLjac zfRf$k_5yYpYFgJ|;)@^W5X6PYBdk&a3 zCV)TE^Sizya`wU2t|>&|bo13Y@)@~LSzsjneLC7Llu`tfMmq9czZRnbLiDW5+jPYK zZ;U(-X?vUNKouC$K1`^RW^jLZXMeM0xkkLGQP7}LD^)j~Dkpd4a3UE_#tlB?IxRd@ zKnh3BXV(t6oujS-_R-Zp2P6;I_FyoUpm(+ZK4CC&$XU;g_Xs6bTVYG>`7Vb|mrd?E zbtL&cuYvG;j5^gOZl0xKb904oxBb=;h#Eekx~n=+emm`R`@7>OXm1C9#HJnBkNzgv z9jWdMu8}?+Bda^xW{W!hNEWr{XwJkJbmTknVB(s@({qd*@Xjy+cSTQ zdDYptru4LsFZETe*TnTIG#0Z z@!g{d@3qG3K9zN_?D#o|9p)gg&B@%_fW%Bwv^ zNlYGg*nE$?7)cpKa`K!3yzMQb%fC1pZ}lnf@-ID(E>Ana5Pv+I6`)F(=}!+eA<=lAz^H1|^uJB|F+ zt{@)hyPK|KjxcQ9oQ7AuM284C(ItW4q;po{zl#+Bm1s%;8+l8k+z*M`4j}~u1ZR~> zLDc4<{);%n2hcG0B{xx}wB{U$>Qz~tcK@-`Wx|&QIOU-Ah)&4p12j^h_0n0dgQ9)Z zD=k#Y&Mu$PNQb|RVFyG(5U6c<3OEk~1S-_DSy5f!wrgEuTm|eNbVLW5{EBniY|Q!AP&gd%hw?g+VYu)wl22 zrA7x)Kq<|%QA$zn<0w+!_dBBf+Q;U9wS{8~;LM8Kz<&OK0>r-%A01u;$)S|5S$*AD zW?U1mygp(U^`lpeOTRP3-D$kzQu%=YQ^DWZ-uJnR`ocR?4(-3oY%6vX0W!C3gCdvb z(T4`=wZ00~b_%r1r^Wc_MTm5J?!PEC*D>qA-wImBc8aiGoaP|>87T?BXu0Vx&f8o9 z3Qk28&fojWj)I&Y7bt`n!EZ{zYGtnuPZDYwnSbTfVqSZ{;4|PB4BtZH2-)$u&g4J4 zqIyRV$aOg%J!e?MAiX|(pq>_0fa&6C1bW<{h;#JVH!k=7^{zn-Jo>c@D(3-Kpn3n%+Kh&Bt9;z=!r&Eoy93Hn%N zcjpvF^XI*VzMP?^mAxm*?(vNO1Rn6tX^ZmnqcV<=Rw1V5Po2V>4`0tB_AXVGi#$|g z2x9Y<#JACNj~9St-s-ZHFqSLaUNAL@(+at$MI9*d_AcAK$zTF}(S2QpA%Ro1{Fv9) zsG%YsFe$M~fg=Is&3T(-&>DlZ2I;7 ziR2Sqt&u413jG{#oikJ^Ex4bz$Z+yNuYP@k_Z9KLjuUG7A@6yu8oZBPAp zH1j}#K}dN}u(sV5S(c2#c+}o1O$=9UuccbvQtr_wCVDfHFM&EdP@$Q1W}H z@_{_#CZ8%R%~)?k3oU-phg`Yu(zTRd*M9p`2RU8{O?Q}5F8sD)&@Xt0EdeDm&#fm16T0%1wc)XJebHX8Mxi2mZr4mHxjlODb!dGx@wL)2@oN(x@TvcBg=l3qz9+#}ze z(Qx%Q{k0N(28&~h+QhRmSzQe8p$qCyV}F4O8q_+0j)fBx@qqkw;z*t6|FxI{Xib(6 zsDQvQ{=DD)-Me?8b}g`XzI8QgQ{hD)bJL@JJOQIT*X%XRd@T+1p3}_2;ctB0d}|(9 zK}|3aF2bdZD_}tH7Y5cFAht0ARB+O38#2Hnj{@Nl`~jJ6Mt@Y78MKt%^&aehSdKu& z#?~B);5^Pz148e{m~^}lQermUR$%omhdp{z2!A02hZj7f1UR$4xMEye>E@& z9ddqU=HTGyS_|be>vxMI$H!l(Qflo8E3feyp2}}h^ps%qaiql zmZ2#`z8FP}B>gg)qUO3J6$cdy3+8%%LPr}6`w2v|R6ih- z5{Jn2IKEg5O^=M%n$|mL95Ugtu5opJ{StT!QLtaM280o-{9005`pGG$`V@@$sIW&C zUtIY45srpl8F^L)i=mJSWK2vr(4gOTDat5k|42EAS z4b(?X-yq)#A0#2D{nnp7Y^F*Po6*?E!NinY4U8x^oyH&a2DukkE8|AJX*9PI<*O-8yli*A&$zf z>^hdAYDv1#+&!_z=_-u1AF9>R1~6utaFb6HW?{QF``8&R(;{kpYWcwW^cROq5Zu1r@IrSeowAXF}?-u z4c8wCes7SNb(v~*YUtzR-W(K9U+_|Ro3)iMNa?p*5+WwsLkm|vzbiW~?x$E~1t~Ej z6?$(!@6P<`aLTTC3Fc(ni=#*kOJvI$_VKp-*A~3BWier+jYIyZ9SI~Dxu2lt4KXZ+ ztrw}YBm1c@_`Nnh*PqSQ+c4|Y*hTOTXg0W#zI4bt9(LnUd#tHgG!b4QXx1dc!sr-a zZwfyr|Eu@ITyjt}H#Gk2T7~8wr=JrNc>#8T_fCIl=^<{v$A8pkDU?2%Hvff4O37pz z0qWiPM!jCh86=KP*v&w~Hd)0}Z_3c8jf2p;42*p>H|PYhDt>D_I9?&R5K zj8w}*=;LP?w_f^7m_a43yTs|r546Q%`e0|B=fsUr2OCXRgKwpFl`=xg2S@lapuT;y zBdCcDb~W;HUAI=>LJ_|RbMxd{qUO)p9fKD$!ACP@N9=J?O>2zz>S-x7;UQ$IMJdG= zmQgeRn9AWKLCXJ-1h_9>#P>>sIo|Pq^=4}OZDf;!A;g(2ukFom4V~$gRA<)2J-$rM z+pRgsg>44-)8^+6#zp;E^lo&+1+)%afDd$Uh(Lv&e`jy|U!3G|y5WGIDYV4n%j@!A z0>4-UXk-baQndQsS4gVhA&5O)CdDH>;uaEsb!pF1zO4tz;7N9WFusXW~{8auRC&H*JlnChl zGql_r%hUfdnCH~!0i1{kFDV)nX98uuNoO$L3fu-~4p`VykMo`N^Ql49!SiVDk4j~y zf&TuClR*9{1(b~3d$I0pZ+8nzwk=oBQeH3H2y9&cnNJ#Ita!yi^Gbexj;X25bt9I~ z*x1;5Ja-c*ZmrYwtw`cPmquyeOQVsi$*6P=wrX?nh;~UXiDYV`>J0qE4aFZJt>N=6 zhuvLoiSc5&86bh{%x3mddd)Sl86UA=#vspIC^yH=23A0{%gVN z!zkN_`Lz8aB=fo8man-3iCGd2*tXZq=O#xQH!68Y%H$Ol_e~pi*F{;(8X7NC1UP&# z=w2elt`IxZOMMovWeB9GVG5`dpR~Zc*napf)gDt?*;V%Ei3BN4-tFP8qtUzRdXn08 z5AJORsr$yRr^L#4@eiH%li{CZFfI8WD6v8<=4&+r$~;T`wpzmxl9_xYOmIa`xZIm9 ze*7|4xnazT1`=Oycc0X<}7AnCneshk{YUVPlUJm@`0^=m89I@s}mdg6E-4 z_zMB~GsAPqWE2EmQSp|JO_}yZ`g96{?&l(poEb8c2MMj=b*Gy~gD56ZtW=O^w#J_C zV1t$<*e`^FpTBWsbaCqG&RQPF>f#{wcDf`1=>ljIR@ylEHZG?it(61(LVXyRMM8kG zYX!I=`GJQ(^R5=(YO+M*9|_Q(No^kJfquX;#yDvDu?UTmZ;Au!d0%)X8Mj@2NiXe7>(W8dXZPMfC7gINFxS%f_YS}C4SV}xKem&$Ap0MT7x z1U->Pmj`-Rwhx{uP?(b3<7!d7o7EIK$tf%y-ALGLGmIYr5zI#`X9C}jf>9@m^vFS# zt^|NX;L48PUfH=i50p2qd#yPk21Xq>&hlw+Mex=G%fGuugxrCI_+8V7S9BNfmgXCCy*R)I#uEzcRldghndKe3^d0*wZ2$IT(X&dytYj|-M+ z>jnQ}tvzL@I@iM&fmrU(7unG%Iv3!vbX8i9b! z^5FgQiz_g9fKPhB4zE?F#j!Dn)a+V+oA?X1C~{ZsQM12jg;Ft^6fmdDM1 zi`CL*q!6XAw5QK!?Y2g9W9b-a_-T=zHwcC8@P4A^5=4ii^8Z+WaN1q441|!0h=>%Z zm5GRVv;%L8KZRHum^G!}y#uT_zWwIV^SN5@=YRv%kgimPWiW(U8vmhRoZu?ZuZ+}A zE!c&g_O4fN*N2r_yLs1bWQslK;(h=5!;V3M%zpoHALfxe2RmGHE(GE4mqWp>z~8XY ztT%L@Xl&z=Rs z&9}XHbfj`tH_ledBUZOwSnLR{sbaV$o{qcDTdl9o*K25fj;j|)TG2I?+lU8|LGf{_&%SnBdP{kJD znpY8`KRU9_^j&q8{T@-}RpH(IMKKV^>?dIGW#PSJdcl|b=WAoF!qHd^Th`Q3>el`5Y&bZ%S&h~oz+n-s=gmT0bnkUW% z1_na2*YD4~mg&?P4aCsCz^|!|!SpcYhud-+9|*+r^#ymO#SF#YVhx77b29MLdjixp zCtMV=}}ZaB_wY+fdSu9Xts{|&eQ9!!yhO&6(7n3~CWQwXXpekfDrYmoV?d0+KKH&#jlNeLiw643%*>3_M57s- zhVTb_+M%?+w}wEy$8nRbJW?ftlgdujZ4Tzj1eTi@hmGfyDZjqMCQIK(fQv9&w9WSh z>(nE4NNwY31S?OSrZE?Z_?oL9m^4=cUd&6qllIF`Yo9_Rh;A`NAo*Q)w0$+2eP!Qi zKloi>+&G9c(2fBX5ecQtzqG>N%0UVjE$up3XbSr{3pEjN$Tj;>O>+5H(myC@;5gsX zVzH1Qu=)Dg7m?YgKVJVN-iC*ifkSZHX;X~SBU$yuVX&zb@)!DqFHe&5)SIr=F`5%h z`?;$qZsbajOi7b#6D%Q$g_OnV)Dz#XBtDXv(MhIlr>kbPHLx0hWB!P-Rpna1J}RE7 z4I9$=YAISM!q>Bq16F6hBpOr4&V^2Z#2)KPd?(%8O}scFv2I2iKh(gCt z>B(&lAX@=cWNPTbE>j6Jg@KP5IEiKJ2jnou-lRb?K-iG{tu8-vCYU-s|%o~g`C?$=n)mX3r z^mm1kXH_kGn#l^AUms<%MO2lF>s{{2keeQM5I3P#2P{&A(@j=zwV5Cp_LU)GdwTkI!D!oGJcelYci`h2cx;kyf{9CjP>UrI_W4teXX1^p|UR@A2K zw&cF<^j#lWeMHBQTGUV8hgVgEdm5MF6-hH^-fU*GMJSFV_6QGE>m;!kWto|6nu5fi zxq#)v6UF$JC6=N@REq6JDQ7~3(C6-gO&BES#@c~-czDIf?6DOxcu_Br5js60t*Dy~ zDo~I4{^~XU;I#}LS;F<1r8kp(r0PGI(trM&0_+SOAe2@EL1_2~`r~`2O~dmUUKjJx z92JwjdmEeuuTwqYt3e>Qq?Y3F*kK8OwAS6(bsqugam|W%+1c4D$04Cp)!rBh>^BG? zjOpu!I5XeSc z1~X#y)bZ)*-|@fz8WtW*Jn&bW?j6*f&W46Ae$f1)=n7UlttV=an}^0UwRArmzQmHM zeN;ds{;Iaj#r@;;PU?)3l3d$f-ESg~0j^U>Q@a$6POh!@a#5|D$17sIK6vOm!BY&PcGs{3I#0AA5m*r(xF@Unw4Beo`^#&R(rp!LmnC2I z2^9^CCXD=j5<>(zPX7^*yJzJN9M55}_h(?P#6*^{&j^iU@ABD6g!H`lJq0L|wiC*P z=!$*Rfrmq;+9y7OH$0?+88hXYQ&q)UU6w?wIyG(WW*~z?6oFGKl!`)8qK#VW=)7k9 z=piWE+6z#tOzx3y4S3X^pE~d!4;=HG-OQR6R}UL@&$*-W+5I%W!Y3dP3mEVgojzHQ z?^%S^KxSdrPd$ecmvL`kW-Xje#GPbfje31M@{m_pyvT$`;fMPziJ^*4t0YK7u4!pIE6{*imdF`Ci;N{HlXg!eH$!R%8 z+cg9XxHf)FjZCvZ;j`Ws*$lMF?ZB-&wzmq_fVf@2Lr&*;j3BVVw^fki*2RPiUNfLs z`Q1-w^Ax`O0?}s{Faq4zW|JNXbw$=ZN8tM5=>_T+2snTO8{{amx6YhRmVUe)%2=o-H}NQ1w3dMs99)w zMZ=mwF*b|6@J|m&R^xZ!$v}lEVC8*v`awYfGmXckUold-?=m(jE($4udVFSc)t5$3 zUL282{X4ope{!)N3p29bc1KkbgvWvn3sC4pa{uh6Al+0-?GT@CA&6h!7!MYs=1=}m z!hf4V0MRu%Y;KaRP4rRx@H(uKHMvF|X^BiLjr0lEL0BD>JM(Orn&W}8Uu&bzVO6^R zYW8oP<6DA9m8;^1A{(lB7s+2aHNIaJ&c?8&Ub)`BqE=z)2#N<)k70YL`g}hdr;ta<0shk24?Tz#pM%o z0Ugci7OlJMDXttlV;mESvl6S0YumqE!M@0nBLu9qmBVbf9jZ(t{(1)tsj%zP12P*L z3|IPtFarKyoE&4!8#4V@dIUxfUk@4waCbJ@q_2Khi3+l<2kCxBoqoNRnz@+hl>YPM zJhnTHSnxkAG3fSd@xxZBZ`4qeP*z)yo1di5Y*S~PpB(y=ZHo1qw*P!+lmbs3gwu5m z0j%oRNsmS#tZ`U$i)-$<1w>OJ{)Xpx;mu?1rE|2sfNpuIV(`mNZWz!VrQlCe>|u+&YfT{>)C4c8uK4dbQ~NzKb`96ggg^!zF;~J4n>KINF3F0AN|puYZ4>Ojs+55E3L9u z*P)4wU%xwTy!=ot8g;;4-*hy;q@L|!6HazoZfvrj{P$|{E21OW>-CR;IQIsm!Ot5W zM6X#3_W{nX4Y-@ke68K*a7<4xj#rx1-ZDa7JA~iv&WX2} zh(C*Pq#N@X&1uuYfN%16yOw>z8Ed)c6omM%gq1Z{$2~48KSZj>=KWlEdyG|P9dOD` zBPnk?>`mEt{FG(D?Ojs(nuTuq>6eis^#_AxoLFJsTP3TI>aypLgV$D308yww|28)B z)sF?~UKLxEEv@k`CLx!~fG5ceZ@2Zsos0M*7a2Z@PnJLjWd$Gh3p%8ar>?hqJNq8C z>Gx_5e-Jm9tP$RC^<@Wm-``{c<+~fm9;K{i{=bnF`zUjvg4S>VWbI~2BLXq8mP`NT zzjTzB9K*6Ab}p)uJXq(u1M^Z^W%?x(QszrW$mU6-AjTA4m9TOHrdfUvA6jJAU^NRU z*H@E3A*>J!<+EE*SJH?0fE2i?Jg<@STDN246n+PB-4@{HzXIrq8rD1cUAY(U@kS)Q zqdYP)j=2}e!^Xm@VFdMd;r-xmHKV|XUq&L+`Cn~HB(i5<#}~v z1d?!OB|aS*mHM$aU$yTxf=)iwQc88hZXjQ2V%yA3)K@Kqf^>y-_1r-S>mxuVw=0%y zU?7>n2VeahBonNZwLF{@h5P#>f!+z(IzAxMUtfdRc^QYlJU;LO-hGKz`3lB#(Zf$m z7gV2c<@hSM?p5i6pJtGU;(I_f<;@Cl~IPOZg zdF6ip#roQe8DLI`qKm9rNM4Kx&*q-RQuC<65;&P8B_*m1F;UTD8a}2AyRzxs?LQGW zomRKcJ>g6L_p(!gOisBXr`td%yH63|?vkvrGwI0KZXK}BhQsWgST0;FhzQ9&g2>I< z>gQ9a>jA~X>BWcYyPCtPuYQkj7{Pl}h~XKYTF%|xGPs(nlIi(0peOu2che`>!sE5G zc})w0>BW_@)op&a0TL9ooQ9bEM8q1&fP>UO6OCc*@WEIJ-zc3LGBM~Yiq(m^Jk;yt z%!X`A6@*H~d4Tqnql`gBSq;1UQT!h9*t2jajhrpDAU)q-rTHhu3k7kr(YrW2ch<*s zW9yei=4%4m|A(xz0IItEw>=>Z0wO8hARVG~2}qYpN_PoJ$EF(r>F!oa>FyQ;1f;vW zW3#!>{-1m1oICfOabCyKEo}GiiS=FUv&5qeuuiL*%K4+btVJ33F!P8chKyhPu045W zJC}13fgU5?UHk%bIcVP;v4PP`Tve4zhtJMlS7p*dMZhLOW3%0G6-lqjd(gOCseGE` zc1e!r;3DY}5&}hQl&fk-+7z+4U{w0K`S>O9b%VDz8+6m6XbQNY%1l`_D>VP9L)Qu; zTP-1sbIVV2X>zrMA^5ai-89dCM6n2$h>;;sC1Xt%E6SFBE3~!q<+Y1g70N~rHo@~J z>Z{e|Dw@ONA1OA~xJOhlFN80EaU~=qgm%PPfHc(#76lGvQ;WZ!i!_#*bd$%Ya zzh*lGx%H=|-dr64rvqBVSw=3`{>gvX7-^mZZe2Ox0Am@3{i(tpT zJ-~~IT#4OIN#=>zxfxt-T`|E2-`HpZc2K0=v7tJ_DGn{r`0VL z+&Wb$287YS7g3dO`QBua1`cmZUT3x19+JPVGQb$hDVF+k3C1a2pSLco7#!laM)4^q zl=?z996rG`OEfVO6>Tox4=1l*{m`AhO=@pWCC~P>;V${0WM{dsX7WB8cfc!oHqUkH zJ)whW(SpD=hqY|rKaNqlK#juUJ@2)z?F1RC9i7W)%7#Ff)y6nONr5zegB*DL!Xtkc zVEi^R4`7{`)mmPIoBmam{+;ex{rWZ{0wLDMGa;lmpAirmC4V%deulcNmd#r{YPzpw zyqsz(A8AJccW*ej3^2SBGAStjM~{XNCH>IwQ%=DIaSb3QiD!Vgo&wnLK+c^!P%+Pb z9=qf;kyZ)UVw^!n1+1Ifi9Qae)W`}GfqQ@7pU#4#>ZHCafYUs$J_k7=cu2p}=N62c z93Spn94UZ>7Eo9IfyMM;1!x`FPK&_UQF(BVfa35l6w!eVfi(JKn6NG8xgmhOD-*E) zBOt)N{h+ud3Q)Gfw!u$Ybp7uF#buCrJ+F_V!2sX!Vd!P$EGm;n7l@FuA?mT~)=2|# zqu~?ar-5$TbWJ-3K$W>USsfB_c>U-09Qg8*fWyiJ`|+W&DZQfD3Ep7_2s>f>Kr~qe z6~)y)xQ#E5=N;O6K>~LF70!=J06s3*57KqGmjaChf69}e55jd2fQW;~Rz&7h6cypd zMtGOGVyoVm)ler%s?<3FF4?s4;q7KS_$H)QkP4*db9I_G_qX?}%^u6zu77>^7wgB%>})cGAir&3AWnAU zy|B%EF8xL^o%?UnAe<5u+Y| z)wMIhgku9xKb?$~4QP}iG5p}zTlcr#*udsF3Q}UEZwxuoKs6$v4DY%rCEpUqUK82a zr7*p=5l_IC!!N3t=QSZwE#g4(;k_=n8}K`D7p5iNU?Is6i!x8RM3tf_{cKL(N<(7S zQpd+1jh*vna@Wi`o3H{@I|FwqwQh&6xy9nr)CuCul6$;v#qBqeSR@9xSql@x~N8Y zur)qTo^9?v)xsv9sx89FWm7hP4H=k$BGV9(_+M-O4R7gNXCe7auBnQTDudt(?PI(2 z3%@FgrARZ^Qzn@4uC^ubZ9RV$;zpEA=l024EIg#%*mZiB~9OA1;*2bwGUlB zP>)qigdAi4+0cXNKv|q#6WRsQc@Jm?e0_y_jy&L|GB~|$^0{&lPvtS=vK*&|_h*1B zy65cC|6XQ0{Aa2NmWn=pA0z1o*RfO31IBv24A8<;W$%Y=URa$nl&gF_d1U}_=W0cY zq>duM$M-g99|sT`P5)gkWm2V5#5w^m`uzRT=bdqyUUS>;m&dkCN%}xN-Fy-NCp`km zx2}`Y{JTyqCYASzzdF1tWT6N${?Osg1BVQ1)cU}Ag`hpk>g?sqJ{%lj1V8pyVn@hL z%vazTO=%Y#6qIA3!t#2q(U}S037?1)y8v3R(0d3E0V&Q1Fgpv0-XHKf`W(*j!*T5p z*sVpG2PZ&Cg4t#sKq4m@e)aQ1z@`w?Y@7jnDS(OT{?Q5_Odrk@1OBl3kym#(>KNEC zR7huB-LDtj{$qvtWbOP1Y#fPBaH{u zew}~cwm<;La;AcU<5P>J4ITT#YP^c51b}b$UM{tIse#h9?*Lx^>H)j}NGthlY9@kI z5WLOpy5TfQ|3qG0lJ?sX6M-WQ;gn@go=I@zGq#TB)z5G2M7a4Gj#vcg&b-LjS*Sax zRC+}iDz-VH%HIXZ1Z)+t(|p|~f!W$7A_w%O)|qTqWUe_znzQG~eJ+SR%gRm2ow`-N z)x+5M3Q<(#*u%NQCHDj3t|anjIvDB}r=FkArA@w4sKw`_g*UpeUwYh>VP#(}y-^@; zK3`KCO1kLBputUF?=8Bsxm|E}oEmuwAKt5IY~$`oaEq}U1otb5RA}j(uFEHQR(yavxcv2)+C+UG@FXT47EMGySGW zR&ptm-T*Z=%lzbGp0V&~p8%Lo8q1qOzlCtk2N)R)+!XeW;fZn5;}-w77l4dKnv~25 zbxXW{O@)?MP0Rt~#&QBz2zIw2jv+DC>`sMgR7Lic_5jaOj80}G&o0_Kq>8ha^vr;z z%$$WKMYO-^>E2XZ{t1pS8ZHOdQcRZ^?U_Bv_47R1e6}l4mc;D_)8kH1Ux$Fv!@+E0 zxAAr(WvgnHxc`@Px8~e}xDTX{yDMWps>n|YC~(A6C(eY}d*kwDTWujtqTK%Pmd?K5 zeELX6O6ByO3jsvHWWfQKZ410^wehAr4J(m}X1pYX16rR=_XeW1pRD31O`>ueIIm(i zIx0T5oCOKJqF~$a0$y4G6~UPx<`FBuWOJK)JZeTsn%teMw}~PD=N#)AkfBT3{f#P# z7PR9HPFC0nJ!jKowu7c#lmqEFqIFbP;DyyjhSIja`A^X`nE&}l$^q`O)QO2(r6@EZ zu2hw__8Z=igalJI{T8i3(25Y~k8HpM-P}*U%fX)^mFCUW9{zwH6RVTp<8@67>%(E_ zkc#45%^tN`f|426P(`j_7GaH2aju&SQ@uHegIF)#6(-;3PQ)i_Y^x9<@sMZv zyALFHkEu}G-$uWYYd-Of5p12>aVXF^zd>f#pnH=uop~A_Lou3>RB?)~!V4MG)dOqi zidq0c%4&zihXC$s^t@s-W=QOplbFsU0^-<=yn5T-0Qe!9u<%^E*{AOM;;mj-duH&G zuwF(JS-@MUY_)nC-RGp!IQ+UT0P9fjC18r7tw&CKO2)IK5Lx%aki&ZuBk%3g+ zVy6dCR0)Du5_)h24wNjxneL#^E4{20{E5iZYOibigZbj)qGezu*%(S3)|gh5^+e8O zZu+tt01tcZgHQ2lI8#;!XklV2eznl*MGOj~;KeJdAfo~=5s_0?t`o5`>hMEk)~+dN zP?nPu2b`=hd#EOZdJCxD6)2FaRg+!h1?U=@&NGMKkAp(~?f{pFa-*4UGBX{zz*}V7U6H z;2i-dU?GDyvH^T%H0W7G1~w}AUXkb_!o`IL60Z0{hfRV1iZ|{7G*Q|A-6nQ!1@Dwu zonFaKSU8%DXQ@!aD@z>~CxT7VvA6uBZ}}W16bp2!tx*v4JElvFq|kebYV8sTSE&3@ zFJB-a0C#(+lCG&wt@R)E1eS+{A#wfrLLp->r{GVi_O~294P_Dl z+rx=%OvP-qGa3NDHy>H(!t7Pr#!c1CVQjtTPie^uN#0F+SVKvzI17EyAwPPVhbl`QbG93r!y^nLAwc2#h$S1SrDg6XOwZdsf$_33kPgc43zuFb3WBy5l)S{Ee=Daw{qETSFIx z6ASD6cux)G3p|2s>@d|CbMq8Ny%#Y2Rea0EyhMiWDN>EM9(%jw7Z=!!H!9h@lg9bm zKNnFTFoUviop#4e29-*Ck%`|1@$2;;a9rZQg28FzDYdys#TZgTHEo|*w(L8drR|OV zKKiNY4Yrpf+Oy%t(v+R?+f#hd)BEEF`@5&=<*pRZS@puA=(L|@Hj~tknYP*>0K24G zp*6n|Cs1(!wDbK^=^mN*QzjW(78{)<(LOtFXp|Rs<3a!VqL7=&S#q#8P*TEXP}^7e zA)5>;ckMzzYL?Qr9PmYDURQcvvD+!j2%sFSkaoP(Fq~mG1{>=RhI=u-HcIZJKi7Fe zqJPWdU82eFjX4-Z(SPK{;3C-u+#D}7v2VRmZ+1H3wbgGl7CGdj=ac@;Fm(6s_v)7i z0%K>SGZ5YwunrGIwVP;O5HcrA_EwU1o~-_n+LzKY_G92|>L;hPfSO?CKi(|mJGyP} zc#&@r_nTiKJb~(EKt-n1zbVS<0jJAUjO1YkBC#koU-etegB6Fc%>J>6u|)XLjxk{{ zoj^_EpX2Q`#qiJPeOwOrh}dD}w(;lLp^fvn4L(V{^l0*ZI&KNK^)%p_2L>itAj*z6 zI$HpU)u~bQ#{aeE{g+3tl$Oq)6ihL1fX>PV%m?5QEA=m0ZIZ9$ddUlJq~O^Y%O_8X z)5!vmK6n!qTopz{*dEK4jV9ygG9ADJr`;LaFOOj32qsBIqn^d6WTp~ETMP&gV5v-Xd`ptE- z?;!AwChZz}U>%PDG7KFcEjD;vbAW2Aa8h1#t$l|P|(7rXIgoT<@KSt*_HaV7ZA5Ok*? zTu`trdu&s{-!%}g<^+UR$J4d9dM)mMXfglrjb0Vt16M4Y&M$Ou0MkHv23Q;cU_*sB z^8&mgAikHS1pYJ|4gq|84UCBMkV()L!>-JM=tl+G1L1uy>ILW^I1~pW)&K+?0XqQR zf%+v+EHH>|+X-Asm;~=Fuve0RNo9Yg(A~2B7+9HAL~s8?zwK{%{jIqNl|m8TjpR{fx>YHT4Eil$t7wuK86~{2zbnH?0Kz zp;{UGTQ1+)yBzhg0t@t$4}{76C03KQZqzLA-A7FuT5joQbzu6}_vF*r%)vz3?fhko zqBR6Y^&s$J3~F^B8WLi>^!<%igC)(9=QRcS8&By|Zm@8GEmi}GYa}cpswZ|PBxmfL zbC32_UP+puNts--h?lGIWYG`mclvzX1>Bq&s5Ma=yu~3>y4b(fU#I z)UOZXIltUR#itdJb%8)j{`dG?^arZYKn^S5y=*Llo;nnp}(py8; z$oo9}X5)|UC7Y)cm?6?Dsa=Fz*C!74>0IoVvBeGQPkEt?+hiU6!b~iZ#;hd#XOr7$ zMFuwNuZNL!4GT71@-b-2Hn25(qwBHozbmJkiLmDb7e275{d-K!N+R_zbzApQcN*uz zp_s4j?-?XucfCGX3>1UiPykHV+sWUDD+ zBH{(vpwRgn1fy(7ogD=B&tB5Fhe@3i6LOakc@!<7QK_si{Z?kR=H2HOn`@5Lq$r4w zA^xK+(>tYwq)XFZ_&%G)a^U#%a<&D%mqq>DnTu`e=OcpEW0US}mFqw;d=EfyX zO%dI(eb$EsI^VZJ!vumOCq3C#7a~9M%*v-h$A#w2Id|u6q$ur8y7fZz>39_vz@U_2 zVHoMvn_K((ahnk!U{;5R@`#a=zFRJI_LohWo>(CLcmADOEwA7kQ677$4sKde!O!)C zl$4SSg1z_*7~jSKzUko0SB5zzGd)t!VG_`WYF3R;PR>@oDEN}OoJng>Izy`HP9aNS z{4$dTPf5Gn>ecnmoxF+()m&k?Yy8zFTj7YeF>8XqqbpPcVRr2Gf9%%(CG-TV<{Ms) zv9Pchb04l`2QMq{h!KULqUOl`dY~dAhkC6}@J;!AM`)Y(7{9tr-uIPiM@?LyVz|eZ zPzUF8``OJa552(v`}U~E`Eh`@g_9P?M6Suf+Pixd+5R7A_kUZwg;}exMo2(wP+tC_ zij1P1TnA8$9q%rz;OG6CpJE6bfX4?wEuCOR%QT17NE&8o-?j|$8uy^3A!(}{{MIdT4kx+Ncj#tXb`4R!S@r%ibvd8jW8 z1BC`$W5J?mIjH;7TuB&I(Wb5er}<_zu)l%ULdhp(@FTtf^qrz}5jT`+*t_QRJ@UIQ5>!n4w zI5=;?-G$3`maC_)Y1y#U{d5fuAL9n}-Fho{`$xVkE|{neTzPojf%ar<5H|B;0WoHP zQtJid+=Zf1@CKtkB@csNBxq=8O6O1y`q*-YK4QP6B(5aYA-J#RxPJek#E~7hfJ6hG z8i%kzk(1C*l0^2e3mG0hkw5T`tR@>k2;cs){i9wGFDV?)iEVlDg%0>P<E6FJH#tx0rp5x1!R1wT(ewzZOgt$coty&9lrtzf6%`3!^bY`>DC zrd;5Cm-RTxrgTrK#D~~9LQ)4E7R>EKsh*3pQg5yhU2y8Tf4i*P@cxJ1d$G5HYNSOM zainJ2J~KWe6zMPCh% zqqYa*(V!1wB?R=XH`0Nu3pkFjg_Ov_!o9#yC{IqH_Xi}A6(bm`@%e_@eBVgu2*Zf5 z%4|p1a>^q~wSyb&F3aRHqdTQU_O(dhj7NIT&g`sK(_R2}R}S5`d*wiq?|4!f7mT7c zqs2&r+KQ+e10S0OCx^Y$MlF6i?4`ve(~EpNCW^Hu$MK;^!E3WnN+m|Wl`@UaFbp#_@hjbK|n}}sO zJ~`jFm?ZZ998Z^}0)>NbK)qWy2+}k@_|Jd^xKM}K%P6L3=3juKN)M1%ExJ(&2D z+~1gsyJHRmFh7k2XIXgjE3kvq2yc^*Sk6|_fKS5lRX^`CQZU?*8xOu_%wI!tH4+IxZHk`4D?8Jfoi%K@MGDg zy=JX|6r3j%)A%p|k`k|ZS>pzPY=FiN`lN_K95%U31ffK?o&%6psF57t=li3auqgP+ z9ISyvGx+#NZqJl(z(5(UtHJB4;9oQV_EuBKf}KuQPmesy>*x)**oeGueqa8f7aYmI z0w$LcsDf|s);@Yl4lbfV{sOI#DBz9(=IdSHb>Y{sCn&qkCTVUawNe1I3@O5Ht&iltHF)3hfN^&mC@lxA@`!MS2z(QO zShlc5B?6B+yjD56yzGtSYzqVL5?rdf0sZifYdshsCxz14**O3>FYx;oDDt8KG@DQJ zO3I2|->rC~#i{f+;H2}@)bflQj?pG}*|BD`Zbo`0((@wJpx_`38k#=@n5)D=Inkt& z3f&kczhk?&nz}^@a0^5g$68ERjY~*3c^wB!^cO?*8jU|&j!Bdys*RvSN~suOHW0o1 zjY5~raLB0jU&osjgB!aU4j{?CprPp;NEQ%t>g_4%dMyAgR?J|V59vaNC^@eVkM%3O z{k9@iQ}gQ-tr|CfbOicBY!N;B#VhrjNj_3LkVs0O&u(7ZJ`N=s)y;YPlL+X4eSg;b zPi9uzf#D+tD4<~5ATi2a4T~NPe%33$vu4D~TEA-0uB>1CVC7@3{&;vfVV=N-flcyVvHYkW@i9k{=y18O-R}K9&&I`p_3#P91S0n|hTAF@0$@eCO zrB7Zl^N8+$8X78nfoicCgu|79Jr*o;t6wV2aAq z8y8sh{z5ppsK9(Yp@BFno4adS&f)1l^=4F@8|p{a_oF#AIjaT} zZ9*`XAzrZZ3YUFG;w67QARpGtb{iOJg}A?x?XQb*eY)-OfXkrr`~-$ZhxW+9_wpk) z{u?C6%eqT63j~sy6$|*UON=AZ@-ZOguq=|ZO||g19CM{lpue5j^bmY(={bqwquyS3Se{@e912ug> zOE?iU0F6s&HodMd*?=b2RjDv*4E4xgVNY9X~VhT-!6pb zDK92COv5|!fagK^BaA8An@4K%9-v;p+wbV;NLtgat{(eEjFc^y=G7~KgXfZIw~}h< z$TSi(k_1-Mn7i3H)wF{On{*KgL3^x??0K;oPu4=x)E3qy4T|KQ8fxA*y@eKg@TKbA z{Vt%gzrlKHwQ&r}vdZ3@4@9%H!aLnX-(qH})sRU(tnOl?nNN*rC|)LVb49a|H&&j}KhLK@WFZj^pBj3aAldFL;cM+(DqhmIXX-~9}#X*BE9w8~iw&%Z(J)@hfh3#MIrOkmd8g_<~=5 zJ9zW)0R38+vjh1280X_o`Ta5!ZhT1H_kNQO+=k3Bv8Uf$OBW6e0JnGK#&PU$G6y_j zk4H*acvfFpsX)wWe7KjLkVp0MJtjC@CH<}VUVD=!^Mfahk8BXlk^Lj&EcHV6r=79( zIrJx4htbp7m6x22us^oLn{FkLve2`sr@$*Ca>)Q+etG_D`IVeKr0yUVdkWKj{rRfq z^T80LN~e5DPvZ!{C}_aw(P=Gh52J>~j;yS52ke9*7!&_0~vke7q?U(v6V2$C{zeQ-RU;+bH zFb*^U(5lxycfV#wMP9uk0_)#f5KwKY0oHPZ!r@R5Sn}*66ME^!L;) zVZgRk4`3J0m5ZZgR`0ow<^rSNFrcbB5?p-daan%~Do-~+y&X_+hWXN6(J?Si?^;)=o#Qf6qBf*O&{fN%3yf95d<&3N z3GMN5VrZp#pA9a4OMT0hhh8x%;6XF=^;Yv6?IcexpGI)v^Mq_#twcQ(g7}-k)#DSl z8?Tk)XuJdb?XkD^=5cLVeR%DuK?myCa@Ty*cJCaS2|_(nRK{|yO=E-j#iay?6A56Lq#zDNHN(yb` zE2{77QYm3|E4L|HxC5{9B#_81I4pm$PO3yhUG6z=tPaV(>(>(rLFQRrQOLa{aqHb^ z*1vBS=m=#Xu(Nx!+D%ev+(hl{QI)PlbF`#{=lld0JNI_c0oGyq&vfqRS^R^zQu&>I zFynr3eLEWL_H65|-UI5*ANnwu>lUB)MJEYqZ1?=~$}5vP{;*QnnXE1~(pbbe1CuJ- zE(8RSY#|3lo6f@nx;v5&&rh_~mlY*4_Yt)F@7RShi8LlV?(7W_NJJO{A7!2AU-T+O z`WMhix-^RyRxCDmCp%zv8vH4HGhBO{_3TN9AK+ACQb|*!1iWw;Ekg9VKIq(|`e^jf zlwEDNPqZG?deKb*;ht6kSDBzKr&1_?*cmROwGS{cCMX7f+LmyL}7e=)iVSFi4-#Jo5mpoffkYr*=Xlj-~ z+l3U+q~eQ5@phRZWb|iSv7JdPS#1w!B|h3w7D_jjGc1?-S-yyqm~wQ;orZMNnp+yY zBc(gMsLwWXHGe2FJaAQZ^~`6^qBOn~F{I75fB}q#Z*dpsZ8)pL;r3JPad&@ypcx z^KxRY9062DrAuAAH~d0C5tl0MP03U--HEDt$yhY&5gi?l&YtuHSDKKzmo{ zPB=1J4C)38Da%>WxFeT99<#YRCV>a0N@ZBW4F+PY6`x!j(;xgnrKNDZ`KtV|icuKJ zTTCQ9?2)jS(o+Qn3Qm0GQ~U28C3as!DPT__^-zuO{NDz07h!T#8(BP5PI26ggVKn2 zzV8V1WGqZKi)Fb;e^Dd9WLBXao*YpbK_pjfba)E&W5JQbL?PoUkVLlql-kx2rM}vT z7cZi9$jS)oGsMR!?7T@%-P7T{3t@D-Cysfp*2Fqq%*4!`=k-nI__yNg(zvstu~Z}c zN+M=egtu7d;^srjW~@fZGE2>_4}yU3V>Va|a$ybbyWf2Ga$dkXJ0-%}Nh>#+J@%9A zh3KG*{#Y)9vpI_fk8FVjz-X{O98SOmP{70QFn5E^kJKpVmPK%!be>QnZTpt}Rm81lqooj^G9!2=nfkI)Z{Pdikk?Guqr2UrJ_|5> z{yCekcdt@)jLnSEGoae{EO)G#DI{Fno^N(*;7qmOa>@TCxpqzGNO-CHlt7fqq3lI8 zLF{#JZRau{EMA{XD*_v7jW_Eo>y@o#ktSa>xs>T|Q>PDRX(6V`!)xVRbxNl1G^03t zW;pX`f9T{1gtP`DpG(Nq&1vzR@89HJh%xzf#e;;8HPPo@BVT@` zPNXhxOmp`vhm<*}PB^Lj=p^F_QEGXwBwFxW48;!@JOwAr-54XESEwU%57;_VC=*sk z4XVhYKdK(TQ>Lu0PpAs_-7h|nL+|kj6DW>|6ap6acSiGZgt6aanNbh zQ!`3(8~DINL*A`BEu-an?0NLt%BxrA^6kv`0G>!Mf*2Z z)-A6yHyLra_Jg^+Cmprq`j{!D?_H3S4vJ-L&;bGT7h*F4rb;K_5HD&ks>-lWl1olj zOHS5~(HcsQQQNl?yhP$=P6dg=`jX^gEmo*Uxg5;%oO`!YM%e>FJb2t#)`27FW7QeIJpDl*9XBojTiPtJ8M2q~;b*@2-_cmhF z-Add5?$7T_iWrYoO<>gqpsiJO;135^&ZDK~(9+3boe3TdArEVaTbHq?Q(%g3%3y^W znFCYW_SxTIqI4JxhW;D>iQf|wOV#=8k!;48fs4XqmMwnsS)M(u8wKdbIR=~0NYB3< zdgysayGOiv73rfS9c@NLpGhRNLGM-DH|s+}n@2&P=9)`Ckd->(}2_ zr`IE?lcXz^gFHFEnHDU3j((((rfu=|ldSqzs*Y0sF7vB%w5vS$YGHGQtdzaYT0F(|2LTlWQ8#+#X7ZYMb+_yORY zm~UFD4#tm?mRcl|-ICx+h$s4ZK`?)jbu;P45j?y(Bn&J+tN~Gw%`~C?;35?f!oW)H z8z{or2rAhi?pc;P)(XX9G=|de@GmVdX3~mE{i$RSLWLj)NP_NMA&Omi&xk^NE3vz( zIxATiLC}fiL**U**!6B8Q~7&YElcK#Pt6h0`!nnN7zS$_z>0fk`>)1mZ{#1iNTcAi z)$gKg4Bf)Ko=P!TqKgL>{dRi{^Fc0~s=!5`19)A09F_!P zI;n}~dSTY4OlfkXRmF~-u`=g>cuM?6<@)ufN|aa;Hg`$cKiw+6cZ`VDy^(O|{zPoP zOb)ib(Dr($NLK=*#_i;t0H#TggKxG5lHxrzf&5knTG61_9lyrJ>DY?L6QKbc)Mw(k z+F6r2n@R4=MnyH250i$^_;DNrd{wTHMYs2hT}fQtPJ9-sOe_zzm?>-i;1zi15#h0+ z((He-xMMK_{de+q-JfhB$%iTg-(7_5roUW38ryYYYOk1ZGTJ|Xx~RA~ zt4GtA??Ha#WQ^*!acE(jUU&|Mq$L{VuK=FVzou|F&o;G&S+gpqs`v1Cv3}+im(=<~ zixtF8QBK^SkyXJ-{Xn%1wfzANSIbuBtxSYx!RCJ3H$w#7u?t70{bcPvB;1p65*5zv z7xx`h8b7$h9E-1!$Dj|$NaKwrOy00wt=I_vR&2 z1quH%0ty^pt^q+*gN|Oho9gWi9D?}4R z4&s!Un31j@ljd8__04@WQp!)B#l8`9%Mwmv1G3NC=rn$_W=ErT)IV)gq+~bL?$$Ct z#;-+AQ|FDys;qBucdl$L6jpFJ?}4XIwb)(+zDJu4B}uK)zFl44&u<)Mdov#=|C2T3VLoQ{Kxry5q{GPs4IVwWiIdo@nezq5ia7Yo%U7 z>3i+8ACm(hEvB((?Pv&Y_RD=e80&WDRKitMl}~q$tFaN_REmahgZ!52(vXWGbd7O@ zK6mjKx7gfsgNdj`Qwd}_x!cq#Iw@SM_85JrU4Z3pPE-y8WW+a@&|ClaGX{Pz2VVydU>C?aRD1l~ zCXoC8w@DZdm~&tQUIP*W9L@%Y6&JB0PAk;=og`B5$ilN{g#Kg=a$|V*NUD6&nntYr zf{GE@*uC+w7Z`T9x0#Uz$TN345!C7-jFV?yxKdT2`Md8|(|=)EAm;&p z4!gyCpc;WMV6631x4PS`O0z}2@eR*Avr+R@7in_Q$b@q;j>IeYOLlLbPNxl0)|!Yu z1Pq5*$usB${i@X=G9*HAqT>7Z>G<0>`pfJrLkTerm>p)a)SuX24@HOjPPyi`Mlnzi zqo&HTFjbtP@yC49g`Cgv{Oqr}Z?&IDt9FX;ZNA}!5oY7yf*v9J)xXs~Xg7CvECC-_ z1h+TwXt=@<7J4Ehj+({h7wahDt{o9C*yrJP+kZ|;!t-uN16&Zdl})d;_KVO$cb9?k zq@1Xg9K$HGQyOKeH{pp2AJ-0z9CF{D6ESO+;4Rd)i%d+zT>tgH!_;#h8}OEbZ5E5D z&a<%fUb)RUnGIvm{G@%deM#^AYrQZiR6F3?Ya2$w?v0;}Lj`Zkxb6y9BkQ4FuKQNi zzfAwB!yl+=F_YIGd(Z10nv~vs1U{hWBL*Eq%SDeCSlB)BiCLOw25nBH?T1T=uCTSA zEp_RSDekD+X!41JB8R1Ri(y!UqHUh4sHOrNl{#vz1&Z~p+8Up#*C-tV=W6%0&c16u z5RjazT>7J`?&0n+dUG zw-;Ep`R@oNJZ16XXmhGxevp2PufTOXCC$doU8iNNWc(~Tt%p8B-{craHIVSdM5JFr z;bD!fiQ94O`Ge!{krv+VjAks3X112GrPD}BfQQl~|M5AHhd=?WgGs0;i2Q-9>5e?eD}8@rpT-Kr9k7(Vqdz^HQQ(GEq`tmVQ8BtLT1&VMMu2f2 zx?k+#dEaBvkptsAV6*D^MRGKuzkmNe`tWIBry&;!HtK)61v5I)L36;XRdCdDW<1imqKO*UBNfdU! zJC1P7$gp~f^`w>gk|3y!(YEswT|O~F_hy$JFQh*0vdFxQu<^88UdYxX-OUW55%h9~ zxoz6*^7@O83>g&*#99(vmzd>O#hXKY<`Fl+#4>?#-R1YBhki6B8=eytvT5EQ z{7^~_{+cP!7TVM4hS}atUm6tdx=;r}(!z}TR!(P0v2Es2Zc|6;Zu?h)^GOW;Vi0_r zz(qf(osHjPK`1Bu5}Qk7BAU3O`HhG{0<{chXlVGPYnT(&-2?IYCy!wRxgV#hF!knd z!e2b)Rc{M>X8)K#5rU~HJ)nQ&V00lArx2iu_QXZ z2{--3B((|SO&_pHM)_*`Cp=Upvmg!&+`M}F=F4+KxC|IR@EHxP+orVm`!-K-2PG&dc(Wm+ONMe;qge-YtT&9X;81C)p)l?^**q* zldE811(PBJ|MmhuPgFZ`d9Fl`DI1vyU206FEbM6kx`1J3gxndH{?jXR#e?FlO|k8Z zW(O&B|IkNR?C-f^1F;c$6`CBX23~zg1m%AiVfzlhMy>TCG)cn(q_BeAc zGCb?PN{BKz4q0c&q#R1=VM%SEoPD|tR6Dpo$-a?Gg{d`P4gfdFsH!H+u*Y@+f^#q=5i?vhe--PCx_{%V7$BgYf3%!Ao!OBq3p+0dR$^m z*N}-P`m~SPaJkg%W_WiJg#?3t-O1NEzN5+dSMyeky^o~o#iS+X!p+d)D>8rGc5kc~ zL-nDqrIFo2mvbyIM!~)+{I>R`s>}Y!XSsK4in-Er6JG1}SNesWFJ2_E>lYdnf4MhU zX?zq7Jv(!H>9P}>OEO;Bel>IHk7=4{_r5a6EW-vvyvI1jbGq?n@z~+%uT70H;bTQpO%EnS#tlX z>T6d^(0I%lZg9}7r^$d-3O!nFXM~Q4K91B}9h{G?-K>AT-ZI1xzVC9Le)xd$hywV;VJ4iM#%^jmrM~ddYj;MZch>g&bGpL_p8^ z5TI`*hD!K;B23&GkTeZZ<9wp|H|?Mm^X8|8_7Nt{$!xqzKI9RxDT}I?s`M6Zo2l8b z^#r%vpMLkvhxcm&-;|k5n9>TY7*=B*{T>A8;u6rry%jn`yH52*RLUyFy~Bm8gRYwQ z1yc9HWHQi9A!$dqIKx#CUgC!aJ5^b5KWBH}8e}?M&G@HPXUh^%Xa9EI^>Dn}M3(%O zFVffS*Z2>2xLiKPiyse}GafK=1T*VUmFnmFHVRE<^YiCEzIJ_b`>sD$46v;Z1zqAL zo<*|8Y&Ta;D2i0DOMK7$0P{L}=}n4_+Tl-%EfW}EPd#O!pSMk_gr$HLdEt_M1>J)5 z{azL5kCAkt^-uqFm!o`JpYVQVP=y%&9dx9 zemJ$q%-_M1)Bobq^^We+#==r`YYcj=2IFu@Z^y{MD`3=7zPYkhOFw0M27~5%YtZ(7 zhRN8=%)hfjsU7Q4No0y@pOz_F!|lLH$T=u@Qg9?o7p!r(Rf{oLDYm=(P%^wf;X~497{`5U<4)n(8}7;bICMc%DfLS(Efp$@cJw)dsc!JAG!$RoU3E+3T?U;Bg}Yd zyZmYG0?iKBD2BgX?0x3(SZZ+nvX7AAPr$H#{bhsM@2fsPqFNlUbji5KdQmi`mq=*C zI#tq`XGP$}whuu8E%Nlc=HLs69h6BWEvmfoA(61;V#ua4&$|C9-|+9gq2u=c7S3($ z%M6b`Q$Cv{ilJqF7EOJrQ0&ei$8~O--?nzerd}9FE!)ZqzUPN7+bUTit-gXTsiL&! z@wKRN-d#crbfl5D>&lW7!D@FlLC>noS!7+r6nTTL!v|Gnco%JvZhE6$e(%6W03})N zhI_xx|Kys;im2>+4tO&CXbL)vNzIDF?I|vdBu2ZiZoR+g95?D#l%%*NCM2Z6tUZk( zpZsZUu@%aHqHgLh_{d-v7)y?}sxPhJ?uszq8NUYp=ET@zVE~I>Srv zyN4;CD#F_e*kTJ!6C(c+mAMtVSvNA6+g8R~&Ld4gq%DaGmbUOj-jhWhyIFRdrG*JSlYuusS|207 z{=Z-qs}Q&FuR91i6=8bJ4<+nDIy$G2ij!AoG2QlW*~nC9k4pvQXw*!;UFF?RzCLu* znc94wVm^)fj;IJYsWPe)oLqz%^)}pIr>Ibs1WuG2d9N_;VAEuh*wDbCCcyUmJc-0m z0JsYYyNfm1s%Z=)fq4;!)R@k86T&A^fVbLngoxK0=F~lRv7GSfO+NDx&hxJ~M16CK z8+^g$NoZV^4`Y;aIl3Z40h^(+wO{>DcDyFRK|d*9eJhD*If*={3sXL$AJ5jDio}7> zJS4n2s-!F>7@rp6|7J2TaT%FRbN|h|27PGx6qhlLh^l-DlitOfy zMh&aG5WDcn&D5-{=;4%!S`g|Xx~yWI9JpbB_1X}BE*Oa>EMXQ~^2=9WI2hu$0WOCP zvT(+^>V7xZ7VnHZ!2O+u^HMw4Y~s@0yyDje9V)mh0(dz-zaeA3cMs|RKAv;_Yb8+% z2x}6S5x3GThbmiceb>zN{sk>yFcEx2B<1C~CYo5x;ax`fM^{$b%7H{(rYE!OENGYU z9P#cnIA+&{U7Ry11%p`|FDJ*x`^z{$j*Hy9JpDPR?F1^(NOKA~!k}>}jRt#9UV?p`4)!PS1QH*OTC? zWM6pVRFDB|)S!l2OZ&)PR@{_$qnaNtc!*mUJ)(_neq(tr?!uiM9oDFpDU+&YmMjqf z4Ab_7!=MA$(soQ2zH1clOYq~fcGSZz$TRBaw^q<@(s!8u(*h_fB%kjXXgGb}lEAZt z3(?V9XiP<=5)0WPSmd2mga(&?hKj;qhf9P=gLtSRQ-2o)Q_ge1(^*iPJ&L}sQI@{* z&MlAEOLgqBIT1)if5?&{j5qxmxK(iSC;zzhQ=((J{X7+8%Hj7U$tiz4R>;OvGj7I? zvE#Z|({L+HRi|A*8fC3#hLJXc)N#^ePcysCg_+vpK~p(+Wt~5wylZ;u<4uJ>MYg98 zIixQRt?_4be@~=~Ap%NMU^fgqIU9P@`8Du#tvHozzyw0+meV@WkQo+?NDp|VGJ|hX zoyq@)M62wVn|P5SakZBHcz-u!Wg^4$kv{JTq<_xh%p7h)W_22oI*mV68uQ>Mk8tTp z#!CvDqs7$Id+kT9JzUV}nqb+_UGaOI4e*PqY@|@>G{pWeOlJ(rOYxo#Yd+T(*WJJ}4%=ooECL6J#y-5t1TU(@tygHpo0^D%-E|?${{7qr{igyG| zh;uf`FaVkQuQ81LZJJzq!Hr zbWM7xi(N|3>FS#H2o>9{dxaXTytH0qRnP(j*VO0=?Qm%h7o zUOy9cTO=Pr%%*6`l_b!k+rU2{%+5hsiO1v!KJY!Mq3K8cQX+03H=KT{nTXsMc=H^Q z8nXm_z|t|*2?isM7bm96Af+C0DbI4_2*T;mn(!|0 z`A^y%n&|sy5L%!f%JCd*=hTdhtz{@gUbFVzA{*eUv}?)Hh8sMG8iYHPUc-5U#f;V-n?z2Y zT<1zXlo4~fjU(0)bKE+l-8Z))8OOROOAzGIpH|!rWqx`|9)U1kzkeU69vCQ)03XKa zn9bRv+n?%G=$dDbrLsbX0Z8_n$#25J@Ezsz#1PX?pJ0Fq;u{RDgK>eWJ5Hz>RX$#a zZlvi)aI~Q8s@^0q?nteuE{UixNH%a^_&RR7ffI-kFp+8^(X1XFVsH~11NsW(QGD0I;46_%&ukboPvPP>ed|VN;Sf;V_)mvi)-qv%s;L_l-d_3axpyfC9s&Bw- z^5*I(m2N4V(RB8WY(mJN(@#|MSwvbZWz!qm`_v`jMj^aemk>HWVZ5bywSa$=EonzS=b8&b(PH^ z-(|palHAt0Z*Nep8iH$^_m619e!Ah~#%q5k+^j>4y;ij(N2p^nM5G@Wsf6Rw`zu`- zA`C?>?d`ub%`?Co`Oe4#O@EioEuWMn$V@V*W5P}b~1V#e^L*4sP) zGarXG!1unS5rvZx6UmK}JMO_F;aJ7gVse;yM5JAXiIaT}cDb&*2`IqJF-7JD#CCVo zIuTABg9sKYC?(i>MQ z%HAgxuV$gFnBhkxDvI2OjP;)NBU72B%#;&pLMv*ZUimOGTMjsqWNdL9 z;5+{#>89KuyLzWAp9yWMhMhPtFG&y>3&l3)zS91rg4_C~PD~_0ljcwI*&ZgKMkKNg zl|bi3X=B=K$-JS2-F?$o_R~L!dV%7XyaX|{{Psx{uN&%WiFLIA6zY_GO^1YcayKaV zOCZLy>S>IdEOY%!GxXM!0^c#h_`s>Jj)Mw5npZNbiwh6W9Ck$WIn2eoJLX0GSMJqh+$U|R-%cUzzsge#F zw;AKNYh^`^azLtpafG$LBe&{B_!?QabScSUPV0&U1@j4O9o4KP60V-Y0^6!#TwIZ0 z(unYLLoYJ=pFfdPeX)4rsbf`>#%guUqD&^5H01@GGQOqG6?SBN6+JZLw;n6ShiRc4 zEFg+2Q+P%{&i2YFcN-nK1p^?BN+NvsR?X(D8KHev%0R(LCI`X{9Joup zvAHowAqkI6;<_>yZ~|nxD%o^D!c1o~d3PR4o@zgHCVXIksA!+-3L$(FM4TyYCprf^ z3+*pKhTe(a>|3EM@Ga=s9JdY)(C0x6*M7>-l-80)jr(R)vh+<;hR05_5F=|(Edu+%!? zyL8k7-fVfm15Ca7*{};U=;Q6(BRzPq%Odn_iLOS;uTJO@gm*gb$H+<~N$%EhnV#2> z*24G(xo#w_qQ6 z#$-@je||HA-+L%;=^RnPyV-^mgtM_zqA*CO@XK0>OJ*wHbFf)yj>1f@GII8a79p6<-$ic(Eep7x|Qe3iC zq^pHHD~4Eh6L9S7zPkk=qU%qJ3t;$Sl$)nSQb8oW5$mT!GQ{0$!tyRK-Lx4Q^=9oS zz@V$(MZu!HXIHN#oJcGPP-rZ}oF(L4RCDK#8^=Bg(`C9>OMH@hOt~4Rc@`xwjay&C zKiOduxu8blDW9T06~?XpX=it5qxPJv@*8r|xM&2?abiLhK7amRF!e%P$!(1x(Uap< zGIYP|uBpHP_l2lXkJ&H}@sqHvvt=`rcn;f%KA0O=NmI&o=?knuoA={yK3mZrA;yn# zcFoxh7r%U`-ecbC1mS+=cVJ5dpQ)nAojR-{;)V^-Tag0qVF{3Vv3S zUFOHSXJTA}Sq-8uWUuC;e>Kz=6g?@HY&TQ+V2)KN^Q$eu3AWcm=5bWEb+#}F*@)Jr zGKVjH_u%eXfAO$!tZ;8NGK9LXmo&5R=lHjZx_Ykyk#rc60k%Y%wZt!mSW!_H56aN} zxE}%gg8xl!vR{liy*WKFwmz#tJtF&=HU4JJ%&>_-`f^z$N$lU@&W!qC!f|HG|TbLxkCnL#J=WH#sT-%e;d18Z8%Z@o^Ts zN`tw!E~|(zDyKA8o$J)X?ZSE#e7WTBJ*{Zl{2LdEt;x+ zT^GfB=^hJh{wW`mK2EcZ3ZDj#x81jnaZsWNv%2Nj*mzpO_YM$ z2hAYwF;*eg(Akq6eNZ*8v>11A=h;Q@_OD0E9z^?($^KqMp!oWr7$h*%Z5J5ZjgB3D z0fN>j3;6ZeSH1(wy!Jk*FBac}ef-t#`|$~bIQ7ZxGLcBM_}{(5;jxs)zWz67Xin+8 zKA|Ls1Be*2u`U|jXV{nmNq7F~sfdWk+g4{TEh#S+Bzg!_P>xd!ltYb)jj8>-gZKIJM2stdTE}Sq zm`j{<2y&}J^0oRnP*#vKG_GH^ko);+EB__4$@3yGf7Z+SJ@lD~AVZnY!qbhv8@}kL z-z9y?ODM^M@+AOvRX&RWJ8kUzRdHS0H=0`x29BoMv>A`VK*I+6MbdZ8&fUmRtvXBS zhuK+0FqZ202&N|4$6`;V~0a+-aBIf{hOB4gd# zClot7e;I0n07M5xLkcO9RO5c8k&6{u01A6$>kbdz+w#VVl!?<{B=_3(pHN<0}!5E zgs377>`K*7p{cPQv^yjs6vh29I8$L*dTPCAd)RcN{tI?=M~);0UZEhA(!1?3`YZ)_ z?u9?4vK5wDF21@->($2mV0_QLOYtY*FUQZ9y|12gt;96; z7ju@a1fQh+Ze(CLfvCjxC*|Zu!*-EzLrhd1%gsGWkIPo_pz8gk`Fgp4#d(3xckb`K z7i}_S0wg*g{zxJ-8qi)El{J5U$NdJp5%V8OSGQ-SZo})wJHBm(KF86z+tkBB*O}N3 zws&Iw+d};p394#~XEP7YnWMW08y-~_3Ei+lg61o%xb z&S6Tv8pUbe2dxL?krv;^q}S&qHc^aYz{HIjcD4J+4K@eg9I^zRgrma&K|rt;$UOdha_`++E2`50X7_ml zRLp`j(3Irwd|bao3i&_jFI1O_jP=O%W76#V2CeYEec3gy_-XMtAB(%wFt-$)=Q&B~ zUI}TE8dv<#(;Hk$rkew4W(*|da<++_K#S-4+~`?l%qhF*bo1`NO`V%n+q>jMHYE~x z9ey`G(>Chpol+MItan?vK%5;&nJ!2B-EnND`|JiM4WlJ5 z9YQK%W>QL;jlb976bH_sEk&cu;K8=$dzw2Xp*E@}aGUb;iwx&eDVX_ZxRQIE@9()P zM6W@uR<6Xx>8*5>(4;h74vY-_uQ_?o^vf zMmjFsY0Tvp>np|X6fh5&|Ttg&4apHJ$+rM@psMKh?SN1@7>SCk;n&!pL@+9 z?kD5COai&z?O{BR?R$&psT6sptn}~mG`#C2{!bVWh0$2=n|saKI*7HhmcFJ0=2{m_ z-}_k*)frU1+Zu0%^dd(RJ(af*{On}XSSsG0O{LhwDQ;OmKZzIFfdWWXaDG5B?BV(} z@c{7fk^xD}PhCiQA0vCZ&cBz6k#_T+)jH%JcXF!muOqtHaEmD?DK73bUWXdQNQCKX zxC(tQ${xe&^Q663(-UP?B@X1cG>EmTq{xKUZ--M(!Z%UYy$M9_}&!i-z)wE&x)wm zrFk_X!_*HK8C1pN3V!r%7@kn{(_qSbf;hdd-~4cfSo|Lf5lyEIN9dRq1dLWYjIGL}@l;4XHY1~G!_My?t1*uPKWIL z6FnGEWSirY^8uBL+99_4rxH_de`5Hd?-WDww-71LZZg5oW^4|CrJ8d4%-0~C-bT(9 z+>5iP>7Q=Eli%v=r#FS%yJVlx2x90BRYMxI(Pd{#PQ?iBYVYodk_|<(5x#pG{cdjU zgfH^^b{$rHk8)KeRfu)~)>G!~mrKjykH<3#+7nUoM+Q|MCnEEk$)HEZY0J8(_one) z8wg|u1RYs|gp_bgk*MdN6`BmQ3-$M(e|c^rczI_jZH5!i9|0+PmaZj`i<3Zc3oefZz4hBZzbeBsd(O(tP6BNYX@GuEL<@>>Frvq@t!fQ$aZl z%XW4Ea4gW24=ZlcGfQsrIZ}nzmip1Rd7@xwO_h%4t(og;S<4#b*bP$TLS)!`ud=|F z6$I~E&?SQ8={&1>m$i~2PKY&_u(_;E&^cdl_pr|ZjosvEUd&Y*ho>Y+V*wGjK=%P7 zJ37d<>6r7ykVcUKZouT0TqtcS!KvCF>rp_YU=#+s2(TpdR zqdGhL4%Gmt+x$3sy$dN}LH$+y(Qf5o5WpfS`L0CYz`z(nqe)lMl-U(mUDX@-r3=X? zv@s$R@CK1IVWfdC`u&j}2IFp9!!f63J*mjS*g&=*ZmHBXIcbBj35}-MH&)j2D|U|Q3*!utYf{pL z1c#cvny0brjKrDq-!AK+JR9!f2-)mW(01LOWamqq2e#!}HNNSG;9re@8KpSTC_L(*A);fP>myQ|5S(DSa| zD&0$68IsLzsU}cx5NXjaM5u=MnKykDm0^I>V(wI(9Vbv}ZL{WKBC2_Hh8K;)y3`z> z^h`D!GNL>B%)BGsEc&kFbYKFTF(3#TJ!|y&Mdw)w|E7OUAan5zs__cL2ejakz031^ zrR*{(OazymR(CG~YM2i}G5^EyQQ%Ll#}`;60bN8506{CZ`hg67Jp@MYen$RxRa#cc zGphkUTPA>*_A)Y(Q6ZmKqQT9~4t}!K)LYrSHn?MGl3)iyZf^_>N9OUaw-hG!a&hE_ zcvuavNK4a4E3&MkqX>_Vlz&7h%d2@FtkCeuJfQ7<7RPRecwzs2Me1GZhnQIjyQ{=j zL(Z)ReQ~XyPiy;!h;_^QJ%RGx+_5HZ%nE6#`-Z3*8`BQN(Z=g)OHh=6{3MXZd#cR4 zN)&vR28WqvQ?6AP_)olACPVR_hMdoUP&&>XL$nhlZ^WO_3z9FZHFfv1&mgoX%e*#f z0_q09S&^u2X0sK_+GD;xqNV{SB2s6G*k^wpPFb=vUNzCIKhnc$1*|-}8)DtZJO-Iq zc?n2^kQ0TsPo{}vroHgoTyH8w?tPQLqhac0)1k=DKPd-Cg7Wh663|t^r9ZhSV-G9} z0h*W42V8czs8@0Sv^$i-aI=zYZyo*s4?*_xiWVCYsV8VCtF1nR4k;5|P%6`~>IWYY zCpSE}QI^rCT_}~uW&HeBH+VHsk>yK$0&=6pMigseUtfyWfOdk!(oCCb^h9pketnF( ztE*NO?A>ldA1dW8NdO=zv#f{o)9^gB3B^uuZvwy@NX)AO)f4;WvOv zH8fCO&8nu&i0$+5d&)~FbMJS6$ZVMIA96Qup_tGDFUP#{_S7NAxhL43r-W2SMn(qG zJ=}cpz)tBM!})4#CO!b9J`GadWo!S47@(_JZg%O_Asetb?+HgWJ0wH4hJdy+w5vZe z*a{I0itkL?Y`i~DNs0>*;VP^mTw4zGG2wAIDJg$aX0;2T=;f|^Y=pU!&4mLzi&?EU z_N^TcMX(SXas*pYX_7it=&w)2f;+Bhe{s8Hr~?r=M0qzbc8>Q)-Oi+;aFgT{EGx!A zUXTO#GFUJBL_M6}(1MdTRz$qV}G>)r9*m)nOX*XZz> zL9wq24=6F-sf8z@^B8LkYUki#LrXp7H7lWiV1o)lmIjMXuB_mfS!CXA6pGop!+}to zRw!p*sZz<)mHH5JHfZkYE9~t+j!sEmwA+2&`3!zDb`KA?b;g0L_qtW7qX2hp=qrl- zxsD`1leZ^yd4O=r@#%1-nB4$C8gU-<)C6W`bWN}2|6oQ!fx;^&Sm$x*G89#Oat;gN z%_YPUfDF%Q98RHj*05mY&I z=2x+|j*JowL;dAH-0*g4w8msHfQ5PFfin{FJ}fp*0M!?~4tzA9 zy#;r8zNYJ5r#aE>N?aWUE+a*p=eu-whdDKM1@7pALV|y#QJ&5alE`?PSoq`psW+U* zu)1%wrXxv1$m;S6Qx-@ydKA zi87odI2E#CKfBLyTYn_7wU`-*9~vH4k_$wY@HvcQ4#l#X>Iz1F0sK1N=MV)dmZcX3 zJI?T?nm;}>9M{8;0IV{m6@q~`O-;_LA&D~gjFc~ogBa&(`kOW_|90reil+47ed2L; z7AoMpFE=zcrYQIbY1yk-TEvb+hBr^L~!d zdmP~8%}{wJfXHz>gO-3Sp)oediJm-ivV#m~3Z1K3UhhKpHy>;1Mb^+k#(pqT!d%mS zMVkJ?Bo6r$WJOXbP$+b0l23LruY><{U-$lWu~X<}^GM_Z0Z%gz%mvXg?af5pNLYc| zfNrv!( z)vx!n*t{G(3r!_)1?BHJ678Q}`jxaL%tT1QZkYDT(GsfJio2XuTQ5>r?mXMiPDf}{eC(5tob_74!_LMi{(xw{&ws-2xceR>zJTZw%Id^+#ARsfrkgU6vuxrG z!PATF)w@b}{q4tSY{DLOGCo)F$bZqkFxQYZX>>N5HH!l-nMpr31t%Tq*W10-*XP2r zfkXKt7~UeTO{pVf&4kKnq*H=O@@~u>Uziw(;d?9rwCdV9jTwzMh>59<0_a?mFcy?o zh6D3gE1Rl$5cv|((9>lYk^lMRo%M{P;>O+M!&Z19pED`Ur0V^wDuqQbr7HuK{DZRd zy;rNvSX}xNbk8tOi$C9y&OCG*DKd7+2nZ zqZf7vOvJO!-*oAnbj53{apY3QTrc7toiEj1LSkSeI6q=_0yt1p-4#Hz;zl77Ohahc z>UFO7FGO~GjZ4AK7mMqUg5-S%woaU5Z zrSp+j1)gNX$&dKnT5|NInt1Jn)3xlrA9;_$OSPkqtx?c6CcvE0I zI*O$L6XoahcJ8mT_$97K*+oj}g}3s~KX>HOrN8=_1#b9iytGQzS4KXs83GO+zIu+7 znac+ALwsL=E*=Fs?2Z%@~Lo0Qqh!( zfI1dNG{SVXU`bqvhO_pKr^0XV`HmCDp zRqbJhcyQzQWb1A)Z>a8L=KY`Z3{-e4oEUEG{wzvVErX;0w)&xMz)TRhTLT3&UmT^% z(V(~+OonDZ0a~a%G#^7pFu167zH)Ev3fL)e;t1Wog}C^86K)X@e9G^UVXmY_6P4{e z@OyqC(yz-xFK1zD2un8tH{ zeJM@C%0qa=rWiKb;8F^V0Xtf$M1t918)wZAB-vo7>vtMK2bKkdzYq{7SkX9JL@Z>g z;6d>~(s~z=GC1b&onS?rQFem{>A-cH@k=PiF@o#&)D*4!<6N zh>{D!t33FedxI`l84z$3F&E`so3hxq1m*!$!ilvYF`6wrUVBxpad#PG&v7;k;GT7xyjh46c@NC}9C*23ifjogX zitgrrB@(k_o5O5#6#j$d9)Evc&~-;Dl&p}O=RcjLL%z8krE^`HirL{>k39WfWs@cl z3v9s<8QwQ}uVpKdaI#j7D!t_6ZUEXCQd8H?+Os>A37qGI)G!Yd8 zj)q$0*oa2FXnVIf!66}8OwHX$9gXf6C78^{UM$W8BpAOgNpuoDN8Vtjh3UWIgjDgC z)m}K_sWB>E6mQq8;_Yc)zAku64m4CyQreuZX6Z6(rl~7zd_603-MvGU17=Uk`2KYi zG)KS9mj$?loWR6RIeXJSnkjN`+u3e~RX^rX0`J_^)AdO0s@bE!ofum98!$l$O~+GD z2Gx;}1=1i&*2C7Qq%XTAom2UQTY%??VtwtmL6I9qRPacj!{{#$UYICxrwc;Jq9{B5 z_~s)iKg263DBo>L43?(yE*X{S7}aUy2-UW4CA&;F@%Q&mJi~H7w4H*ZBDW<2^x*|v zs1$%RU>8ygLw|i4w_5|Fq!b$mHKC^xFKS$b%+?&g<B(XIRv5I0gs?F8N;F7k?MA#C{{6 z%;zudna2zO^By;iI#rJWZ!hMt*j!Nd3Gzj?F29$)k2ey57t$KC5b zFACoA5_QNN>^8s3aS%dqbkHqi;4X)>euJE}mQw99jvwg=G%k51cT*c%xw{B;*UG_> zv=VZBPfPMwdB;zE9mW{b#F}?ysY7I+0zt~{sGmecA|*PJ41PF&lZhiJ_|&p)flje! zi8b@WNp}A`hm5gC70sK!pia8GFRQe%g(p>G`y|EfVZTb>ujt4TFJ3d=$;^ntk<27jK8_eI2yZ7u=1+y!Fu3djFX&Ej&eJZ@C6D96q{^mG_5SOZ7ebc+F1L$hD5%nCPNjJl zxC>r}KBO6!C{Jk;JZkOn|ELpic!MTT08%n}m2{>e0k6_5ogtj9Z$rHRnFMGTbG5nB z%kKx~%aqQ<%m$#8Mi17xRz2QEO+1_?!a~s6eyP5cb5=WK)d1k^RDj&BGV4(Dkmw)9 z1-DHa1Im@_Z_7WN^uD}ie8qBrtx@fyHTZ{4iG7P`>R!)q#hy)?dKVXk)JEusI9j@Y zJWfbY1X4++{kEe~(Ts5_TYC(7aQzAIZ%-4Ec3#@k6@Q^@jyK>cpMf@fe&9z3bl(Bw z8~z@;1%2{#!;P;QU^S?^59)eGZ<|P}`U6{_2u#I#?t|mN$I;H7;vadt>;E3>8#%Tu z+*v(6R-GMeYfb_@ef(eQejuC|an*wuZ#Yp?*@vb^2)WVFet)BWrxvW}Qr4R55=$zq zgv)dtFlv~#8dZR)L4Rl}4(!o|P#JHLjes088X#&mHnc;eu1Xgf24viU&!QX9kya&t z0YtVn8r6g^>5n-+1@3Jd+pX!~ND*GRB78UINJGX!rtzhTLVl&o@3y%&(sH8_JFH%K zR%WZW`>%aXrwHkDu1+Rr-TdTVnLt4cRe%@t;!RpG{lQOP_$=;*t+cJnN`Ee~8k|-oR~T&Sb*Q6Swt6X9GUAhLJrlI8Z+-@tPi58#7DPub`3N z1?<0k|JwrjBEXYd@0WY7v?c0a|4ip0Fl59n5A%URg{CY!=JlHi{DswGjO}##U9dm& zs8u%}xDVBCj)!XJdTF9dRi@ajAnbnC)xgW_vgMOk!=K0?4n2jXPm?bUWI=< zBX@+tGGOO;77qst7UY43KzT^vB7P#`cx4&%xT@ zyBzz4@)<~AxlsGlQa!8TIK$T6vimrW0Ulkl#_z516J8-JKG4XAL1bP0N0I!uE;cH? z8d@pVcV+eat6P+N4}84l9GXXfG3NI2wZjg{RZxbzT?Gx_EeK~#nJY@of31fosR%a{DeH2Kmn#!kt^?UK2){UCie58 zfAW4r=}^?!t*7{OIjacp;EZZ6z$Cqaz{M&9D7)SdLq3a}KT#SQuBSFL3<&Xb%Dc2! z-2Jl8{oNjYUScW9iZyrhl;r7GxAHiOvvr`@S2ivOZ25hO;+(`K4$<6JmC?fwvu;!E z2Dac;pAc|RSO4Ry$cvKeeeXz;D?02ldmY@HaW2Apfp6d3xnG1|dIyN3xu(6s3U4@^ z{^I~C1$hTWizTt0D<`+MvveX9lXw)41re*00CE{%i&vQ+TimIm7PAcj@G^E?UK?s?n~Il4m@(srdBUn;Fgb8aQp^wQgtgR>nzQLE=Ze3f5nA zTtbo>l^gLLSmm65X_vW3x|AOZ%@lOjAb6NGe8){h3Rf}jv+pZfTAkQ0Asw(P4o++M z3_+o-jvykdi$xdgh~prb1#~1U9*~AAgBayT596tvbCQLL9n5~CEK#8asA0L-S?Z$f z|88qed;eZ9%nsx?;u(9PzsS;A22}vHZ#D%35yOKF;juE0_o)0%Skj5|0@DF1-h$s_ zPnZa2tU}%|7W@##ZdBS+PE(hrnl3jHX_h#bm#`tnK4kCsFyH15AC`4OYHt43<34#M zZLum!mieoUsf0utsc4U5s;{p5KPecFsx;T#C&L;a(pKqJoS@+%&tW*4p5(i`j z^At6eM3VK-aT=3V=bBM+Iisd~DW~O+M51iR4bq53zI56NOUV5a)NH1BW=vN2#(DKi zP{r?G(A9g{&syD}CEP8(`1`Okd-|r9K?aH>1TwY=*HrESw$bDR0GTF%oY7>HM{X#iBmySxA9KXBPzwAH!G*( zN2u@EQaoXLsPyTj+L;%#u!*xoImI)o&YbVvnC8{0gKE>NAx$ZynRtkk6>ogb*rjw& ztfvpgl?-vk%-jNM;o;Ag^KaZbYM(t#*wqQKt_e)Z2FkN&Nz zVYNy>tUqK_L*ATc6fq#O@>9&{ zKXpcvH{Z4Y{pXG45+)UP~vWrlEE)J7_; zeD^>##_BG-*V;AFu$P*@HxQn-^!_f)hK@LIt+I=Bk0uOe%LcVr3q$YB+nYf&s1GG{ zadZ;^=a+xgqp?>5-a&tx70ODU8;mid0|(@?EnilDBoRX`7e^;XxcBuVp)L54Uv1*& zIGjB=l(EUsa+?*=8=y?k<%=#UmY?zOW0g9Nv;FbWRwH1?$@zIry&LRyG8oc%>zWhV zMk&1tv4&7+?MI|M~*oFD=w2=hi zRE6MS2edVnFH)jsr@TCFZszew;&Uf$iZaB%g^_cyD~`Fcj&|PkI}r`4C%>W%wa*v} z7w(~9AtoC!?3ulaUsW__V=cbs(RWnd`68?x0~h;xa&GxsnLf-!hTj$z(h$hYWQjB& zC&0i94Oq><#}}qZlJ+p-SXqA|^GCDU#+OE+6XC7_ zY&Ep%hc6t6geG&O(i3GCTkrQYe*zMKnSgS>_T981w{|VD00nJ=^NT}~7(Bh-Z*@eg zM26vi7B7!pUvqP)wo=C4cb0x=9ky70g(o?8X9Xvi0H8<@-d&T*)#jzJl`+EKeurJZ zMqcRot`Y~^%oVDAPL@?cNPcuC+tqH>OH?13KX(5O+xz;B z8C7-F;9$1>Y!GkEM@>g8l2|k#(>p>PBwjVoY-0!@%TC=WZ8`9ZLw~an@Qsnk1aRp_ z3~#Umh4~y1ix#P%-+@}6Z=6DeIk8ZHTd;S24 z*6aO(4ukIR!d>KWpBdVaZC!SKBfhlV;wqM6+{@ZY99HBWagn?Q)cR-rH#A8J$|#ix z$TA|b8Tr?=ji3Legir|og2_0)9zR5198xPV$7hQKn^xLA(zh$2f1PCnqmE~X7x7$| z>H32LC%T(Ut*;+oNj!{Uff3(3mE)+McrVpZ=+*dyx+^)hqR(!)YsE>{ddLz zlt>yWMRlkMgLL`gQ921K8)B{v8X{@zOTU>yN5{ewOT;{^b}vwx9D188pB{; z%t76O%gXbiw`e&;pGA!nO@KW=2DeYe6dYtXSV|Ef{iPx7OS-69aYYcV{`({t=^P|s zwvk7#1gkM{w8hf(fy$MJ^|jvZ=S8h3hOq_FE&XJ-81zesKa@&e-`v83*|z3g1XU-3 z5<=l3YeGVXhM)$}NM9^v-{(*Re3`gyuNIyTk^H1nm1Or#0#A+SB=Ebaq>e6jeX5mEzBy{WY%cJ$)J zJ<0EpZiKP1F_g6IL&xVP^%zJAP58WNATILN;q({VvY?Z8-tgWd9 z{+3s7tjM(+#?SR1=wIFL$0Y`SH2sHtr{=0_tf%coJdzls>COHevoJB*~X4-@z#&afqb8%^tMHXSJbYV58STM zt9X+app3NmbQ+@}wXNHOe?DJV5)4;Oi}7x#jj!92e-#)_+&*j7!Lq$n^);&VO(2?_ zf8#1qTSC3UOz$Di7L~poH)GF;5CUrl%xV-`f9RMxcZ|bqAO<_1(se%ws#_BMjf>Su zC-OA_a%+SymaEMh!RA}$lC5pH;qHAE+mwsrI>#lOuUQqATtC-7f^E347lWz$dk0Gi zW17uVHZrH=#xLZ?Cmr~Nr7vOXWqXsigy?oBJNy|cT9eA^LVX07G`ID-xD?x_-yZK24I+co#=6FQ6|~1 zlpre`ylUEb3w#SyyssO)xZSIgxCLhbzAz}PXuP(r#sfv-s$Z`9qIk~WNY*edqI;u5 zq$jEY1<+xFiif9&m3k&rf-$hi-8)ojcQF34w$k%gd7^^AcRMC+7QPD8m45BmWOGk#({MkXXdu`OKBfh?RllE!v+oAJY}{NB6ooy#h# zb+d>9IeV}H)7~W&|AC2zC)``A&Q+BINU>HWXSM7H4oFFI z8f9;63H_KHO?*_2a&8bCo9n~XxCyt}8~y0y@)5tA|A{#Neg$kaG@k^iUl=x=8->N_ zaGn zqKvl-096x246HL^h(&*W%0jAFOeQzVV{6@F*CU|bNj58R6tDMK4W+;zlGuQ z{T6=#>Jke>K$Yidd#Q(9o|2^nu&GKN&(Y*S8 z#rLzG+#8ok z@+zfNB*l3BbaVjL-gK;Cr@JILnn&rzEmt!w=ontyaDn87DeekHhO0q+Pnme@I4Km$ zWr+{=>cTzLTDWkr9n*#m!$`;QIf&{w(x`PCnJJW}Pn(J+DLwIIIfH+&d0Q04^k5_( z(*g@l)GQ5e!JEZlH~gEAUGLzHEa@>fnn@@p@5rQ3cxreQsT56|v{L!q_U5hBvt=oH zUtw!DU(Sd<&_Uv+a*?G8cqC`|da`-c4D)%5B~V`jfYR-)(^*9LmV_A=&sT7nJ;8|< zP#!{0&gJ+n+Cvi|c?ojGcze>Sd|8qa2EH&+`H&n-T6x5Lq;YJ}6>VpPyX&wXG^>?a zpg7~eALOc#>1#L+)T^!8)ALG)bt#B=wN+CXKkIkIeTO=Y zv-`5a+(T$Gb3!>!v&#uT_sV5g~FHN#sDm|LRoK)nPz0XT*H4bFv zNAp)A_i6K&a$VqRYrdIR-&APC#-=)7|MriGS4inAO4~Twfms)ZbS4F^MEsf<`x9wn ztztY5&3I?ihM7@k5|ugX{V?3Kt|oq-j^=q)o#&!qW}5Q8sFxjxB+eyxjooB; z?cCEa#nj&mk~lWKyLk~mz99Y}x0t~T56U~1^w4qsw->-O@?NwQ6RhND3NIgkaJN^L z-4;?9&_$+u!EYMpxk@j6&p+Ne3HEH*RrgfYU1IcbWzP`H(qV9(XqteqNh8eSD^S|&@3)= zrwd31?p&ae=E6_6|KghrZyFaW$Zbl#>cm>Tuuh$M7r=Q8pm_PZ`)&W{hv+BamugGX zKSGn^K4sc^90i}IN${lfg0j5A1@wWG8(t3#L|y{aa8H6X34D&t7*TX|F~cXf*rrcy6E7j@F_(Jv|; z!Be&Dh*OTQ26cL~JxJDn4;>si&XhY2{|-~8)i@XOS0bV6ce z2`Y7@!E14(B~nsfiI)Q3{VX85uW5btjMP*M(-BC&wqpPk( z#x3;X{QCO?v#x$3rG^z5W^?7S>r5MjFT{b~^mVbN93sNyE>>^cR~($e$RtGCki5@1 zjQU4{AkEqKc}BK(cXKP3x!QDjPu&AjtU2S}3HegmeFK2s4 zs`9;PSWD_ryq%t>_dfrbe0n_!C>$ji{4tMMrhWS{RYqwj>rY9QM#5qwNB*@k;l{e; zgGl>Ji8sH}PsYEmwPFVZ2VUF-ls^)nyGhQ0Bi*>`<2fb2w%)*}&bbRd?p-`^=I9;u zW{pRUx7BJ2Usd11pV)fc725Neh^~Gcy3Q~WP0U-ahZPP8op{eZ(=-ZRKn*#;@3fgz z+h-^AyaH3&26xw8{_{T|(>*u4%=&X=39UVC0u6R4T4lm@1m)Xc&GyK(iVjI980V!% zJ4u&FbYfK_VPx?5$eQ^A{Mgw~1rH#&m zO1ygM`w#Tp0}Ym3#YQNHXqu{C7e12y+T7YP5r@0jRY@tC{_{=GF$qh<_DEe4I5c0B z)qlmt;>9N>=CrnA4%I3In_5XQv659t2zk4f)rX-vF5fwjTUt75RPVFt4g>5rx0kk1HsTBPnWa=*2-QLAU#I&kv~ zOzAihLrTM2e~Q7O^j5~!3Jp#+#c+m9baR8X~dlR;A!xKRzV9Bt}s42>z*pk%dc}j)BW1 zXCd+>saCS{cb{xC);5mIWMHv|MOI!B$xrga_b<}F{74Ohw?6QSGTl|{WR-^LS&Id- ztp>EMHmZn3EJER+`Zb*TO>K_ASbB^fe#vFk_ZvR?Mz0*#jGrr+%hH$UJVDIJX~q0* z=AEGU6BN5pvC)^+6HVL9xidLaAlI_Q9>EXt z)tt1-8_%G;iQ1s-L1cSqSf)jR^kEFE^IqIFNAK)Q#-DqPd{Wd}ZLMK4uhuJ0_&<|8 zozTFST1iJto;>Cxs69aJ+_!BATu{7p6B5^jimZ_`QkxezYdFO3z} zaZNkE`a~ZPIRRpe(Q3}sJNlz(SMC_!_NOfWtu`NIn(62IXkljm%<`#LDU5fvOGrQZ zt}8cNEWfBcc<1RY+ZK71jPU=-j!8_6c)!Nk|NAV7X5W+feG`g#Se=fU(V5>yPEK*9 zzL(vKR4_?3&s9u@@=vpr7lXrt(lw(<@8l<>UCh|tjaUVypF|E0orNck3Da^UYH|6% zBjH8JKaD+Vx1*Xs!Q*UV1O&L%3-Oop>Es|4Hwk8cd2VIvtBxl-7U=UScA?x!N{0!2 z4AWn}T-1PT4+UVGD4hZD`wDe0xlgJ+N2gM5PE!SLUQ-}VmDZ~NGm{VlS;x6oOANa^ z9yuuYjLw|0@J*9>IX)!a3{D&-pMQc@yxtI%J-d2j}Su-7jXi0Hh*i@ zIty_=Gpj-5^f2`o^*Sv0-dCWh$b62|fCqh5P{+HlD_axOyq}#h&u2Y|){*ZDXb`k1 z@eItlV9hP6EYyCEFAa$qK z9~uVP7yGRk^2J}{g?bV9^;Y$9)%Tv6h?C1RX_rry>Eb7ZCg$~3@G&x?P%!y*fw96= zX}@DV(JW)LD=tH*ZOR%UQ-s?K(!(+TV?X^Ydiq$m=P=pD*5{S@+iuBy5w?2Qq;5TQ z&ERS+9e0H9X(A*8uYssYKVk~xUn1~@ylRCUhAiqg3D4@YZm4EgJp}2w{%{oZ;kiF2 z0`h&T&HeB@$AV7(;YLzTop_1x6v>4_##jScL?t220;HcY(VgvWTPI+Dqlt|WjmNOZ zb}?MQM3-3@T-(Acej4IS`s$;nZe-UQ@V&~(>$m~gZ!`7oZr9f}G4bGryC?2b+BcIq zOFnRjSUr!7orU`)icQg$=(Rlz8J=MLJMcpG)+R1Tm^M%mN}HZ|oPH$e$fN&7!*x}; z6B_h(k5%+`O}KQa-L;+LU#WU-(QjuLM#j6-VEG{GpY3Hj{PiN?9-YIn9B#0n{Nx7v z*NH^7-AB`9%*)EYaN~?u@&72y|A6eTtv1{A6Op!goy0;q5`30gkpIeA6nchdw(9k& z1cE=){-?K^A5x>#5J_uw-(Gx>B;j%CUbo_45BzPfwh>lL93L0k|6rDm5LSus`ZykQ znm}C(U55UP%B5I+BG>yESVf~3shn%+iu;_dH;TlpBTip=sQ59t`&je#=*RUr+Q~Nx zh#@Fc&u#=Rvjl;fi%*l>wkV1ekYt#`{X|}^pN31X{KX>X1(3`b>`#AphWcCdT3V$SMT6i$1k7QwV#AEl}0P(ZVzcJ5r<|O(Q-27 zXJ{a+mQsYbt)RMt4%iDuoSq3oMF}Kz8?P7CUIKK6Yzd25K2f0}m^z>w970i?#ECje z7p{bkoyU!^vs0zuTO}lndC~BRqz$S=x(~zrgixb)YJn4$+7asV*9TP}Sf9QI28^086!PiEjco( zXr((UQa>VDco+6k;$9H_ibvy(deQpVhBGlxDYWV?{W{I^-0@g_P3KP8)yKGSeBHB* zZvir|?Ri#KYbNw6jF#AT4`d34V*{>4p^(duZktUzf=(We5L4?nI4@CJ`~Bq@L542dqJcF$Rp-{Mei_v;L?(ug8u%4p*KyG=C8|}l0W-mU%^jO(B+!*PfG?0W566pmR+Wz z+lT9ES9!Ne?B$)`PwxgFP0Vg)B}jh|A=Wu}$+RrMvp_VW#iiNBx)``E$wY7uCsqW$ zP@;Y&$P~LJr4WC3gO%Y%V$A;Am!UMJrk+K4`Fo9fIe((&v#wMgTSTs7)K+hbd6jb| zvBY#mGgC%gI9)+|>yKC-gw3MdtZu=mDcKA;L#{jbdUwyW`{y)97G#7>@mtyLtlvYd z2qq1|Oi^CnX6Q{3I^(1PSjq`2 z;3WF#gP{55VNX_avgDW0=M{)((xTRFSF2nkTUSRJWGOeRvo5Kvs#>od?f0YiH1^oXKBcXiRoRQ_7=(>U>!eU8g_~mm zkyaXXcR)gOwzfiapzwl;*q@UwfV#3Y@Wq)ufB1m;1!QVs^GaS{;XL{(Ql)G@UE1yT zpkRJ>!m)1^VniW&vmoepPyyDKqqNFudX;1aF`Fr^PF<^j$M0@!Gqf#T|M~Mv6n=tFxwu3`L~qF=R*8jIqE+BUu0+R%fqK>z z-((G#_+{w}6($;IJOufReUsPWZ1y4!>RW0#N|H?K^>lMN;DGp0aAw<2<&VvK8V^=I?h(1cuU;!&ockKrAjvO%K+xkznL-TA z+e>2&&ollj9`Es49MwPJ!INVtX2(jz5e4b^h4m2GV4=%g zVI2QkvX7>UtonhWno?egYJ}$u=J{^QQmR@3-3r-hB?9kFD!L`yl-qSx+qjqHJk)Pe zim;p~Wj_2QzIE)Dpv@g>Mu(C|1D(?iMNB5`?P`JOiJw2Xs%)PeJ_QPeY(F#6{yYsw} z)tI)!vtiBGhRiTtV4$2d$+}~u?6nS^vziS0lk4i~*>f1>Q$xq-C6_CXEW+)1tGRWC zF4A)EW7wFX4&{#)ThPdjmOskVc8400-BP*d#U%c@?Tv`+#riyUgPvT5?(9(5EZeEV zRYBQA{f>7v>Va10PAs0?(sp^e<4=b!ropx1&6Np&3SF!_THg*^ z#yyHsr(26JKc+kBMgkgM;N713q_i~>4w3qexU^wLi9SDZoDv)0=W~%GW{eZuo_V3S z`R3>|+>VFL_O(;GW;ip&L?9GH~;s-3Fq{`d=Ed#kXt~&bv_SsiN@H)#icKnXW8o& z3O_wwbTg&Xqn=ZN$H5rZWX4%8??H~p0b+*QaVcw80{Xhb%L-btuhR{M^{Vd4=|1xC zV@`xhs8rXQf;ZlwOAKo-4=<#TY1oE6?e-_qN6-CQ#`h@&;Cr(bir(A4g!0K>kRnis zJTr@5^-&KzK_B%YTOc2tJHVyBs4K+ROr`%@a-Nwe`7~ZRN8fs$u=Q<{-^m{ng_vl& zb7xp?Kf{-Byz^o%7gzi9IzW|6WI3&HQIKcFv;A8jLbIccvjNlRJD1JzlJzEj#d02x z46RjXa0>znjQ+jEhp(tEqq-4kcfbuYk7keL!}G3Fjc4zHtaEbGg6Ea>{3UVzF?q<&0yZ^V>X-2FB$K&0GL zpm}Wx6;?e_(`FEFX(YBCdF+GYzkd5z>aqV;Kz7mXFaqEkuYQ~MczkM0-|rp}<$VYo z==w;lXQ_eY`&Ig`0Qgt{^eD^t3x|lvtf!rhKF0y2ty{LcElLC6igpYB{{rQIVWZ$j z4V^Iy!W1ivY1xP*7C;#u&#o4MUPQjye*FyVhZ23a&Kc~_ z^PuSCC1-Sw{dyJY$7ntA&5DxOM7JevCL)|)#A;-BRBv?VEg#7s3%tOFPnOV$EQqMj z-HdI|H4`Apo@zUN@(&J26tQKES}hAbv8p2{Vc5e5$I8U*jzg$T>!TFF|Cq}gnWvgD zXvkw^5Dd{+xU*>^h9-t*8Sz{*OoWAjsuNn6Fl_;9|G~+p!dYl_V#DLTn_73E?jLMURb5I zS9fikru$lim#^*qm;F!T0+sKtx`DF&p!@K8lAm zEY5b|b=$rv)u_$IBI$H7pWckJ^LhuUbq{?S9A&jhc6;j!+i5mW?l&GanH@ic&+^2} zSD&;g#4i~rvP2rU9vTu{RnP=ZfV}W?9VT*S4xb`_Wb6vl7)`GEvE6#%X98}u(zV@e zaMjm?_P!NWP=KcI@~#w*b`ndVRQfL00I3gXXE2PTq;g60m6>O~MyrK3x7!OQJ2SW5 zCBRB+7ROcT>^%qZ+8L(4!*h$>lk@qnHmz5o#PG9`{#10XQ#NcJ5{pL$PK6L&8@Gj{ z8T&XPaV^6rEl)qasVtTe65qgsqim#~5Oxo`+>P0B8(7%*W$>IWP*x}Mf4J%&2rkke zK+;^_x8I0Cs_uTL30s~_4I2wmd^0jKk{u%P^XUM-k7IBc7j(bM%bXY;{k?LkAKi}R z3l2`_eLFn36D~@n(NXtur1vJTxS~%cf3lrmM5BIXSmv$vtR?k^EfV3L+Xzg7 za()K8eDkOze?DV>TqAXQD}gk5Zu{}W2RS{=W*wdIr0O|c-88j=4`|>sL5?A&2uaGE z9gkeTY|GH*iSI1A{5q&f+p*RSIWsA&zlz@GRSi_W6^{T#0)Eb12a$z*hyWWTn*dh{ z%6MSaRMC~z9)Mdb_+%T&a~clF^JB#@Xn^Trwd#qx!OqJ6%9b`CtA324Gjk~|=Dw}5 z%RqR9vkG+6jUng+!APd2To@;VF!h%4L#19?MA=`6PNcxTHEp9NRuYorIB379GUuCvg5Hv4*rWT!Nj-J9xM{FH%eMnuDc8^F+vT^;bAaB{$BIUv69qV} z_Gvwcq&h!L%|vY9__;iK5DOW zbbRNs47lR2#$R^OtMA!ae_UiANPSd5KX7d@nz+^B7F#Scp0=x<%AO_NnY`rM>^<}! zBoTSq^I{JHK)e(_tbF0hFFk?pp;EJD;#|6PCb_A9Piyg2pE~JMVZ|)``Xv{|lc-{b zJKoNto~w!#TSY{_BT2+KLSZbm@D8pp$zLSrPEqU=MH<>b-zxr{Z5`N?oCXLFoRTf& zcd>4wvIWj%m3wr+E3t2;cRlEEnpFtxDNsa4a2Z#usABs6fcNKvya44gb&`mI0~fB$ z-tfS{7wqiphNAk98eyJoRDb^b;ne)_>rJ~i@#2XL3!>NqnN>qGQ$Oj>6v+==1}l2P zuGlw4s+5CVVJ+@S{*QQ+CR`T7b=ZURiIVnZv|kX4>T_{$f8;_Z&KisUBYPx!Jgjwjs_gl+*iu<5HmWUF+3d}Wo^jHFXg(R+J{oSd;7 z#NjVLd2TJ;A)@n8;5Qk*zX0Rtl05n_Fg;G5Baxw+^?TZ>=}7r_&R@quuw?ihsmHp* zXYhmka|HUXFgwKpUusyf8P|+^2e1E#YkPQnfqwM*MOgo^qfQjWd-^>&Ebp|sdH&q0 zk5I&*%KctM*78rI>Rl$UnMaGg;Q||?hQ{_7J(L5nGNMLRT!|zO6}Ib^IBYM#X(M{9 z`5q)AF&uWS#O(cfQMe6Tr+~A~5W+Ok@fs)uGxv~fNhw5J*f{!43ahU7)y=gzMU*~0 z8rCVmHawp7?SCy1)#_lv7*=}t$>P4yITam|ts9X4YeIgjqDOjf#k{;LGR2Z#6v%6n z!4cSTQ&BIBF4C|To}pt~JQDlJ!@|gabn&ca5N98KOaWuWlqjL3)UA!LyVrc2KTw4% zbg>L0n9!dr`HGey0VrJ@4x;FIo=*RLHNms6aeopFcEcFW+tGv zFv79##_%roC`0s`T^yWnw^;>(QsiEe>Nf9S>2{nuH||f{_Nf7%LLUiU>VB8}_6eRC zvg4coqD#-LsJ~k!41u?k{$IJ`Km4mHccavohN)=Bez;TsfwYE*CH}N& z2rDXLaT2zSOU4T!^Bs$f$D340rAV~gI(HNNKxJ-dWw2>8oFR8vNLU@s!ocNzl`~x& zYY}sxxf0I`sAgmG%0$ewqODSyVRUI_E-v!kF}~DjnyO&KhL#KiJ_guzu3o$(`);wj zTqVF;Vbg#y?%h6s@LCDt40W7Fyr|M;wb!!f@6gq) zK>KNI`we#394RqvcKg|~D!+$op-^ETlvOi;&DUsrMt5If48;==8lNAq9x`D*(ikV& zd1I`ad5uAAm9D(Z7FDFMG|u1^|Ljn?$^GZ@o4$==QfJ3amQdo5o4R^kb+CZ~3b!5p z-~vN`ekz6Z+R5_r_O@2^Z8H_K*-~9jd=_~$*iy`~V>L=}GNjMVpT!?a!sok(nNt9nTH6 zeMP(zhjr3f&#I!2Cs{cwq?^NH72U6&HiD0D+pyYfzVjjf1WQmU!{Fk$n4NEC{__4e!jT zBDkqc4MkD=8C#2Al>k(N0<?bEUzCcqcYvKrj?(C2!KUGa}s<&`PE4fc)}9kBJ@p?f-x# z7S6rfJ;dB!vXIi1$zA`5u0yZSuSge=DFRCLH2B6Tp!L|LMDmGAZEyQdb`5a+w{5k6ro=y5dQ%V~K`4Q>D? z0+_+u;FIUSy#RN39nsObrVatuEIP0=&E*!*!%C^<>mt^U1JI6a->mg#IK$c6)#91Tg%7^;;c|~ng&ClO-rrW8w zPj$9aX5XEA`=PBqrE&>u;EP7>sy5Y|B7AQ#O(nl_nr$`bF&F1~2?(y7I5f-={pC@I%8K}QFra5fT zWJ|Po!MwoR(q8teLJgLf!C6jl&hS;1fu69pCT6;!IFm4iS$$mjhUK}+jQa(Q;Tr9e z8)VX8GfWA}h(!gJ59gltxTA(Jthzj4Z|(^|2%_V54A6N>LRH%+8@H+jwz3NV!TE;A zH>QnFEAnte>n%1sE1s-*U_>{w785yBp6e?|VGU<+sO^?IGV?fj_G==uMRK4KQy^Rnb*AbrN z7f5VTGNXSHYPx+`6aDkcBJ%A;q^T(Klf8NtOErJH7w4V)KJe+kOt-;N~ zadp--30nvZY&w(0h37x-exm5XwZ1^le3>;L&-A$H`=k{P2Mp- zHy>*5zdmyIGcX9aWCG$dB;^$?>>#`e_8le-)=&vqEb;d!WN#U-rRflRE zEA^BgPvkGscVii^K$<$P8f8=QtJm^7HmpZQZNklr2aTFfrKbqh2@GbTB>Kb%o%~6Y z9ref!Oh$ZjQ|`Wt6YtEsfNfVGV&(`PaMc>Lf2_^Ro|4tFWk2eeJbi~4JYmhdVr1ZO zYy7$0!QsV9wddUR4|@4{(dB)0%?oaT&S3lf090*(xm-@8Z{}B)gu|$aA;Rd!vVBo} z0yp3iPOp5dCAgzeiYM~BDzH$bNddIKZ!!<6v*JFlXJ(Tm~`oPPRvM@1A%MqCP(d@E87J6H2W z#ih>I-u$}4o00PBkwaIwCvbniSXjmc$0@pq|!3~OjzO)0IygG-&@wEBb+ z(8b3+_)VO*(+wMjLpi_IdobRu(bc-K zv=l(95lL}kYqfcu`mM%j;w`22Wq~#K0-OopHl*Q7>GWC&JMiRwp`^B*5nW(XP?D1n z<7XDP58~q8RUgH|4|ybm}d zpY)^Ro7ql&ys32hcZo8fIB|Sge+a(B{_x)w$|8j(iH_gLjv61>mis%htEF?`Zr#jI$4<{|Eb3% zgN=|)EvVwBfRp{}sq9-Nzitz4_KopkcWVmPC3OdAH;QjleyPpU4QzWii@O`1N|5{` zU3)@!ze^ChI&mz4dzd3EV6oJ znUr9os(HY`ZxIEO0=10_2A~bbo>>Mt&|K+JTnWk#V*m<5zwLP4Cs|_AigVr{J8wx~ zyhUV9x1CjfFUY<>w?hv;A=L=GIdn%8U%1E4U}{HPK5CIfA>+D?vO%v&X~lNXt$z(Y z4gmbVOD17+Egy8KIF_}}+76E&c?5Z;oby#>4_MHNc#b)oSLm|g%Lztmf+dajpPg@y zy5^e_o12M3FNHLqR@f574Tm&Jh;}(BdI>hQqbls|@4K0_BrGL#WW4neSAnrFv}UiN z_r2HxnC0!Y1)3PLj66i-uiMTrZQ8dzFFJQRnyqvusM@H3S1GQ>E2D_3K44&wPB}#U zrbS1+b3|fu_1`I8x}b3gsZIecH{E}xcqm9ELA<%yRM^eO=ULESJv4ACn_#2KT{wns zvi&`CsEaU>7!<3-*~bAV!@cOAiW_(nSIowuWHi_VjJLz2MIQ~i0$N@|DcFV(W% z%1E+qH(TYnx0r$R%9abARhBjIly=#+)eIVg&0fzk&IrvRGN@Gomia;mM%uYhp*@$f zUWbR++rIuVuE-3b?|*+8+65>hQIX0C0(i{NWxek=!2=pBECleX{ClKQefvuPdz%jp zB0;GW9FSvAtsTniAW)W3>Cq~`=hJ|t7^6R|3MPd>y@Kh<_uy%fTD`6QT&oM-gS92`< zE`3f#VgCIgwjbpY?uoq_lJ0XrVWZfdWPN8zz^aS66}C`bz}Vmnd)E`)YZ zkuo9xk8EYsYnX)A+Fh4;&p%)V$D`exEEizu=xKAc??q^u&nsy~aXTD4#>~ zix4iD&Z@^A(0`@k!M4iusG6{f@+JF=<8xbcWH>7Pw|XfU%s$^OOve3p31P(;?$}?c zh$ACI;N^Jo?Pwsv$mU~7tCyvt@WHUbt;z9kczh5b2poAfO2)92g8*B zKA9YC0KTyWTGN3>fPYirM&=EohP3qjgGz{2k=T+_G|DT>5>$*314ezuE6b~e_Tx)3 z(21a6m+7r)w?T*blow09ZSd%Gh82c-dFUG|$O~`0tdVaP(+llv%3jvI_@EQ_{N@hb zcsRU*I&L$T?+X$g%9+;C3yyLa^4vGbhp>7LS{3l5ZaaM!l+gY?&#j<6miDcc1TFD(!$O1L+OSc4L6tgnoHqaX;*K}FS zZ}G8QmG%RjERDJRZt|?_c;ZDj{}T3Is?LhYpj)+f?WXPn@iU7-s%p{scAVe~ch~Jl z2#UP+1h%hOVD)^COzKZ7WM(DaveO`D;@e)XFCw?ZyIBvG{JnHX9qlyLdMwgDAAiGZ zTJm$KsTVi}<`WZ>4%%1_O4p~Z3P`lObraqSlu<)pbxuB za@^tS`Qb{-B&7By*;Xs_-7kz`_rh|_-3+2+BE$qcmcpu>1A^*NUcaa^es}wuDIp!Tk*^^u-emrc5 zv74}`-!>SP`h%K64LOo_@bZHR?^Q%gWiX^;FhQs@EZF>8 zv34%gIpe7mz}v$ZCWe2*C>)5N@1?h!)JA+|-OxG%+`clDAQ!$=Iv#po=BvU&u=GZi zewG)}NUpv8mCb`kkw8gAUVK}LsCOLR#T=A_f6m{Kzl0vg0p*sp>OO_#VKxUj;Syg~ zw2rqJU643H>bkg}QpT4)_2|o|tU2_ZQO=H!$?E+H;rOO89@5du^&{P82mABBLAr)9 zM@xZ8SkyixrB3Xxa;1C8my>nHSR9;nD%zFDO_ec4gz0)!nPht>Vbc1u8<>WoMTe+8 zYCtr2ajCxQwOJ;}eMivlc7c4q-G#l`yBarAEiz6gdb4Z0vsK`OEnsj-wCerbQf0m0 z`O2O0B?*83h7BsbP89xilFZF}kiBqNS|#vbu)dE55a6T6Gaowo6DG2|mavlN-D!7>B?Fdu?K*I#v>4kOD^R^zhm#Q|s2f<)1*6?LckQqXdHG@j73lcYwXE<&L+r=u zxC>yRY_?&zltG4`XL%Sup=|grs0WppEyv=nBZ)EjBGB!ZnfV!&* z8SrZ8n|7a13?b%2fXxHnJ`oO?DohD}BtGE5(+9>Z@<$Jk3Oko2GkfGg29^bIv7_=u z40RFC-@s{|Hpj`NGx#j=XB3fVc!*-phVU%iDz|U|w5pT>>AbB~s;9G-f8w`VFX$#B zgA}dNLNcg1oM%6Ey`QFsL=wyqHiTvBMEh(zyJB9=esi0a(Z7{CNiou!5i~U?T*h8- zfrR-)lq|6c>Hh8QQQxgzYjHNIi3b=x=`@RA>jq=~^hma;#ZsX%w!w9jz{n`J^Se<4_OlFwPYhRBAK;c_< zjimwMJ{|CF$(!wR&B~LB$yK=Sa2wr=zoOaXsmtWpoFduI7Ris3Ko6Fx!V$|gycOCM zqRo*uDptghc8ESi_^C*0S7RZ8^Xtcgb~`1NqI~MA9vfvq{-9mmLsUP;eRtgXKtacC zSh9{=b`cv}UwWDMQr+RYV(a$}*RB1L^-w(>o41+tt-9%eb1UVrXS|F!!3ie#hx3Vz zJVP>9g#35CwF1(ciGCRnw z3VW;CMzFk`a-rROPdbP7k_Xe~^icOo1NyvhU#G9vw5;3(yzHpXT5JA(f~Rb-LrIEf zj{zmd2jU~zG--o=$wp&hnYQzUwx7A{+Cl!p-h@QN9EHuUb}6H*}u7oG48AL=;+G z0Ya611!-EXh&%b>^7277zQ()#lQn)swtVAvyD<(3hQ4n99nX>(RX&HSA~cjTf~{zo zFwnI%+BwCP=1@nI7PgBnwWYnIf>gt@;lPpY7bjd=-yttr3V_`v54j5b3XIstq9mqP zIoj;Z)Y$&JZXnn9)A-cA#O=4_a5LuAb-mE|$A1`&O$lZWuM0%%?!f2$H--ztLX?ZO z|FYCFnhb>hk6Qa5h_l%4?IsmlpH9Ut>TApUD{3;Qx#EpTN zMiG&#QfiYL8+-yh^E^Jww;Di9VQ}MDwNUCS9O!k_SEb(N^qsk{vj~CZ) z3K@J1VTtT(AAB)lf_Lffx^D=r#!>5CrtPm?BarFTgB_)h*pCa(H>+Dr<>A8?oTVtR ziLT9$H9Ca#gC|M5DQT<6YG;tpA>=KRvlzcj)4G887fGI}IbwPrj3Jl_p4b%Ux^;6@%a zB}6o1RT4Qim7?KYT-SVR$-f6_sL#pt9+kJvCV&;&(G7eMH|v|_5yY6*ZkUb){t9GT zkfcS)fydST>gCAA`nA>SnhKOqsHx_zu9y0gm+s0tzokd^ilmOp%k4Z&>ycBVI~&ep zhOCpxW)ZYLh}z8pNiIKhjK+^aUJak2il>Fg`o$!lJL+($=>lt$utT}AzD|`1mI5Cg zaCepKgU)lsv*2Sa6%kq+VZ!7$?DU{~H&0Q-S}DN;7*xw=_S$-VXyi%GwCxH-p zuk1u>&M>=u*j8O-uR& zA@jSv!3qs!E{UrJ=<#>*=Z5_2_e?=6MBXABq&$p!jybgkinV!_iJ4@gG7V+n?=4r+o>fhiah6`NdMLogo1!VG|S(R#?zmQRLRYh*ri zWJV|8tG-N1=#{0hsJV(^H*EJLj67w$>(=Q9A(VK5_d)ZK8nQqNJjAB*;FLur;2m!E ziYmG$;C;U^LjO%_1p^0se01$y#`)!W+jRDU@q~;%ah#gt*?|Yup*};Vv4Xb!2Y_YC zEuVE>>pprhrWTk~+x79KVmUL596`jc>d3#n0M?8ic055~<%OX{B!%Idbqz3zGw&%tH?qMKpVyY<`9MmbG060Iut@r1AnPGWuo9GT z|BD#Ld$R7a^U9OFanb$~^7=cx&s2&_&u!dHO~d!!I4cRFGgmymlsix6roiF`0D$Z0 zqzG_{1OB5vSyCrG-o(uq6Oa2+S63z@;OsXBX7gY!cYiMTm0h?Z%}@Ed&wW4pQAg;=Agdzv(y+XguDzV+B-k}0!s+q zOrZuAW<-|!9~^S8viewZYd(Z8Yknm+*jHgEjgFiR>g7s%a_LN$ws%c}6IvOCKI~0@ zLOsuhjMBmB(@e49?ySosi;4~|!#=T=X@yerF0GrR#M!&nVT2;o=D%|-t*?#X;(sfo zKdV>1;u%-;;{NF(MH;3GhEaoj;ZklWw%5(;#?#{S0Wkpx^Pfi%^~IIWzR)kYa6eKf zkNqF0_P83?-yry3)xpu$;EP3WV+K5)f40f^q8D(|-g5=0AHY3uo3ijNP_OfB(AI3w znzCY~Nq4piRYc}4t^Xgk-a0DEzWW{qB?J@%q+@8L1*KyY>F$t{&Y`vp?MYA%d2iHxUru6vZ#O zZ5mkhvL96K;P~*4?JBUu{*K|s4GkvaTbZPl>j3# zYiT?j24!n(8A=FiR&POVJ4@hjx|jNn*Ac(e$r-0aX5^bybP{+pi;{o3O+`cr9TJST zmmSL%Pi&-%35-?WvCK!B{#eASfq@%3%I-APQd57+%iOfou2!~XW2MHKJX1I)6eCY6 zxk;4We$=R+(4br3w$^;zlpGAC?)$nKFqda zy0rH$31v;p8Oa9r6VlXONG`)Z@zRAW4tXXi|@CO?^mJisKH|5w554qdlb~vuxi!q!8KO%0O zj_LLItuelyH#RBxH`cw}gZ zV}?4OUkqDsm7C*s=SluPkmPRE51x-JW(|%nS$QWEG?x=MXw!(Udvrb~_q;1^qeL)| zgf5~h$|{8yuR$3qHd>5pu0(M5Vt#r>}IpMSjaYrlpUP z|2LQI10r|qhGNUN4l~iibJx8Yj-R8Wc|KZlt;+)k2i$0krt{3L9<4hPtTCxFei-tB zu_RorHf+rku=+jkW12;|+Ny1mv z6Hv`06^Vu%+}J>}uCkWv?bN+I7S90j+b88iYhgsISL7047$&vKUQY_>Z@ewviUl68 zf}`fwPLJy>Z}terpgf=VGZGr{j&+hVB0^geSKa3P<9%%m3xKV?bGrXMS zpXsJ>K>KN4sPCA;1)WdD5iSo<<*{J$1(}1~{*Nd6{4a0qX-B29HV zfly7~Ju3efpYiv5l2!fjR7I1I&d$!N@o<%8OQ+GMMXy~*1AEGN>{|DKcWl3g(d({elIQAfo9IU>WTk2!S3gj(&HYLkmhTw+IH09_p((7g zA4=lWkW>|%CazXyppyi`i}KA}ntR+--Bgpz@#*pholp;m6uf9Elf*WA1{y6Gtf8LK zHxyNLYo9=O(UXR{HD(4vcfMY?4{;w*SsX{|o9Y{LEkzMW&opmiJ8H^$m%TZO zy^cP^`FanPek0%hSilEo;cT0k)%!|sbUz0hN$w1ot=2BRSa+H>_h73Ro7~z2ziAn< z)nAS$IAZ+#qsQCv#jRqHlJ#<|Lu8cDZL{)?6IO)@_QL%ys1zb){F3+gG3(6yD@Bz` z3jXRgww8WYqx)c=#|2TZQO~T$;$3YR!HdEJav&r8`xwNZL+v{YZY5Opd?xU=&&z0# zS(^@`N?w|5X6b3Nyhpi|@}Yc!RNKgarjaXs0rwN7y6k5UXc!K_=t(_0Z6g-n(CYdOP@wT;q|{E7(iKflZUIV4ghG8!3Vs36Cv);}gyBUM zl!PY7^DPGpckhp__w7615iN9W4LJ6#ucVO@?`6sGdC=WhGk(giG#HE7ZCe@49r5^0 zphCavJ)$t`?%KI|tLs+OX(KI9rS=Rd>y+h1{6VIQP3_zaatTu+Td%|>4@`NaGa_3& zYN4wGQ!f8uwm0wor(oGOM{v!)@L5O23$5jm8zK~iIG7^?!0s}7kyqOr`Je-T{LWdB z%{BdZ1H;z7?HOyMnJen7hN2@(kp$Jm_3_-yOc>?)v(GURyzNYU-*`PyXKlIZ&1IMh zHl@FJf~OY{pH{(6(tZ_`s!<-pfQMpQk3Yhr7$;swx#a=Jx!G9}o`aDD>tv3>nvUGgGD!Yqb)Z&XS}lQtbQ{?oK8HX z;@PMhJ~n-5Nz_CdyZDZOdkOmxFlm=>a{l1WnJnju3bJ8RSd%?Lok^K9QIL@>25@(1 z(Wgx8ryPnI)0J|wIZ%|#%>WBvU;Wt&ZiJ&LsLtE|Gz%vs^V0C>pFU-AVH?LXGYqH` z6?#`zTA*+@fN!^No4en6;{5|Rzt6yfep@RW7TDCVTpMu z;M}pSmZb7v`+IN`+=uoMG~``3G554~^XG1hyqE~huwjy|E?JH}C?&1mc5$SkQdm^- z+YQDz(?}LkljV-Ryw%1MXNVN@+nUY+AH7mnVjia0ycCK32jTAH`(_3{&__3=Lx z*8}?U6eo(fa(b;U4>=~;bQWx#zDDwD!*a`Kh3}OYMw{_94`bwbYzwMhTYS^%FX<4P zI>@3sHq(9Y^>HHw@q_RFWgz10UQ%rw=i$#iiTCZGZM|^F)_jZ4l zLaFzCkt7cmxk6Y_6?USNHr7J95GR!T%az5PgS5`>cjT-hajM=>`U^{O4g`GkUH-d0 zNZ#X|gpXh}aeB(v?Q6#NS_Dw}zR1i?U*EBwKTa_Wil4F1Kh`{i$EL82QO2}eC2fQE zzI{N7pos=)U6ri<4vqvN(+AgK85;@7U{i9ik)?kHC=NIzZik%pZw871TT-jI$b*06 za!|#miOFnM97=q<%L#ISQLk=Q`ypQD#Eb$ttJyI>15&d2C8D)fP!qd!%1cR(vb&23 zI?72V8@VkQw(oijI!>l8bJ2$e+Vj-jV(cPfo>0s?j=dWMUAO)kAEspm3+tVR$`{!k z%aRYZ(Ztm)zEcXi-)ACStW;uY7_LLinnR8Csy@jP{Vcv7GyJlFlOC${@eu3d}T+ai-qEc%Lus29!E4KOUqg zxKXV&7B@1e8VH|145I5k&Ik6H=tF7l*3QLX1**H%gaKK(2b}NCB-NT}=H`@-%jh%p zwLcCCc~xhsXxy4B7T_6{N3sYt;2S94a+_KOC@xQn;;}W-I60URhz}d(mHiAOB+tmc z>-aPW(d%OG(8C|8&V%f)W|SG8kKo}r0JD5^50es&hjguh8Tm6Wq!Oz9R{KkiUCI({4V6RMu0!Q_&>2q?`NPxp2~}qYI9@l|_=^Y5hpxt*Y?Ga&jHD#H%suSBmgG6Oc3fIXPH(m+)-U7-aEp5IyHpcE3Lf*X9xw4l) zV1jn3nt5g%l{2Ub2*+0BFlkB>@P6Om+MVl-AHD9`u)njL?o%U zlMmx}_ zDoL85C179GcRCLWneRrdn|s%RgH9vW>)w~snh6(L34uN<9U4U2UT^|OOdd3SPIm3I zNmLC!XzNd8xyZh|p_6KG|Ea@Ama@~`pW6l?SxeE#_u)wt;x0=yBMWYr==xL;-63`l z>I*oENx}I3@z$Y@6wxr1j-5@#c7iTk)2HJ+!;d!s*d(avuItpMm5aQxARg*%R7$1M zN$p*7d*VHJ`x}^wUi_B+nc#59!$QQH;C9R3eEXlC$#s5+6=O4djT)vG)v`HrHt!NJ zIdJWP1uMi}9U`du$MbcTlP=#CVE?Z3_g9^>9%XF=8Tl?{9%I`VlmW2ry?UV)-{4w% zY=F0A8kS_uT+1G`TXYcPKDi`g%_C{Xd-z>JjDUXRNK+iGV{Re86-^3a=iu)1WgO)g zpYTlWdeU&h6AzaIlFh-Q=m4SCuZ`I3z|A=UKQ&h0MlGN=ox$dOL(5g)W^mAFT(hfV zhi28Cx12YRxN*CVULAcs%JaRgl!|rayPNZHhQ1Jk0Pm6NztxZL`D4#c9{5r&Jby&y zh7K2Q(xMxHMMs`**Z-J3@BJ!Ik-q?}^X096bZ!7&(hx?X*VLww@+}4Z}`} zrz!&x4y_HFDRd5S3W8?|XdUDF?ZNs0JK);SDi+_GMM2kq_TjGg7uRt?V7xH&{Ov;L z1tFPU1#lk%eJ(~om_|9xn|@Xbo@08wsQAseOvJ`kgv{C)HZa1*{S43C8ya}vJ^mcB zE8_YDCE%3;#e0wiT`y#w5Bt24`c*>{YxC$%W}t?x!{(Or*NnH7K6Xq0I-b4g`CL1cdsLrg&;zu8I$|sV(@#(G(iau^nJFDlnc+E~j9MEF}!3=rg zZlg%41!bK|pRS&2K zHl>&O9=B-ypGn|BZ$TGEKDH1(%mx3imNcu5?&Z?jF8b4dCmRDl2|rjFy;-*x?gvh{ zUo+*}nK?N|=t_lVi+=umjILBPp^c-_aNm^2FdT z|7ax{pFs9LThV#|@-Vvzqf|7^A;+**fAmL?rT4%BgMy}NFdNt~lHTIMUe1(0;V{v>|j3vz3t zWixuN!6_)@;Dl66Ge^cN_2nWc;O+B^G8DnaaExQhlP1!2<-B(ahq9?HjiLB>igu72 zeV_Nw!>AR41}lcaz6mr(HI*GFa!$PS#VAqP>jE1}7A^lHg~#DRj2J zw-(0}>j<+>Pu9C?E`{!W+e_;knDoU2 z+?@i4z(FVA9^|e}IeDYU;e0es7sz+^$vw>)BH65WY|*g`{Jm;e7oZffwRA#ZPY3Qb z>US^69iJ%}5dLE#N|d!Ue4sB{)?a{h(`&dc>w81i%C-eM{7QGXCpB+>a`mtnrld`k z?5oQbr<$~ox^Hbcz+^ytbJ}*I-{CbvdS%a~SCdn0rurbUh2^rU%ONnr_?7^blL2kr z8JnGVx>D4_dEw^NTOc!#9j8vq}f~X{;Q||9V^HeP?PO39*OC8=jdkIY?f{vD!t&qjY8*bEc z$9YQ}&;*7GyQelD5QdN!${Bv=lpL7kR*Y(< zpXFFCOJKck@0Y+DL2HV2yqnoDoiY|Z}h+wX>h3xCOqY1d=A%({GbLii-1_{Qe9{F}IK)rw(KBSTs>u`e;0#PUV^V(qz2(#hgNgK~muN0XJ3! z(9s8md6|jl79Og|GVG<6hfx%Id-^rj2eT~{0Una%;}xHb+ZPoY%W|+k&&A8NK3k1> zpC=!2Akyo*YKoP|)v4NgeSHObuH7 zSFbFCPM-8!Adi^Oorc-)ucWMM^N3K6KcJ@TUr__z9uRlj5)0yz9Y@2ZnX zQb7@vgHicDtYE;_l{V2m*uF>}hPuL*yrqz`ECr!^J8YI#1Z-Hg&3a=cKice+Nm4NZ2rc{mdlhDKWY zdl%fW;aDQ@@72Hdd>U!R+9_F%Rh;`?w(z|i6n6Jvi&;;4Z^@jG_mcQdBv75rVOpqi z+$?dRNGEq5I#~Xc`~k~BWrRCRod+JdMa<1|^A4RDiHeoOx6Oz=>wC8I zMrsIp+MCM*8|}#A#V+TwK;2~Sieq-=*@7y~+HBSxvH8Z^QPCI@q|B$&+v_)Eg*E#? z3KY)$=qNBo-3vnpm4#TA+#;cOn52k0mn%G-uWjph0KH7FrHc(kbII;N~Ks&jmb&P^C8g+G}Ou zx1-qul0j1t;~5S(`?9yr zd5Vj-He&UNy;9jdZp0Aqy|2AL*HC7s#J}8bKeB)->t`Z%8n0rQPD!6E$m%F8JlK=2 z1fhkMdhxy@k=)aGj$KGBohg|cE8{fHxqbjSGi;wQvfv;3cu~dBXnHr zCjc1+jjm|iA?m38lg%PwRnueaK-QLemgk6!5&G`z#EoKwxxj2Pp7k2jAotx^F^T2pfH`{b;nw;5mMAo!c{YYFKLJEUwsaVw4D@orhI zbPnFzR>m3Ip22dtG8v$n5k!|qPV+Wq&VqVh=7&tx^cDy9S zWwHGiu~JcLM%xRc;H>`&g}?9cBlH-mR4uO$Ju*O>$I**=EBvTgcNaOH0-dSY%Mwg8jRM9&3L?u4C>A$7MLgV-@05=gTC;&$CzBq zW8IVx^#T#%g>_g&B%B_7Iu7TuirCq-=Em*$t6R+v%YT_&O>}Hvx%U=~r^E@eqveg9 zp*YvCq5E<77VrexowKD}(tBlQ!pR;nJxcPMG2puF ziJ3SmaaCY9nA5m8fN#HxT~4I;bNzA{LfU&(O@H{<_1jk9y)bg4IAV$7u(?j(cOy{V zFHi_|eSl0kuE`f3hk8XOy03_+iJ&HeS8F&hMtsB+?I(`j56fGpHj-cd=tL^`O}$iJ z`(?GTd7$9u#c~yrP_I`+Rj+*ifC4{kP4DaFB{*z;_4;^qj545g{iE>O-H*S1LxyjU zA2`M#mgoLY1A`6-bhzYMNYMYK+0X{0wWCicPG-t2F+Qj%wYl$)u`cdi_@g)D>fa8E zh7RQuZ=h!gdNk$JZ+t4koX046VqegYI7=369n7T5F7A-xsTpEs?4uSW92xy4&jIx_N@?U57{Rtfv?E zxbc;Y0JmH)<-P0dcg8o2T1nSvaRp7$_5wqT?D@KuCO66oR=6ZUw7?#(yTU$$avc6O zejKJocAuQEJd-Y&;w^UnO3I=VraX?kqBLMCll*Ie z)wu*GLw4aMWvy(~-Yd5Gx!S{?h<>kI)5yODKxf}bcZ&)AR~MVTIqC?Xf{p%}24UP| zueSLX{>MJ}pK$mO2>lh9AYar%y2YVe!|mrOrkHZ}kn)T^43Xm;>&Usd>YxHy@*KFs8b!Nu1z7H!V>N zuUa5`#t@mR~nr>+!8CcL8W0S;;E3% zfuHwZHk*j5%dO+l>vH2me?0IIn7)cQ4n|wN zsE)3)(wz84Au^n7{y_JZ`}Ym;FPxiAxZYp+2#qbdRHPKUx9}@VJz7#@OJylUcJags z#DfJ;v~8qwJYYkg&2F_U3FpAa+s$u&uk*IIXtDPaMe-(0MIJyK#zDpb6!+#=@izyz zidIHJ_ax*W$tUpL&xbqb?$`S42d2idGzxFNg{x*Z-RlJ{moSd1K zoLkm7>8-}RPp&cwv?G`^Gv)FbZ<{WIvV3=az#CppyFXZ)P~P;lOeNWAYheyjB;A;@ zQg0?}4Fi1^8*VOJTlXzxxR4AO_tH(}8wnwZf8*lFVvY5z-tr$CvWIm3NobElxtlG%+4v~S9&X{6EBy@|xh=562`9IZVV+TZ=>!^7tl$ouNf zuRH{JijNE#(NT!^G~667>UE+jxf=!MY%k3=4b zF*M+WVkJL)xTyHO8@g3UNs5wy9(%tU)rI` zl(_WJdu5kQ9ov(H&%P+cQPjQE+K|$ndYG`l2!CFAFrz}LAA`^}P;8X9(_rpUiqIa+ z!omf~da5Osz8RQ&-)H$QgI$HP;JSjwsf3_5L7}SUiE)?4sJyoNtEXQz&9cl(`lJQa z^pLwadC}TwNkp9P&Ocj-J+z3ssc^M3E|r(2bt#NRtD?wfaOki``LJ3ZynY@yJK;=* zvjOd2PuLI+o|t*)PDC^5A@V0nfX8drIE8S++sa88je#m?C|olL-Au}~w5C!_fBo2NI_5Kj__ z4oQSDrkL3yEPJ^#a)-tPzMQr0$s^H_rb>?)sr&GjZQ{&E*v|LORt#!Ne#Cp)uJI?7 zq6k;p_}!DJpJR*qU-_m#vU+@|+I@dm{+dVSpiZ6gO+F0)wXMrWtF$DSoR^lUCFkxm zi@pXieNe4?Q+3=lm+;0;u{WE&bU-)dy&!QnHO&e@_F!?7kSp`@YFOkxy$;m9SYK=!biRd9DRI0K7G_RMF2D?knd`8!_{j1V{R-@wuNye< z^3*HTzW4I{PHl4j9wn-u%;90!Z5#qW2bfyA^gVGce?iPuEG zjmdQ;iowez?)=k{5rhC0=P_B4(v%(I_xgHu!?-Wzp)d%3KYK;YRZtxSC%WH?p0Noq zEeCUPLgF=!reN(lJh7pD+(Q3nVa14*ls-x_vE@|=lf^gh?dzhTgjhveF0G-1fEGJ$ zZ<-58!3Ds1-(9G0>=_jhm=zaaayDy57RIi&P?{iAkFam#r1msWn{RMcB!3SQw70xv zJF9L0c`4HHvUK1-&T@*78h{C^*B3t?L6W_!ul8V7lRR)PPI*Xukfou#$@dW*4PCGG z{w9t8y8NT(s282c>FDTm+0iFX1U6UU#IXlrw=?$wiCdhSSuc^#5W^XpvRY;?a1DhqWzbBpFPVtytkAb?Q?g^PD zr>v*fZ)l6S_B`oL_N9`W_zB2fWAsxkxlNxk=Yu0vB$72~sl|Nwsnv2+x}in5dyRwl zW4-5U%US?k1kgddw~>f_xJYU_JzD9qj9q710lRH5ozH>=p6q_}^OehIA!$dpJ$8^P z9p__fxHh0nx z<6S@u=c*o=olQ+EV_VSfMx^7&wUvug=uGp@#Cf5jkubLe&ghUf%q0++ZCr4keN_uq zGM;*v*SSmUxGnZHV9sYe9ekhDU-~^z>F)DR2;yO_nbG_L)6T$*$K6mr;AM9`+z1+$ zqPWp|B^o8Vo}SfsU_4MDKWLWoo}3iQ#W+vTv9aDB%F}TOq$=mh-z28JGJ39+vjpE@ z*AJPewu+yEf_YDq=2pu;`1)=98lq00^`srC=QLJTp~u{YO6_leJGq1kOq(HiWlhjQG9W2YEjZ zQ7!N1LfTkeDNK{g7ak&7=X*#6#6Wkp^)VHTax;Rut{5Vpg^?rkk2 zIyD9%R9!Cqhhx?S!H{?agSplc*yPQ(!G-Em`Q^E;_2$bDklu6H3rp>vG3oIxUZX6Y z|1BmYs0`)*P8nElp1&>Bc&)Eb(b3V-c2cE8?ra+A#Hc_?Den46j*vcdZcb0}S=qw~ zX~q_bEETb&EQUvYYSK)3;SOUPd@(2hz3;Vw1bogG4s^+d-22@sVs za961-*kRd}yLXi-qS@Ls)xtr`W@oi7mJK6QT^!7LD`GL9%Vs@DfgRA^X-mD* z4F)cC+Z&x4Pqi2?OR=DE25VO?T#nz6e7Y~VeDynIER5maMZc*KLSSx`UH2QO$Ede& zKealwP_bu*yxBIe=n~lj;Q`Age6NrtgO%QOAlg;QUoPr3zEnoaS;qn-DTZz7zRI)~;ygT7MHZbm;g(WwWmJWYaQ8V(Oaf#Fi$ z(8*nQc6q6uHlf>HN~o2urcqv6G7&m~AIfk}a%Np>kXrldUkOE8;+>zzjPkKlPA|KjerFdIKJt~MnO4dt6fi~DcG;@N7i%OWmP`&nfes(L8xLsajh!9JP(zfv9VGpW%^GxkT zxl1ifOCM003EInVe9(`)IUZDpxmY2)KdocS>A5k=B-8G8Jx#x^oI-DBeQgM8oPDwD zX8LQjbBR#S%K9;k)KPuuCMZ45OrIF&$JQTTI=`lF08f!P_^QDcoU*b71R@uzja&2 zI@p9Fo?i!cZ}J=F$vh3uiyJ%eM;Cd9=CcYp9g z|I4RT(r45hnYD$Dpt$#=q_gjW>b|r7REP@PwVdh!GPfR3*Tns!eYR~Ew zc$rUj8fTkT>ZkrLO);?tsO2wyei{XX`W;ZELu0DL@r9G>^k_}kx-P8rHVu{#Q`iaj z_`^+hJa_>B;JSPR{umg??&?%R`eE;4QAo&ds~#KBrq!aRyf#2tXCy$N{wYUy0s{B- z;x#n78@8l~w6;)T!*E|uYuJvT7B8A|vWb@|fX>S7kK?UyLAjS|a*uH*|mheZ}HS7^T(>n1y2hyKbV9HwMPD7+EWUtYjGK zC|QMVa%JW5^N2zpFqu)K3C0KOjP+P}n0KurAe1@d2V=@`KfN+q^VyF6#RWWcWqtt7 zxu9}7G}f$l=3ETrQp-+|79uivE~nS^3G&2KH~K`wa|{3J8v~Z|Fn0fi4ix{1x7#6e zrA=bXmsobIOcr8#S9ncm)naRqWQQe`?7UsV@}H zcgI8z;`7{h0`!a1-43Pfz$&zNiYnCi_UJyu!LA*AwzkI(FKz7(mF7nst4pDyQce5- z_`(?h_qtTs<@u+5{TGkH@JR5rW1N#vj4`i1X~2KlRV7S}Z4d$j_kP|76CDjg+J+*2yjJRaALuxCUs|Vc>!U z9JirgF*M$v&+>F;B-n*SxI%U259Ba^ru+*?J;jEFzsUdH)LYl@YZ)68c=`-kb`@`l z?h+9`U3_Zi+7CW<8?9C7t#G!ANT*Yb>Vq=Xxb+}K0ce( zx_H{YskynH<-@!lU*od;QM=*MFF4Z?_puyq3ls`b)&7cOJYBo{rXosjHc8W2P}y5^73}kGDnWx zV?v0`gX-#PG;2l}UJ^b(*VZ4)ET?24C;2?XAVr0Zc}E7F;A)eGLA}SOx7F0P1AvV!xXtr{1z z7o8j&q{Z@hIZ&lsHnfafHZ!!26z*lo??pDeGTi;{GS+ejgB zP>NZd$A~XWjVVj*bK-DOCSP4RPRg&IWabYHcn|AFgmYepl$|71e|$629N#kOsY{R@ zTc{9J4ta=9v1 z)|BQlJrs3IuC*68v$dwPy6W#HJuhNz&D!hg1CQuQYYCVt?dO9lBh&UjNf&gh56Gx9 z9hLhu?^cQjd0yd{=|Ux|wH<*s8pvqp{t`&45)phF3$}M#&bumVS`o}D9=sO`p4UC? zG?qxsV?>e6=els#s12Mtk1ep?a?9HdwQPBlVsyMzC65vH+!D4_zSVjbopwK_JA?hT zdv|DI2F0tEf6B~4idJBoy?;#eig*XL8irVPMEftz zlc2|rR2nI$h!1F-CNydDt0&~ixg0v!12zdveBCd1>fJZEbZ6CBjog;Z?;&pA6825y zslVI0Ped?Hg3A^9uvGg$;gNpHWixRFeX67^S3b89f-rvpYp>TtYxWUAfA}8e_vMmZ z{hDQMt>=%LUV36j4Iw&oBOfG`Bn)^gg@sOe{3V}28Z~izy5Z%vKafGD@)4}ryqK`& zm{nflumUgsrJt=`6HVYfICBcx~tT7Bw|7F5Sz z?XyIcr#mZm*kofWs1`vI5sUqlhPJ~V3J~4rJBFHs%%Dr`sHKyZAVAT>9?QnmQ}!_m zXs|Avd9U-nWYY2BdL$){Qw_J5)b~V;&A>W#*7Z`apWY{uKWdLht_9@_K7L&ZhQ^%# z0EIMZo8C1&$lkrKB&m*BXbWQ0bMnPJ4m!b_bI#JPA6+mXg2jG2mKB&>IYeQNwTz|t z9yE`?cN}V{*duaUB;BFCX25BUt3@Y6pZ}c<%N|q3}P*4@vH3apcPd4TRVJQnon? z3rcqP_-sqll+ULhOB~8vQ_Wu0WW9OqxLoJX`HPSLLA_L>H}`Nz z<;V8Sydie@RS05(pVIA6FXk7vOAZFl~U9K?YiE=h1j#ITNX*__UbNapU%F`BN~ijoIO+c%jE6BFhw@Q7Q@BcQsxUxpm|ZYP-+{E0E+U02m4by4i`c7vKU1z zUk9o3oP7=BbfK7cq7Aw*k7dfE6*q9r}x>IIoTkZO6kM zIPR9{{zndfih)(h(bU>H&&|P{rc{V7hJVqNZ}3*9_bs9xPyrzdMbm{DDkB)7XRK(( zh+=XAF>Pd4E{6Vbr$a9-91NCZynh&Dw{d>5ip4<8l2%gMt0wC&Pn5ecU>8C8M|?|w z_g3~*bd$92%j>Me0x#JW%`uw}b$hS&Zk)dt4|$>n~udM;zh zh12tWGdEFv+I>snVt+p>JYneP`WN(Z4Vw9rJg5G0v;aW0nyZs5y z&xe=uB;iG*$2javM{!GHE2XHV(-+S<4Q6C==~_QWIVy)kbwmgc_cGnNNZ5AX!j5U+ zVFc!*`25+I@_|CxtM4;^a`G4MifL?qylg&Oote#!O>0+IMap@CuvYRxPu&_J>xeIQ zNF9vP@lsVCev~2-4*zD#cED7B1ra(cIQ&S5ewq!kuM6e`3v8B6x@W-tqSLpL?d17< z?lrL*;(`5{=7lKP$KgQ>@>%_6I|$O=W);#$2NYylHl$)JXiqoB1>q}lI^gI5e81r1 zSSafm&#rG|kSxjDs05^x=iyzzc#GhbyD^fJ8Vde@WW9A%lwsE|Oe>%uAOcd-DP7Va zohm6QT>}V6#~|GZNOuS#EuBMmcMpv;Lk=(u=jK`KeCK)JkAG$X18Zj1wc{6iU+e;Y zWy(=jy2;ZA_K37Pe!pPYo#J;NQ9c{>c!8H7meVQd#j zBu3Q`P9{R^n!38YU%z^=3ID9!T(6{`#Zc3Qlhqb3-)Jc*K4MefB%N1C@>TtN87)^L z*63JDFZYTBo|F+yw7ojZ-Z`MQWV$@Msy4TaMGg20>Yf&ZdRVP+j+%pZ8mCo#LPIM^Wwdt;b>D31K!HWS$cB1zR^C!pkJ_%4`GQ*ye3#`S-Q*~q`FPKE{4y$#W z-Ruk0SQ9(HKcNbHk1zJJkHY2I=(}Bt!^R@^P5S>Sk-z!+A3+o}0`x)tg@ud&VB*j% z4p5Vfo*VmU<#%Wpk!ktZa{Mg7QP$JZ;N_+jZr>wL zgi^PNcb<_z?_ceJPwnz{zKI{r3R79B++bqy#qQwD5Rw)fz8Tjb7@#0-pCra*m0C(g z67TgzoJSc=oips4S<{sMe(x=}Y;RT>a5TAYH&$4?Ui&LfcS0bJd%`R3NJ#%e#*Rtd ze3S6D6Hy?LqEr=Xi=o;%M-?$|-uNnBL2AmM zLfP+)8IZ?4(8LX*X0X`)I8!wtnrrY_I`_7D3&KvUoGSgJ@_bBo^&TQNEK?!Xm;*NV z)~_J`YIWVEWS5{--KV8HI80@(xsTQtey?>Fm=zmu?9WF%{RtTwju!_nv7tWyHMIE0 z1OZYp+psd5h=vE|HIxW?l{IREb|TxCDnI|IG12*YSVvBHo;fL^24YB*Ru+7?(tIwP z*+;$W(`arAcd++f@3c{;NwqHbgx<%EP%57;>2ONQTN-LzGR54`t7Z7;XSNcu(u9*q zXYclq7)K$veWrhZOyRTnG;%xN<|~4{20tVxMpKHslBf3lHgfx7zwh?)!08U~^By;! z^w!xgHO&abDXgWK#dKIC8-}QZZ>P?>BK}uX?GKQdfYpN68^DSqBO?IsC1(4udkyWu z#(#Ki2NO<=AHULbCLMbWf8K z!`HK))TWS+R{ZU}Il9aM>iKN(+M9r9s_vZ>rE32dG$q3xZfW|30Ed5s+bAM+4oe1z zs}V@(tgQDisl6T5_v*so?zLGb4lK5qDeYIgj(r5#1sysKr}lRGu?`}s#6~+2@saJ0+q!QQVFS}Z^jP7LU6|D*Hluz_GwMHs&wnWd zT7J(jI&Lmoh5D{T#EkOP?QofGjPJxf`+Owmk+1u*pFP}F$Ph}dJxS$kk*0zXRd8BG3`-o6XF{pQ0aJQ}K0 z+|Q5Okjm#QMi;@hOHxEj{LKUQmpJgxVeB<|Su)Ca+M9E)=Pdi8SsA`$+NEIeD|p`elsE^g-JSy9YzE+RwC~T9c-z|@&Q~?u?4&ylFeG2Ba{sTM z%A_d&19MJE2^%fpKNcmHf~h?t$jg5s6$mP**Nq}d`>%wU-qs=mP26h?47U7l-@g46 z%>sx*K#TuR%3-Z`T9OtOJ~#n5hcaCqsdc&phYqPt@fnmcpx)37D;6-oFatUdXh^35fxuB^RT9bC~s#8hl(4Do16Ap?U8PU_}^tA!_#YQ=pf zjkQ|R8L!_RQ=bpsSH<@B>4g4(ACN(8Uhq<7K~zR4N$5mHxScSxesglerex41SWvj{ zws_-z6VDZ8^U=VrnUN}kVUsK8G(3*CE8{$jIqoE&Z&^EipXJ551yS(FT6-WDqSTjj zAty7r+)4=kC}Wo2=AA?*I%)OMEycm|b0J@StHpnkN^titzo>T*(qEAdOU zv@`TWiQ8o?55{hq3O9mVQ6~w%>Dw|HC*N=GWKOxTWtTBAp}m5HK}L&bq+BTZa?#TI z`ueioCy)p6EZ?gIy(U0y{U3Sd5W~7GZoqteVS(%}T}quR0I63xjhO!H4qOtwiO&q| z8|O&WmQyU6dVcoEK?yH5&#nPkL^JUxD#{ez?JS<+Ad0`a2F@O;>W2Xt=7{$)l8Syk{j$ zPuQQR=dq(*t$whrrzS4huaszF4Lw-8%J*z^ogsogdFV^vSMip8p6a{VoX2KIsxL=j z-P_@PS97B&KOkpj=0Ul=tb1fOgOwgr_h z)~#P!`UL5yQKM)NtAq?O5=?gR_SIG^Umpp0X3gKlMG=#eC=F+jXFiymFo?)2BV5C& z!yAYxGdPi`vgl0b6g7A!@~6%`7;R$BC&0ol*9WBgeNdp3@7dCn_&-rqpQ{sYFQI@v z<>W|X*$u(IpN%VL3BTyv_sIXL4`p44^OeS9$8i9QU3b^7!6ZXz! zoh!;0&FOc@ex2cf6|93ynUC&iQ-MyM9re9bLp${*$U9#04SBE$d@bp~C2c>a zu#nzr7f84kxv{;!l{5vwiC=iWj^hJrmpAONI&h?j} zMl($hl3OfQgPfCJI#)st+jtCan4wZ&-?NZg zVd9KxX!3nkUF}r4r)Ep_MCM{>Q-=dN4km#>oS#alAFCc^QHNz|{Q60b@BLw;LJM&$ z?%(=~pm!kXw!83cK8ep3)&~SBjQyMk22 zBC>xbM^KwXyVW-$%tN{vv_C8vA$Gj-eS!XafOMi-UT5s9#qq7Vi>Zo%rTF${X=f9o z+sI=4!f2iQ+t&Hzl{IIOg6O5`VWnB+Nmfx0mG|y_=>DQR*nE1Nj>~s2Hb-+C!v8Ab zGh)5MxP2#v;rXe`X(YW`hO<}SJSzp!2T{F<|sC>E8G| z_}ZF|1(%u0`o8J25v#Thh2&v@$*Y-Qyq9G!<}#Q_M2Waq=N6w*ubgWv`KHT!xvlP0 zhPKgu^v6~yezSZl*OTdI8b}Ol3c_k~WG_zHBm`4#>d+%kdkY4b7$>^IJU%0EmIYON z2cybVaX!R3+naKkRVX4DvB)7r@7T8GhF4Yj{Eqr6N`>Ybc@+@+k$E$WxsdJ{5?G8}>j zV)>;4}jN0C(y2TQIe5D2%)77HMwf`R>5Iu5*k5_it#=Sv5N ziEF@dlg^eW$MufD>xZ>0~CKPx6KrWnvQ+g zmaF~to!=I>JTvb|0ZJ}{47nQCD~jaxr3(+wM`qceOWmX8d}D5_HdR+=CjDb*ACHAb zjVQp~kNZqX$6?atKqQr;-1$|z=IvJ`X%(OYIfo=HQK(Fv5qZgU9aHk*kpo*s7?7!Wp^8A!=)-T zQkEi0Uzi?#!t~Qk78Pg-4ROUUEM~kKE{b?Z1()m%#IQhc+4IAsyj_oU7gP4cPmGlj zfM*rMI)2^y6NWNtrPfNDTkxoQlD{M&-mvdBKB}VWmpl4B|Iy93tx(dX(##me{x^PS za5K}&z+-^-RQEB#X4twRIWTL47e}YSi}8B}49UVWd3j?OcP&3y`dVF%Xpz4PCeX-M zeC}@FAy!@M8of-n6<*d#_t6_^OAZJ+r5HJE46-`B#ZS7hD8u637xhxo6)L8D|%Eq9kYQ^ej;1>Zm07tef8Af1>U?|}n0*o7|m}fQV0jh!@87?$7DSQYv{~Y_LEa&f`J-4xQ@N4f zHF|QaiPE$*62EW)#s%SDrtCa!9HAwDjvtZgaF^AaL{M3^POBtpaT4FBw=BPd{+cSV z(&AyH$i1+};h(w0oM{kGR-S2rB2xd25dB1J2b`21+aLIaE&qMAR>ilvPg5%`{}7Dy z6c|a5Z)D1<<~kGG5UH|UO;Jf;(cK7goq3iMF<)Szxm>i6bKdmbL*V7FPI7g&Nd_KH z)$8ySy+(o$MsT$UrC1^wc34LkqYaOLq_N1y@`!g2GXHR`nR6}1pt>1LQcc^^rvj}rc0~I+z&`=|0VgK{ zlYa78X^a%4z4_#zCzx9)uq@>ckv*L77?CiC0uGi&vAY_53m=+uNNZmPw3OowY>o~| z3KO4qeInv6M~EwWl$+^tU&r_L^xcZk2@~&liYkQf^Y@Cy_FX$!iG}-@Jz`8AE7pjA z9}%TyX+Bc1$r0H}aTw3j{iQ(NHsY!X(5uLa$i-cO#wUl@EUJAY!>JeEiRAe1DPt(bIPHxWCQEO(lJbWFa!N-|Z?|>z0mQaTtUFM8foO z(Ugq=`2Mo>%tB`~FOs8k@|QAD?l4gr)|aX`f6nVsMAZ%!-g+G4km}0E)%PWaq{td z#$*BBo}}HE_je*$Xnb%|ku6qh$c^!iU9S`g5!|aoP zuMgcVI|;sSQ3?Gct-AGsZvvf>Mv{Q05T`eq0Uf@S`y)Q2f8~-x?G$yx58v7dp##7go&@+xqV=)h504wMgX2#woEV#h zUBuR3?&`!l4q|(#SIG;@NYwd|l{Fy5)wj-6%_|CKk#~v+5nAM0nvPnj<4#@wbIBN+ z=c-g(j2OJxOZK!OMOW6I;}xby))2R>=h-%kw z*@j;5a##yK*yst0T9!LWeDuGklx}R6mEX7CO{b*iH7ciWGQ}9K&b(F5!mWE-yW8{G zw)qnR@bPch5yR5IEZC~O)RVh2fq8GfoC>`fE7>UtsWg+}RT87ECRfR0qkgr0l=xh_Osj00F-^ubQKIjz9ZmrMkt2f6{IbhDvgVBeKuhI4<-X6cJ^!x1@iEQrJR9Hc{96k7HYY|}5R+qTvV-wl>@&4<)N$Am= zSpRycA2}4UBY1>t|BlYU-L)A^V$}ZEV(1VV@|@f)NASPT9new<0&4Kz1<;`*su)A2 zT7GeH@iBx!v<+_G?0W_eR~W#-!2+`ZL3KY_`v0IwDxhzKl$vq}lq3y_k6I%Tir-vViVClBpbK zT!_ZyGj47b`+FUvPlxxMeE$^O_GS9_iDv-Tz2HkI3u})HngY`Z-2hQ{(t=ywhf3i( z$6r#v{1EpO1-LjjpE}%rm&f#0z$r}9JXaUsCcR9|{J!#p1V6hW`5S`Vag_rIl9=$+z!7d)jB(8a zm5dq(yZJ3N=cOQIbKRmH$#bY!PE>ZCn7158mHtB%rT0Vn`fOcR65Ngg{8e>nD9LB< zl!*JAZg#o0$(=x5KVqO)#xA~LV+Q-qN|De+EcqG1GN)TDg)9+!=17A%`c7bU`tqMR z_(uUh4_I{-JGn&b*h;P3ro{j;yI;bKtt@bx3`?f8R z%OF<69dp48n4>ZTF0J4rY`doVyMupSBb)rKc6`WosqcgU?Qr1@{vGGpoPO>Y(e-=9 zvgDW;W#o_T;ybFLq_>d>T^`S~Ey^ubfAEolwED{jsw8fJ^Zc)lEtlXwhBz|7Aw0v* z@}4C)Dd`n3lO(w1m>Ju)yXxgW+orL(EzGHP7QO^>rs~VA z%B4X4YiB%C)a(gVTlFutJy&wiNUkJ<{MJQQ4JlrmL&G0{)v3rfqK=Tdnx(6rQbud0 z>CLO(oOrBDJ#IAz}V}ZtyNKC0mJ)d_|YUx(-<@QFsOB6Lk zFv$oJcT4a0GYsl5)fh*=pYrOsnZd9mK=!EIrJ<<f2Ai>24`!x7G}m|SYJhfMxKh>XMPwc=KsO=O~|!yiZ+j*Kd2Vw znz)La`hJ3mWc?i~rF1S!xFqJCCh3qV`h#y`MJ+*{79u60n1o5Hpv1}VYm>aVH0fta} zWrI5kqnBn0AMj$J{92{>9F`#xD2I(N#04@a?RO;H4HCGY`8XdDAF=yr+vv=gfOJ2K z*qHUjOf%Fo*O0_wkpt*L4#q@Or@___q@@UuoqMc*EWWbzn>KkuLJ*Pt3ID4GxAXGs zukG>7)(A_LV%7a@GS1h=)_vJ?`LJ{3pGfGr2$t%`ksG4WArZzVT<;0f@J^dINfs*J zCo~x_=oYJ5I&LO@_{K}GsHXA7t#x7YPOjgMOrPC$yZ$%z$R17AcB8a+m(Rb7XXM}B zsHI#~Xw4W_-&A-wb+{iK#=Ut2jZ7Rid9$6zau+lgSq)k$uQ-ib&_$gTCZ+!WC*~#K z@B;?k00%R_H;V>soTQx{8{mSnGp*30@;p(!G_=6_Se)iY5D1WdZA=G4abJJ-Fx&C#3dQUkj#(~M?gkT;d>VLDYW*qhcs~6)`t7!;1_}W^?X3+)MuFo}sB2u}2LPInj)tcX}!3Gr+5iH#!>O4!?UQWU02E2leHf|Gf@g2zg=Q23iP zdQ9uhSZ8S~O1A>l>|t>IBKq~aDA_=2e0ybtFO#3w+oc)-tgj5N%>3SEP1#m4j?QFSWGkOd5kAlF#ep0|7`(JJP_)}nf79dwyaZZ}w3unp! zB3}G}`3OjR$Pwy2YvcIAdoLn(s;g_Bj~p->TCrT>|XnMQZmf z@!^G79C|q&2J+^&34Pv{n{)Sr3&pI4l3H3O7zZ?E-Bu^ zMva5|sa6OyqT~elG0kr|wiXH8ccbfvhSP2a)h&jzeV+WDy!It%vkpvBMO#;@2=fr;LXh4pqi^y0I&5C@hd`HY!g9!P#^dENdMC zU^QT>i^{&R-!VPXvYhkO1)Z>bQX7uD!3T-@+K_pV23;3AMlxdmQ=sT}pA;8v#%~*kTsF@VFEpwS=ShI;ao^9T06H znV9CUQ-d`){C>t77aR4&rodCFwR-W-L6PCW$oEB44K}k9x5RyFfBJKKN?E1fhH2AM zq3RtBMnUS9@Ycz;f4(m>8EVC-4Ef8D%)}MD_U6tC;N5w2$L`;`@|s%L4?BM7N2!!W zjVm+%AwR40wTFMZo`sHkUoAOG0G5=$f6L1`5JM2eP>j>l2|M|CygWXyD8NRbU8Wc8 zdA?(Exj(~yPoVu@{mrAbRUQCs^72oB`ZEGz{pHrrN)|Gbs)n%G_WsWKLCB68fRt}% zO7kYCYwU2+F{S1kJwyJinM{LWo( z-&q+i`Jy=MET%ZjknUNOC`)am@q|F`d|X@bVnhjQz5P|r9@7Phky+-$r4)z{AP9Xja0&R%|ymf)L)v#eGZeO&GrQXAXjC79o znU4vAkn(`HdyvLGugp`Xr^#?3+QZ>kaBZbbI$Gh#`UyrZp$IE?zM!vp^=Ht0B`Ud~ zgA5?Y0E5(SP+#{bGG44=%_E0qz%3vf`O0K_Fmb-clQ#sPIwqWm$#knfj{hM4HIQKh z>=!k!{q*(pzAiiUt?w0OTW&wVs2{!q&)QhDt0=R3aGIvu`!W#EFyG*mzd|hlBE4Gm zK8e5F9nFjsT=hU7O6Ke%vGg(p&KO6{^U+yRJ>p`WWQO^}G2`AQRXz}FD+$k$<}YM^z=rP!^Yp^uMaR~cjw7QR=OSOJ);nM@r2?liumnB z?8c*r{%<1xb2`2_9A!-Gn!?EYh`;50R7Cf$IW~}XBkh;!OjcVw=fMy6uu+kdHBRsi zuATc~Ri7y!BD9`e=Y~>s#xp4Y7_kI=VlgINA?tR=cX|~dVD|9;Woc>S|ICZ%I}ryR z$1D9BUtTsihtf86oxExd2CU5}LOxqUQRIBzLT~=EePDkTH?})8`%!7;LXZN8)T~Ok zp(T%_R*^q{yoXUAg1DQhwSano7jBLgUdQk=LSJ-^8>|bwFOK)|CX6xj;OU1q0*-C(6)wA9)DkJaSXcZ377AmuU~3rKP(<~E#VClHWwPx zRt7tlNTR6K?8!9tTCNqrGRx>CF)|7>87;Jb7uSlR-wXJec6pd!wv}@eh=>rptu9%v zL$fbh{$<-;EwiqKiHJz5f)5BKcrTTUzek+u{2VW&QhmjBO+%aslzaiC&ZBwO`tLCA%ECM^b>FJp2ZB z&FW{TQhhU)bHrbU=KZy5L5sd+_xmMo*nIV!QC_I;ahkYfpGH*`j|I#REv@@K5wR}i z;%JOwBYdJ7UOZ;8QDi)=VjKr=#dxuZf9J3Xkb-2{Dvi_lu%9Zx%_nU_ z`@i$Q0@CWnw1#?57(pWMw2zVRrPia2@39ppUuiQ{7zWiSROv|6F$!1aXvDC$x7S)a z`uDFL)<-=y_$Y!=IQP@UHGz@m*|4=h{Ef!ltgg;r+&Hx&GqZAj9Ya?wK)SGtJ}7U- zJD4r&iWXeetrtvL@w+?n*e@>9T>wI89tlJvY#krmP@0L$+492peqTqK3i3!I9vD9? z9veFkFr;vsVU<*ybYUU3m?S!UuUA4XhLRS}TCZ1|%}slg-s+!DWg}lg5Zj#GU?gH* zI9<@O_X)L+zaZ3y$bH3?Bu4a1VcByxQ|PRpZm1Un<)q~tj}f?SplUU_?c!I2E5Hr` zO^(*(ank|E^0z6~`8s=jQ0AlYZatK`_mM=;j}gY=!QS|}ejTXeSF%yW)s>q*qaxXVhk0i?K!Zv$CKT^QH2!BQ>>Aq%ISgra zsF#4{zIV@IYQ~x=O#(h_cWa&)U^uI7{QG}+QjTl|ER?%rPhq@;yT4c-GuH|NzkVn% z{5Tm5HeHqcX_>(FlYo%!g)`v_HLAzGr4?-$;(r%?cd#)uu1hep&^U zUflP`w7WB10!(qj(dIau5l6sA5FNwbpIzcF{L|#Sw zw6mLGWC)5$!@%^vQ^B0$`{>`cl8qySYBhH|c9^_JttN>hl*?>iaqEr9Ldot?_pP&U zb*iHEZU6?QK;7>7FRWbosP*UlGT+Mjj4x*LZaz_e!F9Eq@g;#sK{}!v;?j*D#OC=z ztd`(fgrG4zL4rvol{~q<(B{bt{l($bE&FS8E`xZPAS1(581RNwjhkvtum@yw3u_({Nx#RM- z)NJ(4^5_WREG2UtoT(`?0TpKf=2uz7hmhp zt}Em@{B{l!L&j^_eG5VWtK9I)+iq=vg<{aY$3RI?6E6OvixZ4yIhHjt2sHNd$m%ii z$O_*hyEw0Cz12G)+IxVN=CEFJN0}Jk>t<*VI=-kspoSAzWqDeT=$xhqI#MCweG*A! zfO(nDY?If1vF2~zy^C^1j|yX;$Vm%P{j#$%{k!%G<;F{Z4sm?Aa*UJ7QW{R<$L*sA zi~8M8WpA8kKlm&()gn=A2p@y9PXg)Ga@vWjwdA{Dw`u9YVm}UE36))-x zR`^}ACH;(3p#M6frE}Sz^j{?tAc2X2DGx*K0c#tZ;^L94zvV6>$Oa!&|FzvKTzuvS zo;SIoH$GH=aBA8rcRvcaNIpbBTF&i3N4nZot3YoGi&L!UYtL_sRH6sQ-P}s7+Ml9# zZK_$3LHB66U&;3)c8CVoh%^V#y&&KugN6- zbayGbYX~v=swc8;TOdZsZg1us020jk4u_UqNXl+}51R}xD+~G&0V#`^op+;Elf~j6 zx4{xH=v4L*^EMjRo$`7{XHXy>!tp~G7`Pr1KwwAC-J^Oxe_*~M^Yhw+hd+!TH@%-1 zX|zV0XyqV+xGjwqM#MsiV0x|oc&*cx{Fp_RG2ImzMQ`j4j4v+I+Ysk$uoF!HQP*VF zwcHpd@HkrqT@!cS%*=!s}z6m;8SR?Cp-55 z)}vAB`j&U@SE~hrlcW$m|L80jxh|kj);UjijiDNlW5LmT`dMus-bZUc?Em8~Tuga> z&3aWmbJMEtNR%M@;WGFk!r~yy#AWtfpLleEk`4jnT!O<7GTe(cOL;!gZEriVh3h5O zGq(=CHBjFQFSjAr$i7y*?jl>D3XV~jr~7TRb-#l8<@@ivY~BscDytbNd_Gs;cr zm~tuaV2bs6R%{N1H~%a5|BvahEi1(dICvYo5)YoSwsJFShUZ$9yi2(=VXa7P4xqF-wV07CdAIZVMKqTwhQ|fr~Hx z+#f$r?6p2xtcB0_iH88?j@S7RC^_97PpG5n>IB&J>z;w{4~(k-@052-bu|%*;Wq-e zC40dPw?!Lb-vM);D(p8v2I&IY*{F$pd9%&lXbojw5oTJ`FY!`>GLB3EzfBs>s+;l znNl2PW(2ous8nb}iZ|mGRqE5i&ugmfWG>>&_=?fuoR4O>!>QtUSjRDcaNQF~u@D=} z%R&uqtwPnB#o@LuE2UNFl&1ali)mhh(&nSX1f8R9Nf!CqSk*7=k3x_5V1a{FpG%u1 z5$VFnkfL2*?AMqr^;hnsJg#UV&xOOfPs+y>N^2xuL5k7I126l!)u$KZW=K1g)cjAh z^-lYiBUDl)YTh2sPqYQX0qsO`XcRC_IgXWgu<)0bO~%(y4({1Tf7P)>~0N)RM1-@&XOTf^cM69 ziWxwhJ~naO-~N4giGyifR^@eRJDe#(Qf)b6ij6s7PDsS0#=bPRq)wCes0GH}kp*?b7JENIHrguAnknoTBa_azY<5*HJcG9gf#e4*ErW1Lx z3`+uM@+J4zP-=V$1Q$?wmir^9u*&#Xy$;^C0F@4K==k}66ON{f5kh+`bfco@DippK z69VhGdRL2foD_cW_0mJYli2=8tK`rRpzVLMXy|4Fp!BM+79CG02PEOdW?8CVkJm@( zZU8b><4NrX`prkAypa=#7g77pwEO9S74UaV;xOzCATtQ92N7`rKh$;yIG6_H?E$yT zj>^u|uK4vk3b%Qac}K{->D|0pte7s^k54#2x8ATG>uqJvMw`n{}L0c>i<$g||fr&j`>C`t!@1AurjSADMy0Y)h4a=YoE+)R-XsJ1#>y@=m)F0zOIK^A_Y5y5 z%T$@SaF{L6bLWZtRn5QBsu34q*LZcF-uY`RHQLj4(&d><%`QH5b*|$a3(ZNB<74Uk zW@0yQ#@E=Xc*f^gQF|F1Vapq%0J zWbmAfzddL|prbB?*iQotbg*sV6H&SX5X`Y*2p*1P-HU&Gcodg5D$C~yYC>wamR0dY zi&Jo@9yj{AwwS*`F1jpbDctSY1RvNX(@IVVLF01YMjvOMKVV9L4whTEs0uHAsp?I< z$^K5@+?I+j?1hXzdCmPu_jJ?F-&EF9)egj?8>Eu)x>T;h>aDal5`WbPI)gT{xlPBn z{0P8Zqu>TaEP>%v5b@Ms$kS8-7O7ksXh;C7Ybi*o8~7Kz=- zf4Gk|C@Rq&!aLrbu>0eL&gafGEIZND-aQx|w^q_%{W_Fos$0z?3XG*=Ei;TiN2b5t z0XHfh9zOpHSHv(eA+6pqQ$g@uQ&Td5XTm382e;koW~LV1I(NlQ)Do$42)I2tPHH*= zZUa3o6(Se)45-NIFu-h_>pU?i&#dbk;e{H*0?NDB33>ABibF4M32v$FN9evzZc(oR zyCPhnN6K7Q3%>JKV^fv8KZ>89In2o+2bnKCz0&wTo`?fIqeH_wmbQRNCx++1%XOlJu1u={}a~3=|=!GvbZ77!rPv2FIZ*w z@Xr|p0(|Gf--8MWl~uN{08lyW<9&M=I?Q><9>WocAt0e-0M2%ygVJg)puPjGXEUTZg}U79_#eLAVkxeg$`&a(Q|2&c{7bvEN0obr~l!9SQMP~=rT z?8p(Ep11;R(PoEz0T?U`otocR4_@p5)?5p~rBx(LU{dd$(J_w3K%bO5FfyM*jFTRzxNlJv;iQx*0Md&B#_)!%c;!E~j_`#szuv39X!20rG12P(l^#sw0r(L& zVrll^x1#ZL-@C+|G|6!(ELr<4DoOz%wvV&KjZ{q$ptA!u?}*E^v@}~}a{|ypxB~*( z+xgYnCev1eK>S_;>ZWp3s-p~G!z2AC?5$>JNvS|f6Xw5C7jA0LY-a+$DhXf~+Ez=e zm3ewkP40aR+dTSq0fCyeucZ7hi|Ot@K&j!)3IDz&oM1 zLqV9}A>#e}gAW<%gqWp{Ti)WC4=aPRm3718pGicG5k)xfC{|m#f71rIRK&K=Rkk{d zW7r!=Eb+2ceY;FBlEJx)x)oYXlP91N+kYh?QQmcaFjJy|sKY1p4^i&^EsKz93}*wW zQv9+25o6=j7QLKx^u!%&fxQ!WHQtULx*YzoncB`bPZ7V)n4C$MQrlsX96I7_vp+6_ z$&)k<7BBp5gBVudL9hDA=$E#(zO2(4WvmrN-5tBOs5#-X2}Z?GEaa*t#a$W(y@59W zeCtZpZk;WT8tJHA>zJ~7B|$cRp@y#SWovAm7{v#iLKU~Hrn74UIj z5dJy2Z~bQVUhc!c^NX48C;;DL0i!8xE9#61Deqh?7Yd%e@jy=|2;($tdO0Qm0M^@N zW50Jv9EO8~#|@i!2Hr=t3`;&2`P4l?ctim(ntV+Bj@@5!+4pgnZYSN5V}ZkgqV0C3 zVxxA>$P5Wy$2D#TIIplcI{Bo_)>V~sf#;5`m#@m3_E{g3(28xdX%7x!Qvyl%$UFf7 zj1ExM2XXkwl$nji3-A}jWd%5TbX2Vw(nsaJ_J~0^8n@#A=-dkdbD&N@*YMNeW0yQj zF!lXEc@G4v@AJkGz$%3^C?|dC48qo02yZTIYW{@14ZMbS`}&pMK{b)1ns`OBpFkR1 z6NKD6FI3Bn02pah6o=*`fk!tV1K9r_77LD&&i!&-q@GQc{!{85klVfj^QCJO^3<3w zqBm7Q4mZyL4kp`nr82DrV|7dG~ z+v<#wdGrA4CswwJT+C?kJmV#4aghDN6fJ^6w}f@{CDzRdK|9)rj;@;K4=y^eX0;gTdB;czhLB;3Z=eQ5!qed=Fr#u zn&q>R#cQ>bd7YWcyX$;%o>6bgD{u^!=P|v{O#BpaD;fN0$JuMmskiG$$-j>*RM!!U z(9G-2+j8nW1MDx|qD%E#pRVo%hNe+zWPaS#M#;R5tFmyeQ_4z;?O8fWrL+u;!zBBj zp710Z>t}#fLXMQgK6)aJUS2nb+dH$hAQ727zW&sVuzsJKoBqCy^(rUr$}OVnY8%)S z``#5P#r%z3F!5wl!|VrycPzVX8RX~n3X283!6@@@bH6Ue#0}H)!s+jDasj{KBli9x z%^&g>%^MZE)EPB{$JFBZ0U6{?_0oQWTYhq{cR#;=1`dW}Asm(a)Qh!r)tGN)x}kdK z>T4f(g-M_MmGg&g?4z7=fBGxKWm6phv%%{8QFH z*QSQY)e#3TCA}u!bbBo7cRzniAi-@~0LmJfS_yy+;l9~=@^Qn)8KG7*fuERR?p^#f zvF75wyBR9O>_vSfCF6$Vmimc8~Dx}gPLdofA2MkRoZ=haYg&GPIWIQLa>j7 z!>=)`$t#LchS;m>K3MhJJlw)qKG_ z034swqD_&L={<1$HVnQQ8+sqt;Xq;jQLe(M^%Nl3Cu3lF$fsz`^%gUen9Fre5Dco_HUdy-5t6De`0B1 zK;Z`vd+XcD#@asVBJLbO*uRd8-f078``y~~SlZgMiUUk_bRJc^q^6&rd~UXrl@^{0F2DFFQNQZNMq-K54!jEq;2wdnAOeSa@<*oqktjU- z3$#2N03zxpvyw?l^O`OF{JXSN6GSz1J3Icrzl5kx@9uw>lvLmQ!E`5*s?Ga7zz4Q| zKE5ZpeG>^p*=r*iM#zwe^@{za?}diE5Aea;y5@18W?w7EV&hv^B0 z15+69Pq9F(;umIIo!KgNiD5-3rCX}np_$5;Per&EPYZ_&K@o=jD)hwD&3|rv4q5fa zeaujpCO6b&$A*V~WOCzC>7dED;RUj*27P(o*c&zgqWI>u^}hDkrVT<|pPRQZzN~C%mZA469YA|^Q8p6DLYEaex=usO_I9L^=G7i zcFz#J%`%iOuM&=KQfHsq@WwjkeulS%tY)#5rq&V{zcWF6it6iqf7A|jxF z)n%Sigi#cg*$=kh8g7(DiRr1}SFrW!9Lu(HXvdKKTuMBc4;S1r>iRqdzii(--9Stk zbuT9-(rBv{o6`4L)W^FsF~!{1ZohtA7PRBH=~v)O5iOdPTvV8#s-R%4 zosIIPH;Qb~b1X{?c33?ow=B-ft3l(QoRp-8!NBwSHja&r4HpW2@J%PQ=qDBT5qgZS zt?g|SK&5Hej1d`c^)@$FyS?`VbZN@Rt|0%8->Tjk+XU;qsVVI%cHMF7k8&DZw$seY z3x%rbv<}dW&L}{C1xN@T7H^;i$0a4rGK(ZIs!D(R#wQ^d$w`WXi|cf{CiM&SZ@k~{ zDL*c=l9Ey-P<6w6TL2M>fQTsnXDfi^3F`k3TW=W_1=O`|(Pe2wg$T17L z-LjvrHtjzYeEz>5NvNzPWmQ!QptTQQH4rA|&UnVh$LIVet?ul^#Yr6h?vQTou!m?7 zF}dL-3v*Zx?cV-=^6SZeUd^|H1qB7}9#-l<##qZoB^Pp zY4<L2IQZo<7G8J_eu)~93hWdA;V zNB&-L6WHT$AaO=@JbxIYFrRkLh){7tM+lk8Xk3Vu(Jh%4q=v-0Ri*gK=shu=2^JN{ zZMi0hrv8chvBC1m-C(_R`=(r*c@V2tk)z+W#Rb`5eKQ#%xSijm7jw6qS6g#Xqf5^= zw!}j;G|k4E`dw%=ah#=}b#sGtF{4B8I+)Mg_FBZ1X8MneA^|QuIN_FvQrGo*ikn3aU?Ku&hnzlARvqsK>y*OwmRiYAL zL)^Ks$;lRHinlbj@L5LVv$)ziI_?{Z!t6Ex>5$RVn$lXT1_Igse2u{GAElnBdW_DzOT@<%7f@C#%o;`S<#kE-U= zHAQ;$?kQi|)N_g3u0&$0bP@1~G3O>GDcdn{93ptV>L6YDHAo)JqnMGVwVUZhJWZgX z&?r8;St)XX>R2oB1i6_^wyNuJOO-{?wG3B5*>tt}>OiFzVeaqQ6?>qR@VDwv)`0Bv zbqq~e>yJU9WzSrZRwj4NVC7nSTJk#%*5h z&7|pOys}y$>2KoL{NWwjVEULjJBF=Gbafk~?p4$M%b_~rc3f<4dFU)%I`(r4&5jIy~j&5Lq&Plf%p$ypSz3*Xv9cf}&V7Q6v~awq1#udXbu2^>v?(l@&}P<*?Zz}W^QhM z#brfPvnJmlxS{!8_GG{ zzqySFvZH$Gs$p{T@EFt8=iO#9ab}zp6%{pDN2`QrSifbV>3{LCH~!`q?!NOq&!pqN z`Jw>AWe`%JOt>|RQb7*wa5rhrK^n$uD!V}ysB{T-Dy#2-*jA2xiG(=%r4zK8{gPsT zqTf~HzBIj1iHuH@tL8HOORIzU6;WWg#DG~ry+)vW4v%4^Yx4@KnYoyMQ^z!|Ley}; zjQp)9X&&Cc8d*1M3sOY3d5d7b@q-0Y+*_=j2=XheUk5GLy-vUT-;&3rnEv8Jtb03F z8mevcNR}$B8+~H<8DFYtWP$EgFyra7diHOw<5CQ}9>JNpDTz7IC$v$ zWAeTZ6))K!KQ#QH+V8V)t16M%ubD2HQ|}d^ilTOw@%~Pxu{Q&anf5&>p=OPCEpCqe zG>uvB*WI8F>#kL|J8FR#ngT=$5j5?IF{}mxiL8Ch=x}KEniE0YNwM;C`o9~Rogh{l zGV+~a(5mJwd56b57%K! zOy?$5<|{-Rb81@{JjZzJ4G-5p6pg5 z`7)l`$)r-({I)7qaTRqq@-wqZ^z6|_P*69 zS~q}Y1hm^R_uJHAjhmmDq}k_>rr-UWJRZUH#%lLxfr^oWf`Yu%UwwW3vkkD0`i`%S zwda;%JuxsaoCesvFURXzTvs2<4y`W^mq@Gz6V?#$;a~_L-@Cn;+Iyfp_8lxXq}MBd zWEQ;7EB~LX2>fk|5*$8wcEa|UFQ{>rU9QnDzb^#)JVu<|{iH~I&tzxrJ9IR(SVVxM zwn>2Q)r^USmADaGb^nwYR-d2zx+d^U^I|_hj>Gq2KlIl|SfBb@%_+PLdn|i@U3#G7 z&qWa}{hvEAUWI59PTl-e!#TQHif^yohqq2t*3tT~(O3&qME3=L=Y}Q4+7;?dXNfcn z^(}b&V$U7=AvZnZvoXfmh*O8p=SEb{JTt#{aTp8`LaT`TB1^AN5PSQwcpsxcr`?6w zZ461zusU97&5LaG{SDJJ4+ASc`8L-Sw&1U*=_-Crq2WYeY zhT?{Sbrn&0S!6!8(iOW7)FO>!&kP;|PrD?+i7;Q8$@CNT)r?Yh3A` z8azLm>NQ$cSdAOm$5nRWmes{PMwo{V^##=T<5+w{KW*?Wzs;Ggi#Kb2nYm-xnM5pQ zC@PhfbuL!Jb_>K}@{k<$!+9+&AdwcmhseDtR%vCRq zZZGBzN&eLMV6UJ3_4JJ%14Eq@ir04{imT2Q^Y05~5(wD+NGNlb6Y)KvMF-Pnwpwo zQTv2RcI@(IB$?$xJpLD^ApJ|wAjx08paxcKMNsT%V9(r+o^Jdgf%QTs=DH9vTKQvx z2`t&o12XuY$qh`|4#i3?5xaD4f?MGIuIInZ84WOqwI4;BoLkkC$XchB;$>Q>o}Kf71rLY0S~c_-rY*=p;+Ve3#S zSv!{pm%HkB(+ES2=p{&FnsQVmKR?)Qlr*|--?TyMX?yK!&;Je?o{rHh?lK5fP*qF5 z_ghL{Wdm6V@38dq;~>mhVG7nVRUH8fo*!dE7iO9+=q|bP#^(GhGvQwR3KvC;K6sfO zZx%PNCa{sOu6EhVV>=LT)JQkPVAc|wA62LByiPJi_$ZCV{tYm>sBfj?Qp2?ALO()| z*X9SRM}6ei*wcTY(@6ORlvhd2DU#!0VZqs5Kqb71IA#4VC71TeVjofoznPK#BHRrg zaBTEj!0RX~Ed1PrBc3YDxOoa-9!pTQS=1aaHlPBupcfn?$w0)X=iIKj+b~pm zNbTJ@w*Wf-%}F25X$Ay}Ou($xtw3TLvDO#8RDHZbH_pngwtZ@%+m!!j_hn8pFp8!J;3MZBRYo;WXB})dPE7$yC*BmR&|&v_2bgU#$8&RYRhY{H)qO`Ep`hS4>MJu)p^n5zp0|7!p#i zhC%#?hJ~$xUqg`b3i3@1(*k=Ej;@U2VWfUEKW=(tsv@M<(FQ*{YmXWBW2+H>*(?pklBtJzdvp{ zQT2AIU2WeB>>EFFyega!L}*ZV4^;^owKY$m=+IExI>3n}WWgKKt@sJDj{{531TD`^ z9QIGeGyRGpIh|6Df~VRTF+Utq>}yt!&BrpnFyDD0_whN>nE=y;Us%~zrJ8=}!mL$S z{X<;*>*DXyVrIaOHR~uiQ!B^Z=Y)WY42T0q$&}JCB0w9=HDZKG#m&C7b%{E z_ZWOehp^^oymH(BhK)GfLn`i4eM^P-TLt*Yz-I`Mli&m(QX6z`y-s5x+qn#W6!CrM zA!9fG)BYURCEP!#WUU}pvDMz=OMa-NtgEYo85;njc@%@T1bXlrKsKL(;rZIvY?odz zC38~!{Aty96(8+-BVwi189*-hbOnav%TWhEwN5F7Gg>@s(Rgqdv+bl>CwXxg9-0n4@ zvCx?ZU*5B6V(YgH{UNL=7h9EC@`v{0#Tm4dlr=tX?!ftsm>9ILc01_^ zG9WK?Y`t?b;{9snKxTdKy$cV6o6MVAK^^EiqMS%A3&wpVT)8Ac;AmU8JjKYf+YuypALU5|?*?Uq@~NcP2XF1+ z-l7M(AD-}>{;C#sYqiFbMicv*6Wg;=N;|i7Ri{ zMfw8Ly6^Ehm!bx-PRQtU<&(_M_z*?7E=ef1%+7MPX4AyFW#ZXLKzT9xLlgs$e{Y9^hoa*){6NyH+ukC z{!MTixz%i~bcoEGrL*tW1}r(gVZm^zdu*0yi&4*ARHT|uqhlM0HZr6pd5tkPam=@G z7Tq&%=n|6y0vc}?DNh_DSg)gU8`DJ$=LEK+hp`#Fi7!n8T%J*7BNO$rq82|6bT4*$ z$vN6*;?k_3?_6aEb*_l86+i-K?9Y`{RU6RwNM+jE%rgq;85oMRgkaEwiQiT_;Ic)5 zX)ghs8&-gVEUT!%Sh5A2Cn>0i0IE@8eaLGE4;NA(7j1cSvX*#OURO&H!N{Bkb=@Wx z^C~Mj7*1utYjUniAX6UzJw5CU5F|AK%?b)OWz4~W6C(=?gQzGO7^{3bz{P%vXr}V{ zr%7+Z?yh}*e?O@BK4%=RLLgJ#NyyvdggxfCfTt39Z->?6cq7GE*)5~5iU;yfo%XNAV=GNeEM%8fmqYbEcx#4&bCPzEp%w3 zZXznMaIMc-s<5&e1ui8wE$LbNh2#(FT*I=O8k}q<6BN2)qb|pJ*qXp#cT9d?NmX~V8pB*jXKvl|H5q)3u|H5WIJalD9d6?@pRkHzgF^2Ig-_~lxi7G{^4bb6lC zB7y_2Ji z#VDDIzNaSNyPgrSob@DC0y#)nfLn4BL=aPxvR*jW7W%fxR_QpXyuAy;P7^Y34=CZ!kzIpl4A!SSw3EE>^^!!C4#~+-AnlXqX@Ly{ecT+ax_4MC8Q}j)@$;da3uu zAu(NLXuUm92SXf@Nad30H%t;>9qk=C8|Hh_6 zVtAR<4?er_aA4YzE#%w_Vwmd!ZarXR!6?Ncy!mW}-p&2$Q&PE3=~?~Fjj!+bH%vOi zc@pnmn`BOzFy0Yhd9QzjrMmrYj^OR%OnF-|L1Gqwr&FrYbo0AJl?1l9NCj*$Q7}o( zvr|jj+kexKi%^pZz7F*=u;^&ehPz6BiBXx4e#>UnPz^Bj4 zH9%MXpO3*hdQ!~7=H|JpNNM%ZU;iTJ_nl{+S^wt$v(TDAvnp|7A`*nWIwA~C59$6w znwF)&=}I#2CK8Y+^BG~i@ewU@x2<_wwUMA`=%!7}r?b^P5+={R86nBhlPNW4WJQlH zib{juHgga!-~SPrgddMbJ`;OZzvdYQ9Ubal93>OvK2(;|IRBggbtd}!HJ_N+5%gF~ z%$b&L#P!Ty)whCf(;aRy&J^Tw|HSYRFciCW|BOzc{bBUttcNGvFsH*tq{WuGYGz6a zPev|KkI&c6u0)sd!#G%v7O@RnN_C*C65eS20<}wc?`mM1a;aux=ocF7=rMeVlNoh~ z(t67Sd2~b`eI*HB-g*+Aek|cs=u; z`f_qbmtP{u$epRfQLuV}sWiQQB3oG4kp@&jIzMtXSWvLYXRJHG1UwuSXYg-NIG@cZ z;pWbc6(HXXYt2Koj{z$SL($4`=TNc8BlN!MpPs{TzX9c4h`vRX=^&waY8cgLV|jSP zodPzY3{Imk0Ld%WW#!}~z`UF-E8a_5!7&bdpY4ALz5}ipj@|^&E5rtGw&4B=I9H#U ziTI=MbJVu84#3_4omUdG=5u+OnWSpDVniT9KmYR~mXm3R_W+=7lE5L6nE|W;FHJH} zL21Y88riY+$(Wv)!@O()+1rXi!I zX^+L%_J-nmXj>ah{ro9%I#sm7WY}~rIy1NQ^y7K!y>-7rldDb5b0?WEDNi;o)TKjO zGHyi0wzeT2j}$wyvh?ZXJ0?gndZT$K;cn!4%IpQwU!RR;J(tyeq1ExlvIw66uDJi| z16r`=-Z?*$qD)Gf0EQAX5pgxHPFeA5#jhwOy-~4RWA(Pf^2)4faw9tIiREg9EqLf- zm(udy7`(xohM&nHE1h9(+NCjOmN*ofT7aDxvtmrr%l9Fw;2}Q9;!CPQ?W>d>B?&@X zE$8oI{s1wF&Ky)MF^?}u*`c9lwB-Gkz6#AIh44S6)HDS_*ZTFHC4wBk0-CIqYf|dl z(6xarw)W5&*Wk6jm72NEs5{#!c3rfiI0~Juc)y*Dl<5 zmjiBX>$n>e@+P`3`xW2Wiv&e4G)xr2E9{yx|5Xh`p`Wd~PA~c@L{m3K_19y-Bm0bs zcInfY>~^se4l^FI)Tc;nxX}t9y5nI7-C1fybyLZ`hb=c;lI0_$e*Yx~rUDv%0@S{J z<@$@Ni$%=SzUAuBoBaSL5yM8p^rm}F9W%^i4s^ahUe=7*irN9LxXjGF0iKz2cxFT& zSP=(zScdsNubhL2 z*hD;XTDQ!)^V`OE=ln)9LkG> z#g7@e!H>6byjDG7$Y@9iKy#QlBI&Eq%dE4VAXm+LL4sAl#Bck&bOOlJ+IY$R0|RS- zY9CCYOD&OhLAQvi>J>+Txkr7sv+QneLC(zySZ{w@APkS9$wlG&JcrAbp0zZ=Eub0^A?N0u=hb$T} z6U`hvIR4k_rNjay;k$S5MpflMBVtD*YH4Y)m=1<#QFQGL315g(jcD-=O=S~21OEjt zc>dthKbQ#e4*ZnHK;M%R4kLvdqZPUXNJ&-`nB1s zl>;mzg@-}vedcWh3cShse))qOvtyjL8+rbv>1bSc7=Z&i27Az8!L(l7L)wB)3hA%h zj|Rv-bHiOSi`ic$jOZ8C;u($o+<3TwD4{S%4+Sc zeHE&Ch1o4+g;G*GW5vgog_QXU96c_!6ImFWn5gtcF|;QfWatril9NukDBt+EUM^&!(Nw9;~>+B zo|g>jNX}oL9~?3}u93DFU?wzp47-ySbqKU^!{@Q=d^;RN6EYsrU~GRuGI5JcUfY` zS|<8_<-vr^xZ>0wi09-S=7t>6tKVEu)zZ+l=?jeF3o+1CeomD*_slL#=o)d_H~FGYxp8 z@OMfvBZ{wk%khS2Fj4ACPgD;^pAe$sG8k|xb)4!qZgx4XeOeJpy>6&F^BDJ`1ksUB zlXH756wC$14yeKlE$3CczqX#p++zfD&Dycsq9uC@*0%yUc|ue^U3X0E2^eQdIP~b}Y!hZlh%wTB$ zC*8Z^_2AYUn^mHo7`C8}O2K*w(IAX36<54-hXE+>pApmHHU_)DOc178q^ee2ttP8q8qicHPPkwP&#jPK7PMocEN=Z`g&>7;89vo1?;ZH9;nSn_bg(i`Oyt` zP^>zw!`mRm#LNZ0c)umU&X?wpIBlf1Oe*ZVG*x-TFPOB z#aeO$xIkW;(KP0zd|}tTt;1_zp>h6r7!}^P)(xNuLJJhQgOv^gJVe+|0L;5PJE+){ z-Jn-Ae(tDfOkzt&LelroOQ^%%7Lcu<>VcID7fwSFGv-8FfmAE$&T>s#p z<^M;ISjJzFVZ*qOp9OM$b19vjFJP(j42lWe>jUwA-_IwdXubo#p5E&J1_hr#50IqU z+uQrRQa!dMtE;Qquq5$kK~F#8mAA{^9Uq(**CPI&mIYm1)Iq_0#YiX_W5^k*Pm~p4 zlj-?+V!c%g~p@3iC z1*+!2{1yM7be=msI-7M-!tmGtzFMQS^?KoMg56rm@7cStla*#vu7cdW%P+;AxQkRG z=u0Q5`?8GnEuv$HEEyaKC^C;IEE2{eEA@uqLtKlg=&Lzy+_&@uGB&9wG>+$Kz`QTkL(5$fFj@)ZVU)dJo(&S!&BjYwqy8^qY{hNgeX% z$K6nF`Mt(her~oe9=1Me*8ds-mu8j>eJWQWp7)eQ&soOkGDsP^Dcy1rpLT=z_?nX2 zEL@I>Bh}!Fz#(v;tbzv#SwU8prSX**)q~h_%;v&@;?U%Fh|=l&U0fZ*F~Py`6Csme zhjh8GsI9CQiI)m_Xl3KGpKN|2Xzn5C;+3AS`n8bG%}fnKmcwp`*`NrKMA^>s1afH{ z=%w#Ihdk!GgpT1cEVd*|;Z_d%EYT=_uTiVh(QYypUHx=zM#*V3qNbc?K`XtFi#E4b zsPhzR@AKLJN!2kO?+85vOkDI2{jo)n&1jVZKZ#&}s_vcZYrxx58GM_|Y%aaCBpuVy zbIBv`Dt|FBK#_9As?6K%d*b8-*Y$)S5--%>H7vbpj2Nw|Z`F5XkYd)3l7_-1?+53G zE3EO)R|4f7goN7X!`io9Gh#-i&-j{fX4M_!g71)_{`!Lhq_e@yG@4my+(W^|9vu2k z_uwX@W{-~LE-wxEnVB7nU@ht^5-xc76v8Efhjul2@91v}-GI`ASh@BXOtY2+vxV%n z%LYJhsa2sK`H1bS@r@BW3~^ErCkcJmCypdtXyrnqICsrr_+=Z9<@ui$zSbe#i=zwi zcifcy-c)eXp!@><1NZDMY2@T=1XlLdh^D1{**E2P)2k_;`U_&n7EX`)&Na0fGUoR) z{gY-i4{`(YdE=?kWQ=UEKRE}%4Qyp6lS}Qh;8qUhK_eGFLU8}ZhVzyU1@5MZP1AR# zAY&b5{Ww&n@z}f^7>bZ!pgTnWdUL(a(~V>N7$X+!7oP9(Z6BlV?e+db`?18u?u)qUFijX zzW|dzm#$me7f;Z0m0NJxMGOGOzAKxR>8PB}Lmu_m;**kGv`!J>00c9yP5iv%CnW%+ zVG&rf-we*{S@L`lGEBY6*4Nix_t!LYkKce1{Ru4g2gc@rjGoT}+skd9bsk$PC6zCe zsYylL%;gU!T7{16Ken&X(_>Bw$o1ac-Z<D#mo~;H4~)v9u<{=pKa_k$=ekI%YWxncffsbB`ar+&vJ>tR#pD0R%*pwjrO_ zN*qH*-7rVmaSriOJU<9Bm~zPC%7QI5TJ!bCzK2(F|6->~Ulidgp}!v!X842fg*nV_ zn8cFj$UH(%8c$JEa|T(ZPVCxflW;s-%FwY1y?ZN0W-?*b+D^ZcA{+PhtOZ%(~#83BS^I!koC1i1KRFNm=jfhiv`jgnqcLdtN=&DtIW13kQfK zC&?2YCs8P#L*U*sL$V~@Q1|*Y7c)>B9%R4Z%>q6 zW~>iM@L0V3V@K+_=cp7r5`{J)_Vg&tnQbj+^Y#m=FmLf?V`QdfM6R&kj^3bt~ae(Ncq0v9=Y$)Ts&omi0LK$7m!{A1p zqef@1=bxQM^JqrSihpI;`8g!Zi15D9JLRtSup3px%UYD194cw~{SeEeZK0P?0f9ng zL#lbx_3{c;(2^1EOm%K8Tb;nqn_GOkHEWq?9a*KqyYR~a3#j^3@cGL4J|E)gv@MrH zGwi~|RG`Kn9Eiq81Jz!$?k%;IC<;dRPEB{kVX&gstzyoK9SWsemh74CC% z2Q*nDEoi71wDqB8!OvVMlVrQqnl7@Q<#XO`%8`r_8l6<%=9S+|{q+tk9nBq_ClB-U zPHi0{i$(v+6+Xm_+`uHZp!AHd{T9SAnU;i}FK2Jlp{pOIXjFr{Xk<3-liVB?qNFro z`>j>51?yO(cK&KwglJ73MOnpI3y}>j+#3Ua{Eha$eT~p1qQv?N3D)X`aRqNA>BJhe z_~3S;jGR-x59{@PgRa+xEsKZA7|b(PvY6)*x<-N0?f1y|R_|#A-m(^c{}*%iwfDG2 zHfThQlJoHm9u~2IQxB+tHwp`$!p7D_QE&vG%ZixPqb%VB#+~gwD8-H`=4;H;3U*DN zdViaM4c#=*V0Rk$9yZMrp1EsiV1uziB$$-_%RKx6h$IRjC(Th zGRjw?vD)OAQBo-vjs2+}7^Gjd9@LNB_<`?+NSD}Mf?YX=~ zTqRMffcnLz6bXS{?E-Ud19&PWGt+nc%KKm;RQ#y5Px}#2R-%>^0ALzzo7|Dp&`A35 zP+VuvZJ`JZTVOnxe!u;#rmGh~$hdWh;1-Vo?K#q5KyGl_fM=BpcOD%Z!=s^bU77@D z)Bl@^xbvTU*AE{*p6(VUD;|)*LBW&sz_v+_n$Btc%r!4DU{D!sxCFj)j!a$)g!PRL zirH75>tL=p2#Q~~-Jf)D-5}*Kou*UV`=IQA?EeK|K~|I7+r^fSKV>6;!m(z4>FXQH znH<*gs=@ch{m;UwDLo$DFSh&PO9-2qn(%5`KKfz(XFH}u#RbKq;!hg+FF%IJQu=k- zT@pDVUpl>|u+u6aMAzr5n6>UHO7oUzvWlt| zo|=YjM(jRp>ljQ85sa3#R;u{XX)V(9A1f9myCd8#^%Uyn{)-X^biRM~0B5mob7DVriQ_*V_n_hL!@i5J1|JjBy;-XUC2lx z2X!qy2->71|5zT`@K^KOs=>)Kor%ZbQnNY6xXD)Ix8Na8R^u@T3E-tq%zf%>s0F+7 zP1x+5OcOlvK-9yN^xFv+lLa5<7)C({)*#V5!S`|ty~UM$S(cz@;B3N z4*&G)Q0X?7-ifE)iI##^hxh#tqpVdciIekY@u%T-45D8RZf<>^ukKj8k7-WDU+4#2 zhJw5D;Ar8L85Sdh;(SL3JZp^H znxeKvrnaNJnD5jCEIs;wJ^_@v0}+vz{*nlG7eSQVFKs4jTLxzKtP}f3NVO z4rqcc=ZU*>K`$)7lXVh*^!n){Ei)n(04`8+*pK(?fKCf8G~Q!j?zz`&W<@D(8a8c+ zLK{^Bu*EbxDW#6@NffXA5K6t<>Owz}gZA28_DkUXl`oiSaz)$%4IK^Ggs8;;Ic=W} z;w6SmeO7G#?EoYozU%?SZbaRl?`**GH9)!*`Rp|SSHI=3Ff$jvqWSj0X}Q%Mw!xmj zWVU*c=1RxTjsYz5`u&Tt?Ck6(pmSe`eJji_!D^vsd^Z&qYtLHZ3miiy$H7k&u<$8x zsjX!3*RRwiO>yt`=hn`~c!mJFmv#mw!b0p;Dlm)10SvJK8535*&m4m?b zMJ7n51NJKO5fywiBwo88lrX3N`Of4J$m!?2%F$qv1RFLiC$^+yJ&`b3;))d5KN3jZ z_`*|(M+Gym(g z0Je_<;sU_74C3M)MytC!r@lbbAnbYt()pA}_S`{Ki6C2i%Kx0I!OB_2FKLC<)!0Fh zbdg`WU`Duf{6~Yiv&)^0J+R>TQbYYPgwOOnja{+^CV(!C>XW0x$F``nx)mmFNbsldIudH(_HtGLa1ot=D8Dab~a56E5KMY5`PX(lmoa&{+d8bfnkB9MRP}zM+OtlsJ zHev{hU6{*KV7o+(xzb!9-XINmsrvouTg^1QLk$Ig=-Zgf;-WdTsNOjB zvggBVZ32x$8!WWu*8Am8@ka7Rih6?a9!<_BU~nfR9kJD>`jYEe1+aa5N7 zTEjln3Gu>-+u%aAvrsrPOK*-4nJQfo+)WpyF0Tt*^YGU)GK(o3ow(ULaXR37Oq#E{ zr0SVBKI$O~mqK(GNxz&N)af#~c{3O_C!$|3z}lrGi#npHv{3wECj5Db!oI7F`>moT z+&}b(snTCuO0US#YBx zN^2=U$;ay86~NtW{Y5RSAaaCxbQ6x6CCI&4>-PHEwjtfGCzwyzoPLY-}rlZEq+M6f-G4%y*FK}zY&kZ~1&n1e(Ly1!2F^T?9>DbP{ zB}B~g0+)ULl+YSN2sop*j2}a2iO9H(peswJaXpK_a7lhCk0XcZs!WLCC*;~N;`C(p9IwaE8o*6^UhGIbN$39%rez)- zb)ETXj|K#AjzUZn6-2}4!^vSa@{o&&$Dy7E0>nEC32?^UI4py8U_GpYSU{|h~;W@-XC=+si?#a4}t;|Ht$KGmLLbW2=~HhGr$te ze2|e*q{Z!KNPZCpCaQ*PPbm~)U2-_{OR-OxL^>fnut$*ape5aa{$Il@?b-D0~x@*8>h6uk7O47AP5@_!?GIw z{rd+%Isb*A@$;W)l}y6RZsGLfaR13wct*nA4A#d;g)^6@n++X(1pZ7A5&~5OnO;rHWY4<*i zOP0Jt1C2rne>5x*9lXiBF3Tb&0jC4Ib5#^HPvC8UC92ETGdP8dhD4s;M5`@Ai7l_7&{WR(gDbQ>gr>&XWOT9=TO$AIq#BR<^70bzStv|t z>4Rix16CGH{6}a*IDRLZ2g1Rdb<>hzR2O4nL<~Phr0z2nN|gOIcx_lIoeQBvRW)Fb zkj#gCAefh99Os|8AJfwBz)?sy*3xc53^o651Rr*B^UKZqs%SWY#ysVwIDrC%&WJe7 z5E<*r`r#*&ku)tHYdK*sDTPe9(YQQqCwIDBt*tw41UjL7ey1_pw}@Qn5Zvhgep|wq zG8eXz8M?>)g!-P;J=Ab~P0`CLdAir?^?-DN?GX4ThW^Zc3TLhP6P+7rWoL%G1c)P7~@`g8f2LN#sL4W-z1uv4AKM5cU6#S z`#YmMM>Y6+g~!UeCWW^5#go>NwMp=urOc_|da&yNEjUoyazjm-Eu>3h=Wc~>=_iBH z3U1;!gsg0iylf~7SKhW3KS`yK`&7spCZAi=a@#zw*PiU_T0cISXhv=28PJ2!mi`R} zZ_l6lN4cQTRhk@W?s(#2iBxo&GIwcoJXzG(+8;5~0n2bmVef!&i-z#U?w-S4KmXrg z_NAQMraKG0WCcTeu~|gl%b@O-Z00_aGX1O5mD}@_Pi~*Rj!FA!mTN5u%XN!S-Z6%W zXAd8uJ~7;4TemlfuoDWd{GBDOG}G}W2ZYAHGRKxO4FP0NmlT7u7jVAFbAjI#3HT;3>5{Qxdn8* z<;O_8Er1JJeBx<*B|%|2%|o~`JV!~QfRuhaB6@+Y^38)04@2hqYJ;zJM;8zQd<=u0 zFY(cpEJavB1#T2 zb(NdMHdrfNh5)1hqVU2pX_fPJ-Hg>xNJ$dq)8KLjSC#>qyQOb_Y0An!hsW`zcqyTF zszFRYn)tcp5U6&~GvpiYZvn)b8#uRXjMSKix2PBY{GXX%*LbY58mScDnEoKe+&@Pm zu5Q!!b9ktKlDjw*3msxV5)ceJb!zl;!EX+(eMPU9B9nF>6->!T&ZlaWMN(ikZ@hNN zINDCA$)0z(_bZbgOjqld%#w2Cp0-LtrLnxXCgfD+kiI38lVh2WJqAaASA2{6&HF{P zyPTB0Lb3*@y+za@IwD}4!4-gnut^x8j(u-I$N;a~U+EW@Gdh_s{5-afjnff+7$@fT7d@~JN|oAJz}Gch2pz+O&`dl6>V&o{&Nuohy{&FP96ds#?KBP zSFeKwJY{9&vg&HZH*cteV8IL~ZTMhcB&MKFM)lnJq2TT9T?8cuB7EnYn)PgOQh)?e zH*iGs9(sGOzmT)Apc8Ugjsej2;%}$w1Ttx*%u|r%Z*hIJq5{H*#_9t6cE_GETc;k! zM*TDl2H|1&3YqW`M+2)MxW{4%HcJHfpYzXc5YNCD1ohR`jS&vk)zh=MI#|q>${Q4CI7UbXlZvO=Qszrcr@&$Pi?jRb7=A#5{TFF)vg-iF- z!|D?}+@#_eu>LmpIMMyLgrp9nA<6v7tNYony;~lj$*WjAY*q+pJ$y-7jS*NnPsfcn zpO62zrAkf*;)N8e#DT_S8?^MF@F0=4wG$C|7MU+UaFEK`J40xf;qiTv@gmFpP2bu- z=Pv&f%Oku}=*|97yRWD9$V0wJb+m1FX-yGK<8p=VdY>7o^~jUwSYx@bz`w7Tw5U_+ z*UsAgq5LbS%vEkqI01JQZ8ZUd3xc=$)fEkalOfu3kJ*k&2kB4*SM!0WH%ap;0uI1! zs?ASYbY%iw%AzE8m%d2KQ%07wtP0vrLSjt0k)gTF7PmiGYK#5~-2ZbIA=H+nMORty zt=qtD(7Dv2hY-Lub@3l?yy-oBZ;HPA!J~S&udKXMwc?6viP_soF-9&yfMM;|$+;`B z!HN5aZ59)#cOf>MQo>%``F&Ty#f?r$c0yS1{~_xyprVTV^$(OT>5%U34yC&rX-O$* zkdhd>q`N^vKtQ@ns?u3A3dZe72~gQf-yAf()EQ5B)6AEVAo_j2WlzoTZ5& zWMVy#n7g*WLRB$Xl-sI{=9_?oA`Bzj?}nC@NRbkCxT%(Nz&1!xG}y8$ql^3 zZUAQL&co)!I_OmlAI*Z@6C9<^)Ns)$cqCCYf+qrwg=2;0)UibCRCo2oYIR71MI0`g z#yt$~kCz{yeJZ+J>HMwE1SU(^*t^b&bZ1&)DO~A63P<&(49<-h-sPr+XuWb;??HwR zVcK(ee$>8)BujAVA{B|a1rwS(8y%WF2~9le2EnSbNaJl`yCh$Qz? zC|i(Mxl$~M3RX@yY5IE}AV7FlQW_wdg0GQGreckB>05Cl+Zu(4tBIk{HvFCpWTY^5 zn|0TdGVpcTRMq-0eyJSpa}!t%4?uf8_n+~U9&tYS3=M`VboFB zr{U^4m!WuD`Yq48^h_x!DJd9uv$x0BEgTckF)`9EE?flw&kQ!%2KIpUH3r(+A+T@& zz(R(%GBq(V2-NT905!FECTIxo7sE~}AOyv+egE=)^YWf!Potawz^c{IO+*8KEf_%> zILVhE5WP~f8kLdMq@m|WvDJ#WE{N|Mnm;7TpjMERS z(SC7RvX~~=|0b`_#tritUWbwWRd4WAs#KO%A5%~( z`|FZNF;v`8%KO4)IS#ZAKI`_ccjzVJ{8oZ8yFR#~Yw};xs;SmyxgrO)w3S-IgY8O^ zcAAF@9qwb_n^&tPix1 zAZwF9cBcL2dh6h2;#7Cb&G!v_+t+(L$jIlFuLhmtb$h=!))jH#cXy`;g1K7dC0;Vx z=~I;8@Fpc+c`2@!vsA5>7>XXGF(*@`a^mF-)V^RV5B#cqieC(1xl%Zd?FeJxFi(sN zrxgn_${L!i=L}K$5Y%H+(U0}TqSvk9eWv_Jk5uWkv#9Yc?VsD#oXJjC$8Li2`(gvg zsBl`Q^~i)lKbzFK!lj~>rmVHqUqLYNcpFb04`T^EgmK4;a2x#MAdNw#jJ=t-f;F#Y zI3QIw;f*RFIPX2!GORlmZLfMABpaY-Fe+C6z&NDIy6Meq^HqNC)x*)g6n38_G**3YHGf=v z+uf?hls%{HT1qpkgDW2!8q5+}BnDrIoNVXEwoM@aQ&Z1(+n?rPHwI6-6m1tC9#L5- zf`LITMLB!)YTZ@x@peSKGvD(xje$va@#vD)^Q^ryV8Q3CaoWbVrn~;}Towa_5Xx`2 zik!%--ZYSYuk$i%JgtuAp)(k)%&R+Pju|~Z#+hpwxd|$QunrP@PpB1eCH+1OdflLH z#qwN4X!LIf?|hGr;wVMOt|Gw6>o^i074*i(n?B;*4-r?^4peM5XeTNTjj-ceLPT6w z*=nyAQX0WYiB=FjUKNH(_o5d>9JA%E_YR7quF!iXbE5r;)}E5+jSVjx3cUqZtav;c zdackO&pEW?PH)a%nRe`gGY%S$DxKV7bw*m$Z!1NdhcoAO&gCt>G z+Tx<3&9)WOb`M4%9?e_r8)hVM0+JIE5e;Op1H2;`Uj>-t$B)r?c3IZ}It~EVjshH6 z0~yz!yA7K^5WsE-w#ojGBN5D670 zuzLFG;Tp!KbqBugi{FwuUn?rmU@=K8t{VveOx{{acbL*=HN?cV+e;60Ma~M#dja0G zG7(CK{pvM`l(se=ND@G61D@VPx$tkW!|nfl(Y*dbONf#0rW zw}s$;lXRYcyWd2=3&%}#V1{=qV{^Aprrbvx%Hv&@Bv4J9$mnT>Y@c#(*Q?uY|G9OM zeSh#dmrx6dM(z)X@%G)nj?of%fF@5=?i9Q@_#JvS&NU5S!$O(WU*}--l|8(l3&#E1 zAkrp{aO}D~r=2)bg9d;v1_nhHK}Qv>_Whh$=I)+43}cfdTu@Hz1GVl~L7EvQlw;|W z9FiWkAHH&G1Mw{4%sq6?J~tJAA%b-C#WT>>=HX(nA(eAoCLCn3uJ4&P3Y9wk z;K6(+mKzEVymf~&aSJz*}mixUX=Fco%Asu9@VlL5vWEyTBQ-62!#Zu}O6 zQ?_Immj&KPjTns}e!EONdxtIfOr_~IxWj!}XjnHpW9PYn%^JKlvLO-a)RSlnWi8{G zL|U)(H*~0?J9ARw>ay3n1O*Kd_i6lu3tpZARX}O)R@6}rAL!BVZGwWMi5P>%{pt7!JLI$n$(J;Xj@PCXWaw~r*WYwp? zU&C?aeeRr{(t^s9aJlEY?M)wz-@foblS4r+4}{G|a8F-Rw3(4X$(p?D36HATHhLXw zwHO`(;UG3pZIX!_IECZitu5W=xWQdGU5!hkK2|&}Z}aiC<@lVBla&A2dMfVZBMx=m zhPPv$J{n3`8xXMK21~I4!0oIB0EJ%rNxPz<0e|CRzSRxbh*4c~|6|rHh=Xn9U{ywe z-##e}h!5-7ctu1+K6Iy~;G25=d3QJE(-YRv(4c*7WNaJ@>kZprK~8{43$~||cXX_B zT(aPaE>q3ihHcXT;zZ)=>Z;|+^w^jO2?_v{efyn669vGcCH^Nw0{Cm414G^&9MByi z3{ZP@bro09V@U#|z@LXvL*dx%WnG{I{Ch%NfgYMYvxtYZ&KsGnG1xEa_NxY%figGLLOH5KLMkpYNdB2XwM zJ_K3Ngm30J{^*0D{{d<~ESn=fKHmQ0M;QS!dEg`hBp3C-drtrbtlV&lgkGnPQxjw}XDRWJ6;)QJA@F*QcqZ9;REV%20%;l7$ac__!3 z8k4fLd+F0VOu5|jx9xo@96z9B#PhG}%T^27rmjAR{#4G57E&g`Vz|a|YIT<}A`p7k zKMrSN#&kcv$`{+Rpji!#EST&%nUG=~yU1XLrt4zunl?Tg6*{4MW)ko({$o-5q#pip zH65Ibkd~w8Opgo_PX3f5Je>|c_DC6#Tr&t|OgA4ImOYG2Qd~BdUd3e8Om^SeSiFAS zF%Xsh*6*J#Z})DjHbgT4eAx+H*;7#Jkvkwt+IH&G)e`x4%C)1<66lep~JVpe5B$mfIyYq)!>fcjm8^JkL75?Fu%8qlma^nHl8VI z8237U&wf17TgRFV@h?S$Ka~r^6MDo|$mimgt*rWewSU%2taNB?5PU!xmySkFi+zb& zHftn{FnX1gtskTYt>o~|^kCf&r9gGx!>QC<(gQJQP(T_>m&e2A zREeWDnP2N2>8E`}=40l6aFQ6fCHxfhKkk5Xf3ST(ny7>lD?Y~7nG2Efgar#oRJ+bc ztVRYbBheyZIoFDwc024DK)lllm`eS%W2Rj`Yi&1PJAN^EZ=P3mt_8J*NPoIHd3R`o zGOnH1x@bwFJY;^KU^!0dzutLq;OQ*#JUD88NKc{_k4Xr}?>)wB&2UgMW-c^b;W@im zgN|73G-7c?ymjWh!37uXH)%HTUH+c=Vk{+q@@kKk!r4HiebN&v{;QVYsfSaQAKcT{ zFztA^=dNXSj?as7?BNsQ6X=QT%n=5+0_KMTKsf~g;&EUgY}g(7UY!g$GhnH6?*Ga% zfwt^N@brNwEid3A+<|q60P8wfjxGeKh%A9IACMa-?c*a%my8AgeF6AYI4lbpa1V_< zMTG!IqZP2sx&x}bu(eK~lCNLkYiequ<>**AIpvLvNP!bZ^6J zV?b>{4si8>;F59=XCUFs7g$|IihD8e^AlueXR~l~kHC&jAdvuuJ_bw)s1mpB)0Ssu zTlh6qRRgdi+Vu0kvXTTC;o;o`AAlh{P+a>z+n-1UHU@n3@PREtgf44TTBJUU^DH5D zKk!Z^qU+9D!Y(yGe;_>cDD+apUCx@k-Vn3i&}nclP+|l1@QMg<@YbWNsCPB(ydFyH zs{=zwfy>){|4LLt`U4p=!5|G#nI%ULS`Mdf8#3V}3AD@$j>&%?iy@s?%y!tzlH6i? zhxQ8chPXl|Z(a)i6ZY}IR!g&Qtpk<}Z~c;q{|i-D+tI5mZEr>ifxXW2&$Eo~g@4|B zRmm+D&5Y-3ztP6G8AtGE3f~Q1>oGAdmc^)~NE2f5;*UhrW+nDwheWrSb`YY#F|O~H zk*%N;!nqBX*3vr2Y42=re~4mbSc<6<3g=^e<3FxO=K|e>hJHCRn)()>5;E_07#e>m>6Zy>{AV0eQM?`MZQ4@AO5 zl5r=5W1Dzu@useI-r@1^T^he8en?m@((X<497?@fwg)*nKhs;fO)JlKS1t(yi%Iw@ z-6iPerR`VXycY0s*(`gMQG`tFf8i;+;#1@7L_l8hl-9{nS-q1*J3MJmE8Vi<^xnd8 zBS0zjHd4gOcV)|D4c_izOz66VsP%0;poPOR`h7`%K$5b4L`fsc8+hfB+%st*1E-g6 zj+nURlZCc;;0*znP-u@2@FA%*`30(=k%?|J4N39zoSO!Dj_>U~cn^dIApUf3u*yAeiX259uXge)5yw^0ViY#ti6KOUO+sSmVrUk{=V%MP#2Vz zBH7s30Ieak{H1N9HncJ>~$9#>Z1Z4Rc_Dfd^pr z^nQo~$iIOczQ}$cIrn^wy|xIzUjznj6H5X_0J3IYdaA@7AVGTjtQN=s1&%QsZP;4% z|9x5SMk|y6-88E1nQAt zrjIN0U&{{i(+a^Rx2PQXH(n&WgHALRye(VkzLvgNg9FMCPU3`dIxDGVn)mqEMs&J~ zTLw*GPClLp2r4YZ#tj|S5utGa9HXK?6y3bPAo6ACW*HS%Shkw)d+tkU#(I96@ADbn z6_L^!hC3VbUZ|5sZ{#lap_4FZST(wdNV-B6I=OuA_N-jr&SO$16#b<#?Ap2AnBh%v zMQ+>@qYIZU0~>c$ZAK5JieD|>;2@MpMnr?LUJUPHd(V~HA1+I)&U8z37NXha#G;DHR3Xm0 zb2hwjHm)EtUuj#=%o_^vA%Vx-$+`n>Vf`G4KY!ij-+}&LUk7_9Y(@)t-=d`s-#;wy z8;-BUWFtm1J>Z_(vO|q5ZBsVyY32SU8uwjzIK?13c`f0W7%oV`e<)YSJHekJPJhV6 z!ss_FStqTQ=(J6Y*9m%ucYJwId$raDj!5l^-2c&Pp;B%;NPt-3;!E*JMin)k8&iB7 z!7^qP9Gch8@-rvw6UbfVnIpboDbzRuYo%BtdTVUsL@@oX^$Mu30P2{X%CzL4=n&ew z#^=Uac1sd?h6yy+&Stx)tjk%zVx5&cnvNNI^$?PpA@$+gDBFj8F%5_iqJdwUmwg2`MzTn`y z{v+lE)fs}S@g8#>xEVukH8OcRJm47vL}?;EJc`6ykHlSQS{{X%ThYwsHN+|JEc)&G zh*W*FM;t-LS_V{%%e36wIKZ?6Q1d-kV#@>YuE1zSRBV)-!7+~OBdxl>@%Co5t8w{kzbEv(b6-bnPl+2nF^ zResjsUOO6b{-U3^9X-sY_8W+a;{+a;h>mxFt)Ili_uwbJY!FraZHeSu^zl^;Gb>%Z zF4i{h-9J*LEK|4%DigKR@5gtXPYg=2rbHneStOd!w7s4SWnwD&U_T=B-rfFJ=d%SS zzXS~jtdGc66A!$DuroP)DIC_t)^ld*lEXoja#5zVEGK7bl}Xep{qlz%_=xG_N^}Oa zZML<4I@F@o86Li$n-6Yd=CK6g*|xyRgDR*HlV6wJwXNEmD|b4)3MmyZ)Qg_5>Fa*q zmUq04TkOIncNZHHp+cwL9>=(i%F-bl^=tl?%T<^=5Cfypc17+=5BlL``61)e-h3sZ zM#y*E=u|w2PcAo2B+JOhj&mP!{sR6O(8b%tb)jeF=dw3nD2L;w`ogTB&d`;|b=@&r zRAw4>9_&q@k)LA9nC?#1BWE<((+Nk_!?5ZG2|W1vTJ=3ro0`Js{@uZ8+eiQL(e`527U~j zc$S^%!?AI;FS>P2hwY3*hqWwrc&{~|umSBfZ)Y_LuvY^zoO?ndr-bhgkc~Wf%8ots z;$JW^eVw6uMP*Q_>RLJ~z&$AB#WKzJ1thZkWANYg2L{cmO|R-z{MH$*dtHp)R8ww* zbtg=P72jm7QuXYY{-%L(?yyV2Y+a1^EXKHT90g1p}YUnHme}30Xz#BIoEQ`QT?XDc)u{ zINm{i|2Zh5*;AO}%p0xv)1JV;IDdePE7-n^IN29xyB;1DRi-Rv`eJB1a~rsHEk)nO zA@IQa`Uc!IXAg1BgU*wdjB^7f!P-XehY4t#ZjWW`Ud%q-yesk9#C?#(LX$UcTD|>EJANYmz|2u_L3G#snScz%dE&qKNfM8UNJZE5^mLSEUY7OR zac2wVc;?3A8MqK^)?|+dWU70wy8oYzNI)H4;s{=hoC0GcH9F>i6c34*CD`0wvcHs2 za*@HC?|HVXQ9G}|3xl4l(_+79CWlYr=cOtz>^m;1@ew8y6~-}&4DLM}mr%xYh$F%c z>&@K{BUSBo_g?YYiHO8zZS|XvCFhO?s|1cgzdk=1 z;yLTu72q_9l{bmj-08d#m-*#NP*hb6q9r3{j&IwY$f>5^I~ya{H=ot>**m*o{=|0i zwSbOxKT~IV+dRo=&z=qc2wC_-2?|dz<6EmEv}Qgr)KEeRGVqMeKXZ=*I}G#Ux+s{p z!2`GS;3Te9j06L|rCnhO3CMqyP$PkUi#jEIpP6h%PSTv8gna6kEyCtexDz291LTci zY@SzXJI8{cm^4obsxVt!VMB(=L)6$p?|!vNAEHyc-QL~XTH|vm%%NZ_;jCb|M&{`0x(Z4t|JkuU^Q0hm6=1?Si}kow59D+n1|olCd!uqmjE=8U zo}kNYI>u8eUiK};(Vbn@poU?@N}R{R)M55)Tw4upZavWkA^D(@ueHoWHou|o(#6EY zua|z4I{voe9~|!0!S{OJ-x04saG}(_;LG!S73V|C)73m6b`eGQ%ipR}wburvK{_$yYty+EwJ zz~}xIV2lq84w<{wZpjN4!HA+OWN>h#5|Ta5yY%HE#r5cbkwE>Hl4@=9`t#QHp`;g} z`i{fu^1R!!98cTjl=+qEgI_#D@`WdWs+XoHSwv44?)S4c@t^8N=|c3#KBVmi_^?Ga z!ldw~c|ou+IeS%52)O47U5?Vta#2!{cioUeIDsDf4LWkY*CGrj&IiJjABoq+_#i1=$G&`o0Ev5?__75 z8}oZOBg)38>3q1dcOnT60t#hBa>23|2FC_c9nlcw3v{NQbQf+E(Q&{7;@)*At0SU%Y-*ym32 zc+&y#*|Rjn!yckO-I2s~P>@|fX}ao(PYCJ$`*$M|iSqenXK_@Bo*ML9pSonT`cPcn!I79N1`hD|H^#DO{547~TtCop^E{s;vMCnIm-IvX+3 zs;IpYa7-Yz!i-7NRrr!^UVXD?%4TY6wW)ykx@0gHfhVgs=MU{vstik6mcBQ#iU+Z^ z|K!KHmKtP+l3?+@W4l`^EVE^IO8tpP!Le6UJ61mKI-z<|XqCce#>NX2&@$d+r~(aA zw5}!9S2%oIIbQQR>@>0RZP#coI+vJe(z9^Vclf=UmPun;a1J3d4xFhI7&;;om@@Cj zv?@@TTewCE62;4<&@c!5I_&%7R@5-%PDbWY5;NNdQ~Q+3 zyOutPjv5qy<8k0IrtChm8VPxcicA2N?(*V`sMC>=(MN6MMi>zl4g-^Z%7)b+%Nv&K zgVSNS)5@{H9rM!iUm2-vKcIcmHZud_Do}z>zE}O|2S5puAL)^0U0u0>#8s81rf6%| zryxm}F37NU^Ch4n&IA|0(n;I*bF5<(|KENI_!Tgq374TY==%i;#tpULK}%G8q2-cR zU%j5+00yvJrV03g#*ysBGb}*k6g}SP2isEdzUBcg74^$k0~xu(kjodSg}|@?W+FWO zWTG4c3coZhxj@!GnfWO^<=&dZESr!b+|Y)%$^#*vv5J1G)b_?TRMl6R5$RLf-;=8} zyk;w2*>!Y3j6CvDP{te`s?5W&Jp43HLZfP4#^luLPH>+?*xAjLx+xk*o?>5U{L~qW zKHGjHu$1sLh(yCWMaOZM>6^Blr7MVB>uG1X+rrBW2SRh!^#pgu($ zWFxvSGP1 zG7?^4PCSW$)-D9baQK*wJ!(vO(7=?gE$2{XEY>D?j9?H)$&c z+nKTAXROx;$?K|aZi~1slfQD$1&48RTYmgEqG|QPni%Mq{_~=x#YNj>mb^#*0no>T zYFb)ee|gQ>59~SOTtSa3B*K6`aryABr_?;_2fPx9**0PPeLa5q}Z)TWwW)MfQZVx)R)~&>dI(`W|FBla`~$~_1hPA8*d!G*Gpaismc&2v zXd=4WixpFXJ}G=FablRyB+S?$8QzFMZFbq-x*Nd{Tnw-mTz3qzT0HnN{ZpzJxOTY7 z;a!Dt{C#>$-IGNf14$uwEBT~p6a+6t+{90KmJ@#yTjG47QMoTS5W6+cnRX|dy5}u~ zAmvq8VI7vYj-zmJ^IVQNa=aj=E6PCT6@nw?m(js}y}T*Q#P=Vh;-yKH6ow_&%p;9< zY6m7D3-E*_(L%*FkCaWfr-R8Y%_L}lJYA5KJ%=N2d&0&uy3q#CqoH^+Eo%W%a3tRJ z@v5fPltE`Yu|<;Rlf3ctgbuQwi6}%h$co-uDuygn#N3S)76x|HJB^1@dAtoz48*NzB%rYMhSbj))C~uig+HMY$ z9PD7%z$1MF8o7g4zD)dZx9O;e@$3=D;ngKhfW7l2AGC^TebVAMGk=-Dc}A5+oEMMI zNG-2?L-)Z(Ews=3GSiA)oeJolu>4y@K#$@MDtl=MocvuOYomOiV$)2B_vF)}-(TtU zS7=OxASB)4_p$EC2mMEu9em9}9-M*{UTcLXz~fC;-}ue946|@V^=T|4m$Mm32kS`W z|LK?NwmOb}3;;idbhW+h;jrq3b@l&b5o)-G4_FTFK(<~b;7b(Zgh*|Mw>}2R3*e0;3WI-cfG*?S z{ls}I{NcU`7)sKU#V34E*f?9rod;lNaim%wi#xWs|MO%-!7X0k!h#<-fQOJMgxc{ ztlC!pEno2iEx@^0_1)d!asH58R#K|qzy^Ul$EYKjOfYNs;pp?zx|8C)VV40utty?_ zC}#gkFm68o*VfbqJyaQ|skCv8=kQnasaQE8i#MTj1*p2QTn!Iuv5Q2>qV*ceNmyhY zX37;f;}$y;f>IW7v0xMOxew*J!I^G5XL$}Oi%Xo6akZ~rdX!R2YJ#~7J=5>~yGd!z zgJno)i({zZt`>(km?lu*5I-0`KP4-4)g7UHiozB>MD1>885bvr$Zpii5+u0)$Dd5f z09T_}91?TKn2IP& z7+fBch|@V7hj5%@1(!5*%VEppvF~iSkD)Jh$WGeQM(^vLy%kYWPO_LGTLy~VrNF22 zS`j0seVOPL`H&VTYcncuD6qFtSG$$CsPCC*C38e77Ct<6O=8|=N}LJ} zrF|j%9aa1ChBS3%u3dUm*8fbjf~8B!E&0B5+ZC-Z$mGm>F*)}gBOb2jT7fm!$4nIZ zrE(Jgn}S@7<4ByxF3VxY$0zxe>4WW6d688*A%Coqv z({ENhK@!03 z@IOItz%BK|1^{%yxar+TMgMz;He8XU#DI$(MF~QaG{cnv7W$h&Gxlcmu6E6J+f5S{ zu84(`z}&?5xf07B6WIFG;K#&$PZ-$=**JS)mWSy-c|Xtjbj9>&4J6q>*EuG>{~~vB z5Rt}2aLu8HD9z?=-Q}I_s<)vfq38bbl>E~1KUx6F9!^MM=_}h}Bd(Op@aei`xCQ1M z+(RdCEK|8$C&{mKc;bvY?mW_>O8|N7w_m@ihQW^R?-T6_$ z&-u7WvCL1cRQ;3`br7<+X4tCqP(h#-6T+CG`Wnm;?v?J0&!_UtW$jF2RUNr`_7U@I z_{jJ{L>je9S(ox&4sh}=kEs_j3^rkaLRYU;K4DSq+K4{fFsiH0@jpO(M&ZHSy61_E zD3JairiHnET_y@d)-@S|qH_T%>;#naw=cQK4aq0E$_#zl2 zv&-q*@SERPcuwzBb!=XO-CJmXtdhKB)0Kp3f&xU@Fgpero8pF$z!z0|60l)pvU^pe zvCFEH7ovMV)8WYc)F?9?*((e?EJ>^k^l_GxpFuwC81y{q-$`+?qN~dpe$>-B!d2zwqsL6&nFQx6CuhjUlt$gME^+7IBn=q{0OOD!k zZ5G!1D0<4pjXH&Pvy@gs;yg&yE~}x-J-tfQDVVurFxg!3c`>gkUI;nDfhk2n>-!H{ zt9QwTRaRKlKORf?{JRQ11$>w}OUitsPQp!7Ohox1h$_1rHKtk{MFE7NB_ z0dE%#qey4tx=+g|%s|_MUUNA2pLwBD2!Jrbf4n&v0Fvv~KYXBgbnym&>uo@WuC}gj z>TDW3Lp-T$-wtFmS&^y_;NvB}dHug9A@Mj=R`rXLLur;ID6_wRH?s~zo+_b9epb!P zfYdNjOJ_*>0&_!u9(B(-&siQ!q_DSuF^SCjmH*KKrpdSO(A0Ckt4d`uRw+2wU#Q#e zZ2J{uO{qR6sNvAWn2SXRav3UhUuiCsCb{U7r#~uqH0_Pz$#StyQJ?A1p%pa=_PS_f zHhnF);wt^B{}>Rm!FQJYR!RuEcHV}aDWr1vDh*=U-~Jt^@|Nh0y~n@*_uCTpy3^Tl zLqi#(5~H`h==X!N6K`8P#a$(Oib#6Q5)q^xSpraJi~K4+)fa32i*F}hg*}cZY;Twv zTlh)p-E)A%8@_$QahxGZ%Z~hLh46|XmS>kply9f|p2kEs9S~t@?S)f9yG)zH`bjJzd(!A_;U-EObYJ~eDUJ62*0JZbalalNK9W7jk&JB9%rcZo_&x8y91$MpOs1V&*# zW|f^EP$H&@UB*ED3?C-Uf$1Z--jHE1-RrZ~f-t?o=?murS6nj?&s^NV~xNC(rH=Je?ltG{J{hL#05*9Ap*yVKC$T@prT;O#gyJMvlTOBER z+GDDUvK3@(ACVjsk$ZBWbVq;@$1SGmU`;a{x7_lw<38rz4gnYxJAphlQ*hBsm0TH^xp8^$m$TOY_XxKz-bhE;y$Rhh_kJE^m|nSUWo>j*e_36}n! ziD0CZyE`uob1}EDumf;424IM3K)+{s6i+Ql1q-Nx#jqFG*W_$I#0&uX-{=)Nbu zbjQ1sNZPEBQp`=>7>(mHV6L?r4V3rP8>? z=L{gaJ!yOm#P4j`5u@R~8OcK!gM2Z#J3H4tUDxeM&OxaY!0?vdNdZWvzg&s)$FGb?Ki0}d{LQwD z!lw<_&vaI{=X#qu>17p2D7M?2ck#A5@1xqzK2`ApqeYbu2h@}Q8ymDTTWMHP@43IN zCR6dYQ%04H9XLt9$U6H`> zZyERrk{6@903%%fx$h%X)jCE9vfads#%#H?i-N36avulQw9sY}oGNIL{`KLjk>9e~ zTp!^GTO52vm8X3D3P+!Wd~i`|T2jV>?gtrusfdj=>h8nM5&fp5*J}Dcfr<#`AF_B9`Xc0{8();t1;8BZ*XR;m86@grqw;sHh55s3S>Au6?+4FT3qZB4Jk8 zj2GMT3Nb3hZ|uc}zBs7($5t9sY5QPL@~HFJFnjEJpRrtV{zvRB7d}9h!O4_q8eKI0 z&w~$z-nqgV^t6j45c&VB*65`GhtQAi8)KMl)ZWQSPEipRptb}zJ1%U)IIIMkVj-}f z11fkK;I|T}#A9I@h=unPc1ij9;>8lsAW0a!D4Bb0l#ELeERHmfaj`E5NNxGUw>ntE+BEw6oZoJyEH{79B!pB$rM zS%F}{rI4=IBE!P*1)7DHIQ9n^Qoy6GyxS6H;i=grfYvy%;mSxW&m7?k6XUCjwXwY0 z7Q}US*JH*N)qKU!IY@U#h8yeennZAwAAA2|~ z>Hby3X4|brw(+<+cp|6e-|bU)|SZiQyo}X|7BmOsa(>=-LE4Bxt2ghRjFgZe$X-g~Is6 z-tO}#vs83)%1hdIVxMCvtJk_?0K%62LB$BT-LA6)G;k-{184j`%N$+_9Bf|3<*ht+LRy( z3svNNIzy zAuj6Pnoykh#tZi!ir%SWow*u@g{e=o?CjmzT0N(6Un03#ikn;>J0^(1jlIP%Q{*LA zGL@Ts=MT@%v!sp{FiDT($p%JBJlRcJivop}Wb_*STX1PeB2YzB`?#&O^V`?*vOMkC zw-6sx*0XYicg{Weg6qNejm6=Zs-iE~|1@|s4rSon^=K*LM6l|e8LoA5EXcSB*PFuG zFJk0J7E8t3XBs5LEnA9@0mCyWVDO&zZlOLG8eHv&UxS_M!s~S5gLJ4cp~Jh!hUdvT z(q*!@8&c+fS-{+es@snR%l$V`w{NYKe~`Oq`TzsNJ{k$V_{ZJ4y&EdZXT8zil+1fh z|Gs@=nwy&|>h7jQL_{Q^pb#Tn`)>|Zp57-fFL*fb(^Ws2l{LUqjP9%{yW^Xbni>`t zhnbd4m8N*A6&OY|x5Vu0*@McT)sb$IZ^BNgg^@+@0o5(@|)iPPI2R;TQh! zIPG|pR$#y<1&X|b%f5r(`#?1qUmtZC$sEPWU$y<4nHE3(H$v<~MzB_JQYmY)@e7O0 zd(~_<*G2WRhBPg%O?sNYBo)IQhpwT^8nS>)CMFiz*lw7F-ke<@7E`v?qmMDei-%y& zbdwfZTogU@IP+637ULZgQs!WSlcYVHTr}aw)nh_9rm1%k+jZXUnzVAIGMmb~w@R^c zRltNlp#-e&(R}&$jHh{*;OBW}sGHelvD(KSH8i)jC!6q{_X($1By<{5PcG{6*z!!h z*5bb|@@D6oQdEf~Mwu!EL3&%fqMrtNHH4mBHm-LBIF?BxU!+Qj6yKV8?dOx221^ox zT6tGiu8<@I?lV7=r z-Yu>wiX3bWgFEigKVcqw?!%F!fEQA~k+^=ARZNFaC%hyJW$Na!YR?83hPd+J#JT#O*CUibE2Gm%?@}@u&C=wg7B|-0;y%v* z{e2^H5`O=J+;eh{)HtTJFR2vTyv>s!e?-hRVbO$_)ZzoGB}K6BBOY-lIOsaTXw`;O^pN)OR`tUAYPnSb)*56|+Z08}1u_SBu z?_B!LGJX}Y$iWlvaaJ&THev&Pv0jZU_Af#~Hfl_R!b?ShNnSCpMLG*g5(QMoEO-Z! z+D$)@GNqfQybT%%R#rc*2}D}CSwkd6>Ye?!0c@bgN2J9ZEl6e6B2Z0A+8tzb4jO(I zK#Fg?(L-3p8&hs0zeYd2Q5>~M$`+zh{r*hp+U-;RlQn*)*~eu#%5E)ebSFF}rTnKY z*H>EvFK6zZwE>)xnp?^{v40;yTu`E*q=J7Xo0?L9?BwwdOj&5KEjoLFPq$J#^2YN_ zu>;J)`10*W`268VEnR^U*?8I;&6u5>2{4NtJQ^fer5w3C@NduuJGH*>Z6dB=@;-1? zE!mMzAl8g;Vu`bDLBnO{0iH=A-|sQX>)SbrP*$7FzJp0Z<_o0`RvBe7gh%A;vzt?yd?lU0H(r*c|x2P>)^%3r-lGw#(!Ts zPl96YeZ)O5rQXq7~QVCuc{u_4w19tvw3LZHvnoVfF^&j8_F^5DGAvWMWdu>|$G? zzjG#uYrZG~>QLe{W58+Ddi1P{m*+`>au$E?%@CBKJVg6!C2HYGA6Yc)^GAc0gg%nN zxi$ASnzVi$1;NFXqH{T}aOBQ=Uz=$Ix0$YuzO%^&4@RV%<1~zn#`Ry?UG*=hQ$38= zExw#FSAEO4g^i9|_QVO^)d$YV-F_s6K0<9Fk$YOp?@URwqSFm5yOf4DWb+~y*R^V_ zu$6`iXOW)k&qM*WzFX_$A42Gw*k&g=mAugnof?N}82}j%xa=H^vwjK@t*_myO%VE) zX%=$agf63&7y3d<0FKK6>R!3H1@Yx;6yTr1E6>~ur)&KRxJNd%9*w*FHZ_>h4R<3q z&69YsuGhBH(&;H{iz@y3hxhWcyIMb##K(gUHiMibb{llx@_dKjJY4YLI=@~O-RQMw z!ur=EGjcbwLwj8DDEKYiG_))3-=VJ-1|ZgqCB5BR%3laI?%W5;0JFs>`8<Qtx-DX{I0dht%9W%^^(Y zwQ?uQjEI8<9@AA+xu&Cn;9bViIq5QDZ$wm9}RG$h1n6)nGJnUY6aFY2%g}Gxy~!=a zkg2ccwDg9Ni5yUBUM3x$M&=;+{3n0+x_i>~Zw?Ce&uc4grCyw`H6Gqx@Rff@c`XB| zKM+N+SHJB4;7oXVED+pMP~&_d1eyITM;N_LnMiCns1R`Rb_aXRMsg}%XpObo7A`$T zeR5V9I`}o)jvQt3JT=ZV!7>ki#F`V3i1?1aP%QRh>f62jp-`zBwPtN)X09HuxrVz~ za&=Jh3nNN0PszD20_(kJN%+;V$m{1FjA?nBQAO>Qi`4!_FGPbBGTd8o$RqY4GCudkvMBq9oSV`8WIl@8yZ3?%;KXyNYfM_ z(vGJDN|QmW`mI+gG~qOyoX&TlF#bt794c8MY0Jc1!t|G1iLXh1g#YH0|M z+-R#$<+zacQW{L&rc13myl6eD#u{0uK;&r#k9N8Dc zdjzU&ufgfNk?kkn?uSm1<>qy5$t5E9R^pRn>Vpx(pu)%5~I+wPq>(;!!`0xN|%fobH*WEa=o4cdMv0lD}*s}xj%-u3g z&+ZphPvZX%S6>0tX1i?-6p9pUafj046nFRHR;;*7aHl|^xKj$HI0Xt6cei4}f>Yex zrFbClznt%$d+zz)Nixg?5+*x)KU>yb%UphIrgE!)^tKK;cC~I_sIp=Y9r~^V8;I<9 zl5Pqw`B2BF+E6?)4_qpbP(sWzTaQgjS-0S$m~@Mc)XX=jvspU$2lOqnp*pffbW)4@ zUofeXy))3~^F_ac(!Ur+^JZ=_Ory%gU2UbEvcO{=A=>;Zglz5HiV=b{TYDBdcb?RU z_#@AWFKf<~gO1P$4d|M*cXr$C&xfehK0_7{Xhe*ZCZ?pd*;3ki%pvijB|ngq>ie|y zuGqmJ-J^_+hTfbBaI)@y!Pp~5+U+hvCBbZ zB_ERGtB%~!1+ZP`r6^wQ5+ULe*Sn`nw?YlNZtG#o57_AFL>5tljczHFD}{{ z_3D5m_juoqVKpmGvdW{E{nDd($_J>QnaGQ+*+UN2l)nU1b!|}9;rCz_^%)rF{zpTV zSJgYw#6LcW2!s-cwS5^hCgsZJdy(IyI5u^e>^gLTN#3LX$194?9?t9ODDJ5J%{}xr zF+#671u%vpvNoW zU6#QzU6^Y}%`2;!&5vP`A$j0xm*ANMl<%bh)8!k!@5In0H&sMvkbn*C-3d-K-EaH> z^#Be|!V&fcO7@7->UP1Wur$*7%-i)YKSlkMKmnm~)cPUHDJdcX-N#Q}X2$25von8n zQl{WZ?2^4cc7v*PuXSz|{m?o)lXsHp3kZxepz-;*UKw9HWv;*4N`bSVwye3|X>7Hk zUTsj_wTE&sbp&OsO3S=ipt9>pi2Ghu@}Pbpm-YpNWqR#~wl{9Yg)7A4Ps7Gi*kfnX zdh{2(Qt7Uk95Idf`M8;}sg_}n2IuUAxNkLJ><)T!>3ejvkrZcU(iXnlvJ=Dnvhq&S z){A51evG6%;S&}MWCaOZa*Ahn9B#M>s~q?J*ec>PKj0SmIk&3Jw{PlaL?hlC zpxNPZ2MvdxbOY-zYDqjedY@eoXow@YbJ!LmmYod;Gq_@`?uT5z=d}CgX#gz`)Q4IR zlnJ;@1O&#f8U`!JN-;i@={4y-QO00Napq!BvKRULBHze-RGa(CK2$>Z{W-yJ&`%ot z199&0?5~R4yuX)l9nZ6?{XVu5oTH3}%TP@;)1+w_E0!=2%_(jpEBw5QbT`ViFK5^4 z^!jTK^4QqMo*U>Cth#)`tF7i;y)F`r+Usi+pIdWc=>FbK&&YhvSD?M?@HR#0j4+Ft zPSX0UI)l(+L{|2rz;j6~1$}t12hj4UjCHCu>WcYM=gT~ZG2*gya*6EHc^`f@{Xk`I z3^$MJ&qUg#{3S6e9$P7bYfTkG%x}I=k;1j7Sp37d8Am$Xgph=h{;OW+FeY_6^I;)B zE>FvAw&!dcDKF|L88K-C-F6-@_CB|q87)!$5KT=yksSA&l}O?gmzZW@$$D`3i4qmI zJvuDSZA)!R9{;&x^n2*HXv*H9g>os?-O3?8TmC6?q?D2XorR>`coTgO)~U!z4eVBk=YZ2XyTxlO99&*^yTUQhT3z8n2g%y#+k zm(c^#;+3G%x&EP2jTy{?q&SqsjvyeFvN>87lzyRtzxA$b-FBsGL<%RjY6B}3YgTEd z!*rbgWs1g?ORFB7Dgtt+k-SIBA2HGn?;lMAzoI1*;(uoj0a&X~d)dG*fnBcs$p4@c zH@JTTOs7?jOM;7@3l2Bq@!$|~YUg69Ctd9ST>MAkj52RtNeCamyB7qal@W4qC*Jb$ zUc`eg@(NhWhp zjhyem{fbc|>oS65+qd-w)`fL5G#zj5I^Oq%qEtMMjVi1!y7RrzJj^q%-kc&g@~6oV zHRWc3vh2<(;#*3vS)e;iT;qtPm(D?nb)UrGC#LSYT{3OIqz+L+hq8@=eV3xF%ihn5 zJhxSmDUS!KB9(;Sz5vJ&xFaImh@=7?Z~K;VJeCaS7r+jtoYOCrVrH0*CtRoJFYbL= z!?OfB?n{TAnQEjB^`y3l5*Wpio|)b2xOBO#ne`ndNtyXT4) zhpDjU%|QxrL~Y~M0*^QQz`&Oi)<|X=UG6n)WdB?5gH;i1^Kf}Q;)r_eP8P=cY@>U5 zmehMJd9|#=$el@z3g!ZIc8)NsneYF`0@Sgqoi0Sb&vic#d5k!i%ryHncZxWjRmSEc zKwGcJT48u~Eg7i#TS=jMk7i)zt*m5a>AuRQ^)Mu>S#FF-usDU(0$VC_x{n|u_w}dn?JoKMTcnO^4om zEfxcksZp_D?@D_}<}a38eqNnNR6&?0PO5p99B$Hfb|mm-CT3@SCd66eXW#iLnIEC6 z{04t>tSk50gj{~@ImLY2mHc#cZDHoQrJSO5i*h5fmt53I$VO(PA9r-Jqx^uufZ|E{ zDKMROX`2PAwD@){lAYE&jV8Zn4?p9ojL8awy}4Fj7nQFOs_90h8?vE8dT z2uSV1N-XUNi3)5IdY$3l7I7IlC{+=NSYWJx5FR=<8%272skSIrk$YP3RF>lwCU zU7NY_xdmE=Y`PumZ*U=+$U|nPbcjf+CPQvf>~3}gz3j8thovlB=I`$<@euexx)tH; z9TpROV;3WJ*e;?7DG|(F0bu~x)@`VwuPd_QNBg<5b?%$0^RfHPVBWeLGr+@pVDJ?g zQ1+0>S`e`Bsw=u-v}p}}f5ngSfFRM_L7Z)HLDbrOO=h!C0iJP1!m&y=jOcHs@u$n6z7tsw~!U`aMsfxfbm=Qd;QQkZC6_CB7_>LHNMk4SCH6a10 zHkf#+9s;_r(!cYP)Ij_RwJfvO%`9)h$+zkVH4ww#$k3rP?cq`9N_c3JnK_9OEybkb zyY9okqp!uz-vqD%3zuEk&g7PwDS{jXgm=Z1(fSKRX$b#>n|}_w6i!NIr91 zAMn0t84Hw2?gwub@?T>b_-#+x9L&WvCx0IwYo`nzCzLjmm&)kFlTNEZLlJOO|Jp*l z@nTfU6Y_>EfZvGuIVz)L3;Krct*;0Pzx9Y6H2bgC)RfrgxOOjKp$Z96;^PlAy*)g2 z_1ae(7^0ZnXm1Ym;RdaTBsWihKm-KLp*KAnucuiOk0l7Z?*|^E1}wj?J5QeP9aRY;x#wJZYAk8$Os%c1t=t>!9tGwh0x-KTAC;wj=ebJv>654uvVG#Q*3o2{aR zugRuxKkwi}MKs0+A`Fd~FRxz~_cCdV!)S&N(T`eGFcl~`3=-Kj^^$}ut8c=#0Z0KL zgmD8YXC=mPj3;$$v90g$|E*XGi2zEmu(yiIt4%vu-FkppTX8qA#`=FQ@0DQm(JxGAyd#tnA8;HWYYKqGoq4PVge)a*E_JgPP5%15$}_?4yJ%fy z(lv|*bNwm4_51BP+79EE(aZYi9FZ|t#sqX~T``519NM}L$?nfcd2bZOOz`;iFtpL) z;c+$gnV9s>>O)cnx-i3FS}@QGF_E47c1k)xG1?}J3*cRm5!0agoCSLYP+dUlVm zGH7i2u{^H>D1|-{8U>PA>b&N2aQ*v0gADA}N|jX zJQzEJ_IgPtB&am?DPj%ge(P6E$F@3NKUd-8!%aUWO9Gw^`oze7BX_902FyB%C<@U{tn(L3F zpF}}8*PF|uH8WYLW7$h#Ieu&kg5gSjyqp69DSU8emO}x;Xlu&o5CJc4W@=5X(ExMl z0!ei39+M~@s1E^w`WMqwGp2>B*a|pmlHytiD2O_=Q6U`Sz=V0)x28G~|4L}DvLt5+ zh59}9OLqYoT9wXcY<>v1)L}1{FM{$0GDbg){XTh&Dla1@92TUEwxWvPz`hm2+^jd( zS^0Ef-H@wxDAhh2@68hIZbn#ONoc+XHUAQ!>V=`F6gL<)qv8_%r^EABuF7tF&fD_( zkvjcAhLZztZ_^%nD2T?@oSbeZo>ie~pe`lGjr)sVo5C3zTX2;eKPs5Gzb&Nm&=dc{ z#HL<#xbLFeG6E%X&S#0AKGP74QY`q z(0p{^{XHTw)9?FKIr9f-p34R3;W>iZG)mGCN{_jrO6xq#Lm9q3RXpt#1GBw@mRowm zLGRoku759K%mjoGXC^SO&6QyRoYof0%D32^RK@RBMN36J5{voW}TdPQE7M9)T+XSDR(V}$Hr8Q2=#mrc@MHY zmJb?3!%p#FDaa=>q1N~3VMUk~szh(O%kDlrmim}7*CW2C{xJP;p8Y7?e$&eq=ZKsC zL=5&M&j6_Ue$TH!k-$Zkz@=mK_xGP|aH7icJr+1zZu9-%-_p_oP~dp2_TZ`7Yj_4x zqy5iq>~{0q2OlFejK~rgLI0ez1x>${?b&O15CYdTa@)YiySBV<+P=#MNM<)D4OwCW zl@yE|D+nP~Np?g6cqeZCPXV#n@T;I^hwWi+))D{i(-J#0ym-)wAhD&Pdp!zM7*5Al zXhD3N?H$|cJuj$TwYTsY)2|hIP?Dmh__Ih8QZosR0dKy7!ekSbYnrEzRJ^ye?+XTJ z3P4wQu}v9QmFyh(!sN{Xz~UY|IyGcNmd zIS-KEtQ&66iWi-t&sch@Fou$(J{$HUrLR5b513hOw_f$R-)$&N#dRwvg9yki*}2I$ zz`=`AT@j`i2d?M~cUe6pca**2V=_j8Bvi2>$zafsJfK7BsCP3 zKgO+O#(%$hz~QIz-qIPTz(;`q&VXA3;cMq6AcGk2E!)S!j*2~EH$FYLNQLPR<_>bA_sFn39B zqaNt?Dysd-VaykZhp?Jn0xRO0KCtJ?dC91QW|Nqo>fIzp1kc$utCz^xOMAb|k*K4> zwuc2^N~@a2TRtXAY4C_5T(>3Uu|V!ICU+)>8c-}lqD(GZX9oGBV=S_s8w1cxWq3^M zJ#q6@0xg9nu0BTKs|xr9vZ-0M?Ihiz?@8Me-6x=&h=Y08clGc9ZavRD=>cR3pO91a z42u8!_S54oX644m6y%p482HfMCv!_Y(4PG*gCl{?P{p#2#~7@~X{e{AL584ByX*nGPjzdlDi?gUmwTlsl+NFarKz2Tg5<@Py0V zQJC|k_UN^2)u@(pBgr|)*H`DI;uLw~VDI__^OU;L^6|y$ER=U2B`MMgpoX(G;e!6i zOrwq5frQpb11H42?9{ays>i!93%AR#W7DRNZz&oC`Yu*c3WeNcs*3j-AZj4b0vEZT zViBfm&>8c!7+OTpa09X4vRptYhg36GI)DHPx!#+av!ej7rm}Gd>$s^W8iO<^n<5|| zzxmZUdzm%Z?b5eTjO0X?vwpA*JnUlg_e=-lOm{FPYiR?A!E=dMF@RWKi~R8;>={Fn z1gyKi_EnfheTQbu?~{OW&pfR;fojN(O*w-xfoSCNqNZ(j(D#}n(0aAERR@Q++(Hs) z(R2PQyBpGMK!Rr}IR6k%B|6x%X60@DHvCkYFYO5V^k^QMzc*C=%+BeqrG))P_CBo_ z!$7}|BX^dLEkC3F8|-V1uyiVR>@#gIU`5WOz`tQidY! z#M=Kp7e_mY9u3R%Pi_N_eoB?g0)=KZyLrmrPeXtfT&ODeZ(?`-!Tx@iwb-4W{aiK5 zjB$X-2>%8qS3o2ISZ$_PB#g zdIIY4ktJ+iSQ_?hA9>*{IR5EsXrLyOKvP$s$x;x1Yc7tPdRf}Q&dtKr(86=t$;c4f zoa$h4ynPhArW(FrCh=-%FLYM{`WeG)`o}MOd~>rm&uB?{^XeT%d5P3mu8NCE$+avf zu?>FA%E+k;L$107bT`ZiuAB4sZ7o~x* zVu?KOp?eLk$F>w@9rpH@@2+e&HFs|GYj>%>fjPBn&guSY9WbqR3!D7)JXW2rS3j&V zJNorGh%9(s=l&o9R_$9ShS=`^@ytJJXN}10NB3okb6rf-hU!2Q3Q|-I+{&z0AUtDW z>M+CV%v(Lkm45klj#OYfvoWgIYC_k@`6}Ipn{Y+D?0w)mKa2*}SF~b8K2I{bUsPb+ z;-7hElMkM-VxyukinE}xz-MosbHpqEIL$%2@T7_bX0v;g{^eK>SWdG;@Eg4 zH--+I7KXJ0ln18|*Bw+_u9tx39zcE`1K9Mr@%=gxhxJHC*c*m_EUM%OFdIZasWAaW zb@YU+A3ro40aPH)ohU>xd+`_lIgHu=0C5I@laXIJap%27LjsQDo{hYZ28Izg_uXD5 zpcP7l-x(L&1|D4`4kN$XVyyFHJ}`yqvP}Pk0@01MkGX|ProOVlG2Mp?yE~@bl6CMs z?rVHp#U5PM-khNRayd#7OXa9FyhFp98lKLtaMcBW`<5ExDncl_(sOACr3k3=Ff9a}B?Ch?P{S#^zupe%Vv%NCs|w``1?s=f)TD(j5~j z{8nb3@M$ahL+}oCl9wnimgj0SUBIkC+6#LwW&5gh7VI=)D`v}gq<)*l?W*eCw~sSB z`kbjNVq^`YM&$68*s*>mZF~@1KKuIh?3JH_t~!!apUk=B^P?RZ1}7AHG5Y5A-9Mv+ z3M07zhp@H2+_P4u=UK*Da3dPjx;5Ca2>-lwc%Gz|5UGE;!M8sSmgP>)4$ZkZ1k)Ij zwCYU12T`2J>X)`Dy2TcMOcJXDOJ3g%f+&PMrySe>FwYv0Ty+9l`D6*-|H-D<(R~i| zSE8O=8_2W_mOTH(UkDsDgqCmrQY#>~&P{WpmMd>NVnJA11IWpzS=*#ujTmuK|%;jq*k-Ii&EJLBui>x$+5%?`We zJ&KAB15<{#T+9WFXY?Xg;^ShaU=-i%Jn|;6b$YcIXQ8+_NFV<XTSCmP?I`}4#&s_Nh z*~a*4P5a1;NA?)^-rF^NqHHm^@Yu;wkJASNnEz5c_-Nnjym(5g#-yBT7BpZuu9U7L zh*awL-2J}5HUdIyXB$+HjgIM0J2%F+gF2f; zH~+XE(i2-Q@H`HHjdoq~e8Nq@V6cx#-~KmCrdFb~x%@1dGj=*VVDTzdso-x>XjcRS zC^q_}4KdUe9l?2hUF+tYr>|b1r-&?1om^@_5PM5ZfoGf#CrH?v=2Ei*VNPW&jT%w}lSL44fjRRE;G2Xdr%2d| zFGyHuYu?sSe55VlNlp~VAgi+_4|t0x^lY(wm$2eS)&*~2G%t#diD7I+#Q`fh=^0rF z<_PIq`}x}!iSmKS+E8D`or4N9BQ2&%s|A%A)e4JO+AK~_1|+!jz#!07a+s{NNtVLz zo9lDE+}D!ypP#YWS=c>uUAvawFUhO2CC9K8Ua=R8Eivii-9A?NL*>n@!#Q@|y4Ol8 z)k-@=cXD_>Vtn47R+UY1^=%2!>y4*l8u6f`wb%(X<8-vNq6xb-_xbqB8@Qh@7M$Q* zOG+$rwC>_y*H^{+cHF>b$MwTu$2}Nxhm5pN=PI-MXtyRikD5CQrN$`UwkXtN;c)R0 zzdBTebGr%%hxE%arvh4zHrhkgo=LV;aEbr)qx9vnjm_Etnj|*n*OZl83Ar= zJ_9X4#r{o!hX#0okZtxaz633IVB?12!{cC%JdkZP=c^DHawPHkUI+*8vjp`~Z=`SL zN%^W*kwb$%R96-EBYEm^&lCU6`FVQx#M{|Fs&ST9Rys<|d|4Cx)Oke^#TF{* zdK+bX#hp?qrsc^qSY5FLRi;AUO2)P3#XVIbcpl61VA7~lH%V;C@mCouzR8uO_uVxo#Fhj%c%4-U2>3J!wHblb9UzPUy*Oz$RI{J6@mw& zevm8S_hO{m5ulv9*l@ObpPHrAyDv{Z>QQx6IBgQa%f^klu0O(#AjL3(-pdQ2YwN@^ ztCQX4ac8-S5#JV7ff-Cg>$Ky%bg4oq>yW@

pvptUwjudoc3$h9Hvdbd5D4Nga;evR=!pWe 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�h5<&1e5aTm^#MfvV+e%{4e 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

EW42;V}I8pv&zVMU!|K`~L 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

*f-ZiL<;(MtH-}Bd|3M=u8#YN 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

CUHn?NYaCR5*H4~yHeb1Z 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

D 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 z z_cbf;O4Q{McXv9b*{*SL^6`uygh*ZvMYa1 zC?|&q7gtg@Q6-J>^_M+1gZ7xA3RDQ7p3qnRpg- z$sP426=ju-SyfTFV?5RhwQ!X>_`*Ru&1f?H5%bT%M4uk3b_2pld=&71eqi-QN(|!~ z9@NiO7F1vH>=?^^Ix<7N1|bNk#4NuAQ^w*vp>yr6&ii?N2VX^;1m3E8NMHIhACOE( z&D~u7rg^{N;PSC~9V?S6NrHJYr`|MU(xLV=)#>c-YN#cpp;2O#VQj6zq zRKSBQ3kf(whV}Kj-3aS4qe)e05zi`kur)-2?-?upXSLE1Sc>#+>t(yHFZ;SJX zm&&+J)4A6K1SFlWs$DeI2C<}+*Eg^?)?Jz0E}^Bj=Ll+Zg~h6{ib^fU0q(Qau##LB;yFdE1Y0}SSDq|m6wbE?*5s9?(s4U zBR%3xw&S&P`};!i83yIJwwW%kRc{mQbLA|kIIHj>N|D0{I$o;}IytkdpX5fVE{qwe zYmMk9Ch2gLjVR7|(T^iUwxT|Iuf?;NR%IY5i2tK0{JYd63^z@)ZjoBar z>A+P+(j62QMomwT`U5B=Rm1e+Y8-|_{r!KNvh%X(67e|&!(eoP(WtbX*V%k&50o}p z7gY{?@P*9nkV>!(TNKdQy9_~q1)tQiHr^R8KqFvX&iz5TfjdKZ4#H(7 zNxGTpRx)=6$b>}xNgz8+*+l!%(IE=lE|b}^jDxSp1vsCO`E;fkytitPiGOM;`f};H ze&=0N?lG0-*2%4vDQBhLDy}5FdHs{2MEHepB@!~`W)pqsnp+$i&LoVE)8mdMuI8V| zyk2ku|D0_6^P@qq1!;FX@1;@1yXkVx;-YIi^uw0MaCAYa4euWN8iQJGQHDt}nKvSv z^TD7tk1+}vnXH72wZ$Ffz!zK}R?Hb%_x11jF~*jTtRF3R~b{G4rb0DSsDwLSGC<;2Mhv90%{-ET72~GE)b}w0r7kPwub)MA2}#Z8m{wy6 zQx4_3cbN}Wi$_-dddrK2KkIk*x0yzYvI0&857jk?F91Ujzmg0-JTZ9ci`yZ|fB~ae zxq`Y!cw5Cw8mU2GYL*s#^V%O{H$-^1(Gu&YAd|}8g%VDzrT$~Dah@2#L_SSV&z7Sm zc9!p7wrx#pL-EW}PGTa_ks9{%c?L2p2<#Al5(_Cb5Bgsx_u?~kWq_y7$7t%Iw>^Ar zn8$lH{K-Z6?+Y^{1+C_X(rWh%G%wj7n6ojx4YbmRbY5v!#W1fffy7QAAhDOTU?&7V ztPF(RFktZp!MV@NfK(nw?08!`tpT%;5f{&;LNby9NZtN`asMab&p)6FbpY*ZBKTij z@;v0+FK900XVejFQO9r5_N;!Amq0UvK?-W6QE%k88C*>ZHTx-j>DXIv3vBy0o}~G@ zfTJ#*om~HeNa_&C3Y>Il?iU2Fsboy6WTi#nLB8n5ejTte2m_{){5ueN_yVm4Rc$rB zb?bf2+!xuouKb0+ zSD%u=ihS~6-m-`f!g9TwT^Qdn+!5^pUlXwHye1m0g#YuS^wLLYao2zK4(+EVKJoJR zw>^7KCI^=kXbm>lnZ7Tv2_-jN{)8!O^eKEPo88BWAvV}7cLpueHuCD|%}B%&K4|(N zL4T`fZ4BBG3?@t0qnok6D5xM_ue*IN5s>pIL!Oa-9=HI-+_^Oos}5JHNMV&0c!tgT zEhM!kyhJp<;axv5HBx!If~4GN*dEU@*^Jm+evQ@_g@|yLtuqR7^enX#_Q*_$uYV;F zXSJWpqO!^Os#hg$z~5PYfE%7O{@-PgsnhLl_Wovnl}oR|eemL&#KiZ30w-=4>qjgE z&#FLuX|>Z0YXW6N?#zha&Q(6lfN>}Ocrk4VH3s%KnwJP@re%XUak@KqDQRiL_E7=ARiw7C7DH3hw)L5F(8)W_?HL|^8svw}G-COAml|isMp+>Y8WkPabEfPS2AwFS zMCUqsJ5^!`!5fpF%Rcz(K(1rY3;fUP{c(ough`fKaVIBsHI_3g$t@skI1$JAnXD7IygFVfZ*PxW|B>C@SARS3Zbj>Ku=LzQNYBA%luy@ zSUoi!rDa;MO`pgN)}$js=|$iVbC5Gw2u~f53dRF|ne>?K%R~9g43UMt3O3g1+tn}u z;%@!g%H!2ASN#i1=;1`r5+=z2=@4HS-_6-_ONNN+^`zFd>$;Tkhh*BSZ~R%>2NBO< z{r%Ur*LG>M45n!`forAL#B`P?^b6__ybu#E^jx7!C?6?sj!0u*Od>R#Db0XA#6T^sofMBRPT8SyUlEU>04~d{`Rrn^n5F zShpbOi{xg~>|Nhjm{6!_#HKhkJe1xqDDzLbR`(NG9*PoSNC>4gc@gMA=#eoctsGil zbjr#mT#ZXYsBGGo)<1v8QFLqnuENp_f5p?G;Y4B0*w3Xasc`)~EsXkN^`9^jJiL`p zPdpY8(lN+$#i9JF@fQU1rR-+^5`HWGX`J~cS6gE9N*am9hnzek)4+b3mZtx!#Kx!4 zweP;2kwGwoFhOPMiss&mpZVcXQQvH`UP2<6ru`$dH>2w0m6KoG41GbpC+6a+P|jb) z&-ycRmU(Gx6hejQWbdo!$-3aYB#p)hDRR7`e0FDC_lV_itaAEP_i=0p91s)@Bu4m* zsU%17^~c4?=U2SF|H4*7hA`Q3u6nT_$uETdyBs@TM@;JqoYg##_@z+J0a9fFEg0QDB?IeIqL$3qsV@7VWF6V3tagDSEBT zgGPZ}&+aL`)2%w&CfCE}J?+}i9p06#$a!rKjp{%(Xk$n#*gxt45~$omTaLxoc(Jx7 zKWMJ8CBg59MMh#Te!FF4BH@U%$kpk`f4t3HY{ZV~5)7Skj|C6?lYZJ*I<8{b4}BhZ zlSL&EopJbEx#17j~_iUK$AAK{9L zb>!wD`i#xi$P1!ZA$tJqtJeAF3+L}Kj4$8KqasH9rONdD_WldTw`w^1Dm~Bli;gwu z8C?`5yqDw%xx==xG0G(R*SQ5m0~c1z6+&beDK~JXm9X^Y*EFMH+(Ym!@4^k{HOahp zw>4BOItXmBHkp~vslIjS$@#MoAtQe&=iS4JBZl0TixKra1S_d@dy9koRYlYe0#+*b zkGA^WBNoAVaj#)k6KgU1nSH8jj`A=V!W~Hq8P0^bnHWMRu7m{~L1Zw6_slB^OH)Di z#EZ0Q85I>A2_6lx-D#&aK_mRbHiN?6^!H@?<2#Z8&EX`yY?8r*KNau;){HrEgy#&L zm6eQXO{+q=h8Om6%kiJmaD+yl5lR}EPbs&wm^0j3C%1`go>9)KN5%5yRRp$L--j#) zwSJxcJJD2UPYORVD4j-)gz>SN*>W4P6ZoHOjyv(A*0HP0fs6(```NviB>MXL^FYNp zv<;kuc0jeyWpM{gpigPruE|rALo>FvwjgDvdC07Aq7U4Pg-J1yr?`?ore#9f-Rn28pwyqbcdO`)I|nlf2Hv8E z`Uh=~>vh@C(N}?At7JrU#|!Ojh+@gjqXvU2oX_Z%Q|6jfD$niu@w zO`xAx+1%)`y;5@zGJk+?py{X$6}@Ht$(9BpJq&=}Z>Zwz%mMUjISAcmW*ev=3F!%B zr*~3WU-VA+_Sg7d(V&#=kQO>B0d|ga{0~H6!i9* zHuoqhNYC?Za?jPO`YXf%{Qk_bgaDnam(`nEb_Lc=3LYe~ z?ksNaut7+a+ofH$TzF`xl%u0#x-62Wk;cXL_1~nPluq2m1=I=bEg*jXMc`E>$VZLB7%c5P;LHPZgAxjP8)5-w64?g7fm-rs?*(BH0L4CuJo6atSap zp2JIRE}cPZgq2E^+mPNC8>kQxS-b7t=L5I@sk<}LI2ZK#3!-r&3vSy=V zW$1io`f~K>sw<}2&!ch1F~_>}KF{a_rynscE&;Ol(C57Ppsj?DDINaHZyd2cMPrFZ zD-%Ik(?fgW|MTzu(U1%4VNNAr`86=3VVW;8VJ9dc1#wVT+!Yz|K_;|7H2!) ziQy!G-v`Hf-s5)vDUS*rox9o?K^dakq(2YhJW%N>~o0cb7uO`a+UdX%L)o^ z7H6$%=bkbb03bY60eqWdrFw$E-8i|n^kmFTvTo@G@%W^*9zgN)G|_K^Juytc%nafq zJr$K5s3LvZm%nZfrQ98dc^Uz`40J}KNn>c1x1`(L)s+We5l_Eq1cG9L!}_4c8=#q=iPS~-455E1|~W1wB=-u1M>cUUoI@smHNS~JVX^ZLA6;82ScPAU9 zE`}BZamoEkzwk!qrna?w&)T!lxz&_CiGbN0hrFcT_fMRzl+h=zxx2tf?9``a%QaA| zD$lS40X!zlm_e@#VPj)T0HqnWWd{TkaK$<=y8HdDsDOB$Il6C*npY=#F1p@r4sy-3 zIKB-VNR!_@8xp8#+CPqCCNFZfe*g9ric2FgVIPz2!P&O1NkO<#!XKsFDmr=}YD)}6 zNL0Y*IA?3w40Lqkt4@43omL*su)53~Y`{TjNp8@w%S*FHA0R(Lip3#B=fy!F47T47fPEzu4(5I@XsQi8} zQH%IJ0hGhO`RZO?pPbvo2@__~S#&CW@pr^7e1WHcx2had(RP36{^gh4o7=p3<@de8 zm3&y8zSLkA4gwAWZmWtab8vxqJL;&~qRw+T3?(otI1Aq5nq#*WCx%o^ zfr!R@Fp}_`N^zAbQ@&3o@;#80q6#whA(iYqa4IRcwD$5wkm=lgmHc`%Jg5C%cgTwb zNr~0Eb=;ivSeQ|A2o$@;sI*zavZE_3GS=4p`&aOa)( zrG`=s)PXzo6d8jj9ip_7A>#Lj&xrv%LB;^G2GMd6DJg@%Harbq_Xc&WqZXM=RHZ?B|#wnc3zs(Y?H|_2`~mP znKlA1+6nNpi~;SF`0n+45j21NQP8y5)YxVBwT2$TM7S2>`pjLB8V;tX`qPIB z{o@l~av?9&^Ca%yTW#%hpI%Fcc_fFF+7 z+b|&kaAW>qvEN0ZP-yctI)709zb44|gQ^OyWF!(g`ueOziT=HQ8g|W7UqiB$64a8)`;(R&w~>ivlz7qEx&)VT9CP8I3@ z##Ot@ZvEPBP!8v#O9zF`v|%o*mVHQ-pZ3YB%>^^|%Ryh`)rr zfNH$dUP>Q-C;9D@h?}k4&EZHduM??W=mg{?1rY{c=X&>yrvWWzr+8RLAre;(S^v*d zSJ)uj-=+avY>3GF(Tw{Z`kBy9sMrgbo>yl zfQ^tl2&PO@!jRq^t6P3&2X+*xOHK`H-lAGk24u80Y32XGcf7w`yj~{aXv+nsh?P{Q z6sVWP8$smM;C+x{P|f?intJG|uefPcvY*m)F-dp>W|jt*}3RMJ$WyEJh5eLs=>uiS%AW3MZ=V0nY~Gyr_O*~$`S zf7M%6%~_qB@V>J>?$+d z*EE?axcgpHqS@)HraM#AQlz5NbpQJ$^fI9NL*0+1)_YE}<>m7o=}6Jm2y)kx!cv#> zP`>Gh3AJa@YwO25#Lmo~ohV_K@xXBV4Qx{cOG-@=+M%0sok8_r!Cj(pl6<*$L*72ErHFAbF3s~W8zfN?Niq173B(KHkvlu z{RA1TQxMpe&l|Ow5W&pgNJ^TJdrR2Iak<#PVv=eb_=>$^o=*6awldDkM3=)gWFt#`K4FUsxWOYG7KgOy&((F>hnK1_T2 z4zB$lJ3BiN-ghbPRbmjZ;v)cKUwE+~1$~m1ZY~T)mq%X7DaUNt{u&=BYq|totjP^Ng5WaaMBjSAUfa}X`SgpZCWx&^?SetVjuX}CgZ%~Ype?fQ9j?~_C{NVBGi9YWG% z@>$?Vz9pfJZC352_(x2Sv}`#-7@X+SGwD?O7!smYNvK7qkVCrES5KEZ>}D)$(y<{l zQXD?(i1}sXaGz9E!Z|cE2eyCtI9y8EUJQlzArr~_M8goaS0=vd47h)mZLi>RrZ z6NZkn-b8c8`IkNKVXOLC_QFyEQ`MQPK5?H2meiIE_e%*DbM|1VP?PW9sJrriSdzkgq|qdo{+x$HWv0WcsJG z7Nx+kDnH&Is1OH~ij`mgya4_86oVUYBJ<0ypx*~D=n?RIa$fzV;^$8(P|C9#ljV9c zkUtqx#l+yBEt3#s?f}u$&-UftMywIZ$@50;YUT1^VE8z>J(`6W6SJ6i%bp7>H6k?kfS2uScL5 z+jSE=+jLNVvbM8h-AuN}cug&51gO4_Za1elA^!gVGWai)Mu*9UW1WASyeSMJY1+$w>h3!|HYF%kCL);*JE{c6?C6m&p@4|q^0dGbb5-A z0_kc)+rBl;|2-E}q#Jm)a}QbSIFBCB0AY@d;OAqbFPg8{jf=#~YG^X-^cwQ4Nb5ml!ZJ z|2BB+c|Zn&MW%?8kOOauUMAFBhKfq?ngSK@mnXc#*NePebtp7l!KCtSJrRr*lvXE3 z2&Fne+O742?UPqm2Z1A-X~Qi0HF$~Q7~6fAfZ6TfV8POyV(YWg_^hDW5Yc-?baMq# z!l(dbFkv@dE`@al-Deb>PZZmm+*C8y1%F_c5F1@>L*2Gr_8F?E@OqJ_zPh&9oP4*> z)wc_`Zt4$yNx=2a7V2``>9pISf=||Wgwfn$m27L!_Kk~fpp1tO$V=ozKYxpIhv(Ho zs0#U!!+~USP>F~f@N?Tf0DZTAs_`JJi5C$!MyGp`vJvD+yuHK5B1=h{$n*cl^vdD; z3&-T3-6%c-cXmwBm5(@X+*f)_!jO%wPj zt}Y-Ro%XZhzFXYCRw{FLgq4A2f7E?hu?ajP*h|TufCTA`LHvwF3iqZNJBbD;vT20h zFDjO61kn`q{Du_f_r{P(#ye0M4DgTcX8rtHR%xa!#sV|X>r3p8@Zuoqz5SJWVhFxY z{6$ESa2`4tBb35j(FAOu;Y-iA)XO?0|HPYRHI<-4D52Pi`@cHQnbBde9+aiQFx<0N zIA96m&n7&?!|J;_GXj_0z$nk_az=eW0mL-KJZ&K4 zA;!k``t#MaDnvYs41`^P%mA()>b;b4v1_q2k#8EQ0?TZj`5oKi@u+=shI2FJqTh5u5 ztV|dk&~v`y;)(-?S0IS_EGc<>Eg`0&0vh|SWt&$ZlA}H$g8#`*@D2&5)}zwr@h*1s z-<>;`Os<-8yWBY4kv0S)jAZEjmk(&b)jyfA0?e7aNcBoW1#wAZ8JG4C|&Hq~S`)x}G6hh(ieKzicWj2<2qoVVWkzj<6j zBwf436m+0(+&!Nn5HO3JGDPw61In9|l~%pA(+@4CvH7hmib{%g%f4^xj(y)so{3aF zeofEJY_rB7>C~#N0I2{4HJar-L_K*+Nn2H#r4_2CMhOvyUCbxF)Dc?C%vPoO|AHD1 zA>Ac9y0ryw#gy_U>?Vq9|2l3A((ALg>n%XUu zFwY^E7;13*4njWEi9;dA*bx-H*BA`^JPB_fZuQX0%Zn>INu$>{)3D6<7NjRjTNM?w z=fB=7)XulX^Bo*z`LswV-~b^i2IdkD+`-oQ4d-jf9`6Oy+lz;;Z^0iK#khnFrt3FLxwT4f#97>9DY7mJg8e6 z=@a45BJS^Z%;+&#k+xLLInnT7oR)? zPI$SA-u=`qq~?bbc`F^Znacdp!V)P&?7KKvAL}MrT{9ELt>e3xQlv)%4J4{=gSw`_(BP0g2Yl02@vN9Gn@-lT(Bp;E_K9 zQ1Q~k0*(V1f2MDB1SAd+x?O};GZ_|?9g-q4^aN_`Po z<1pJ#H#=Y=$iXDaU)z0;wtI0az6+=L<4cfS9%{pG?gG>qA@hXm&x*2hO=f1r?R2B% z>?0b+dT^!nu$)qT_L7n*hioew8_6w|#> zrqGbytV89g-Tat2z#pDn(;Gj^IpvOs*Do2mUTWldkcXp|>VR@eA^E=JmAK}BI)YPu zz}AR>De$Up_0r9EmhueGn~{(Dci(tm9`4s1n$?D}mQSYOTE zdsR}tUYH^EHBap;KbV1tEYpAH8T9ih3_@xvZU%4p_d|sbvQ51fp<)0caPWY3*vU`Fx{Pugaeu+B}g}>2UMo zxdY!O5k|d{$9$_Rn+76A_8FsQpov`FA{ z##m@{w00gMX!(>kcC8YRHJOJw)qIM92+WPuV6ny^RDx%}J|iE-7UWw0KMaSYS(#w_ct_pbdKZa1%r7xopcFDSWeOJTwYcBd^on3&{mluI-+LDB$lI{s zLe8aUhupa29+%c~8)}X@YG~0(7@@DPZ8yl_(7ZwD5D_6z`SRUG8)^ceqAWGbe&~5T z%+wQW`@FB7E4XN#F;fWUw_V2QuLRT%y=|5Va2V3Oio`8a)DsKGK&)A z^q4{FFW`}&=S?Y*Ek$P0mo-UdqFI~xN@rEKy_H+P6SX9V z2A+8YB|lbfiGzF{VYB7R=Rf9w^!7puHZ*iODy~EW_i%m&lsp$GpF(tIB`04HRFvCdq2!K0#L%S{BfFw}50>eH8LoYEF>`**6^Hi)*R zk4C&=c@`zmG6+IWe`cx|)IjWuzTy(przt7AVvE_1H*rN9eF}-l?h4K@S#dCEyQ$Wo zdiB$qmSJhhC?$SG*Q1QW1_bv0_m+By$C|Smq6LL5moLAhDXJ+u5XD$BUO%={WpWFW z%XopIvcB2$DOWWYVb%mEUwY?X9&U-dVa{FU>qc<}I1V!M;f@wiP zMOD?hg`)on-7Bv&;hG(uo~c~;1=52nJVxI`K>k(~C#sjX)m*JT$XEPETKo33aUE|X zIw7||a6q%2!wQj3KZ%ZyB6s+C0y~5IVN+CUB}4(d@kH8q3!w_7 zn}GyuTLStoG8P)hs(+?Ls!H#41kCe8&|H%^%Xg#Xxg#TlZ6%Ro@K7r#u*_M(Ii~&w zraUkhj^^an1Ta1WF@QtvYgoPlN6&IVknZ)Ee3YJg&yR=u?eRi<7LcSlT8N)JKF*0N z^adOI&G}wsvfB!rpWtJ1HIUgja)Y{%IM%ITWJJ+xW`+hLYC9sxk%Pjl+1y^ps%sN9 zudHlw*irmoYlFD`UbgvvY<+c5*4@^&3Q{5s(%mUYBOu*K-E?<%r-XDPB@Ie@NJ%R&O7g!@BM>en7Qfo+iUG>U7=f{x)49y{z*fuiv15MGah<={)kn%tiXJ_ z=p7(?{9c?^tj*CSj%I(oam$Gp5{3N>pn#{#Hc|G!H}hVAMr{n%D{&x8`Yepu4L?nDvkWrwFfuU4r^%DbPIM%Nm+^-AM z+_Y0ZZ}}3_7;w9?2XZhHO>`BD^ZYaV0(LvaLvRBH@UFuNBNWNt3j3YSa~9lFhy2Po zzumnyf>2q!lF27FGaTwMRWRroX8;V=R!U)L?(9kLWJxRbVL}Tap?k!Iy zukaFlX)ZKx9Ua)Xi(?av0D0iAEVKTp@#nE&H@KLIajS6^Nl_np#8eyM?@)!MGFHN0 zg(z0WV7Rx{60ZcBj1FWt8sI-?^WR!VdUgPv$scUB;rDDLhquD{Y|`JDPYAyJ32(#MC~YB+CnU|^uu zDKLSYm4rkX5kFYFjOrunH#;yBz{8t0G4m#q3e>or_Q!LM-Mqp1VA>g)qP1vG+oan_xS?!Y35neeU4aj;)=gfpV zu${Hj<~1h6cE=2)uRQ){PA1`S{C%yU&$xNV8)e|4lwFAAJ>nWu+#wTAaQ#s)ck@%q z-lk<^q`N<70(5DxL5=}wq{DIk@Q*RnXd_;dK&8g6&w>eT_#+w;@*-GB-M&J0a>`mm z;~i|7g+HWJP;n**WXgGl2Ho`qVbSz=g=-klC0;kJ|5n=41H(jn{&B!2hJT|8T7gt% zUDbMicJ=9dqv-}}u#xJk6s~TdTO-km+4_xEGqW|+@-5AL-!5{yY*TK>0sVy^FLJRqM$&Yt#;=H;C@; z)$;v?7g||G!|9!>=;qdk`?hCHZhdlc@1rg8avMWyM5yXZ(#`+$m$QvxJD zz5=KadX^mHW*^{QiLLT^E$8lsuyAh7&D2P}GhXHlduC3p`jXw&VMU0dt5WGm2*!|u zYGdvUJZY+1Sw93^^0k~Omb-o`3EU4b_iNEk3ot-{E5fn#t0ONXw=utuX5htpY(ymp zq^5xe(i<5Q7uUJlANRmGkpJ^~C*$V#xES;9h33^&8#>Agm&iF))$b;loud3r44a=)9Yz;B1?F;=1|{sAT7m&NdB5UU z`e$SDz4$C#RzA!2GrdTqe+;4E*KQBiKHE!i*ZRUxEWnxm2Kp`8$UXtO-O5>{F3QF& z0;B}hBRM63goey%%4BZ?iZ)fpUtns=!iEt<5mk*xN&cmzan~^Wx*y zVns=PiJ(-o?G#fenO_*M2npg;yQT;_Q&CVz4ib`&j*c;cA_!=TCOqxsk>Fn!nhnGtdc5xMui{lyJ)a)vJr9_-&1=ZR@%M=Add$$68iP^d zLaYW8nC;F@cjj;-U?M~(x5w$DJZ~tFAV2r7Ppr6Qg)l7Veu?=!(8ba_bUKWpu9WHI zTv)NEI4r~6OO-%H4I5i5S~8lvgz;~;k@X9S5lShJ(^^+c(yLp9I{HB?p)f{x+%c{w zm-t>0L2>jhm_Y2YGr@l}E8n^J(!TWpI5@uHcwe|WiS5L8%>1h6Dfn5o`jkI>xoz{x z>kx^(>-O(I6%zS995uGM(@>m(&G}U!0*>2L&X0A@P#__ZQ`hoi@L|iG;MJqe$|c-o zBawx@*A*&?AZ4uPpQqrLSJnzeP+AuOZ6t65Tl8Sr$T&Q+`j( z9`sr+CK~=jKpeIgUu91)$0aOAzpUL2UnG`i`-xu}O%bE8y!pt7N_uphi4ejNMe&eU z{3@X6n#e9hVDpRX0YM^u{;9Dg`K;cD;-R?PphpJ%%fsz|n%uvOWJC@hiSKT*ZIbdUwFRzFOVtR~ldOGv6J@mh|@0=n~JS{O^p0o5{*YYtM6eg`TLZ6skZz z?(ckFca;{sNQ^vA2wIysYX#b6Hj~9Tp~F2hPW!=OAtY0)ca?>)!1v$tZx?z}xM(Rz zz3*_py39@n1PRRNlE8r-Q3hr}U_?O*I{Q544oFT#=t}yVa^w+42<24@ z^JIi&1`i75H+WLt|JXky7kRt0uXUxU?u7qEh^wfNrzVaW>QTb}{6_x?6>j8JmmMKK z9JBf)b?8J^z-;NFW^8rRMZaTMMtDGizgtEcmID7d>c{~_QOEGot?yhY)3ppWn!3t7Hp$Z$f zjQwa8YhG|4ekzjDoAIbSXeW?=s!>$8`{Lg)*hhPt5c&trBm>ljne0!O4h#i@vR|3U z0pw<%>q>@;Q9SSBGx_Gb+gR0}B_#hwN&fdcXiPA`%mO$(Wpk-W6xpjt1txx z7`l7b4j20Y@ZnB0hVRU?%BVdw?Q?J7Z$JSEcCpfU6&^1fw|dkvOQJ0d6|vc4xKH_TY^5a8b6TTNT4+6spsO6HEWW^^a1m z^|Itqt_)jt^dz`Lv13*$85zfd0sW_ncE|w_<2pvFXSEYKIvc?a6 z9pSnC5rzKlQ@Qcr3%gQOR$2WiIb+T0??hL;!|5ADujG{DyLb4tK4(lNBkrFPqcnHq zRK2#te*<)GMnfp|WVHg5(EiwUGBMS=jv+s~v;+M*)|%rnAowCqoN^TLg@5d2F?_;A zUwLIm+By(@B63vAC71A@PZA6$`0&+8?3274M!dNc(iTKazBA|*OtaG?khpnc2^1-* z+V?X&U>03`t5PZ(N5SKRQ$wHG#;P{8u`^T3K9nW(u)86Dc}(uNpE@}?8mUIQUQ-Jo4F2!R`ll@sqg0b&J>85Fir|c= zaWi{8dXA*9{7nC}z6;dNPjd!_mQGKcrw_11wp)PrVMcuGm;sYoGaM76`OyF-$7HxL z5t7rON=wHa5a60R>$542#_d9RwJUEjKQmoK(?3YY!q*DfK)ClOmjFHKYX~JeAYuvt zD}4`jfid=t1_VNNMUZO-Jy;(#;`2kT0}%oN>*U=FcM~;nb6O7Ins~fo|0e9|lEYY? z-Z71Rm}xz{-eFWEZ@TjAY*YfUKI+ag+I4LaBs^s<1K+-IY&}=VxLPI#`pW4dwcAl2 zG*Bc%i8?*szAvmF9XL0Mi2*W3>WFPkn?<0?a_S~7Z4fT(?F=W-7ld}}+wE6zA-Myv z0g{Y~Ap%Ou6@T%f%@*YZa2P0wafs2#g4k(?Y^jw`KR-xe4MLem8>w5NA^%b>7M{5a z4F@-MzX?mELP5D9s%4(YzF3zRO9KuNb$VDg#!;-J4D3U=h%#csQfa+#=&<%3vT zNs&sG*P*(#+oN058HJkhd9j-3`DWY*OVIL&OV~Syt%s{RcTe9Zu%P*rGoI>fczIv2 z_zo4b#q979F8x4WKBjp$s{+@l8{MQ*>)PaI9}Q>v9y!~&X&I;zQDPH%4(J9r{=)?r z4#TS0eR_Np!uFo3o#sS)qKtzIpBLW_56{Udot&h|aXkf(Mk(~hj?Xs+u zl#(TOjF8uJ!NotHwpY1WcfRdO#@wDo5sUuUx6~z3p@IuxIEKBP8un_+TT2UJoEm7M z9;kL4#K$4&4MBye_m`>H`QzMN6dGwA;WI}~t)wWV373Ah2j)7CQuv?23tAtX2*u83 zU&<*vr82n;|J3=T36r<{Rdj}9Jj@2=E|SMrlSq{4V;F*G7$+aJ30Y`%Dw{r`+JqiE zc^sAlmuN)H!#q)piZ`MJL|!RgQVORRp-lin;3!l7-PVEM(H<^#b8)DVK};|Ku`3A_ z5|x}@L4N;SCMR|2P-gKTXi+cP%ET)Sq#!5}`Dm|Hu6h!TpWgwlrljuh0#gZ7Vg|+N zNW@kA9eKgw>v@LxSxiuJTiTa~ExjS@Lq^H8Cw9$h=XA_x}$ zoV?2Qg+TXLhyuc|;s8vV~a7VCUi!S|? zi!M?o6}2=!=&=erpCsR9>xO*CADU+&E=Ou!zqa-Xz+O*!f6nl%uuJPf{F2Q*mv)2o zw8)&+amxF$_U{3?TyF)r1lT*ByfgG^Z9RfEe?psubLqM@P1S8UK6@AYgQP23*!)2F zmU5JGA=R%?lDaT7n_5XZ(V<$G0M;QvPO}yrVzngDG^|j-{zcZ{m#KKWh~4FIk9`QwSOUGwP#niJ8(8uzm`qr1Wko7?&I;O_Y+onaS87R;SqX$W2YY_#5PK ztu8K%Q~jDZK7r+vNcOfG#XzcTR6qd`L&*kbO`6FEhPGY3@jdS2swwH`mJs|G+55k5 zO#;2yygo{dz(T?+g`+9ntXkdLAtYsN}JIes>?%*@?n7cy#M;O zA-?5lhu@%}_*1k6Rnb5JaU5qm)|x87aGqsZW2=5jU0{!k*sq^_CQN*82}5M2M&? zMfAP6xdJB}_?##9*A1&-(&0p{Uq!Su^{doU-<&-h_wrkAp30 zz9r6!HIh95+eFOt(=LQ(&u|*Q_V-U0&4Evf{>e)md3-5VCadycBYT=$ByFFbj*-7_ z;BdC;!`WLUh#~hWhc9RP!r6xw;%n5q#7wT#2%JkWf+*ujm>)m~<}M33y5iyvo5esO zKxWKY-n4G%jWb#}l5GVAhP_3n%`>#pXo*o2$(?!0sG_8!}@I~f+wQi>Q?`!k_dPjgOWkm5j z5zD3hvM=J}8<^0pQ}B6R(9^`7DpWrq8ThU28ZDq^IJ~H%zKIJ6>4>LMDs$!*73SK$q{x&cQ1tgR=%3CT_|` zZ8fP|GX@5`ngS+w(>Wv?2E?h;rtE3+kl}qEfW8DGCFif^CL(ODnQ%M zkC+w<8Ut0?@MQ&YBkgZwEN6z|`liy-P$xAyS}b8XXy}(OQBhHaMRZ@&Opy3uh>J7T zjod%NHLN70q_``N?6|r10g>H^$5C3c$M(>j*J|^VUe!EqS3}Mj${M?{-whXAz_GZT zmwM6y^XWuXedS=>E-T3k>cR*e*|wf{ZPLU|e|6I?7)H_p{jV9n^MUxlvs~t2YP^Bw zGCsNKN}p13dpP)Up}ooN&s_m7fcHm20t~#dQX;CCtnddlWu4oZ=Dx-L_E9eMD=ggI zlp_`5)&-5o`};h;^Qok)oT03k{Hu3rbfF6T>-gQ$0w)rul8W+5m>1dgB$UN(VzLN6 znR6zef-59scoXw*L-!VKL~|~3UOBX|keYUv6<5E5dm`sTt2zWHP~x3GiazVxgGhx5 zhvureM*S%a5~=BF_s&O#ItMmn~56PuR! zRp$fS1aOEw+B|xeNfY|zf-o4*uXma{6R@WpD^-E}&N3h5q0NO#2tUj8>eOru0Bac?(rpi(j*)_>0Z|QO zzd||P{>;ox>`(^%!k(m$5ADR+F-NB%p8TkUUZp?zaVE?lePu&Km@MD zwzyT6gy@(vUSkUyT3Q5vb}{Qokk_?jbj_hAIl>deUtQ!1s*il;#0XpEw#q3x$J@=N zAsMm!?-um@5i8Be{UsjLvNw-IX;Wkw|Mf2!+j5_MM>+FHRIztA;MR4KI3hPEH=vPU=gG{DzIs_ObJ#LiK?-a6He&W(KekMj9OC z|Mc0BSpRy_At*RkWgf5MOhSF9dG78NaVN3bh#6EkF)enPwIEnAKgZ_6h?l^Sb%XA@a7#G&UcRug}0}23GFn z($tmEty2=1RdtqjbbbDK6fg4l7I*0E|IleahRd@O&>|V^_$fbTD-WshW}#qxWhg^k zk`p-AG;F9YdfAcr0mR{D>Q~H53_e80?IhYU`cOH0@NH!WRjwk#Z-zb1W^^Z=R|p3> z3+1tCRSW&>Qt!IyfSNnt$~XVL-qy&E40z+osZ1aJWb87ti6zkVa-p+38Z+aBUaoc| z-wH!8hiW}XcAmOIhPF~${*qC!zmZh)MwaI0Eg|!msC)3Qj=~8QofI7EPr){+tb?fM zc`emk=t^{c8q)v&5t^|doGms)uyr<9hvCK4mTJxQE0%V1hnk!o38~?T8Ic{3ENYHf zt0oam&6-7A=TTm5BMmI3%l+RIwH_|H&9{Xr#$g*xF3)Aq?EUm`px%}aKJUeWG96BD zRMknEi|c*kzACE;Qn#Di$OgH@`iRd{3P~I#!~@^2N94ZSK{@sZZQGZUA?98kkJd|w z691UBoUQD!Hx+G?rZl#rq0 znkCzX(-;gFdv~z`lyIt*m7cS}MIS>#yJm5|$_@mD#00qPD<3-FXQ`Ile{^A7WVgvR zi6TSCpRNS^+O;Noi=?wlPmjSkt zo0p2%lRj_ZW1v#E8bo^M%CBU-IWNhb#UxM|EEk~n`4|FlWHNL^y}NEG^251DK@?8( zrrbJNX{N)ys=mfKs18z+tW4e7g}%Or81xzUz@Pms8WSV<09kB4QJecQ2#AvAbA`0`r1jr_YAjxElh>Nj) z|2_Hufwb#0{T6IzlugwTQC}HVwN%D{2)sh%=Cwm@*;_D2E6Ik*8OWNtx?;@tP^hfE zU1lN~XWagC%bfc%^KI?R|Kmn8MY$lEO=t6TuGqtO3fIUT+L3Di`$e1OLKjmCyWQnq zJ^Xh%V|$1&XtA-o_VY%-IhT|mF0N>*G;cDj7A9sDHUg)!(j-0WN9HfJ1n+a|AfNjf zLKSVbHM_(J{C**DhTK9S*Bg<_<0D;KF7>5H;JpN@wGq3!4ivPGWrrR6>3X|qLjTN@ zaT=PCt}d3|naZSqcRJmYX!-BzepDuoD!3&N^2Jx$Lm0y9^VavDPG<(GS9ewz<7>By zkInPWZ2GHy&DWZEY`y(UM-V`Roc*E`PYB*Ye1lB=d;W+Ci ziAOlnr=lYQg1FgB)clvtw+gA!KTXW67fDKFA77tXuGU6WmuN^d9w%@WfaGG<3e?il)8}(+WVtpS4TA^ zJkSt9>UHEXSx&vlX&#X;OyhZQBXZk=)o6u+^Pp>F>I--|D48}@dra;Jzaa0&sNR>(8%M{A6_mUU$?VwYBpJt)y>ESb=u4)OIH{5By}>0Y2=UccmT`m zjQK1u&h*2uWXtoBaY%VkM2Z5G-U({IV{lV^eej_C&(n*yv+?W#26>t1h&L2@4>KWV zbC zX)_ok#!W44kzx)F=&+2xW!RW;t-?Z*^wq$ z(%Zvfe{kp5LVN5pN+T34vqCkLN3U_4ZxYN8UGy7j%3|^#WQp*Vib%n^k_I116NaA}lgAl~S zP=R-m-RZE@-_)i08MtH%E?!Y;(W4~o0^EEyBvT4(bW`{0UmHgDqD=E=3c>KQi_M@4tYL_!myLF69nn+T=J_280}UG&z@GdJNiq`&RxCLNx~r3;fI4(tRDaiD!xF6cj&k z%5vxcV-|nMKuZE%xQOE3EZ4BcfzjFXW+FKySo>(wS@vprvPYEJ`b;x5J22Nfi{>!@&>{fIzC% z-=dO)1bkn}8i#fm&XoRU$M*yqY3wbkzVc){M?n4VLk+GYjJk-HXwcj^xiF$|Uf8R` zC*H6-`_66Y%Ua3(>adnvLV7dK|IpF?tMPruNKd9{)bi#6)uE7@xI@p=;KGy#Vge)k z``P{sTGyP83?(0^*NyBvCe>PnNQwi~EZemMwNQJ9mOuA48=|s@%Y&e^O_qv9A>5fS z=D>QeTRYO-T>xp{_T^%ck%yoH8ZRvJ_HV$o_y-rx@a#wmA}l<2m58mstzCS6<7_oS z<}cA64taWrN`(m_D8$*ZSNs)CLh5UrRA%F(;c_!v6YMw>nZvgat3M9&}yxVO? z`iQ}{o-PovfKB5izKDpW=Pn5nxM+~|ME)EN$LWjcYiKOZFCbGEa@s_@&ij}nBP5&$ zp9PtEF`_-UrhMd%%&g(iPka3}0X1>D&MiXn8>(g3LzWvcNesplEE*}}PM*Qjw)BYd z3(1msOa6~RaXYggsP~8hQWjpXeD(BOAOWqfa}A}f$Pc07t{;Vt z8r=lDI;J|j9{(+Fb*!-a5tFQ4V7K*#<_eQ4fw3IsIw@oCkFXLSJ774pG?lO$&1i^; zPyc2iQ!s=Ath&jnLz`d0ef%N}@#BN`E2K>-aofZKjd7S^P>{q|*@Bp_nTOJgo(+|I z3Zq+IT75)0(xi0VbFHe5q`FXz9kp?L-v7sS3d5C}~A&Bobm=Ox*`hc!L zhrg_H8IN5_Bk85>@L^pO{D&8{jA|Xb$sfi|p?toMHTd{|BUHzV2YT2aNR+beLO6Hn zHiV7lDQG)%S`e-zjAT7(=5-(g{(RoVS+NJ4kgSh_hQzW;mD-~=1t~Lw-Qaa zht_Tz9L56zrsg91R$Ab}mNqY*4vb5+2p`TtOKaEtWyuaZWxb8e|62~y7=a5hz#Fu~ zz^ph~3*rLdQJrE@l)x`Sw6LS4j)sg>pPipvqQjIGW)ZQiI;v%+>^;jrHd-9 z2Po($9pRMW|jyQ3f)JxkA6(4`yr?v zI@`ZNb|BwSvYc9Q6cPkfjE_IiNp9gRFM;LV0TP}Y7|mJp&@r)ILSHuN zcw0}+d=!9KB{AS^CgOMhnQ%^G_TBwUxa;V`!S zjb<~AXQ!$y-5(Ym7iUk|+4jzv@yAby2VyIW<7OKFXgX6{v2)5R0TEa3h+BKt6GwaM z)zYDxb`uTE>OJ-Lv-(eI^h%HmwYuyLuW97l>z6qzaz&A1%0+Cy8!Ov?K|X(MFHf=A z?j_(+sGqoxY#AG*ql?73Qrjb8kx?YSO zZmoOhLk?2+vhgHG9!GPQwYn)|!O_uMw(IJeqB{X6)e)_)az+Be5z$l$*hk*o_nbJ; zai-ic7+YW!s<&M^MHv40T7XUx$o|btP{|UB=bdC^w4ytjNWsFDmd8#|=&&AT+a|_W z3KKcZ*YMG-xat9pnO|v8)k=NjYYVxlYYgpfJ47RY_zX4NlgY{l()R~ocbLBWkW>nf z9&BcZBdR6*S|86&$4oM{Z%NK9t!r-o&q_3mXs7o4zqvZ(Zoq>Nw4D+a(x!t;Dwj2=Yh>3H8z%u&Ka`@swWQRwq0q&{69uM%0tLHp5yX_(XP^v7ab zY;3G<3I+JGelNz{Iej!FB~9nEpjyfrdPr=}a-Q4QN=~q(O-*&GZj^%-jVxLJFYa>7&d3&~_VgPNVME+_X zjCD1O7;u`;0irkW(svq3gzC3un6>ALX**OXLkbUISIgX?xJFcXb)eUOWGkGw`ty22 zAZ|Wuu$oR6x`Yplmd=MO5Cd59re$pkDlUnltx%tPe?04kuPtql1Mfh%)8J@X%v*7^ zmY(o-%Nl#@G#(nJVVP+nSF@?ln?*MIR@8goHTV5&V2*(FLE7e2g|J zh|mdUmetaA+`pGyuJ$7Lrg!NN7X5Wy%Rj`EiQayXL^L|&mn-uAb;`OslaMFU(VP~` zDgv!oEV&X_KoZu&?sr=}D?ntJ#fgrNe$lN*Rri-OZ?uerZ3j=%YUj%>x=DUt0IoW^ z^`9^F7IyhYJI&MXzJ9SessxZX`0^S%L4|(9+P}VbtiIPclcyd`&>Q;`jC>4SDbsJA z@02lMzivB@Y+J6|E+{Z!q;;*;C(#JSzW*a+itdEDj7Et@kPxno9*CmL>SYS*aE#H%)Ci_-DWSp)}tF#-gSzLlovIv@`)x&%J;SuUxf?e-Ox(De(Rb-iy< zX=5l5Ioc00)Y-0jT`}9Nd~AKZwEzwTepcpbfA`DUSb!B0<>&OFsRG3t1>w(_aE0AK z1-+Eo3|znbtQ68v@~h%Lp}=X>Sv%!2GCkD+S77erE1 znYq(mUX{b~)Ud1(Y-7UJBg9h{0kTX?H`uUD$`}c|Gb*O|IOirZZ%t}}>Wn$dimGYH4!Pk(?#DmT7$Jox%`y7nb;r3&1ruK$0y z08FGEo%1bvQ06a2P(^dbk4;>xdy()9B~_5^G@Z(gjZSVrptgk62J+P^NP{@~JFrWh z&!tb0eF8v6(WnMFpGcMSUKixU<8#@QXBq&+XI9&T0eHbZ zM|%;ovQ|fy6cc?UO2u_ocN3U20Iu&#w*F1uy}>^dqyo{4V?m-oN>~HK%5d_BAdqVb zGoIZj0O)cxA!Xf7x14#NEuN@5Kn07!isVQ*;x!Z25x%)!MpdiDQ#qPycf^ws+wpkZ zO6JxVO?z=N-E`b&^`y5g-I0@1WNEQqs)cj6o8x&4OzpNTfS42}0>^)b?3I1*reQ3& z0D7%@ZqQe$(bFe!#c|Q8C`(`~xURigEmM_Wdt?B%zkBm0P}ZM`sq@OqqnoHc8{b_m zrWtLWQG=VocSWcDg?RpD2PUkdco(eZ4GJu3kCtP+Sw1BQMTM6~u5_}W=uG+V78fp% z6%^n5Bb$_Dyb(f|E1N87s)|j-@E8nigyKbf5p6X~g+)Y|t^O#judf5!SDGegSVFyJ zhx@g)wI!d`2aviM>a^dgyLfpB#=~q{?{1PU=fuUw!x@_fqakcyfuhB@=OGc_qZqkt z-MeP1)Gx0(VcuYQX^EJXRs6V1HUtbe0$f%Eh(5uP>HtvzjJ6lsB8N>bD{or#<>A9j zq7jaN`G*@4}keC>I-qVE< zc8s8p+HVW0RqKQ?WTf?GY;-j+VNcx9*SN?pPq1(z-y?D6G`|1PScck`@b$~f~ z9f4VoI%J6hfWMQrlnHbA*~?s$MG3H`3}4E4zX(!JruE3mt}*heW-@1SB*L3smau;Z z$8;g>LfjTgwqO&Axv7XRSCRDlY(d!*=1>N+fRxxw1P6D};|#{Dfl!xLBCDJgGpG{@ zq!Hy%3{54-8Q>WL)2}TW)sp#CzBb<+GrB$+N#KuVYZoz;kDTQ-GZvNL|V2H?0G9(KB$#a4uHBw7?Sge%JNLrW2( z(hCGXKM0W1s!G+nKSj;F1~BYlKV|PGl%tu2W=yf|XSK910C=bL^KvqZfQ*i9x}oF) zcD?a>m$|BX&qW*+Iu6mXazgy~fl*AuWc<56GVNF48y=T`PtZR@ADHGA(n>wve3nE& zcu{{e!qf8SK(ztQ0eu*OCZ7k8hOd@9m=hsWfz`U% zbRj0*Ovw(2ncsLK^o*`4nswzmlH`kYI&w&^5)l=yJPLD?PT`JtZfqAi#blH(OngS^ zB(mwV?{+eLMu5d-gUPAkjA!fjNCF=Bi#;39Qg%j-TN-5k^Y<>F8&jq;%5s5wruU(o zRxNpyq&Y@#l#x)-4sU1#OWhg#eoP~z9^!{&_7 z?Y?>;66j1yTV1ruZLGlvsDZN$46)=l%{FW>er^#VHEBJct-OQude{*U*)p_y< zX4KNPz#pY;Y2=d3;r-%w%9g}tfpxY$ya8T{ z{B*y=j|0ryfJMZaIUVp|0JpvA#671_+e$3xl-yIn<_1lvVWU*PTN2e*Ks59`>@2M9 zj`E+)obP=EGMyrA_mB+bvh88BN!zJ4DeKRAfj8OUCjC7Gz2)+Fv9epnR2~Pmt_fuP z0(|KfSJ-0)FCsjNd%DQ;D)24eKGo%3XFmVae39p%7}3d*&Z9y>QU`F$zCQLb*;%N0 zQGK|Q*0eM7Q)@JRgd0E-AKbTx3K4~fU;G}vu{m9?Jx)E#-Q6|C@-B}qYhCKgiTWrx zTiTkYHn=Yp+coW9=KSU$CMik$$@_u!U~(1T3b@ZzTQ4s(5D*cKLR7T(mYmbhAk?1J z`vHW!?$J{;{c0G5gd^oytyP@Lm(o)t%rV}K1}xZ!;mv!LWzOVvZC+6y*x3VtOBSwL z0tl=H7ImUat~o9mjO_XOK=Xtw?e?W^d(@<}@#5J|Q;n*PIHQg4UaltXGlodPOhqjH zq{RS6k4&#K*cnAYtc5GZoXt3_$Kz#no$8Bsx7^a<$p~JJs4>t-bE{r}v3Y)?vYD zI=o#M%hv^A$K_h*PD>L$ZxhKMiEwYSbur`7cVaD8nk|Ph#&3K8~463)hGn%O%bOZ{<*Ji)_!D&b9J5HQR4s z*<|~1<4x$W8TCN-sP?I&!=+bbUnTzEmYnAA+IT|Js!Y<2`IYSCI8E8nu}x4-481K( zOgtZp3$ud7AP_L3_0e8qHg$TRa41ts6NxFAzC&yj|FbdkqY!Cm+Y#6z^|XHotC#!c zH?1cmAn-c;7KOX(ZH`8fM=;!;uk2)fB{72e$X@X=l|g^-TdMZAU^@H%xnYS>BQw98&iBmnty2K})V&pF5#SXi%sS&C*J`|P`p zesvT}KTPJf+LPu4Tn(jPpHQz51*|3-98A)I(xa~Ow6Du)`S^5eaCzYN#tshS8A9P% z1&a3+pm-m$X>&VVyt|lvo~sJV+9EY!$Jv}P4ToO9MTO}7-W|U$xBpos4Z&#DstkaS z;wO~5qapN#)?chG$u$10$?Qx&xHBSR=jP_}yXm+*A>kIo>t1h$9?5#K=Y-c|X~0Ld zAr@+}mie?Dw&5T*CD;j`RF{!ff0bkPZ#P(dU+No+OC&UG0Amt1+`wfIrl#34lU?4c zv8&sC5poxS`2L|G$3c8tJiNg_kc`O|4;K?PLBT=EMLX&hrizV^l>;E)X3Qb5jJs4o zNb^dC+_Qd;1g6DhvpY1EoVJRAoV=?S`^T5wEp?`k&0jz0H)@yVRaaw#P5bm9z=r@U z;BXkSXCFHH8&hV*Tp1(q7YEuL;Eb+%akCRn#8Il?;i*@l3RfT+2ncg~cB@{yf`Y0i z3l^T-PPFJNu26AdzbH{yMaiH5BSpqyMlLm0P*p);3sxShy$yUL;3k6kbr}FV<}9e= zO)l}hujD-MIi-w8x-2W+pPckcU~^Zi1+$npBB5A{)$3lZPJt&J5^B6CCx`L6Xj-!O z8ui|O!6)}%>PAUa9WXF1Pw(L6AN(!NI{&!^+09$my~$EX7l|b|R6|;5mX`lUd56R#hx`2#sVabe zGB1{sc04fk#;}&I9DtlvY||IQd9E@ z=$U<2M9z*k>JUN;fs+wTc-!a1naI$zO`uA@2d-qpYt>tuSQ(vmCw%l$ER;gnAr&04 zQ}*~VSz6IQPgj4R-V^$5|B9&|1?x1fwQaCY(Asf_!(XVMnFMN563poa7aWcvG06$OHyTiJWkdOiZ ze0kkX)Y<5Oe6*^Acc`R) z4`m5i-yu|1UZ1Z%ZBGIg3qS~jdwLCMXh`mcaLS}942awU03r%ydw5vq0N!R@>HW3` zE4Kz|9Q)@^mzEl=vk@~pE-*2tX~O#&qBm;zDHk5<2afQzI$l?GAJj0hvQ8aWc&oq7 z4E#g!_wR-If+>qzMAnZV*b=8$Cf8^d-)xEsC8edS9hyEGh~C^U62+jRT1Se)`1?LJ zpR;hRu=;`j7`V%ay<;k^eV?=B+rS-Z5Bk_vBu`TQ?AhKRQ`NOEY*MxE%UpJ=!YSD+ z4Qsv0?`)|{^)Z`!lTiB_v8n5bXAKSjBglFBUBG4 zfk$iVjm{*Ew`1De#9Z3B-`*}wsx%(IQ_Bp#wfSiIip}$Gk)OyXQt(Xe1=v2DOpn-+ z_h^ky^JV~;REvUvjmVE?2x$7jrt<_TI|NNyPxQvKmW!;k=(q7U%{wYK8P)bV6yMizAh>tZOz=D>o0{b_p75rQ#kYN}@``95)lx)0l;2;Kzy3Zhy)FpNLM;~wKHBhYOqK-X7O^m_aDkdRFE+Lz zoouhDkAW}9p4l~2Gy#5EY@B`Dy^&Iyd}yj&|j9vmlLBc@ZC(_+%#PAJd**br>?G?&#ev^2HLky zeW~pGI?8uPf4Epz#?eFso~)TNonz(8-~PxfK9Bdbb(mmG0;XW9&92NX?iYm&=>A|b zw63?Duk3Chp2`w}<#sv3Hw^Qv0zoYH4h}%1RBg2gytEsBO7^4)9m5tpfO8x2OqK(6!DVi4mg3~n86Lora^8;-a$}h!S9sDZa>4c6O zf*v&LZc6~z%W_VM9+&Qxt9&=}$5Fg8+}$qyfM!Vi¨|pVtzL4#xK8-?Mi*wvZP{ zeH5=>TQ4^3j7c8{w-;d(AW`eSL$L z)Q=#ow&CoO$MrB`_9dt5E-^4et1ieU&Q8VU8jwIs1LzNgbQU71C;< zpf4$K#}i+#=Tx12E-+h&Twic~iV3D41pdwn-uI{w`CYD_JI&JYC0>u~&68ev%&$#4 zo-z54!*q=xh+35%D|{M-NxftSmxrGVA8E+gp$7VeauI~ndKNX7oK0Omuyf5;Lt__( zr{j4CX4+%oL^@=8FwX*TO$D8+UFY%H@xmu!q*Skr2a^@CpF{m0C@kKXtv-Fq=h@tDn2f9A$1GTr!tESGaby(+D}cO}uQEw4 z?-CvtDQMI?u<%x=%Iuv7o2b?Uw4QY^D@5WSlUZm#V*U5n*Vh|SH^9BJe*3!xAni3Y zEZOxE{1Y)z`Fu}r13eAwPh|5zwiXUPzjrE7nop$+gNbGXfYf$$z$+IYSW~-4ETplT zDZI^oKSM|*o2m;uJV$(ZoDcHt@jCh&*I4ws;C5V^Y}Yz;Qxr))^WBgu=E*(>NO%JC zxOVnD^@D|)Fibk-a`5;)$C6t*;IgJ8VXUW*H`_hDEf{rZzxar;lli>68GpMCk$By4#2H=Rs)#cRZWp*U~Kc2n=9_#%Ln+Wm9$R;~`uVnAN zGqcGEiG=LESCq``Jwj4sZ?Zxek&*1Z$>_bG|9Ri{`FuL3Qyo2?-|u&S@B6y0`?}gX zn008q1e#X6EF~sl21!&c{0@AwlNbre$(KKknD-zicNvA4ChXop9`b`tk*(YQqQ1fw zjZIs+dK`LWDWpkq7o+(Nhx@$^uQCRHW6~5b3JNZC3PST2fxG0SfN{@mShv*CC`tJ2 zc#=$=iQfCDWUR&utZmlk|HX4C&pz;UuDxUP1|Xw%!TC~9xtvjb9fCU-OAgNMKF>H- z1_X&N!{(Fl>7G0HCXpm|17UBq+qn-5Px1FJ;`DsJL-^V6a@gzz6}Xf$hf}W|l~n5c zjhsDG&zJwqa9sJ5DURvuZ)8qcWhQR#U_&$hd zihVljAOHcPWh$UtiB{3HFetk=F>>OyTO)(zE~ue*9l2qdZgay(Z94+ zoc9Uhivx!D2S@thgjxFiB~#&T6xI{G^XZk~-LE5UYZ|;xHG>~Ww8Z{(2Q+JSR zay2hvWC0=M?7I-;Faya%9Zo_I4Gpp040VcltgY3WnV4i6>&h5>9l*iHX*RP`R8(yI zvH#UZyWMvrg-5ok{O7>d{LIPK*n?MTMdg0r0dkPY+nG|Cbw&~3

Yre0dqH^3KT0 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 literal 335507 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

`jI=0OPvGE+XkyM4LCk);n#?DXb_ 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�c(Y`HV;wnHG(YD?dc> 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

ytnY64L#I7zshZtDH3t~T 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 z zs*}+sbT%vu$yM2|;oPTd>P;T{vZ=shNQ`YuWHaaB^RskC{dL3L*xltoEG!#rxB^5B zLudbtW(JK(|B|CZmlj|`Nygn-Cx2QcLMD7y_}<$Pj|U%RNa)5~I4>~%QHK}{HqAcu zupZrRq>82e^m+F5bISWWJzGbD>b`G8NveAXitdrA2#ppVqmdi@awf4xk-t}vlP;U3 zYDRju%PT`?VYQ?|WX^9F!t55}2OHLm!{ib>HUrV?=od@-vfoitH>I5Iz|06xkRfD^gE90uBH9Hp zGK{ehuX-q>FIY-aOhNhu(yK=hAY}`#Nw!emXM9KVc+;_ER|fgH zFYK*W0b)i*U%4gkb-%0rL1dk{ysY2!=Tr+hKlSveKrrwso};I}4>DLq`%|8!fJ-p) z`71Q#wx@`7oxG9Wa!g6?dwKT3WnNpG2x8{~T=gCV!2eOl3HajAgr`mp#H`>a1MeS3 z{YVZ7)Ceaxd56$Dity$Ie_rz>C} zmHN|nXz%Fq}NmEll->Jq*YZ3ul(I+wzG6| zjU`v#l#Zq)e@enx3s1zOrGIHX`@^p@ApQ3Di(jRL)8X2RNoeFKyR;4*o!ie;pnjLy zbiey}Pb;#?gDj>XQAuoXkh*hKS@D;b@6LkP^$n|*Ybe6+id zOo0uKbwnvBgq;Kg);F-jPPWIH7tIwkWI)TaIJuD(t4j^N1MJlA#m&0Kh#nE~2|+5i z!6ZRORq$yZHmgK{_{;tJp^e0{$xCQ0=eg>C;5cFZZ34rFc}+5u>bdtpzw0%^fXeK= zotupUbFHA)sku*(5NkO1RkriN$p+FS;L^(hxb3S&e5pSJfn<=<5R@O%@Ii7K$7FLwJGY>~bNepFoNHzL{X86@6GG(u9{ z!-)+0qdSq}X=%e6n~*DKz*A=3JE-{}KUg}gZS{%kb(}@1mwM3__B>zXsf|my7g3Tg z?Ycv;2LGFPOHod7hRK6cfnmmmigOz(CsgYwK6b+|@_A8y)wd+Fjy>_Z-Z{SQDZexS zq+xJfkGU#IB?&|4qqjpldZgpwy||uwYmK4(kPIb_%5dMdTnW=aQSa?593GT1C4UxX zc?Q`Zmuda&e)mK+?=3W4Gp56+G)CrnbEDq<@ti?Ofu#Kk1vr+!*op@&eBLqB)+ z@-Y>L$PY#>lLtVRfRk4`WH9X0r!<&mdl?Hiu`Gr|tUEM~?4%(TRtNtM^k4)tU15q3 zBuMB8JRso)+L8v-IMfgo-RG3Ur3lN$3l5>n3JGy>F!B%dn)K@R#W4=0m5SuvRGc5( zGvqxaX4PE1%@?JU4;fBEj8-UCdx4`$bTH5k5puscoHkBDyp4vNJw4$>?tsxxFVrHs zONlqqstVOhQ6ab)a=DrJz$8x{Ic^n|ly>xtZg;Uw|C!k~^PVGmQ}BFclFr!66_X=u zhG6qo{>~)9@x(_(9qvbI?Yqwll``a$|Kz#b)f3s>drI(jl#U^aGo`o?OBmgM)N5p{LII7u zf&6d1wgdUJl(?Si^;hC|%ogCR(^wMGhI+;c*4kAvIU54+Ul4i;CMo73ntK(GBc(fj zGYaGWr-6gd8rNI4KxFZ;Z%w37)pkR&`whC?TWCih;2zWOfq@;x6!qHW;{%??)$e@{H?`a{MeT#aqe^%&uJ$ixbHMs zhC~)fro)0 zgnkjF8;2Du=|G7aj!RI1J#^6)EBQOe=0lG`r~$+*P=FTwOg8`w28dVdfU6g-#bNqb zSM?I*F=Jt=zKB_q4r<={<+9$7naJE6yt8mdo=t3t!=b9;ivzq!SGl#dUR=A|hdP@J z|8+AujEiOI6DpqEI(x0GyjpFZRzT5W!lAmAj5^S<_8!LTh#{F1Xi9+*jHLWEK-rEM zRouGA{(RTz&h`Kt%>6K#{Q{vK@Rq(poqp{S7Pk+5vXc)|^#gZx;+SP;(r@agU;e`> z*=dED)Mtk?yi@b--&lC{6q1UG0W3ISROg`x5mrp3v znevM}yG495`Kt~!HvDrYx5kS%Q*36ah6^zY=MlV9tRgbVIV#IiVCQBjXaxMGzuj%@4~&S$epBjequV=r9j}Ku&Ij`?(3*Rv_&K7mvs4}0#0j(LlYnX{@xp9TVJRKr)8iJ0;DR%nb z!tD$F4w7gLc|DC=DNJ|_D92F00Tx7_LUGGD)R2P|QWYp5RFQ_CKjEv)pCFDD9vf6I zKnl+*VjblSZF&DpfeBa#oZbl717`>bD29QHW!dmk930_V!H+|1SU86p=17QS1L4!a zYa!N!kToU^nlo!2^4*2z6rk!VDJr%BTJr@i)ezr=4eT3OA0%`;4!iTW4I6~08n^Hj zn>klq{OmF$B&%I0${i&ixdfoiOEDv($Z(ae^`?lL6&8adqBnvYInZjs?e5lG!9e5La?hy`(O}_rr6!#B(Bamm@ zyZY2sk*Oo?`Sd1?wx{|QzAGBA8TGY#ZreN&5oLx)Q8jCsVLX&m zh8mfHftEI<37DvY@DNs^U0#B?)fFhp^g-W*bR$STk3?W24=%}l`@teq6lK5y1s6R` zrx72Jti$u%{Y*^*VYP@>5Fj%oU)_1OysQkaG;}bcxF#SbkByDZ$ii}>ppIh1sK$aMI22pc!$HEK81Hg>5<4+)!Ib}HsR7cBDZY_g>_Zsp8Xv_-y z;SK1KQ!6Seq!;*wYlg=Rhp7Mndi=JNQVI_&E?irL;61ZLlMj~w;-X_!!a2-iSzX_j z+8&1;?>J|Jjso)lY^TAuVS=5=VtgH&^_+=$>Q*v`jPbrUhTV{%@BnPIn~AfqqM(B~ zX0FjnO2R2)K`e`%9sQ%Af7gEBLkmi@n+Fsfyzl~}RG;DBJc&4#3HJQW7Jn<#vZ==+sU2-vP)DRoPky{%+f{6$x10I2H^?9cpQx99JaT;TUo3FFX54n3^)iYQM)sU@t%p5mP1bYecD8jeH4u&70u$w-_OD|L5rrpf%7z z9}%Sq{UOB(@C9z@vNewrII6GSdX+tIi3?iHPJlxNJ{fYg&HJA`fjMtfRFspWw>!{JLDd7+lY5Ry zFz_M%-17pQ6Bg{ranLQR$pYG|7dI&!=UNHXv|ABMH<;hKhwg#24mu6+pWS=Mj2#}c zmg88DoTe#b(hl_$K^;DTLC1B$q8@;cC~B%%~|oyBZ>Wmzs=Qw zr@Z9aBbFM%CnF@biZwo@o-IqS%VYwmYpy0YQrc%Rxj*2O(N(?UG(rX%P?s&i{O)-F z4$6?o1(XNk@K|65e#~DC6*LeACai3-YPO$#6L_^S#Na+rftw0f0A z+-n?ru=NJH9{g>3Fl!fj8_n84!DHQGW$8WQh6Z@N_8Pszb;iCRkBiZ8gs~3zoB#yK zdeqLtCDRWx%?=o)bi<+Y5_Si|ML^7N;SJ1tfKA*oG;M^TtQf?RaOff)iBOhLgKHNG zqEduz0hEZxSI0wY7s^M-%7+%hp*{(Yp9JK}L00ZS{Mzw1clcn)<%>*BLEJhA3`lS_ zg@p?tSW_*)Ctcs0g&Pd9)`4MW>9hr+PYGymg_aJYmPx?TlYo#A@m50yk#IWqLFX_C zEFPO$ZNwTHte6gAo(RD9B-n2wiCVP)Sd$1ivEvFHq7duY-GxdKiSP^)y6E0W2A*^W zbRzxOj~cwd;{fWo`IGl3AZ^}&v$xHH3mRq-KtLWf9HPRN4{`5Dut0x8Q3BO0CAeXshR{fXm-<-3={}PF1-V-U1WrP8Mc@Jj6H%n!hNo8Z zdpQW^Ps@NGWP@}Ec2_u*18~V~%Q({`H>(fjSYn6KQYW#M{>r>e!|~$ms|I}$Q8}p` zq%72>5|paUOqXZadSfCH&OrGim90C~cQs0YpL`B4Z9w!pY2U&U%A3K*D-Jc7a(VT9 zI4G9&WUjeM-8C1isf43+*K|Hch&KNTX*0x~>T>S%Nf#N>X1|7x(nI9;WJ=ouUBd{} zW8x;n6Vs-GEigK-q=JkdUchdJtQlwS{m^IE37Sw*ur8zJURyM^}E?(;R>S zD$FMbizi;CrVl_>hb(V|iiN1BG-4n<%d>@#8IjJyKnod^A-@MV))AQHB4&zkjDz(Z z%sQQ~2jL2y+<_Y*Y=~2~cp-Ii=NuL`*kvI7Hk1fOji;J*_V90tfaHlLw z)qlf6#=yjE-LiYXIZV~o)`ohs%zq}@)_^c(`R#4N+roF)P$E|?HW@M6ZWMk~Z2PuB zU%I#GFz>plV_D;-jjRbnn;E)qrU@J;9DbfU*23sLvC-A`RNm8Lq>;^WTOlA@fzzo;j-P z=+J+fdTyo#TwOT82`Ie+W>Jw})GG@|!Fug%I$Hi~9w+{-o4&7GH)rIl$ZiR=Qbg2! z{kwa49QPslKl=^Cz96UKBj%8t!BB*t8{b>DNp0=MvwCQC7j6*Rg&UHLO5s~(CoIyn zZi+xQ*R5oNSJ3NzFu6`D+OZWo7z1drsXg8ZOQvjB?#IDwXEBM=@O{wnRCHCqzLd_6v93rXtdVP!0u5Iba-14paP2}_ z`WoPzK!O6Gh&_U}b(fIvMhhHJ+XLvjS}Q5e7Ql{2%HcrHn@G6l7R!m-GG+S+JJ#q!-r2Yglb0K zW0LgQ%PDEO5wxQ zb|z&RFj8KU!y%DjO~O{-)!s~FK0ZR1l{h75q^C+TB%Whs$QT5|!~IyFj8`&5e+pIe zUtfX;H!|a^S^7Zs8w%uxYXMKYz=f?wE)Pd4(u~}WM=fP8UN)tB zKzPyP=e3+9G*Z<3{Ij#wEG-CFM<<(zWN9L-rf$%+Uj_Cf$;SWvMO^iEx~pcr=R0{1 zPn+6MKmN4vU=daM-AP+VP7W#fK`l_y8pDyq-|XYhf=yl_pdPVUpmd2}053>QtP?_qDw;?#eOfjTYY< zf_n^>;bQjKfUpZRFR(nA&en-B1mZx$A22#ZoFv^t)wnn1V@6g^#9RZ~y}z5B)QhJc z`}zuc%I%#h)qC|DmCL1OHt>RMj{+=BpmqCGgpHtx2c^3yli#q8D%+8b_XZPYiL-^u5Q ze3{OXPv9>itS)j7%djJCOAEVDJ*dEs6IV1#L1pU94uOrq{yMwc91bY}XIQzpi&rB{ zRyEi=Ntu(>?56|YeJStH`DNCo^&tZ%?`oE{-f)+Wf8FA#lzY96T|TPBI_55ue8O8n z><`i;{u5G?Uq0kWK2(UH`u4&P-{_WDeo>9MxJnHT@w7iLd5=)oE1Wx*`W;S{9S zX5kc?2H7{KbA_oU7hsyWzJ5r`fBrXcQ{rKNt`Gon!Q+fUfGkG+jPBng8H5 zKJ+(i39MyGAr_-l)Anz0QFASQ??jG!Nvml)OHe+1_E|J8z;txX^R6b(GaZ+$ECfJ< z-tK4j!>~gD&8VdC5DHR?l2?0BZXb2`;cY!^O zNSL9(2K3g0!o3UO+5P92-*HcTl6kHDIzf7S#`(U#SVgcoayOa9`F*46(`$ARqbO9u z;>-x|d#}r(h*Rzh*H4bUS=;Bf>tE3sAJ)?o$yvl<}PhcQDt6oSyjutTGPA|80><*&1Fc!=4sQ{KnR+0OqLo<>?boar7gV8FR z6>&J+H-RiJ=$h>E2b`O>KJ#G;bX4>?Fh@b~lL3H0PziqrgvP3V-0atW1w)2vJ|^Z* z865yDkcs5er=KBB3f{DPXm(cCcQBrxv*d;?*9p$#pv$v*Y$nX3WiGpJeSYToyF!PY zc;JIgJ230kY-e%3dB|06Vm+he(4mkTr-e+jJbo1C0^WD56V$Hf#}?zYPKm{*GX z^=*s9tlhjVaAoVnk1lt=;Jv4YBK54mHH_)J;!2%6c~j&=ML|q~w}bScXjZ||$5fe= z7Y;ZA7g~H`;w}i`VLo61_TQS@Z9a^)trx?>ced4vo`%VEG*vc@VR5Rx&<>T=;K%hu zNP;TIJ!Q358>9bLmIwcwZ^t?N-7~W)l;LrlqUHA_D(a-IcbmBkIHeUQ8+~4mhiW=@ zDNCM(lc-8h+W2+E%NNL}KMcBng1+W;-RUSb<-Rr8&IMEO#~>gr3<{mFyL~pKU`L+0 zboP}~*BiiSt=W7cily(%lUF7oGn$X23n%hRiDyl_@2P}k7H!&(OA=;9$&(i3P-Dw; z@_%~5M|?tL&@uhP*Pv+rj3t{V_Bx3QZVbjo@lhZvLUDm#A#%ZV@eCmc`*N|n`pseu zXT&gldBj#7)b-58$9P?+kMnxb((DFNpqJ>w7=58dVrwuR4)kj0%~6=ND(u(D?$ri-_HLQK7uL`sT4cl)vESiJA%xCYTU~KqQ8WaARgBTI_&7?Sc8LVT_!(uEk}vNiVkMDV{jd+KgfzVW zrh(S4l;@F!Hw|hr#5jG3`9~c_1(>eAmEXG&=Vu$#q2Fp*t)!_Lh#-2FW1hMB41&&epJd6J5iY?N(W3cLX#jG>_i1rO~g?Tg6(5IfsM&0y$<>9#@ZsjPAb3QdOzxg9{5D z3&XgyNWAJZylsbi_a-61Y(A&Jl#5_`=T4=avC2B9NA-pU=c>09ZYsy;9gOARyeo-G zKcTkMt!RM|LPT8vlIU1=-F|nV6pAap%$r&vSQ- zA%zgG%|&)zXwBZ`RJAb}LuCyOS_zRJgV~{zIwCE`O`Z{|2W~9FXM?B?7=(jNW;VN7 zHLYXM8h^fQIelW>kg){i4uM8>2aRu=PYLlf^AABqHGNV2d#*n#H#wpoRn^dPb7fNm z4fynEihQb!!ZXM8&l3CcF4@alWKWz>H<(;C*n*QfE_gAAhmhFI;7NLc`0zE#49d?i zbJpynQ=Qk~DTdMaP;pV;R_^%!-DI8lzG;Far>|1%aBmEXJlT!o7#-J5B8+Wst$Oxv z^@SNEG-LQ!3(qFk`6lSrk<_;jrvLNkOD(!ihI|iwCB~5lEQh8_%wu-!73QfVn9-&c z!syu@m|ko(R~@EW5x47mLZK^LLG3Bjtkj1A%6#$h@p0ULUH*~Ad;Gb{{b_R1sB8A} zdyOY$G;f(J#`|#4baFz|GsMuuZgTd=a2j_kjE?3;F$MEo7fS$QVb}x2*^mxXEBXGv~;K7*{=|X>og!!5avIH^?CjYef9tgd7 z<#g-iYfX{Mb^Y(PrMA7Yr}1YOmDQXT!r27;Eki0He4DBA4DvhI7t#R?NPH)bpV@ln zUCvJ)8yg#hBL#qi)9kJTKfrn(?)V9`BQ#Z*7n?IbXpxmOhj;O@ZoxfOo@w|V2ah!Q zX501|@$8=Uq$ZVllDI_qN1k}GZ^A*cP|5RlI2#ZdL?}4neP(+wo!g;9eruxT*@H-4 zwCEzr#nPiG3NDANgDkb3{Yo3M{~mijl!@0hceHH!9mvZs$1F_}42+x4QFMIxCwuRu zMMR(l_(wReN)~F%!S--lj+tw?8fR{(UlqL284G)qd=>n~T0!8qNVxudm`vGa1xeIR z%^S4HsgP&#<=d5g|DH8eG|+cq87^l31d^bE23@8`x5l$lPte5Uk&$WXrEGSa+_by@ zTynJh!NIEu5oV@Btmq<3Gu}ig;;-$RZwg~eWsRAu(l}L z3=9sI?B0!rek8(CwwY!KCK|luC}|{EmVePKg8l?YzbxL&c=>-HlY{3579R=!MP>GE zsKO#sL8Z+y#3sLbnP0gBS6CwMD7ujOX44I7NRu4C7WG&YIg){r?YGK{rDO3Z7%r z&k@t6GoNT)t|h7n%6yLeCW{W^Ifeka`$ki5AF4-R(HFl;=}9b0(Xrh!X`v&p^ zkB*EL`=1=&Rj&@KhYv{&hg0v{pMbdn(9O3-J#793 zZB6IV^ZDYu4KAJNWPbbTr^TZY{|T$Shan0p6!k(=L3<{?J4UghhSa_fH-CJkpTs5Y zp}nq&KizwiZ>X^^t96WKMM>O)F3w-0Qb6f{6*Q?L@mqR83x`;kbI_Qn*4y@U4y0toKc$ zgwd@~c7p?!4W+(vlq2o7WO+Cr$whw>4iG?kSntlTj9Cd)w(9CjP-L<>s!8a4ziGb1 zx%q~m z)%s9LjL{Y<_K9615>;dkD3PuzZ)y^vLF?J;)Z@Q2N0wQBq9y&mvvb=yE_0@L%Ub0} zg$rA=rBu}#Z3aJa}6PPXxoDRf$YINct|p-Per z4iwET_&cQJAtgj|BhH?kANjItO595yM{jt{cLoa5le#bgwcaa!2k+y=i_40hZUX+G z!HXG}j16ykb5m1V5Q^Oylp}E_(Y`$S<#y8EHD`U!^VW{--@=w*;hOW&w{L3y3;P1yN5L1OWDty;o?cZX*zm31NHyr=;Z+Qn~ zz4(}mwD0;WdQ0cGncAdd=g+1F&<=^1h?pdWDv(tF_%v(Q{?3;2C7yH$sY-ZgNs0B% zUwa|b9(NhL&TJWWFd~(IX%h2~IDBU*Go={RMtU(emK_{J+q0|N+S8Ad9Xrp=H@D!n z^4=z$i{ljAvF=MAy2<1pXf5+w<2Co@LaOh8#fN(eFI4XMbsGLCYOXyFsV|u+bUXS@ zUPNa14hGmJD6RvS4E71`Gs;+mKSb&{;FOCuNfbtpHePBjsJi|H#xcN2^I0*I|6Pp- z*EkHILGJ>2kwRU81!53xhf=9218z)!65YF1iSK6}pTwZj%Qr2iKxkGtQ$Ffbhs`$? zXkl_fsvLhI^Wer})r?I%OAQMbf%J{|H`ixA$}98z^AUqvZvLIi$m29YDEU6eeAdl+ z94H;s&CpHY4f`C5)*BK>ue6^T6H0w=WvP41Zf2MC=WaL@JBiK=ZcxZ`g z`9vB2J52a{lIknZOjM-Vov_f)s(p>{$w6yiP$ON^G=1%^gg)C8h zbfJ`=jD;&&+$R-&H^U8wsDC*07dL+XNqwug&N)Xbhb-jDW~!p=JZ01kivHT<3h56f zqJ^0%z5V^r_dP@;3UhPXiV~1%ON-E~#Hzq_OidvPE)AtMvo(KG` zkTdBzZRhW194tIZjKaSJdI_=;1{J-h2S1*9NL*uSK4WV8bz2Kt8dPzL_)^bg_SPwJ z@wTGPeyF$?E$7N5FJ(N~ID~G-WSo@kz?pXvry-_Qkd0p8_pW0OhL3y`GH$&rbe)bY z^Cv4#>@VPdO(m)2NFwcL8>>@R-naYuABQTws6Ikxim>J)H69ku76Hc)U@mDU0+A`F za=TpGcGZp#_{q3H{K-yDT`X8PE>#EZAr&p{4Zwq;xdl^VTyO}>J>t|>C63fG3m=o# z#genxuhZ`-Pkn46Z?^rHQ7pD2wESCepM_|a5lm}1FC)y(n9k?%7eRrTIp^ng(&zD#IJ;nUG8lMc1Z zv&H6n8;>}>_#pn|vZ)&RwAQscHFIpL7FYh2{1f`NQ>N1uw39gG?T1b6n-gEPMCH`( zkVbdpH^1%dl1qQyn%E_@e(|!{e3KFL_6u>N1XFZ}p8e7LnYYpx643tjE zXS?QC8080dD*t^GzG-*IIUD&Z((1_BKG~#P^-P>-6U_^Kd8w)PhYAPC*B{<|wg6!u zrcyv!u~BbU83oS8;*1=b8&$o-@I9ge&6b&@9qU@bYe|av8^{0B@B^HzdM+E9Pp$_G zix=%ajWTCz`T*-jBL8mvHd-28;6R7K-z9vv=6&=F$L*m2T+ipn>I#&;8BtDucy4+eZ`lAQ>hrD znMK!q2Q9mU8wA`-){E9WCF(3|x^KarJu@o{8N=|w&ytgDU-K_=yW3~11^Liin_0u% z!7y%L-q-rh{!QPb&Udz{SR-#fhKUyzC(IBqWd&NY)`#C4^%=<3>Uq?2wqwh3z~inh z_&tY=O(zDq?h>u$BKu`t7c8AceeQ3xpTMT*2q$O)MvPl@|gz@An;KBiu0IP;yG{z7%9_ib5Hu;ybJzCE)xTXUwfOqPi*)&ni z%KKyLILIbOQ^9QfUc9*T2*bFq_1k-D_GE2K1rIIw>)MT9R?yV)#<&Jg$cUxU{O3%@ z()hr?QEdFPDx-n7>QVLUk)r?ZxLjphCd+9hV!24#syGLB1~Kz2xuk8dJB9KT&+KK!Z9e$s z3^c^ehpB5b%>*BN9<53NeQ{ZhQZr2+;p+hlT1;74Ib8Mc?T9{5HPrv zT*RqLKCBt#j{FpuxWce~+NYAP$f2+a>O5Y9K z(SJ?0jfIh(estX?*9RlLVwj31d{~QtDwBS6=g*(J8<9P)NLkVL%TxYH4mO@8+8*>L z)gF5cUAjLV;j#ZY7LtuLhxQ z(abVqep;R)=MqxCqWY)v_r@>t@eR+Xp6L>^uK6ySc-0uj7RHZj-HG-3!oO3|+)ok- z3{i2kZrA*@c{i4+(D4$ zB})1=)zV_CFDS7tDtK9C4W4L38}X^z7BWNy=I2E#kgoR`9eSmm{!*%^xMB2)xXgMs z$>gC3`&hBYnvX9r7|-T!5}kw{JQPaQ?UgEC)`0H-{+X+*5k!@9i)~Sx4Lg=@=DIR= z%FauU1l84xtdGiK!>ee{Tkjr!e;+o)=b3ysQyIZb^Y55U%y;JY?~T`AGbUqL zce~f#w~0Pf|F^`ad%5$BwpCap9St*}YV?o){VT_FVgcS&sVes-F+6e_H}?8Jta}M$ z@d~1OE7n@pv!8IP1jsA{$Ye@xy2}V+Wub=6`f^Tc?w10isojL*qT>G)4yiSmxc0Df z5jk3pa+B~+`0tZFIh zk3>s+L;x%EgIev-Cd=DncUvd*zD}ler()c!I*_v{yvMfon(ZG79J`p9pZM=oODz8M z*V3rjL9@E`X`@k(BHu+Cs4;kIV)*WF(@_b+gbW1-G_*A1y1u6HiY9%yZ8bJV^Vgtl z7?Y!5v}A0#>Pes(KZC*hNLjk2(;BONG+G)D!A#`2sundK|7Cma6b51T1l5EU=%%-4bOLRhTh#QiynCUR2p{5fBwc z04a_uqZ1H12-0o`(GBfLC_j!{uH*hD_Fs#-jZZzaV2V@Fg!f z@C7Yn90@HH|5P@AO8I^Se>p>cw#(ar-p(%-gM209$-fsJ(3r1?#j@gYZKoqh7C%yt z$R(v)K4he{&4}n*?RVXJsodM5aRi9uv{Dmgohrv84=#V*&o1S92Ugt9F?e{@ME6_U z&vrahXKl|)^mnl6!rUTQQ{FA_t2(Ov8l$mPFv~F?=B&WJZD0D0MDsgUrn`!q)H2_D zt#P}Ob@iV$f}3sj3}a%#Cr9WbFwgtn7_pCZ zZ<37VDFv;w#w*oV{gaN41pRzuRMa=f-2pK>K;-)R`X9r>=y`tkUf%%A6)`Ylgq?C{ zmhE*@KVX3-_f#tK#0rb!DeD;9{rdK)Gc6^v0&QbIbgiW=YF}eY!g3EWS8LRvBa7)5 zKnwGt>-VY>-{d@VewvG~T%NrAS>qL?BKvSWYrL8X28Iq5Uz=Q zr=YIh4P<&=>qQhG6l6g{&2klR@(~X&_z#+@y{S@Pmp?n#RFq!KMCrA~Sc&2n2;;l# zO-TDlq%OK$>!z%kuhe=leH=VxD}#ZtX&#VL1*IgUQ=|k50g(_1mF_NS>5^_l8kCTfZUm&e6hvACq(eHTyPmnu@BNSWgX1{# zxY>KJwdOtNHLqyobL5EpM^*gSK0W+S^r@7eKU{UIS9zT84qG=p1d6U%Qj$Hzax!H3 zgl5NZAI%57H*5GiFIM*R&N%j7ks`%w*Etiye09+ADan`0Qzg^qf<@-Xp4#xTN4fC#(JJVVPo+dY(}?XJ4=W_0XbDx*@6L539a(>cB>FqrbwDAoDG3e6LXf z9=OvMmNzObyX9Kus$#r9h*d6Esmrc7)s-$zgkYk-IK@aZ#w0l#Zx_ZCx2sa2A&tE~t4h{&cRV3jOU`M2yzBdXCeORm;REfc+2#m&w z{lhQ`j7*JzAigshODzv*5-3pd{8LBn#tjE>Oa*oSeQqUxS5bJO&cipJtB3EQ>~per zA*$+X{?r77VNQuwKMC#k-_j|VT{lgdT;s!%VZ1YvEBn4JoQ9F{W@!6!NbNcXp9Q4V zgl@qYItPUD0I5JJ;G%$e#0$a6U}x|QsK{fm&j&TS36LT{Q$Qu00#=!nF0DNG_iwURv05(vk#A3rH0bc*E%iMPzi)T;mGen>vqyO>sR(IRvw#ng!s|sU zdN@@TWb%uOWmrU|6npZ8HdP~IKcm&J5RDUtYm0XEeSSAwAWqS#yPEU+wD^y}la*IZ zx<_{~1EQ{dK8vd>5wVzE9AMu$Zs|C-?R??Ue2MYN`ZPEgN2r%eG#0NRFP-I=`59fE!loj=gHe#Aa3btf~d52x?3#TNE>=yG+<^n(?w-jvMQ)!I&MuX546HR4K+mHO1EAXd zF4yw3E`Fq5fjH|u$c_-_WvJa8_lh@D1ix%y5k6Vq1ff4A1V{(gQMygptTV&Y=TLqc#O{`j>F(L( z%p3Jw8mz0GhyMR4)rSY8Y69#qWu1sXs*1r*6c@8<`#^qE9HaH2KKoa?Xu@IZo9{Y} z3_$X*h>7hpv-Uc&L)6;3SZ)Hiziq?u0OY;?`z^p=28^e{_U_xa5Yi=q#P^)~Y0kojGFrZ; z5I9xmC#tGS1a{UftB!L!E`W|!ECxf1#=x+Y*n#wB4|{+q12P#HbAU>9o#<_eBw~UA zw(szdsM*;gp<)j}dRrm(teTjkPlkmc_@p3|A#jfA1p^xgmHBIs516>Huwed>9|ef; zL+1I|UBik4N7KVmNlD!Z^;*~SV3_Q8bK7RXz|uk~j0YcMevI~o#|sxftusHLVnd#0 zjl}h&zxdk8r6~t*cjMY1{ zJJnB>=oF~}jm={m)MK7!)#@JR9C^yjRA+$@_6Po~o&EhsPkylQ$7~35{;sBV4<~KH zApxVZWgC!O!i`evxQfrLeDmf|WRV;&9D!yx3wFYDO@K>5aC!dkLjs5sd-UWh@u*!q z`At6`ZMF{iK_50nwN?F?j(G$q&K+b5;eh{%(Q&q{UY6W%xnb=sCZ_E5SQDH) zK%0Y#h6beZfMN4RXcYc8Hi)q_&MhO{WDwDslqW<`JT(A}Tv9Sax6$p|Ryj1grC|3B z>lOGiGl43b-IN22QmCa+eMGgj$)T*^98Y({1OP8-WNI269j#Ol?+Gbhh}R!GN98dO`Wq$9~G%q~-%_jbWuIP*COJ&)qJv#j@@j>pQEUnrWo+F`44W;Fq3b z_*E-zde}GNsiJ}T&_Hv0xWbiO*xN5M&Z{Rm)z2#oL)VAT= z<2*51Wo^>BqOh;^TYfLtofY`t70+w@#kp<1F`b$~54EP5s?$U_?%%I?e4VckYdS*V zsA|ZdZe+{YZ<&BKgy*I8KpvXs=@AXf)6n};aY36v?F zuv-GzbE;v;5gz_rz1szR?O;NNpCJ9ddvOlLrP-A0_aUXRM=Igx$N9EbK=@cWUB-+9 z0qKd65?mm)myWoo*W%g(ihjNSzS6R1dd;x*d4$mONH*<2X}h2T42x>Bu#L;Re^u z%8@pd18_~@b6C0!@x1g*Ou^pg^Hc~s4w3qT!WZs%e=s`*M>qH~VQzQ^R$d*ERHpFG z!O0R0ux&(E4o!nB+^ujsBQ9MKfvK510)mZuLLPjeh=&WX2cLKk2*4=+WeTHkaysm zXjaHq1|t7E@I&MDIJQlDNk9Vmuuu+wtNeGz#Ra|`6qplgBU?7@YvZ3dFd))+u<%&` z$*KXEo+b0Y#Vj1gJodUQ)@@Ae7di_AgPH~V+SHXIgM6Wg z{~C0@rC?wvbh2=_)ay4$4a9bYxw(~L$wn#I1yVo67nw3L5Y!q2FB~5w^}@v<62U!& zh9)>X9PxTXLM`Dl>;MZIpOO;01>zOqY}JPb4QQ(z&?CV%qC@!VL=Fj*g`N%ZRV0Jl zLAVVb9=(mJarLNPr|)MU3zp5+|DJWZZ_Ye?2(_W6{LS4V(zscMsT8&4zjm=h$1V5H1H{gF9fVLR%nCXa!6%n~a}`<(7)XFuM= zCw4tH&3x$PPf!gH+#2H-QE>0xoi|K%gmD(he1S*i$=fvoFkKLuN84@0#>Ct$Rkg1z z9&&^n0YCvHSw7sEt*VF3DPIqEvPo`#g9<<4_@jr3xOX^DDyPn;XH|Awb=fU70`g)s zjWAs+iOEsp$R-xaD;|IU$Ye9M#|J($34e?LDu)AO0QjS1oR>xP{D^Di#)joiIk*Y= zBi5FPEtYID-`{GtMp|Wt!F14ff_w`)FF08U#bK-N0va#G$OACVp+Yqrs6{|imjS0P zWQ{v8Fkr?_n&P&`1lACvjqbeAEvMacVXwXJ0d^@!#uAv)hCE*e9Vmp2pdg1P3{7p2 z@l*}!M&yPANoP5jLqIsm)p3V#P-v(j(0h?b98xRd;hf?a4!4o*vJ&LE0H=Qcvd5_x+ z7c9b%rXJo?s9|}fV$!PGCX7p5KwTQf*I?gV-JXtQ@SV>}K8e+)dm z1OG~n58Q#^kC6P$U>OCJ@|~y6U_kx|j42NPO-a=|i3^8?OVB~p`DRj%2+05eTOF@t zVNv};O+(|0e5K&6Fji6m+vP!^kRxv5h_j;bjw@&%lbq)sVk4)(wI z1e3%{SAro`DSC|;ionaCAMmIqiK=Ip%H}y`%ft7yqTZZtH^xsg0FaPjVMgq@TiERq zo99M4Y|&;KZL$+-SHfv?;6ZeGN>PZfYA3gDEda3bspE>ngb}@zG8G*1361vHGsRj# z!`6$f|3qEiZm>+MsAQhtwnE^VC-2ISrb#!v&jxMI=*L%o(GK%H6ABrqoBzYfCK3} z%pwoHB7lq|bh<(ZP2KTG^Cj9d2nJr6s4lrDzXdi2AgD+O?^K}-Q_vYA3ThB%;-O*q zfCJPc06D<9{QZ>m19-TQtr0{qpunN`9iF5&0EHoUX#BwdB&0(!vKWj>5TZ^4qY=27 zDQ`IcN)tgrB$2ntc%%u)QBDsxLp$bQgIwMq2{0enN9}J;jBJgsI`Si+87Q{Hsc#~u zKA>oJ?r_&ax-mLLU?=szy#QGYqPGAOr`=K|^U<#~2)3r@u@j(YqV)zgMeqV>EzsRu za4Is$rAUJo9C1Vg4LQ+-3Ns<}zz^Us0=WvLD}z{v6kdD|tk^MT0a7#qEDv$eTXqL< z;~gX|mV(Aj;dT;uU_zU*u;qPK&&cQU1}qIhu#-A-u!m1bxHysm=Awwi2f$@^Ol*1j znj^3s0qpoVNR80b#=V?S(nK490>I~Fa%)!Iq3@j!TdsJ;W z?1o+bp~uG`NeUe!KIu3gS$ULx7Y@9|OYEcagJ!MxquscuS!#vX($-wJPM%8Qk(wzPyWV-Fsx37%GPD{BfpsJdGhw z6&Ej@_GU8+xv0zy%!30RWA++r?GNhDTI6~019C`-S@BUV;~YNZ$C%ODSh0&i`vf3) z_Z`s2@xb27LB=q)VtQBclw)`Ar;K=NFX4DB?Cr#xbuvGgNsR(f7wzSaRl5`lhw&BJPHfnylWGICwRfr@<4*sl~9~arHXE*!dj_euBm(M(TR~*6S!7 zQt5o~xO|`A2_nHnd>&9h7SHGq;ajYimPmzI8u?KNkv!0a;}WibDU^4iPb!3!*jU_= zaL7<@_qXgQ!ly(5XOci4&q}L_KU?>*6Y=9ZS_k#W`#gqT_UNulmoNNr#>CYl_lV!oS=Z{6v<= zQaeTV0oRD|C}L}-Sr{%QG~%d}C9t`HBEqW=gpR4YFw(~%;IkA9(yiuAh-KA>MN2k% z&I08VP9r|1GFfKIM|K*X55qQ0o?=T4IKf2rJoA~Ad?sg}{HhACfcW4i)9=X|ry*n| z$8!fCj^;kcJx||0l6H2-oxBcdma};`3F^wkbF@eRF?4!@(Yh%?1r4&@HZsdYGc7l( zmoAU`rS>B%Q-4u@$x!at{|k%}v>w?4)>u3WOP-{a?^}0%{DTb-IE^Wm=n8^9aLzeQ zwQvzoe^7KPbY)R+wyXrB6Mj-Mgx`u zUB-2RhOL1R0{$Zx0T?1Md_YKe54;}Br?k9tYd%j^_T0fO`RqJ7*U`CX57smn5q9-c z8KZkJ(;SaoUs_uF4agfj9nbuW=8(?_W^5(96DzoOfnRF1YUT3V-4Lf>T zo`t)xS!mRVy;Ze#tl>~^3xoU4jFsUCe2*O+oX*m`=IB%7V_pb0sS=+3>*v@e#>)Aq zsMpNv|G~m=@XE#1IT7~C&$(qN=G_~!K&5jJr(QL}hZWNIxtX}_&ANce!8$Uz+ob(I zY&R5G3U_D)f|((Wh3A3Q>%M|oOQEkMMVj4ur&j^cy~{ZkovH{52Alu9?~We)NAdId?o;)(W&G$0XcalD8xXd&wZfe^AX) z-aH0%81s3)QpOOIjizn;8#{w0%O7tXG8i-azQI}4Ej(i|Y9Bso9}?1!YzVRQoBm*B z%+5My7HZvPmglZ10O#p6y&T_(O^JNv(;#d=YTLsN4QU3YmS=k6jGK*aMO8AxzHAI7WE`LCPJ_V7LiG8jjrShj zy@m@g_K1Drz2)VL$%*AR8`r3E9{>CL{Gt_0QU6>A&_hZY`rwp;gH|G8SplyLtH!-t zRC0X(mY6QmuPjJcGvbehpWKH`;IO8Mf=9xSv7kzpiXN0Hp- z&npiPkL7Ykqv81aF};CJ&%1D>Q?*w_%8`T;T$sBgkY0H!A+E2~(^2t;8pF*3F+ z+C#b>JWLG2!c;}7QlKD{$i%Ckl7(pwHk}O(0z>AH0i%rXHTj~-0v0j=Qv;IOwqwPU zRI~EE{y42-2Mpg}J+m0W9@h;nn}p@)WAyCreCn~CfBV$VX-*3Ew=?y+J2jAxR z^&5=nw;Ut!~_SYSnJjppb;g4GW>9 z!|vUFsfT3eg$5K|U)ajpfkQW97!6C|ySs{2r*M z&4hD+On@f^2yTfV-N@iRD-D4ev->vlOrNr{<5$fh#I+x;7lIC!HUfkJ)-%v-ziT(R z<+1_b-FcakWW-7H)rH)7HE(D}1t~fS35mgbG-Uy;dGqVv2utPb5?OO>f5d2A)Fuh^q0B9QM+l4j?invUjHFonTqZMzIS~d&SN)QL~pI}$1?)(ZXcg`@D zr{mek3hbY5=)?JY?Q8;e(qPDU_v(*%=og0u4SIPaJR)-P4PMnwSLtLvyc&a5mp-g~wG%2ZFA-hGkC^>MU_6W^{U2H=Z}SH((T|ZaQ>eVkb3SrHp{U{U=0( zk;}fM&KKiw4_@=-Ws!rGS--mO`m4C^0ByDxY;nLS*me<^D~|zHEBswmYJzP(~|JOvMG>U}?jclmOzUpD03_{1R2S+ZU z<&~)=iss|0sQH;&{Z_ouI?d;ZXItqqYmvYy^1?(`VUB?| zu5)#;6lbQP&PQ~Ha-k@9x^3y}-fr@nHo-sdO@+N8!q0f-9B16@?gS@=eqS_NtWvps zwrpD`IP$r~OSh%b%I)h$?^Wr^pzyu7SB$T0Kh&6$Q$BFVJVYlTU->hXX7vz=OLzwoF%YJWc!PL_K+Q z*K#!cFoTN39PND~dh~(#uDJtp zgjmc2NIQ>PN`}ViFF!Yp7eVoCPq787=nP=$Cl7! zA{K*Q;-TH&o?gPIzNq>PX5oY^st7llXh86OfFTeV%%{l-gOi#ueEZJ^mSsD)aA1w+)#O?t4%mbXBCgf&Cp%#3`v^X0 z>eeRIupKZ9*aI&(yRF8f)BVLtL(ZgLp%E}ZfM*C`9Tx%0R~|LKtiraRh`q;U+?oP% z|Gnv|$9YTtO}^B$Y9h8GhJZ4eGeBZz$K$Cd|0*DqE=$sLZU@ivqdaO0?}CRTSh_|l8TE}Iai1$Nv(U4sQ!+JMFJNc5J>R_r18s#n*uRo*CUiuCEw-PfQU?3|rZ&9h4x+HB_M;-ldt6IT@n10*{9u7wVhfSJQ@o>-&6oL5i5Mt%i>J z-WNt?@z#GK0EliXopS*+4Hg!CDT3?er<^Z|#U>7|O3so?&@75$&o?||O_P7fD4>j* zl-mJq2G~}!ciTqR4*;NAuES6Su4H3N1kiziIN1H~dAcI5^3xz7@G?HW^xX$i9mefs z(5J;}J|cT&>;6cur+wauMva+cDD+wJwlG!Ua2F&Db#`^lLFVz?6$}n=z|ldN9<*u> zJ9FZeJQJ~(XsyeM?HwIwga&9oySwLMk%N$hkonEm+lG4POmC|>ozcY|-W=F>yaM); zWG=?~qBeo~{W^ZayX0Wap;2ppUm}x3ztn_%+9`A3rJ`cgvFIZ%E+v5%TMaP!;r=3P zVudzM2C9P`+y->~{F)V+qP+(vQb%t6$Wz7o)kWT@krUP6Ub~L-N!8tn^ zfSh^6+zotdx?r9Wzt%dxgILfYSf93ba*a2v(cqNKfoBYfSprZRY9ylx-%yEOD&&D* zp3PkShP_}SZ}S}S89b8Eb9Te)z<~p+{a{!;Z1|Xvrd5C2<+6pnhnrGPYm>*EU4fx`2d9g^d5Y$+Ask&XU6sk zfUY|*GnE032o}~5%LoROF)J%(R3h*(AAuMN*+sC!5eqiK5a0m2dL#w_S-k=|6op_+ z;$Ukg6}DzTMtlwh@?)pb7wy_8_y_ovn!WI~A*+_<{?uFu4`YRdFmQH_gC7nqvdGFs zHdm?P2xfR`;0wToE>8}K&*$O`2V zM5F+E+5?Rk++0xC;Q^E>(QQOQ)+E-|NwCbj75H7m#DoD^(Sgy?U&xa)0#k`Ob>t^O z;=?RR8&QyiAV6HXka#bk!GZ5{$e1MqBu@Zj=kWI%8qnsbDN{|j_cj&uXoUG+_D4S? zqf_9(*6Ui{*{a$-tTQs8^Vi_n@k&`AyZ*UOv)Hb-xMF=Gj)CGSzDBc9_)|yy^||(V zdxrrujKM6!j)IgFvHL)?&TwG@FLP7ktq^aU96#QtX+}SMwb_$PO|8LV*y9jBxD(gd1Go5K9)2!M%M$EXQ+JC>DTS*aQy*M`f(Xfjt z6Z(*6$3XsG(C?w8GCCy!$~B8MyrNjl*6BB5;$n!*E5&u2WSlp+<6l|1Nr$G_==KdP z?~91Ngymbm(G;ppbXG4L?sWd_ot=1#<@)BZ+hc$J0Xcv4^L{76gp)S1hNn9ebyaI2 zB5I|h3Gc)-w7=>Z+58nE_iG*ulugfs?a4P4MNiydmY?s;Ki#nCtkUn}%)}bRQ_eN` z^c3DcWSbn{yzQHJS0%7?{)cK_KLDLDPqoFS-N!?{RxfC4UO2egw&@fqp4Ux#WW+|? zr=xE;_roW4HWXpDrMApg&f2+yFoI9ocuqR;|F{6yTroKtxwuD@e=SZbGR6X2%|9BT)M}PE1$D0z|wwe z*}?1Ic%5=@ z`cgS(OM3UsnR`8v$50~x#Kp|ei3mAuj^8idMbA?y{G=YHg^LQ_#`#*+Y(P2vTf3aX za&YOJLH!fv4;zFF1CPv2Y;1&YgHT4nt?PJW9bjItHU`|!1i0#OIFtdtTPpM}4z_9A zFeuT*b=R&J*TVsVIHtoo;ueHQ!)w7mDwxrR$9CTE+GAit0AfgcS)`aB6de2-_WFQ$ zcClL^)#@*ND#D_7AzTo%1y40%wRm3jP^T^iiT;AchtEWgTxuWiSZ-lq-JLKrG=x}| zx?^Vv33LdVHG$#=tqUwx6F7|}1I)DuOo82So0K~U+`)gtW)Ns?k?jT|`O2J7z5dIn z8BT-BPjq9corK3yy=4m%T2kax0bT^;jDpGK``i>aX8j*Y&|$-}ABaOZBDgicm?q(O zWQ5y-3HV)znHC{oJ8-LEw9JisOGGdgcz?YT$$vvoTp$`Ha=-Zomc3FB>6-y~wJH-%q5X_QAtR7#=|Ix-dg<890DV%0UU@-HE zBvVqBa+BvGArHIeJ08ZMqblqBUp`fwe&zod8yoOEomxPEyl^-K^6>ch?t!akG?RYy z1laer=|2K9T4>(byK4B~CQ?0+ZrNmuEkzuo%sRM@kCC^M^qxF8oHb=#XT_r2I8EY5PvL&(eY6 zkL|z7aMZCMZHQPf3hJ-mYim1cOWapdlG4;+-g&?i7(R1&`6J|=%6ZihuO&7aY>4*P zhvK|GpAMAk;8d7folv}*j51m@Ep=LEKW~^ft)d$DotV#2+KUL=5R7_#BqXLTuYU3w zq-`H|*LdGCiLMg-#w*f3mHxP$JsymWwv1^TPk}meM}kaqhj$;E2^jd_CWtKXzg>Ie zWZ5nj_#dlDPWujAw+y%{+1Acu+6$?j%Zi8h|7;!Nq`875VE^CLL`l4fvE9TJ-$QTA zJ0^jVkAwNe!h!PiT&Z-Z=eJnk3rbfpZC@>X2RBOD@;eE)Zv%0AP3q`gg*t0bir_>^ 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ɱ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 - - + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + id="svg1557" + version="1.1" + viewBox="0 0 378.20105 327.63284" + height="327.63284mm" + width="378.20105mm"> + id="linearGradient1933"> + + + + - - - - - - - - - + - + - + - - + + + y1="223.87135" + x1="192.64189" + gradientUnits="userSpaceOnUse" + id="linearGradient1927" + xlink:href="#linearGradient1933" /> + + + + + + + + + + - @@ -199,219 +125,180 @@ image/svg+xml + + id="layer10" /> + id="layer3"> + transform="translate(-26.725716,-4.0064965)"> + style="fill:#000100;fill-opacity:1" + id="g1939"> + style="fill:#000000;fill-opacity:1" + id="g1980"> + d="m 266.32136,50.725653 c -0.17493,-0.245241 -7.68487,8.239682 -26.22382,14.73088 -7.24598,2.533621 -15.77758,4.481015 -25.80626,5.394041 -7.80487,0.710575 -15.62741,0.763515 -24.60618,0.630177 -7.10056,-0.102515 -15.37349,-0.342644 -23.09918,0.04518 -6.98666,0.355519 -14.3529,1.246148 -21.37728,3.473919 -6.97871,2.201021 -13.75622,5.822394 -19.73033,10.773148 -7.23031,5.971496 -13.21751,13.650026 -18.4504,22.28169 -7.71197,11.30811 -13.780321,23.77515 -19.281337,37.15557 1.295375,-2.3837 2.694224,-4.71512 4.192806,-6.9856 5.836914,-8.84339 12.980981,-16.45315 20.947101,-22.55626 10.62125,-7.27796 22.31318,-12.27508 33.83042,-15.689311 12.27636,-3.642327 24.65859,-5.659686 36.2496,-6.893641 0,0 2e-5,-10e-7 2e-5,-10e-7 12.03309,-1.282998 24.15119,-1.797386 34.78058,-2.16223 11.26459,-0.389119 19.86622,-0.525899 29.44169,-1.406911 4.09388,-0.377806 7.84924,-0.855525 11.47336,-1.637412 3.18585,-0.693967 6.04795,-1.536888 8.60531,-2.849228 2.21977,-1.150499 4.08494,-2.575182 5.29519,-4.367908 1.34174,-1.920808 1.87087,-4.302373 1.91674,-6.474343 0.0733,-3.475689 -0.97184,-6.941781 -1.92033,-9.602842 -3.19334,-8.90044 -6.36181,-13.294589 -6.11214,-13.451663 -0.0986,0.06202 3.85329,3.801837 7.67284,12.841713 1.14175,2.686839 2.40195,6.281391 2.50827,10.203303 0.0666,2.503277 -0.46622,5.321701 -2.03856,7.820298 -1.456,2.250702 -3.58735,4.048489 -6.07155,5.390925 -2.81347,1.533986 -5.89422,2.555776 -9.20041,3.349538 -3.76725,0.911916 -7.64484,1.504554 -11.7989,1.977 -9.64024,1.09912 -18.4609,1.414892 -29.61258,1.971722 -10.58225,0.530571 -22.64632,1.198502 -34.47024,2.5876 0,10e-7 -2e-5,2e-6 -2e-5,2e-6 -11.41113,1.342488 -23.52949,3.414879 -35.41817,7.033139 -11.14376,3.39447 -22.38681,8.24563 -32.47462,15.22018 -8.62388,5.31456 -16.51649,12.04079 -23.182072,19.92101 -1.711299,2.02314 -3.326286,4.10426 -4.840621,6.23506 4.087878,-14.26449 8.922214,-27.70649 15.564853,-40.02514 5.43579,-8.92853 11.81856,-16.959506 19.57969,-23.30942 6.46827,-5.275585 13.77515,-9.090373 21.29545,-11.380298 7.54855,-2.286045 15.2578,-3.139455 22.45583,-3.393724 7.96548,-0.286584 16.27109,0.08204 23.35306,0.311442 8.95318,0.286298 16.61396,0.397407 24.27686,-0.12155 9.8236,-0.665207 18.16345,-2.307894 25.31931,-4.527563 18.00102,-5.575038 26.70936,-12.858284 26.95602,-12.512494 z" + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + transform="matrix(1.0227138,0,0,1.0923454,-62.375629,65.947122)" /> + transform="matrix(1.0227138,0,0,1.0923454,-103.51834,34.329414)" /> + d="m 338.69593,78.188464 c -0.10321,0.0166 3.37905,8.851837 3.64691,24.953626 0.0892,4.61727 -0.1108,10.55624 -2.18945,16.22456 -1.2491,3.41284 -3.51339,6.88006 -7.02949,9.22007 -3.18537,2.03978 -6.9108,3.01105 -10.71996,3.31059 -4.32758,0.36681 -8.61596,0.0765 -13.06414,-0.3954 0,0 -1e-5,0 -1e-5,0 -4.85825,-0.50718 -9.81996,-1.2337 -14.88816,-1.8578 -10.52725,-1.92207 -22.25938,-3.65993 -33.51458,-2.56837 5.56514,-2.14789 11.23402,-4.37262 16.96405,-6.67029 14.09947,-5.65373 27.22086,-11.20878 39.76757,-16.84629 10.34679,-4.204445 20.04709,-8.578761 29.2102,-12.254895 3.86403,-1.55087 7.5962,-2.912625 11.31631,-4.062522 4.44997,-1.373998 8.80842,-2.424612 12.87075,-3.255903 25.5702,-5.229185 41.77669,-4.819543 41.7651,-4.910481 0.083,0.651054 -16.04487,2.199237 -41.03765,8.188979 -3.95341,0.947245 -8.17817,2.096907 -12.44827,3.538622 -3.57249,1.204947 -7.16926,2.614455 -10.93178,4.214907 -8.99368,3.826281 -18.60554,8.342603 -29.02526,12.707823 -12.83398,4.83575 -26.25198,9.37248 -40.70852,13.92084 -5.86346,1.84478 -11.6791,3.62297 -17.36766,5.33435 11.65665,-2.73331 23.3668,-2.48912 33.70665,-1.70227 5.13345,0.7007 10.05152,1.49994 14.79046,2.07946 0,0 10e-6,0 10e-6,0 4.36154,0.52566 8.36803,0.89758 12.29878,0.63761 3.41571,-0.24885 6.55597,-0.91553 9.05656,-2.49093 2.75513,-1.64741 4.69418,-4.48749 5.88989,-7.34626 2.04294,-4.90572 2.44367,-10.54405 2.602,-15.03686 0.50756,-15.585165 -1.45279,-24.853973 -0.96031,-24.933166 z" + id="path881" + transform="matrix(1.0227138,0,0,1.0923454,-62.375629,65.947122)" /> + id="layer7"> + transform="matrix(0.99993492,0,0,0.99993492,13.017271,44.180298)"> + style="stroke-width:0.2593" + id="g2294"> + id="path2276" /> + id="path2278" /> + id="path2280" /> + id="path2282" /> + id="path2284" /> + id="path2286" /> + id="path2288" /> + id="path2290" /> + id="path2292" /> + id="path2296" /> + y="146.5" + width="51.759998" + height="21.709999" + ry="2.1700001" + id="rect2298" /> + id="path2302" /> + id="path2304" /> - FreqAI + id="path2306" /> - - - - - - - - - - + id="layer2"> + + + + + + + + + FreqAI + + + + + d="m 409.50476,87.379983 c 0.0817,-0.04926 0.83007,0.887208 2.07545,2.822175 1.04507,1.623744 3.25835,5.167411 4.12211,9.194511 0.24011,1.048051 0.37549,2.363451 -0.10902,3.660331 -0.18859,0.47508 -0.48353,0.9229 -0.88238,1.29561 -0.4008,0.36595 -0.86666,0.63703 -1.35775,0.81687 -1.19769,0.43163 -2.45385,0.47703 -3.68135,0.37305 -1.61056,-0.11875 -3.19793,-0.44421 -4.84759,-0.87259 -4.16825,-1.07786 -8.14201,-2.5878 -12.79809,-4.4764 -9.73087,-3.941923 -20.77511,-9.129422 -33.23314,-14.263637 -5.48498,-2.260172 -11.39743,-4.574201 -17.4774,-6.560008 -5.09213,-1.660645 -10.48843,-3.19017 -16.00487,-4.015333 -2.9914,-0.437506 -6.09153,-0.46961 -8.95818,0.325781 -2.42804,0.652502 -4.7293,1.92692 -6.7488,3.603104 -2.16014,1.788823 -4.01151,4.022183 -5.76455,6.441443 -1.98455,2.749884 -3.76186,5.674924 -5.58974,8.71081 -4.19023,6.97383 -8.63594,14.41792 -14.06138,21.13172 -0.4076,0.45385 -0.82052,0.90435 -1.23872,1.35135 -6.99445,7.4762 -15.14736,13.64043 -23.95364,18.25267 1.08898,-2.79485 1.7844,-5.77129 1.81896,-8.80392 0,0 10e-6,-1e-5 10e-6,-1e-5 0.38,-2.40424 0.21457,-4.88822 -0.38967,-7.23261 -0.63616,-2.48616 -1.77286,-4.85563 -3.1418,-7.05996 -1.53736,-2.46945 -3.39699,-4.74262 -5.3732,-6.86136 -4.50934,-4.83407 -9.76414,-8.980583 -14.8279,-12.716321 -5.31289,-3.914842 -10.63799,-7.453058 -15.64776,-10.989417 -2.22769,-1.571719 -4.36129,-3.115548 -6.42213,-4.778903 -1.64818,-1.324283 -3.23931,-2.705582 -4.62447,-4.342456 -0.53145,-0.625434 -1.03333,-1.314573 -1.44675,-2.091148 -0.34225,-0.627813 -0.60475,-1.357327 -0.69952,-2.169834 0,0 0,-1.4e-5 0,-1.4e-5 -0.0779,-0.750702 0.0462,-1.512763 0.367,-2.209488 0,0 0,-1.2e-5 0,-1.2e-5 0.38316,-0.77978 0.92391,-1.386219 1.50254,-1.835437 0.78178,-0.619545 1.62171,-1.06389 2.4332,-1.407758 1.13734,-0.488832 2.29126,-0.844274 3.40719,-1.132195 3.50309,-0.906013 7.05979,-1.338662 10.22546,-1.650874 23.18125,-2.299439 36.94463,-0.08504 36.9438,-0.452268 8.7e-4,0.388728 -13.90634,-0.336072 -36.71433,2.505031 -3.12101,0.390538 -6.57136,0.885582 -9.85579,1.814406 -1.0434,0.295814 -2.08057,0.634827 -3.04947,1.07809 -0.69296,0.321905 -1.34571,0.671292 -1.86387,1.113717 -0.364,0.320857 -0.67323,0.650293 -0.8072,0.991792 0,0 0,5e-6 0,5e-6 -0.12418,0.268103 -0.16576,0.599529 -0.12769,0.918029 0,0 0,6e-6 0,6e-6 0.0351,0.384659 0.21456,0.805098 0.44854,1.252612 0.2987,0.552334 0.70811,1.082464 1.17179,1.620759 1.22674,1.417525 2.71555,2.653886 4.3349,3.928004 2.01237,1.575728 4.11873,3.052334 6.3518,4.584232 5.01914,3.441387 10.39585,6.923268 15.83064,10.840983 5.16939,3.721829 10.59624,7.938422 15.36962,12.963249 2.09536,2.20557 4.09636,4.62677 5.7996,7.31323 1.52509,2.40018 2.80715,5.06206 3.57603,7.94655 0.72733,2.74549 0.93047,5.67197 0.49493,8.56235 0,0 0,2e-5 0,2e-5 -0.86253,2.79257 -2.45308,5.41852 -4.50792,7.73608 7.7848,-5.12796 14.91437,-11.79762 20.9229,-19.73477 0.35932,-0.47465 0.71367,-0.95257 1.063,-1.43365 5.23266,-6.45055 9.60687,-13.768177 13.82746,-20.73084 1.83968,-3.041164 3.68014,-6.039283 5.77405,-8.922486 1.84136,-2.545239 3.89517,-4.972657 6.36038,-7.016242 2.34517,-1.940232 5.06674,-3.410413 7.99843,-4.196264 3.44628,-0.898759 6.97893,-0.864117 10.27251,-0.332556 5.7724,0.915436 11.31553,2.532415 16.47253,4.277279 6.17081,2.084811 12.11826,4.490476 17.61006,6.839344 12.48717,5.339979 23.40869,10.705759 32.98675,14.843562 4.60517,1.986833 8.42219,3.560413 12.44172,4.725603 1.58792,0.45848 3.05427,0.81419 4.51576,0.96734 1.13127,0.10478 2.14607,0.13666 3.01995,-0.16986 0.3399,-0.11628 0.6453,-0.27004 0.87952,-0.47523 0.23454,-0.19697 0.42225,-0.46007 0.55127,-0.74468 0.39736,-0.81327 0.30177,-1.89803 0.16324,-2.868152 -0.59137,-3.720132 -2.57863,-7.437888 -3.43481,-9.095384 -1.05035,-2.033393 -1.60487,-3.091683 -1.49222,-3.159631 z" + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + transform="matrix(1.0227138,0,0,1.0923454,-180.74242,54.998164)" /> diff --git a/docs/freqai.md b/docs/freqai.md index eb76ab1a4..093637479 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -6,16 +6,16 @@ FreqAI is a module designed to automate a variety of tasks associated with train Among the the features included: -* **Self-adaptive retraining**: automatically retrain models during live deployments to self-adapt to the market in an unsupervised manner. +* **Self-adaptive retraining**: retrain models during live deployments to self-adapt to the market in an unsupervised manner. * **Rapid feature engineering**: create large rich feature sets (10k+ features) based on simple user created strategies. * **High performance**: adaptive retraining occurs on separate thread (or on GPU if available) from inferencing and bot trade operations. Keep newest models and data in memory for rapid inferencing. * **Realistic backtesting**: emulate self-adaptive retraining with backtesting module that automates past retraining. * **Modifiable**: use the generalized and robust architecture for incorporating any machine learning library/method available in Python. Seven examples available. -* **Smart outlier removal**: remove outliers automatically from training and prediction sets using a variety of outlier detection techniques. -* **Crash resilience**: automatic model storage to disk to make reloading from a crash fast and easy (and purge obsolete files automatically for sustained dry/live runs). -* **Automated data normalization**: automatically normalize the data automatically in a smart and statistically safe way. -* **Automatic data download**: automatically compute the data download timerange and downloads data accordingly (in live deployments). -* **Clean the incoming data of NaNs in a safe way before training and prediction. +* **Smart outlier removal**: remove outliers from training and prediction sets using a variety of outlier detection techniques. +* **Crash resilience**: model storage to disk to make reloading from a crash fast and easy (and purge obsolete files for sustained dry/live runs). +* **Automated data normalization**: normalize the data in a smart and statistically safe way. +* **Automatic data download**: compute the data download timerange and update historic data (in live deployments). +* **Clean incoming data** safe NaN handling before training and prediction. * **Dimensionality reduction**: reduce the size of the training data via Principal Component Analysis. * **Deploy bot fleets**: set one bot to train models while a fleet of other bots inference into the models and handle trades. @@ -412,10 +412,75 @@ The FreqAI strategy requires the user to include the following lines of code in dataframe = self.freqai.start(dataframe, metadata, self) return dataframe + + def populate_any_indicators( + self, pair, df, tf, informative=None, set_generalized_indicators=False + ): + """ + Function designed to automatically generate, name and merge features + from user indicated timeframes in the configuration file. User controls the indicators + passed to the training/prediction by prepending indicators with `'%-' + coin ` + (see convention below). I.e. user should not prepend any supporting metrics + (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the + model. + :param pair: pair to be used as informative + :param df: strategy dataframe which will receive merges from informatives + :param tf: timeframe of the dataframe which will modify the feature names + :param informative: the dataframe associated with the informative pair + :param coin: the name of the coin which will modify the feature names. + """ + + coint = pair.split('/')[0] + + with self.freqai.lock: + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) + + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) + + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) + + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) + + return df + + ``` -The user should also include `populate_any_indicators()` from `templates/FreqaiExampleStrategy.py` which builds -the feature set with a proper naming convention for the IFreqaiModel to use later. +Notice how the `populate_any_indicators()` is where the user adds their own features and labels (more information [here](#feature-engineering)). See a full example at `templates/FreqaiExampleStrategy.py`. ### Setting classifier targets diff --git a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py index afb439cbf..04eff045f 100644 --- a/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py +++ b/freqtrade/freqai/prediction_models/BaseTensorFlowModel.py @@ -24,11 +24,11 @@ class BaseTensorFlowModel(IFreqaiModel): for storing, saving, loading, and analyzing the data. :param unfiltered_dataframe: Full dataframe for the current training period :param metadata: pair metadata from strategy. - :returns: + :return: :model: Trained model which can be used to inference (self.predict) """ - logger.info("--------------------Starting training " f"{pair} --------------------") + logger.info("-------------------- Starting training " f"{pair} --------------------") # filter the features requested by user in the configuration file and elegantly handle NaNs features_filtered, labels_filtered = dk.filter_features( @@ -38,9 +38,14 @@ class BaseTensorFlowModel(IFreqaiModel): training_filter=True, ) + start_date = unfiltered_dataframe["date"].iloc[0].strftime("%Y-%m-%d") + end_date = unfiltered_dataframe["date"].iloc[-1].strftime("%Y-%m-%d") + logger.info(f"-------------------- Training on data from {start_date} to " + f"{end_date}--------------------") # split data into train/test data. data_dictionary = dk.make_train_test_datasets(features_filtered, labels_filtered) - + if not self.freqai_info.get('fit_live_predictions', 0) or not self.live: + dk.fit_labels() # normalize all data based on train_dataset only data_dictionary = dk.normalize_data(data_dictionary) @@ -54,17 +59,6 @@ class BaseTensorFlowModel(IFreqaiModel): model = self.fit(data_dictionary) - if pair not in self.dd.historic_predictions: - self.set_initial_historic_predictions( - data_dictionary['train_features'], model, dk, pair) - - if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: - self.fit_live_predictions(dk) - else: - dk.fit_labels() - - self.dd.save_historic_predictions_to_disk() - logger.info(f"--------------------done training {pair}--------------------") return model From 044cf8bb2e19b7c96406eb12d434b4ee8800a31a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 08:41:25 +0200 Subject: [PATCH 286/308] Allow new whitelist combination in "button" commands --- freqtrade/rpc/telegram.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 88222608e..8ce2fa2e4 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -120,7 +120,8 @@ class Telegram(RPCHandler): r'/daily$', r'/daily \d+$', r'/profit$', r'/profit \d+', r'/stats$', r'/count$', r'/locks$', r'/balance$', r'/stopbuy$', r'/reload_config$', r'/show_config$', - r'/logs$', r'/whitelist$', r'/blacklist$', r'/bl_delete$', + r'/logs$', r'/whitelist$', r'/whitelist(\ssorted|\sbaseonly)+$', + r'/blacklist$', r'/bl_delete$', r'/weekly$', r'/weekly \d+$', r'/monthly$', r'/monthly \d+$', r'/forcebuy$', r'/forcelong$', r'/forceshort$', r'/forcesell$', r'/forceexit$', From 24f1dc4ecc08ac30fac3f507e342e8d560d65a8c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 09:06:04 +0200 Subject: [PATCH 287/308] Update patched ta-lib install for conda --- .gitignore | 1 + build_helpers/install_ta-lib.sh | 16 +++++++++++----- build_helpers/install_ta-lib_conda.sh | 21 --------------------- docs/installation.md | 7 +++++-- 4 files changed, 17 insertions(+), 28 deletions(-) delete mode 100644 build_helpers/install_ta-lib_conda.sh diff --git a/.gitignore b/.gitignore index d6cec5225..065ac1f68 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ user_data/notebooks/* freqtrade-plot.html freqtrade-profit-plot.html freqtrade/rpc/api_server/ui/* +build_helpers/ta-lib/* # Macos related .DS_Store diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index 00c4417ae..581c1cd41 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -4,7 +4,7 @@ else INSTALL_LOC=${1} fi echo "Installing to ${INSTALL_LOC}" -if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then +if [ -n "$2" ] && [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then tar zxvf ta-lib-0.4.0-src.tar.gz cd ta-lib \ && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \ @@ -17,11 +17,17 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then 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 + if [ -z "$2" ]; then + which sudo && sudo make install || make install + if [ -x "$(command -v apt-get)" ]; then + echo "Updating library path using ldconfig" + sudo ldconfig + fi + else + # Don't install with sudo + make install fi + cd .. && rm -rf ./ta-lib/ else echo "TA-lib already installed, skipping installation" diff --git a/build_helpers/install_ta-lib_conda.sh b/build_helpers/install_ta-lib_conda.sh deleted file mode 100644 index 27f8a50a1..000000000 --- a/build_helpers/install_ta-lib_conda.sh +++ /dev/null @@ -1,21 +0,0 @@ -if ! [[ -v CONDA_PREFIX ]]; then - echo "The conda environment is not activated." - exit 1 -fi - -INSTALL_LOC=${CONDA_PREFIX} -echo "Installing to ${INSTALL_LOC}" -tar zxvf ta-lib-0.4.0-src.tar.gz -cd ta-lib \ -&& sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \ -&& 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 -if [ $? -ne 0 ]; then - echo "Failed building ta-lib." - cd .. && rm -rf ./ta-lib/ - exit 1 -fi -make install || make install -cd .. && rm -rf ./ta-lib/ diff --git a/docs/installation.md b/docs/installation.md index 29511384c..9dd14274a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -326,11 +326,14 @@ python3 -m pip install --upgrade pip python3 -m pip install -e . ``` -Patch conda libta-lib +Patch conda libta-lib (Linux only) ```bash +# Ensure that the environment is active! +conda activate freqtrade-conda + cd build_helpers -bash install_ta-lib_conda.sh +bash install_ta-lib.sh ${CONDA_PREFIX} nosudo ``` ### Congratulations From e7513c96b3a3795e1d7c38f59e519e3e41d54337 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 09:36:38 +0200 Subject: [PATCH 288/308] install py-find-1st from conda forge closes #7193 --- environment.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 19f3c7f5a..d6d85de9d 100644 --- a/environment.yml +++ b/environment.yml @@ -9,6 +9,7 @@ dependencies: - pandas - pip + - py-find-1st - aiohttp - SQLAlchemy - python-telegram-bot @@ -64,7 +65,7 @@ dependencies: - pip: - pycoingecko - - py_find_1st + # - py_find_1st - tables - pytest-random-order - ccxt From a5e96881f42c0e44b4faf3c278bee6dfcde453e4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 17:08:29 +0200 Subject: [PATCH 289/308] slightly update doc wording --- docs/freqai.md | 211 ++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 108 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 093637479..6e81d9f28 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -8,7 +8,7 @@ Among the the features included: * **Self-adaptive retraining**: retrain models during live deployments to self-adapt to the market in an unsupervised manner. * **Rapid feature engineering**: create large rich feature sets (10k+ features) based on simple user created strategies. -* **High performance**: adaptive retraining occurs on separate thread (or on GPU if available) from inferencing and bot trade operations. Keep newest models and data in memory for rapid inferencing. +* **High performance**: adaptive retraining occurs on separate thread (or on GPU if available) from inferencing and bot trade operations. Keep newest models and data in memory for rapid inferencing. * **Realistic backtesting**: emulate self-adaptive retraining with backtesting module that automates past retraining. * **Modifiable**: use the generalized and robust architecture for incorporating any machine learning library/method available in Python. Seven examples available. * **Smart outlier removal**: remove outliers from training and prediction sets using a variety of outlier detection techniques. @@ -37,7 +37,7 @@ The example strategy, example prediction model, and example config can all be fo The user provides FreqAI with a set of custom *base* indicators (created inside the strategy the same way a typical Freqtrade strategy is created) as well as target values which look into the future. -FreqAI trains a model to predict the target value based on the input of custom indicators for each pair in the whitelist. These models are consistently retrained to adapt to market conditions. FreqAI offers the ability to both backtest strategies (emulating reality with periodic retraining) and deploy dry/live. In dry/live conditions, FreqAI can be set to constant retraining in a background thread in an effort to keep models as young as possible. +FreqAI trains a model to predict the target value based on the input of custom indicators for each pair in the whitelist. These models are consistently retrained to adapt to market conditions. FreqAI offers the ability to both backtest strategies (emulating reality with periodic retraining) and deploy dry/live. In dry/live conditions, FreqAI can be set to constant retraining in a background thread in an effort to keep models as young as possible. An overview of the algorithm is shown here to help users understand the data processing pipeline and the model usage. @@ -66,7 +66,7 @@ directly influence nodal weights within the model. ## Install prerequisites -The normal Freqtrade install process will ask the user if they wish to install `FreqAI` dependencies. The user should reply "yes" to this question if they wish to use FreqAI. If the user did not reply yes, they can manually install these dependencies after the install with: +The normal Freqtrade install process will ask the user if they wish to install FreqAI dependencies. The user should reply "yes" to this question if they wish to use FreqAI. If the user did not reply yes, they can manually install these dependencies after the install with: ``` bash pip install -r requirements-freqai.txt @@ -75,21 +75,21 @@ pip install -r requirements-freqai.txt !!! Note Catboost will not be installed on arm devices (raspberry, Mac M1, ARM based VPS, ...), since Catboost does not provide wheels for this platform. -## Configuring the bot +## Configuring FreqAI ### Parameter table -The table below will list all configuration parameters available for `FreqAI`. +The table below will list all configuration parameters available for FreqAI. Mandatory parameters are marked as **Required**, which means that they are required to be set in one of the possible ways. | Parameter | Description | |------------|-------------| -| `freqai` | **Required.** The dictionary containing all the parameters for controlling FreqAI.
**Datatype:** dictionary. +| `freqai` | **Required.** The parent dictionary containing all the parameters below for controlling FreqAI.
**Datatype:** dictionary. | `identifier` | **Required.** A unique name for the current model. This can be reused to reload pre-trained models/data.
**Datatype:** string. | `train_period_days` | **Required.** Number of days to use for the training data (width of the sliding window).
**Datatype:** positive integer. | `backtest_period_days` | **Required.** Number of days to inference into the trained model before sliding the window and retraining. This can be fractional days, but beware that the user provided `timerange` will be divided by this number to yield the number of trainings necessary to complete the backtest.
**Datatype:** Float. -| `live_retrain_hours` | Frequency of retraining during dry/live runs. Default set to 0, which means it will retrain as often as possible. **Datatype:** Float > 0. +| `live_retrain_hours` | Frequency of retraining during dry/live runs. Default set to 0, which means it will retrain as often as possible.
**Datatype:** Float > 0. | `follow_mode` | If true, this instance of FreqAI will look for models associated with `identifier` and load those for inferencing. A `follower` will **not** train new models. `False` by default.
**Datatype:** boolean. | `startup_candles` | Number of candles needed for *backtesting only* to ensure all indicators are non NaNs at the start of the first train period.
**Datatype:** positive integer. | `fit_live_predictions_candles` | Computes target (label) statistics from prediction data, instead of from the training data set. Number of candles is the number of historical candles it uses to generate the statistics.
**Datatype:** positive integer. @@ -101,11 +101,11 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `include_timeframes` | A list of timeframes that all indicators in `populate_any_indicators` will be created for and added as features to the base asset feature set.
**Datatype:** list of timeframes (strings). | `label_period_candles` | Number of candles into the future that the labels are created for. This is used in `populate_any_indicators`, refer to `templates/FreqaiExampleStrategy.py` for detailed usage. The user can create custom labels, making use of this parameter not.
**Datatype:** positive integer. | `include_shifted_candles` | Parameter used to add a sense of temporal recency to flattened regression type input data. `include_shifted_candles` takes all features, duplicates and shifts them by the number indicated by user.
**Datatype:** positive integer. -| `DI_threshold` | Activates the Dissimilarity Index for outlier detection when above 0, explained more [here](#removing-outliers-with-the-dissimilarity-index).
**Datatype:** positive float (typically below 1). +| `DI_threshold` | Activates the Dissimilarity Index for outlier detection when above 0, explained in detail [here](#removing-outliers-with-the-dissimilarity-index).
**Datatype:** positive float (typically below 1). | `weight_factor` | Used to set weights for training data points according to their recency, see details and a figure of how it works [here](#controlling-the-model-learning-process).
**Datatype:** positive float (typically below 1). | `principal_component_analysis` | Ask FreqAI to automatically reduce the dimensionality of the data set using PCA.
**Datatype:** boolean. | `use_SVM_to_remove_outliers` | Ask FreqAI to train a support vector machine to detect and remove outliers from the training data set as well as from incoming data points.
**Datatype:** boolean. -| `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. E.g. `nu` *Very* broadly, is the percentage of data points that should be considered outliers. `shuffle` is by default false to maintain reprodicibility. But these and all others can be added/changed in this dictionary.
**Datatype:** dictionary. +| `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. E.g. `nu` *Very* broadly, is the percentage of data points that should be considered outliers. `shuffle` is by default false to maintain reproducibility. But these and all others can be added/changed in this dictionary.
**Datatype:** dictionary. | `stratify_training_data` | This value is used to indicate the stratification of the data. e.g. 2 would set every 2nd data point into a separate dataset to be pulled from during training/testing.
**Datatype:** positive integer. | `indicator_max_period_candles` | The maximum *period* used in `populate_any_indicators()` for indicator creation. FreqAI uses this information in combination with the maximum timeframe to calculate how many data points it should download so that the first data point does not have a NaN
**Datatype:** positive integer. | `indicator_periods_candles` | A list of integers used to duplicate all indicators according to a set of periods and add them to the feature set.
**Datatype:** list of positive integers. @@ -113,7 +113,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | | **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)
**Datatype:** dictionary. | `test_size` | Fraction of data that should be used for testing instead of training.
**Datatype:** positive float below 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 for time-series forecasting, this is set to False.
**Datatype:** boolean. | | **Model training parameters** | `model_training_parameters` | A flexible dictionary that includes all parameters available by the user selected library. For example, if the user uses `LightGBMRegressor`, then this dictionary can contain any parameter available by the `LightGBMRegressor` [here](https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRegressor.html). If the user selects a different model, then this dictionary can contain any parameter from that different model.
**Datatype:** dictionary. | `n_estimators` | A common parameter among regressors which sets the number of boosted trees to fit
**Datatype:** integer. @@ -123,8 +123,8 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `keras` | If your model makes use of keras (typical of Tensorflow based prediction models), activate this flag so that the model save/loading follows keras standards. Default value `false`
**Datatype:** boolean. | `conv_width` | The width of a convolutional neural network input tensor. This replaces the need for `shift` by feeding in historical data points as the second dimension of the tensor. Technically, this parameter can also be used for regressors, but it only adds computational overhead and does not change the model training/prediction. Default value, 2
**Datatype:** integer. - ### Important FreqAI dataframe key patterns + Here are the values the user can expect to include/use inside the typical strategy dataframe (`df[]`): | DataFrame Key | Description | @@ -137,51 +137,50 @@ Here are the values the user can expect to include/use inside the typical strate ### Example config file -The user interface is isolated to the typical config file. A typical FreqAI -config setup could include: +The user interface is isolated to the typical config file. A typical FreqAI config setup could include: ```json "freqai": { - "startup_candles": 10000, - "purge_old_models": true, - "train_period_days" : 30, - "backtest_period_days" : 7, - "identifier" : "unique-id", - "feature_parameters" : { - "include_timeframes" : ["5m","15m","4h"], - "include_corr_pairlist": [ - "ETH/USD", - "LINK/USD", - "BNB/USD" - ], - "label_period_candles": 24, - "include_shifted_candles": 2, - "weight_factor": 0, - "indicator_max_period_candles": 20, - "indicator_periods_candles": [10, 20] - }, - "data_split_parameters" : { - "test_size": 0.25, - "random_state": 42 - }, - "model_training_parameters" : { - "n_estimators": 100, - "random_state": 42, - "learning_rate": 0.02, - "task_type": "CPU", - }, - } + "startup_candles": 10000, + "purge_old_models": true, + "train_period_days": 30, + "backtest_period_days": 7, + "identifier" : "unique-id", + "feature_parameters" : { + "include_timeframes": ["5m","15m","4h"], + "include_corr_pairlist": [ + "ETH/USD", + "LINK/USD", + "BNB/USD" + ], + "label_period_candles": 24, + "include_shifted_candles": 2, + "weight_factor": 0, + "indicator_max_period_candles": 20, + "indicator_periods_candles": [10, 20] + }, + "data_split_parameters" : { + "test_size": 0.25, + "random_state": 42 + }, + "model_training_parameters" : { + "n_estimators": 100, + "random_state": 42, + "learning_rate": 0.02, + "task_type": "CPU", + }, + } ``` ### Feature engineering -Features are added by the user inside the `populate_any_indicators()` method of the strategy +Features are added by the user inside the `populate_any_indicators()` method of the strategy by prepending indicators with `%` and labels are added by prepending `&`. There are some important components/structures that the user *must* include when building their feature set. As shown below, `with self.freqai.lock:` must be used to ensure thread safety - especially when using third party libraries for indicator construction such as TA-lib. Another structure to consider is the location of the labels at the bottom of the example function (below `if set_generalized_indicators:`). -This is where the user will add single features and labels to their feature set to avoid duplication from +This is where the user will add single features and labels to their feature set to avoid duplication from various configuration parameters which multiply the feature set such as `include_timeframes`. ```python @@ -275,42 +274,9 @@ The user of the present example does not wish to pass the `bb_lowerband` as a fe and has therefore not prepended it with `%`. The user does, however, wish to pass `bb_width` to the model for training/prediction and has therefore prepended it with `%`. -Note: features **must** be defined in `populate_any_indicators()`. Making features in `populate_indicators()` -will fail in live/dry mode. If the user wishes to add generalized features that are not associated with -a specific pair or timeframe, they should use the following structure inside `populate_any_indicators()` -(as exemplified in `freqtrade/templates/FreqaiExampleStrategy.py`: - -```python - def populate_any_indicators(self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False): - - ... - - # Add generalized indicators here (because in live, it will call only this function to populate - # indicators for retraining). Notice how we ensure not to add them multiple times by associating - # these generalized indicators to the basepair/timeframe - if set_generalized_indicators: - df['%-day_of_week'] = (df["date"].dt.dayofweek + 1) / 7 - df['%-hour_of_day'] = (df['date'].dt.hour + 1) / 25 - - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) -``` - -(Please see the example script located in `freqtrade/templates/FreqaiExampleStrategy.py` for a full example of `populate_any_indicators()`) - -The `include_timeframes` from the example config above are the timeframes of each `populate_any_indicator()` - included metric for inclusion in the feature set. In the present case, the user is asking for the -`5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, and `bb_width` to be included -in the feature set. +The `include_timeframes` from the example config above are the timeframes (`tf`) of each call to `populate_any_indicators()` +included metric for inclusion in the feature set. In the present case, the user is asking for the +`5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, and `bb_width` to be included in the feature set. In addition, the user can ask for each of these features to be included from informative pairs using the `include_corr_pairlist`. This means that the present feature @@ -324,7 +290,40 @@ FreqAI to include the the past 2 candles for each of the features included in th In total, the number of features the present user has created is: length of `include_timeframes` * no. features in `populate_any_indicators()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles` -_3 * 3 * 3 * 2 * 2 = 108_. +$3 * 3 * 3 * 2 * 2 = 108$. + +!!! Note + Features **must** be defined in `populate_any_indicators()`. Making features in `populate_indicators()` + will fail in live/dry mode. If the user wishes to add generalized features that are not associated with + a specific pair or timeframe, they should use the following structure inside `populate_any_indicators()` + (as exemplified in `freqtrade/templates/FreqaiExampleStrategy.py`: + + ```python + def populate_any_indicators(self, metadata, pair, df, tf, informative=None, coin="", set_generalized_indicators=False): + + ... + + # Add generalized indicators here (because in live, it will call only this function to populate + # indicators for retraining). Notice how we ensure not to add them multiple times by associating + # these generalized indicators to the basepair/timeframe + if set_generalized_indicators: + df['%-day_of_week'] = (df["date"].dt.dayofweek + 1) / 7 + df['%-hour_of_day'] = (df['date'].dt.hour + 1) / 25 + + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) + ``` + + (Please see the example script located in `freqtrade/templates/FreqaiExampleStrategy.py` for a full example of `populate_any_indicators()`) ### Deciding the sliding training window and backtesting duration @@ -370,12 +369,11 @@ Backtesting mode requires the user to have the data pre-downloaded (unlike dry/l If this command has never been executed with the existing config file, then it will train a new model for each pair, for each backtesting window within the bigger `--timerange`. ---- !!! Note "Model reuse" - Once the training is completed, the user can execute this again with the same config file and - FreqAI will find the trained models and load them instead of spending time training. This is useful + Once the training is completed, the user can execute this again with the same config file and + FreqAI will find the trained models and load them instead of spending time training. This is useful if the user wants to tweak (or even hyperopt) buy and sell criteria inside the strategy. IF the user - *wants* to retrain a new model with the same config file, then he/she should simply change the `identifier`. + *wants* to retrain a new model with the same config file, then he/she should simply change the `identifier`. This way, the user can return to using any model they wish by simply changing the `identifier`. --- @@ -430,7 +428,7 @@ The FreqAI strategy requires the user to include the following lines of code in :param coin: the name of the coin which will modify the feature names. """ - coint = pair.split('/')[0] + coin = pair.split('/')[0] with self.freqai.lock: if informative is None: @@ -480,7 +478,7 @@ The FreqAI strategy requires the user to include the following lines of code in ``` -Notice how the `populate_any_indicators()` is where the user adds their own features and labels (more information [here](#feature-engineering)). See a full example at `templates/FreqaiExampleStrategy.py`. +Notice how the `populate_any_indicators()` is where the user adds their own features and labels ([more information](#feature-engineering)). See a full example at `templates/FreqaiExampleStrategy.py`. ### Setting classifier targets @@ -490,7 +488,6 @@ FreqAI includes a the `CatboostClassifier` via the flag `--freqaimodel CatboostC df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') ``` - ### Running the model live FreqAI can be run dry/live using the following command @@ -499,8 +496,8 @@ FreqAI can be run dry/live using the following command freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel LightGBMRegressor ``` -By default, FreqAI will not find find any existing models and will start by training a new one -given the user configuration settings. Following training, it will use that model to make predictions on incoming candles until a new model is available. New models are typically generated as often as possible, with FreqAI managing an internal queue of the pairs to try and keep all models equally "young." FreqAI will always use the newest trained model to make predictions on incoming live data. If users do not want FreqAI to retrain new models as often as possible, they can set `live_retrain_hours` to tell FreqAI to wait at least that number of hours before retraining a new model. Additionally, users can set `expired_hours` to tell FreqAI to avoid making predictions on models aged over this number of hours. +By default, FreqAI will not find any existing models and will start by training a new one +given the user configuration settings. Following training, it will use that model to make predictions on incoming candles until a new model is available. New models are typically generated as often as possible, with FreqAI managing an internal queue of the pairs to try and keep all models equally "young." FreqAI will always use the newest trained model to make predictions on incoming live data. If users do not want FreqAI to retrain new models as often as possible, they can set `live_retrain_hours` to tell FreqAI to wait at least that number of hours before retraining a new model. Additionally, users can set `expired_hours` to tell FreqAI to avoid making predictions on models aged over this number of hours. If the user wishes to start dry/live from a backtested saved model, the user only needs to reuse the same `identifier` parameter @@ -514,7 +511,7 @@ the same `identifier` parameter In this case, although FreqAI will initiate with a pre-trained model, it will still check to see how much time has elapsed since the model was trained, -and if a full `live_retrain_hours` has elapsed since the end of the loaded model, FreqAI will self retrain. +and if a full `live_retrain_hours` has elapsed since the end of the loaded model, FreqAI will self retrain. ## Data analysis techniques @@ -522,7 +519,7 @@ and if a full `live_retrain_hours` has elapsed since the end of the loaded model Model training parameters are unique to the ML library used by the user. FreqAI allows users to set any parameter for any library using the `model_training_parameters` dictionary in the user configuration file. The example configuration files show some of the example parameters associated with `Catboost` and `LightGBM`, but users can add any parameters available in those libraries. -Data split parameters are defined in `data_split_parameters` which can be any parameters associated with `Sklearn`'s `train_test_split()` function. Meanwhile, FreqAI includes some additional parameters such `weight_factor` which allows the user to weight more recent data more strongly +Data split parameters are defined in `data_split_parameters` which can be any parameters associated with `Sklearn`'s `train_test_split()` function. FreqAI includes some additional parameters such `weight_factor` which allows the user to weight more recent data more strongly than past data via an exponential function: $$ W_i = \exp(\frac{-i}{\alpha*n}) $$ @@ -545,8 +542,8 @@ data point and all other training data points: $$ d_{ab} = \sqrt{\sum_{j=1}^p(X_{a,j}-X_{b,j})^2} $$ where $d_{ab}$ is the distance between the normalized points $a$ and $b$. $p$ -is the number of features i.e. the length of the vector $X$. The -characteristic distance, $\overline{d}$ for a set of training data points is simply the mean +is the number of features i.e. the length of the vector $X$. +The characteristic distance, $\overline{d}$ for a set of training data points is simply the mean of the average distances: $$ \overline{d} = \sum_{a=1}^n(\sum_{b=1}^n(d_{ab}/n)/n) $$ @@ -574,8 +571,7 @@ to low levels of certainty. Activating the Dissimilarity Index can be achieved w } ``` -The user can tweak the DI with `DI_threshold` to increase or decrease the extrapolation of the -trained model. +The user can tweak the DI with `DI_threshold` to increase or decrease the extrapolation of the trained model. ### Reducing data dimensionality with Principal Component Analysis @@ -609,7 +605,7 @@ FreqAI will train an SVM on the training data (or components if the user activat ### Clustering the training data and removing outliers with DBSCAN -The user can tell FreqAI to use DBSCAN to cluster training data and remove outliers from the training data set. The user activates `use_DBSCAN_to_remove_outliers` to cluster training data for identification of outliers. Also used to detect incoming outliers for prediction data points. +The user can configure FreqAI to use DBSCAN to cluster training data and remove outliers from the training data set. The user activates `use_DBSCAN_to_remove_outliers` to cluster training data for identification of outliers. Also used to detect incoming outliers for prediction data points. ```json "freqai": { @@ -655,7 +651,7 @@ The follower will load models created by the leader and inference them to obtain FreqAI stores new model files each time it retrains. These files become obsolete as new models are trained and FreqAI adapts to the new market conditions. Users planning to leave FreqAI running -for extended periods of time with high frequency retraining should set `purge_old_models` in their +for extended periods of time with high frequency retraining should set `purge_old_models` in their config: ```json @@ -694,7 +690,7 @@ By default, FreqAI computes this based on training data and it assumes the label These are big assumptions that the user should consider when creating their labels. If the user wants to consider the population of *historical predictions* for creating the dynamic target instead of the trained labels, the user can do so by setting `fit_live_prediction_candles` to the number of historical prediction candles -the user wishes to use to generate target statistics. +the user wishes to use to generate target statistics. ```json "freqai": { @@ -703,17 +699,17 @@ the user wishes to use to generate target statistics. ``` If the user sets this value, FreqAI will initially use the predictions from the training data set -and then subsequently begin introducing real prediction data as it is generated. FreqAI will save +and then subsequently begin introducing real prediction data as it is generated. FreqAI will save this historical data to be reloaded if the user stops and restarts with the same `identifier`. ## Extra returns per train Users may find that there are some important metrics that they'd like to return to the strategy at the end of each retrain. -Users can include these metrics by assigining them to `dk.data['extra_returns_per_train']['my_new_value'] = XYZ` inside their custom prediction +Users can include these metrics by assigning them to `dk.data['extra_returns_per_train']['my_new_value'] = XYZ` inside their custom prediction model class. FreqAI takes the `my_new_value` assigned in this dictionary and expands it to fit the return dataframe to the strategy. -The user can then use the value in the strategy with `dataframe['my_new_value']`. An example of how this is already used in FreqAI is -the `&*_mean` and `&*_std` values, which indicate the mean and standard deviation of that particular label during the most recent training. -Another example is shown below if the user wants to use live metrics from the trade databse. +The user can then use the value in the strategy with `dataframe['my_new_value']`. An example of how this is already used in FreqAI is +the `&*_mean` and `&*_std` values, which indicate the mean and standard deviation of that particular label during the most recent training. +Another example is shown below if the user wants to use live metrics from the trade database. The user needs to set the standard dictionary in the config so FreqAI can return proper dataframe shapes: @@ -726,10 +722,9 @@ The user needs to set the standard dictionary in the config so FreqAI can return These values will likely be overridden by the user prediction model, but in the case where the user model has yet to set them, or needs a default initial value - this is the value that will be returned. - ## Building an IFreqaiModel -FreqAI has multiple example prediction model based libraries such as `Catboost` regression (`freqai/prediction_models/CatboostRegressor.py`) and `LightGBM` regression. +FreqAI has multiple example prediction model based libraries such as `Catboost` regression (`freqai/prediction_models/CatboostRegressor.py`) and `LightGBM` regression. However, users can customize and create their own prediction models using the `IFreqaiModel` class. Users are encouraged to inherit `train()` and `predict()` to let them customize various aspects of their training procedures. @@ -755,8 +750,8 @@ This file structure is heavily controlled and read by the `FreqaiDataKitchen()` and should therefore not be modified. ## Credits -FreqAI was developed by a group of individuals who all contributed specific skillsets to the -project. + +FreqAI was developed by a group of individuals who all contributed specific skillsets to the project. Conception and software development: Robert Caulk @robcaulk From 3a9ec76c919d619756328b9f12ec10256b64e42c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 17:19:50 +0200 Subject: [PATCH 290/308] Move "freqai.lock" to backend to simplify user interface --- docs/freqai.md | 184 +++++++++--------- freqtrade/freqai/data_kitchen.py | 36 ++-- freqtrade/templates/FreqaiExampleStrategy.py | 177 +++++++++-------- .../strategy/strats/freqai_test_classifier.py | 69 ++++--- .../strats/freqai_test_multimodel_strat.py | 105 +++++----- tests/strategy/strats/freqai_test_strat.py | 83 ++++---- 6 files changed, 323 insertions(+), 331 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 6e81d9f28..6631c271e 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -177,8 +177,6 @@ The user interface is isolated to the typical config file. A typical FreqAI conf Features are added by the user inside the `populate_any_indicators()` method of the strategy by prepending indicators with `%` and labels are added by prepending `&`. There are some important components/structures that the user *must* include when building their feature set. -As shown below, `with self.freqai.lock:` must be used to ensure thread safety - especially when using third -party libraries for indicator construction such as TA-lib. Another structure to consider is the location of the labels at the bottom of the example function (below `if set_generalized_indicators:`). This is where the user will add single features and labels to their feature set to avoid duplication from various configuration parameters which multiply the feature set such as `include_timeframes`. @@ -203,69 +201,68 @@ various configuration parameters which multiply the feature set such as `include coint = pair.split('/')[0] - with self.freqai.lock: - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - bollinger = qtpylib.bollinger_bands( - qtpylib.typical_price(informative), window=t, stds=2.2 - ) - informative[f"{coin}bb_lowerband-period_{t}"] = bollinger["lower"] - informative[f"{coin}bb_middleband-period_{t}"] = bollinger["mid"] - informative[f"{coin}bb_upperband-period_{t}"] = bollinger["upper"] + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(informative), window=t, stds=2.2 + ) + informative[f"{coin}bb_lowerband-period_{t}"] = bollinger["lower"] + informative[f"{coin}bb_middleband-period_{t}"] = bollinger["mid"] + informative[f"{coin}bb_upperband-period_{t}"] = bollinger["upper"] - informative[f"%-{coin}bb_width-period_{t}"] = ( - informative[f"{coin}bb_upperband-period_{t}"] - - informative[f"{coin}bb_lowerband-period_{t}"] - ) / informative[f"{coin}bb_middleband-period_{t}"] - informative[f"%-{coin}close-bb_lower-period_{t}"] = ( - informative["close"] / informative[f"{coin}bb_lowerband-period_{t}"] - ) + informative[f"%-{coin}bb_width-period_{t}"] = ( + informative[f"{coin}bb_upperband-period_{t}"] + - informative[f"{coin}bb_lowerband-period_{t}"] + ) / informative[f"{coin}bb_middleband-period_{t}"] + informative[f"%-{coin}close-bb_lower-period_{t}"] = ( + informative["close"] / informative[f"{coin}bb_lowerband-period_{t}"] + ) - informative[f"%-{coin}relative_volume-period_{t}"] = ( - informative["volume"] / informative["volume"].rolling(t).mean() - ) + informative[f"%-{coin}relative_volume-period_{t}"] = ( + informative["volume"] / informative["volume"].rolling(t).mean() + ) - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) return df ``` @@ -430,48 +427,47 @@ The FreqAI strategy requires the user to include the following lines of code in coin = pair.split('/')[0] - with self.freqai.lock: - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) return df diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 2ba8c5ecf..2378dcdd8 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -961,23 +961,25 @@ class FreqaiDataKitchen: for tf in tfs: if tf == tfs[-1]: sgi = True # doing this last allows user to use all tf raw prices in labels - dataframe = strategy.populate_any_indicators( - pair, - dataframe.copy(), - tf, - informative=base_dataframes[tf], - set_generalized_indicators=sgi - ) - if pairs: - for i in pairs: - if pair in i: - continue # dont repeat anything from whitelist - dataframe = strategy.populate_any_indicators( - i, - dataframe.copy(), - tf, - informative=corr_dataframes[i][tf] - ) + with strategy.freqai.lock: + dataframe = strategy.populate_any_indicators( + pair, + dataframe.copy(), + tf, + informative=base_dataframes[tf], + set_generalized_indicators=sgi + ) + with strategy.freqai.lock: + if pairs: + for i in pairs: + if pair in i: + continue # dont repeat anything from whitelist + dataframe = strategy.populate_any_indicators( + i, + dataframe.copy(), + tf, + informative=corr_dataframes[i][tf] + ) self.get_unique_classes_from_labels(dataframe) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index d8584d5f9..5810e7881 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -82,99 +82,98 @@ class FreqaiExampleStrategy(IStrategy): coin = pair.split('/')[0] - with self.freqai.lock: - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - informative[f"%-{coin}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) - informative[f"%-{coin}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + informative[f"%-{coin}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) + informative[f"%-{coin}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - bollinger = qtpylib.bollinger_bands( - qtpylib.typical_price(informative), window=t, stds=2.2 - ) - informative[f"{coin}bb_lowerband-period_{t}"] = bollinger["lower"] - informative[f"{coin}bb_middleband-period_{t}"] = bollinger["mid"] - informative[f"{coin}bb_upperband-period_{t}"] = bollinger["upper"] + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(informative), window=t, stds=2.2 + ) + informative[f"{coin}bb_lowerband-period_{t}"] = bollinger["lower"] + informative[f"{coin}bb_middleband-period_{t}"] = bollinger["mid"] + informative[f"{coin}bb_upperband-period_{t}"] = bollinger["upper"] - informative[f"%-{coin}bb_width-period_{t}"] = ( - informative[f"{coin}bb_upperband-period_{t}"] - - informative[f"{coin}bb_lowerband-period_{t}"] - ) / informative[f"{coin}bb_middleband-period_{t}"] - informative[f"%-{coin}close-bb_lower-period_{t}"] = ( - informative["close"] / informative[f"{coin}bb_lowerband-period_{t}"] - ) + informative[f"%-{coin}bb_width-period_{t}"] = ( + informative[f"{coin}bb_upperband-period_{t}"] + - informative[f"{coin}bb_lowerband-period_{t}"] + ) / informative[f"{coin}bb_middleband-period_{t}"] + informative[f"%-{coin}close-bb_lower-period_{t}"] = ( + informative["close"] / informative[f"{coin}bb_lowerband-period_{t}"] + ) - informative[f"%-{coin}roc-period_{t}"] = ta.ROC(informative, timeperiod=t) + informative[f"%-{coin}roc-period_{t}"] = ta.ROC(informative, timeperiod=t) - informative[f"%-{coin}relative_volume-period_{t}"] = ( - informative["volume"] / informative["volume"].rolling(t).mean() - ) + informative[f"%-{coin}relative_volume-period_{t}"] = ( + informative["volume"] / informative["volume"].rolling(t).mean() + ) - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + informative[f"%-{coin}pct-change"] = informative["close"].pct_change() + informative[f"%-{coin}raw_volume"] = informative["volume"] + informative[f"%-{coin}raw_price"] = informative["close"] - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - # user adds targets here by prepending them with &- (see convention below) - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) + # user adds targets here by prepending them with &- (see convention below) + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) - # Classifiers are typically set up with strings as targets: - # df['&s-up_or_down'] = np.where( df["close"].shift(-100) > - # df["close"], 'up', 'down') + # Classifiers are typically set up with strings as targets: + # df['&s-up_or_down'] = np.where( df["close"].shift(-100) > + # df["close"], 'up', 'down') - # If user wishes to use multiple targets, they can add more by - # appending more columns with '&'. User should keep in mind that multi targets - # requires a multioutput prediction model such as - # templates/CatboostPredictionMultiModel.py, + # If user wishes to use multiple targets, they can add more by + # appending more columns with '&'. User should keep in mind that multi targets + # requires a multioutput prediction model such as + # templates/CatboostPredictionMultiModel.py, - # df["&-s_range"] = ( - # df["close"] - # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - # .max() - # - - # df["close"] - # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - # .min() - # ) + # df["&-s_range"] = ( + # df["close"] + # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + # .max() + # - + # df["close"] + # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + # .min() + # ) return df @@ -252,12 +251,11 @@ class FreqaiExampleStrategy(IStrategy): "prediction" + entry_tag not in pair_dict[pair] or pair_dict[pair]['extras']["prediction" + entry_tag] == 0 ): - with self.freqai.lock: - pair_dict[pair]['extras']["prediction" + entry_tag] = abs(trade_candle["&-s_close"]) - if not follow_mode: - self.freqai.dd.save_drawer_to_disk() - else: - self.freqai.dd.save_follower_dict_to_disk() + pair_dict[pair]['extras']["prediction" + entry_tag] = abs(trade_candle["&-s_close"]) + if not follow_mode: + self.freqai.dd.save_drawer_to_disk() + else: + self.freqai.dd.save_follower_dict_to_disk() roi_price = pair_dict[pair]['extras']["prediction" + entry_tag] roi_time = self.max_roi_time_long.value @@ -296,12 +294,11 @@ class FreqaiExampleStrategy(IStrategy): else: pair_dict = self.freqai.dd.follower_dict - with self.freqai.lock: - pair_dict[pair]['extras']["prediction" + entry_tag] = 0 - if not follow_mode: - self.freqai.dd.save_drawer_to_disk() - else: - self.freqai.dd.save_follower_dict_to_disk() + pair_dict[pair]['extras']["prediction" + entry_tag] = 0 + if not follow_mode: + self.freqai.dd.save_drawer_to_disk() + else: + self.freqai.dd.save_follower_dict_to_disk() return True diff --git a/tests/strategy/strats/freqai_test_classifier.py b/tests/strategy/strats/freqai_test_classifier.py index 0a2ce793a..a1e8cb6bf 100644 --- a/tests/strategy/strats/freqai_test_classifier.py +++ b/tests/strategy/strats/freqai_test_classifier.py @@ -63,48 +63,47 @@ class freqai_test_classifier(IStrategy): coin = pair.split('/')[0] - with self.freqai.lock: - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + informative[f"%-{coin}pct-change"] = informative["close"].pct_change() + informative[f"%-{coin}raw_volume"] = informative["volume"] + informative[f"%-{coin}raw_price"] = informative["close"] - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df['&s-up_or_down'] = np.where(df["close"].shift(-100) > df["close"], 'up', 'down') + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df['&s-up_or_down'] = np.where(df["close"].shift(-100) > df["close"], 'up', 'down') return df diff --git a/tests/strategy/strats/freqai_test_multimodel_strat.py b/tests/strategy/strats/freqai_test_multimodel_strat.py index 4f8877f14..cd3327da9 100644 --- a/tests/strategy/strats/freqai_test_multimodel_strat.py +++ b/tests/strategy/strats/freqai_test_multimodel_strat.py @@ -62,67 +62,66 @@ class freqai_test_multimodel_strat(IStrategy): coin = pair.split('/')[0] - with self.freqai.lock: - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + informative[f"%-{coin}pct-change"] = informative["close"].pct_change() + informative[f"%-{coin}raw_volume"] = informative["volume"] + informative[f"%-{coin}raw_price"] = informative["close"] - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) - df["&-s_range"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .max() - - - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .min() - ) + df["&-s_range"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .max() + - + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .min() + ) return df diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index e239a30b0..792a3952f 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -62,55 +62,54 @@ class freqai_test_strat(IStrategy): coin = pair.split('/')[0] - with self.freqai.lock: - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + informative[f"%-{coin}pct-change"] = informative["close"].pct_change() + informative[f"%-{coin}raw_volume"] = informative["volume"] + informative[f"%-{coin}raw_price"] = informative["close"] - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) return df From a29402dddee2e1d90fd212c7bbae9d2ee142dc82 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 17:23:14 +0200 Subject: [PATCH 291/308] Rename and move analysis_lock to data_kitchen --- freqtrade/freqai/data_kitchen.py | 7 +++++-- freqtrade/freqai/freqai_interface.py | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 2378dcdd8..730ef2767 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -3,6 +3,7 @@ import datetime import logging import shutil from pathlib import Path +from threading import Lock from typing import Any, Dict, List, Tuple import numpy as np @@ -70,6 +71,8 @@ class FreqaiDataKitchen: self.model_filename: str = "" self.live = live self.pair = pair + self.analysis_lock = Lock() + self.svm_model: linear_model.SGDOneClassSVM = None self.keras: bool = self.freqai_config.get("keras", False) self.set_all_pairs() @@ -961,7 +964,7 @@ class FreqaiDataKitchen: for tf in tfs: if tf == tfs[-1]: sgi = True # doing this last allows user to use all tf raw prices in labels - with strategy.freqai.lock: + with self.analysis_lock: dataframe = strategy.populate_any_indicators( pair, dataframe.copy(), @@ -969,7 +972,7 @@ class FreqaiDataKitchen: informative=base_dataframes[tf], set_generalized_indicators=sgi ) - with strategy.freqai.lock: + with self.analysis_lock: if pairs: for i in pairs: if pair in i: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 374fcea2f..4c9cf1c05 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -70,7 +70,6 @@ class IFreqaiModel(ABC): self.set_full_path() self.follow_mode: bool = self.freqai_info.get("follow_mode", False) self.dd = FreqaiDataDrawer(Path(self.full_path), self.config, self.follow_mode) - self.lock = threading.Lock() self.identifier: str = self.freqai_info.get("identifier", "no_id_provided") self.scanning = False self.keras: bool = self.freqai_info.get("keras", False) From d442383a154b37a7b63682540a26d50aefaf92ef Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 18:17:17 +0200 Subject: [PATCH 292/308] Fix ta-lib install script --- build_helpers/install_ta-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index 581c1cd41..079d578b4 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -4,7 +4,7 @@ else INSTALL_LOC=${1} fi echo "Installing to ${INSTALL_LOC}" -if [ -n "$2" ] && [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then +if [ -n "$2" ] || [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then tar zxvf ta-lib-0.4.0-src.tar.gz cd ta-lib \ && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \ From 464d99808fbcb6e4d22a782ab662daecdfaa5460 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Aug 2022 18:22:01 +0200 Subject: [PATCH 293/308] Update doc table formatting --- docs/freqai.md | 2 +- freqtrade/freqai/freqai_interface.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/freqai.md b/docs/freqai.md index 6631c271e..cde3ea0f7 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -133,7 +133,7 @@ Here are the values the user can expect to include/use inside the typical strate | `df['&*_std/mean']` | The standard deviation and mean values of the user defined labels during training (or live tracking with `fit_live_predictions_candles`). Commonly used to understand rarity of prediction (use the z-score as shown in `templates/FreqaiExampleStrategy.py` to evaluate how often a particular prediction was observed during training (or historically with `fit_live_predictions_candles`)
**Datatype:** float. | `df['do_predict']` | An indication of an outlier, this return value is integer between -1 and 2 which lets the user understand if the prediction is trustworthy or not. `do_predict==1` means the prediction is trustworthy. If the [Dissimilarity Index](#removing-outliers-with-the-dissimilarity-index) is above the user defined threshold, it will subtract 1 from `do_predict`. If `use_SVM_to_remove_outliers()` is active, then the Support Vector Machine (SVM) may also detect outliers in training and prediction data. In this case, the SVM will also subtract one from `do_predict`. A particular case is when `do_predict == 2`, it means that the model has expired due to `expired_hours`.
**Datatype:** integer between -1 and 2. | `df['DI_values']` | The raw Dissimilarity Index values to give the user a sense of confidence in the prediction. Lower DI means the data point is closer to the trained parameter space.
**Datatype:** float. -| `df['%*']` | Any dataframe column prepended with `%` in `populate_any_indicators()` is treated as a training feature inside FreqAI. For example, the user can include the rsi in the training feature set (similar to `templates/FreqaiExampleStrategy.py`) by setting `df['%-rsi']`. See more details on how this is done [here](#building-the-feature-set). Note: since the number of features prepended with `%` can multiply very quickly (10s of thousands of features is easily engineered using the multiplictative functionality described in the `feature_parameters` table.) these features are removed from the dataframe upon return from FreqAI. If the user wishes to keep a particular type of feature for plotting purposes, you can prepend it with `%%`.
**Datatype:** depends on the output of the model. +| `df['%*']` | Any dataframe column prepended with `%` in `populate_any_indicators()` is treated as a training feature inside FreqAI. For example, the user can include the rsi in the training feature set (similar to `templates/FreqaiExampleStrategy.py`) by setting `df['%-rsi']`. See more details on how this is done [here](#building-the-feature-set).
**Note**: since the number of features prepended with `%` can multiply very quickly (10s of thousands of features is easily engineered using the multiplictative functionality described in the `feature_parameters` table.) these features are removed from the dataframe upon return from FreqAI. If the user wishes to keep a particular type of feature for plotting purposes, you can prepend it with `%%`.
**Datatype:** depends on the output of the model. ### Example config file diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 4c9cf1c05..e48de1fb8 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -500,7 +500,7 @@ class IFreqaiModel(ABC): dk.set_new_model_names(pair, new_trained_timerange) self.dd.pair_dict[pair]["first"] = False if self.dd.pair_dict[pair]["priority"] == 1 and self.scanning: - with self.lock: + with dk.analysis_lock: self.dd.pair_to_end_of_training_queue(pair) self.dd.save_data(model, pair, dk) From ad846cdb76914d8881dd33fc8b7a8c031836fb6b Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 14 Aug 2022 20:24:29 +0200 Subject: [PATCH 294/308] fix lock bug, update docstring --- freqtrade/freqai/data_drawer.py | 13 +++++++------ freqtrade/freqai/data_kitchen.py | 9 ++++----- freqtrade/freqai/freqai_interface.py | 29 +++++++++++++++------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 4ba55a0ec..7a0ddd7ff 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -38,8 +38,7 @@ class FreqaiDataDrawer: """ Class aimed at holding all pair models/info in memory for better inferencing/retrainig/saving /loading to/from disk. - This object remains persistent throughout live/dry, unlike FreqaiDataKitchen, which is - reinstantiated for each coin. + This object remains persistent throughout live/dry. Record of contribution: FreqAI was developed by a group of individuals who all contributed specific skillsets to the @@ -56,7 +55,7 @@ class FreqaiDataDrawer: Beta testing and bug reporting: @bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm - Juha Nykänen @suikula, Wagner Costa @wagnercosta + Juha Nykänen @suikula, Wagner Costa @wagnercosta, Johan Vlugt @Jooopieeert """ def __init__(self, full_path: Path, config: dict, follow_mode: bool = False): @@ -85,6 +84,7 @@ class FreqaiDataDrawer: self.load_historic_predictions_from_disk() self.training_queue: Dict[str, int] = {} self.history_lock = threading.Lock() + self.save_lock = threading.Lock() self.old_DBSCAN_eps: Dict[str, float] = {} self.empty_pair_dict: pair_info = { "model_filename": "", "trained_timestamp": 0, @@ -145,9 +145,10 @@ class FreqaiDataDrawer: """ Save data drawer full of all pair model metadata in present model folder. """ - with open(self.pair_dictionary_path, 'w') as fp: - rapidjson.dump(self.pair_dict, fp, default=self.np_encoder, - number_mode=rapidjson.NM_NATIVE) + with self.save_lock: + with open(self.pair_dictionary_path, 'w') as fp: + rapidjson.dump(self.pair_dict, fp, default=self.np_encoder, + number_mode=rapidjson.NM_NATIVE) def save_follower_dict_to_disk(self): """ diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 730ef2767..cf0af6c08 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -3,7 +3,6 @@ import datetime import logging import shutil from pathlib import Path -from threading import Lock from typing import Any, Dict, List, Tuple import numpy as np @@ -35,6 +34,9 @@ class FreqaiDataKitchen: Class designed to analyze data for a single pair. Employed by the IFreqaiModel class. Functionalities include holding, saving, loading, and analyzing the data. + This object is not persistent, it is reinstantiated for each coin, each time the coin + model needs to be inferenced or trained. + Record of contribution: FreqAI was developed by a group of individuals who all contributed specific skillsets to the project. @@ -50,7 +52,7 @@ class FreqaiDataKitchen: Beta testing and bug reporting: @bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm - Juha Nykänen @suikula, Wagner Costa @wagnercosta + Juha Nykänen @suikula, Wagner Costa @wagnercosta, Johan Vlugt @Jooopieeert """ def __init__( @@ -71,7 +73,6 @@ class FreqaiDataKitchen: self.model_filename: str = "" self.live = live self.pair = pair - self.analysis_lock = Lock() self.svm_model: linear_model.SGDOneClassSVM = None self.keras: bool = self.freqai_config.get("keras", False) @@ -964,7 +965,6 @@ class FreqaiDataKitchen: for tf in tfs: if tf == tfs[-1]: sgi = True # doing this last allows user to use all tf raw prices in labels - with self.analysis_lock: dataframe = strategy.populate_any_indicators( pair, dataframe.copy(), @@ -972,7 +972,6 @@ class FreqaiDataKitchen: informative=base_dataframes[tf], set_generalized_indicators=sgi ) - with self.analysis_lock: if pairs: for i in pairs: if pair in i: diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index e48de1fb8..902604989 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -12,7 +12,7 @@ import numpy as np import pandas as pd from numpy.typing import NDArray from pandas import DataFrame - +from threading import Lock from freqtrade.configuration import TimeRange from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException @@ -52,7 +52,7 @@ class IFreqaiModel(ABC): Beta testing and bug reporting: @bloodhunter4rc, Salah Lamkadem @ikonx, @ken11o2, @longyu, @paranoidandy, @smidelis, @smarm - Juha Nykänen @suikula, Wagner Costa @wagnercosta + Juha Nykänen @suikula, Wagner Costa @wagnercosta, Johan Vlugt @Jooopieeert """ def __init__(self, config: Dict[str, Any]) -> None: @@ -81,6 +81,7 @@ class IFreqaiModel(ABC): self.total_pairs = len(self.config.get("exchange", {}).get("pair_whitelist")) self.last_trade_database_summary: DataFrame = {} self.current_trade_database_summary: DataFrame = {} + self.analysis_lock = Lock() def assert_config(self, config: Dict[str, Any]) -> None: @@ -114,10 +115,10 @@ class IFreqaiModel(ABC): elif not self.follow_mode: self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"]) logger.info(f"Training {len(self.dk.training_timeranges)} timeranges") - - dataframe = self.dk.use_strategy_to_populate_indicators( - strategy, prediction_dataframe=dataframe, pair=metadata["pair"] - ) + with self.analysis_lock: + dataframe = self.dk.use_strategy_to_populate_indicators( + strategy, prediction_dataframe=dataframe, pair=metadata["pair"] + ) dk = self.start_backtesting(dataframe, metadata, self.dk) dataframe = dk.remove_features_from_df(dk.return_dataframe) @@ -289,9 +290,10 @@ class IFreqaiModel(ABC): # load the model and associated data into the data kitchen self.model = self.dd.load_data(metadata["pair"], dk) - dataframe = self.dk.use_strategy_to_populate_indicators( - strategy, prediction_dataframe=dataframe, pair=metadata["pair"] - ) + with self.analysis_lock: + dataframe = self.dk.use_strategy_to_populate_indicators( + strategy, prediction_dataframe=dataframe, pair=metadata["pair"] + ) if not self.model: logger.warning( @@ -485,9 +487,10 @@ class IFreqaiModel(ABC): data_load_timerange, pair, dk ) - unfiltered_dataframe = dk.use_strategy_to_populate_indicators( - strategy, corr_dataframes, base_dataframes, pair - ) + with self.analysis_lock: + unfiltered_dataframe = dk.use_strategy_to_populate_indicators( + strategy, corr_dataframes, base_dataframes, pair + ) unfiltered_dataframe = dk.slice_dataframe(new_trained_timerange, unfiltered_dataframe) @@ -500,7 +503,7 @@ class IFreqaiModel(ABC): dk.set_new_model_names(pair, new_trained_timerange) self.dd.pair_dict[pair]["first"] = False if self.dd.pair_dict[pair]["priority"] == 1 and self.scanning: - with dk.analysis_lock: + with self.analysis_lock: self.dd.pair_to_end_of_training_queue(pair) self.dd.save_data(model, pair, dk) From 8961b8d56042545b566d2ef5fea1cb34e2ebdb35 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 14 Aug 2022 16:41:50 +0200 Subject: [PATCH 295/308] merge in inference timer and historic predictions handling improvements. --- freqtrade/freqai/data_drawer.py | 25 ++++++++++--------- freqtrade/freqai/freqai_interface.py | 36 ++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 7a0ddd7ff..c8dbdf5e5 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -85,6 +85,7 @@ class FreqaiDataDrawer: self.training_queue: Dict[str, int] = {} self.history_lock = threading.Lock() self.save_lock = threading.Lock() + self.pair_dict_lock = threading.Lock() self.old_DBSCAN_eps: Dict[str, float] = {} self.empty_pair_dict: pair_info = { "model_filename": "", "trained_timestamp": 0, @@ -228,10 +229,11 @@ class FreqaiDataDrawer: def pair_to_end_of_training_queue(self, pair: str) -> None: # march all pairs up in the queue - for p in self.pair_dict: - self.pair_dict[p]["priority"] -= 1 - # send pair to end of queue - self.pair_dict[pair]["priority"] = len(self.pair_dict) + with self.pair_dict_lock: + for p in self.pair_dict: + self.pair_dict[p]["priority"] -= 1 + # send pair to end of queue + self.pair_dict[pair]["priority"] = len(self.pair_dict) def set_initial_return_values(self, pair: str, pred_df: DataFrame) -> None: """ @@ -261,13 +263,14 @@ class FreqaiDataDrawer: the strategy originally. Doing this allows FreqUI to always display the correct historic predictions. """ - df = self.historic_predictions[pair] - # here are some pandas hula hoops to accommodate the possibility of a series - # or dataframe depending number of labels requested by user - nan_df = pd.DataFrame(np.nan, index=df.index[-2:] + 2, columns=df.columns) - df = pd.concat([df, nan_df], ignore_index=True, axis=0) - df = self.historic_predictions[pair] = df[:-1] + index = self.historic_predictions[pair].index[-1:] + columns = self.historic_predictions[pair].columns + + nan_df = pd.DataFrame(np.nan, index=index, columns=columns) + self.historic_predictions[pair] = pd.concat( + [self.historic_predictions[pair], nan_df], ignore_index=True, axis=0) + df = self.historic_predictions[pair] # model outputs and associated statistics for label in predictions.columns: @@ -523,7 +526,7 @@ class FreqaiDataDrawer: history_data[pair][tf] = pd.concat( [ history_data[pair][tf], - strategy.dp.get_pair_dataframe(pair, tf).iloc[index:], + df_dp.iloc[index:], ], ignore_index=True, axis=0, diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 902604989..5471422c5 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -7,11 +7,11 @@ import time from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, Tuple - import numpy as np import pandas as pd from numpy.typing import NDArray from pandas import DataFrame +from freqtrade.exchange import timeframe_to_seconds from threading import Lock from freqtrade.configuration import TimeRange from freqtrade.enums import RunMode @@ -82,6 +82,9 @@ class IFreqaiModel(ABC): self.last_trade_database_summary: DataFrame = {} self.current_trade_database_summary: DataFrame = {} self.analysis_lock = Lock() + self.inference_time: float = 0 + self.begin_time: float = 0 + self.base_tf_seconds = timeframe_to_seconds(self.config['timeframe']) def assert_config(self, config: Dict[str, Any]) -> None: @@ -104,6 +107,7 @@ class IFreqaiModel(ABC): self.dd.set_pair_dict_info(metadata) if self.live: + self.inference_timer('start') self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"]) dk = self.start_live(dataframe, metadata, strategy, self.dk) @@ -123,6 +127,8 @@ class IFreqaiModel(ABC): dataframe = dk.remove_features_from_df(dk.return_dataframe) del dk + if self.live: + self.inference_timer('stop') return dataframe @threaded @@ -155,6 +161,8 @@ class IFreqaiModel(ABC): new_trained_timerange, pair, strategy, dk, data_load_timerange ) + self.dd.save_historic_predictions_to_disk() + def start_backtesting( self, dataframe: DataFrame, metadata: dict, dk: FreqaiDataKitchen ) -> FreqaiDataKitchen: @@ -340,7 +348,6 @@ class IFreqaiModel(ABC): # historical accuracy reasons. pred_df, do_preds = self.predict(dataframe.iloc[-self.CONV_WIDTH:], dk, first=False) - self.dd.save_historic_predictions_to_disk() if self.freqai_info.get('fit_live_predictions_candles', 0) and self.live: self.fit_live_predictions(dk, pair) self.dd.append_model_predictions(pair, pred_df, do_preds, dk, len(dataframe)) @@ -503,8 +510,7 @@ class IFreqaiModel(ABC): dk.set_new_model_names(pair, new_trained_timerange) self.dd.pair_dict[pair]["first"] = False if self.dd.pair_dict[pair]["priority"] == 1 and self.scanning: - with self.analysis_lock: - self.dd.pair_to_end_of_training_queue(pair) + self.dd.pair_to_end_of_training_queue(pair) self.dd.save_data(model, pair, dk) if self.freqai_info.get("purge_old_models", False): @@ -582,6 +588,28 @@ class IFreqaiModel(ABC): return + def inference_timer(self, do='start'): + """ + Timer designed to track the cumulative time spent in FreqAI for one pass through + the whitelist. This will check if the time spent is more than 1/4 the time + of a single candle, and if so, it will warn the user of degraded performance + """ + if do == 'start': + self.pair_it += 1 + self.begin_time = time.time() + elif do == 'stop': + end = time.time() + self.inference_time += (end - self.begin_time) + if self.pair_it == self.total_pairs: + logger.info( + f'Total time spent inferencing pairlist {self.inference_time:.2f} seconds') + if self.inference_time > 0.25 * self.base_tf_seconds: + logger.warning('Inference took over 25/% of the candle time. Reduce pairlist to' + ' avoid blinding open trades and degrading performance.') + self.pair_it = 0 + self.inference_time = 0 + return + # Following methods which are overridden by user made prediction models. # See freqai/prediction_models/CatboostPredictionModel.py for an example. From 006b11e5d5d7c8ca388dd9dd7ad765cd22da1ea6 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 14 Aug 2022 21:42:55 +0200 Subject: [PATCH 296/308] fix leftover bug in indicator population --- freqtrade/freqai/data_kitchen.py | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index cf0af6c08..35f51baed 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -965,23 +965,23 @@ class FreqaiDataKitchen: for tf in tfs: if tf == tfs[-1]: sgi = True # doing this last allows user to use all tf raw prices in labels - dataframe = strategy.populate_any_indicators( - pair, - dataframe.copy(), - tf, - informative=base_dataframes[tf], - set_generalized_indicators=sgi - ) - if pairs: - for i in pairs: - if pair in i: - continue # dont repeat anything from whitelist - dataframe = strategy.populate_any_indicators( - i, - dataframe.copy(), - tf, - informative=corr_dataframes[i][tf] - ) + dataframe = strategy.populate_any_indicators( + pair, + dataframe.copy(), + tf, + informative=base_dataframes[tf], + set_generalized_indicators=sgi + ) + if pairs: + for i in pairs: + if pair in i: + continue # dont repeat anything from whitelist + dataframe = strategy.populate_any_indicators( + i, + dataframe.copy(), + tf, + informative=corr_dataframes[i][tf] + ) self.get_unique_classes_from_labels(dataframe) From 3f6d427084b8d2a7b6def504b3083b3d816623f5 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 14 Aug 2022 21:46:37 +0200 Subject: [PATCH 297/308] add a check for number of training features in tests --- tests/freqai/test_freqai_interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index a36f80280..3de8561ed 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -71,6 +71,7 @@ def test_train_model_in_series_LightGBMMultiModel(mocker, freqai_conf): assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file() assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").is_file() assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").is_file() + assert(len(freqai.dk.data['training_features_list']) == 26) shutil.rmtree(Path(freqai.dk.full_path)) From 4b708caa6a17aff2da89c126728fd78308f3428d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:19 +0000 Subject: [PATCH 298/308] Bump sqlalchemy from 1.4.39 to 1.4.40 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.39 to 1.4.40. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy 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 4fa6e60a0..d2527858a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ ccxt==1.91.93 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.4 aiohttp==3.8.1 -SQLAlchemy==1.4.39 +SQLAlchemy==1.4.40 python-telegram-bot==13.13 arrow==1.2.2 cachetools==4.2.2 From 96c279f86c9293eb4ad31454b230a93c118385ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:22 +0000 Subject: [PATCH 299/308] Bump nbconvert from 6.5.0 to 6.5.3 Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 6.5.0 to 6.5.3. - [Release notes](https://github.com/jupyter/nbconvert/releases) - [Commits](https://github.com/jupyter/nbconvert/compare/6.5...6.5.3) --- updated-dependencies: - dependency-name: nbconvert 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 977b7b9ec..af6cd0ed6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -19,7 +19,7 @@ isort==5.10.1 time-machine==2.7.1 # Convert jupyter notebooks to markdown documents -nbconvert==6.5.0 +nbconvert==6.5.3 # mypy types types-cachetools==5.2.1 From 025ff27dd2f4abbddf06848dfac0c6e167230276 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:29 +0000 Subject: [PATCH 300/308] Bump numpy from 1.23.1 to 1.23.2 Bumps [numpy](https://github.com/numpy/numpy) from 1.23.1 to 1.23.2. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v1.23.1...v1.23.2) --- updated-dependencies: - dependency-name: numpy 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 4fa6e60a0..545fa092e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==1.23.1 +numpy==1.23.2 pandas==1.4.3 pandas-ta==0.3.14b From baa0af68b214c83c1adc769c062430e3e87c3009 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:33 +0000 Subject: [PATCH 301/308] Bump plotly from 5.9.0 to 5.10.0 Bumps [plotly](https://github.com/plotly/plotly.py) from 5.9.0 to 5.10.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.9.0...v5.10.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 0f6ae94c2..80cd3f4f2 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.9.0 +plotly==5.10.0 From 2581acd75e90cd2b5dbf95a7f61759b6915da013 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:36 +0000 Subject: [PATCH 302/308] Bump filelock from 3.7.1 to 3.8.0 Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.7.1 to 3.8.0. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.7.1...3.8.0) --- updated-dependencies: - dependency-name: filelock dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 11b9511f2..020ccdda8 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -5,5 +5,5 @@ scipy==1.9.0 scikit-learn==1.1.2 scikit-optimize==0.9.0 -filelock==3.7.1 +filelock==3.8.0 progressbar2==4.0.0 From bc79027cf41911632a813e195d81d49ad058fe4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:51 +0000 Subject: [PATCH 303/308] Bump mkdocs-material from 8.3.9 to 8.4.0 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.3.9 to 8.4.0. - [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/8.3.9...8.4.0) --- updated-dependencies: - dependency-name: mkdocs-material 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 205516d6d..a53e909e0 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ markdown==3.3.7 mkdocs==1.3.1 -mkdocs-material==8.3.9 +mkdocs-material==8.4.0 mdx_truly_sane_lists==1.3 pymdown-extensions==9.5 jinja2==3.1.2 From 6fb5fbdd30b3e9bda8b46a6213de2f807a39f708 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 03:01:56 +0000 Subject: [PATCH 304/308] Bump orjson from 3.7.11 to 3.7.12 Bumps [orjson](https://github.com/ijl/orjson) from 3.7.11 to 3.7.12. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.7.11...3.7.12) --- updated-dependencies: - dependency-name: orjson 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 4fa6e60a0..5bf2b8f6b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.8 # Properly format api responses -orjson==3.7.11 +orjson==3.7.12 # Notify systemd sdnotify==0.3.2 From dba7d7fd65e42517931a059b169d73cbc7477a84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 04:29:20 +0000 Subject: [PATCH 305/308] Bump ccxt from 1.91.93 to 1.92.20 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.91.93 to 1.92.20. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.91.93...1.92.20) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ad012ae28..fec5885cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.2 pandas==1.4.3 pandas-ta==0.3.14b -ccxt==1.91.93 +ccxt==1.92.20 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.4 aiohttp==3.8.1 From 398b2946b58b9365bf8d9272dc53283249b5c4f5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 15 Aug 2022 06:49:28 +0200 Subject: [PATCH 306/308] Update test formatting --- tests/freqai/test_freqai_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 3de8561ed..792ffc467 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -71,7 +71,7 @@ def test_train_model_in_series_LightGBMMultiModel(mocker, freqai_conf): assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file() assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").is_file() assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").is_file() - assert(len(freqai.dk.data['training_features_list']) == 26) + assert len(freqai.dk.data['training_features_list']) == 26 shutil.rmtree(Path(freqai.dk.full_path)) From c7e171921588166094ca06cd17f582a1d9229a8f Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 15 Aug 2022 06:53:02 +0200 Subject: [PATCH 307/308] Fix interface import sorting --- freqtrade/freqai/freqai_interface.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 5471422c5..49e4ce5c3 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -6,16 +6,18 @@ import threading import time from abc import ABC, abstractmethod from pathlib import Path +from threading import Lock from typing import Any, Dict, Tuple + import numpy as np import pandas as pd from numpy.typing import NDArray from pandas import DataFrame -from freqtrade.exchange import timeframe_to_seconds -from threading import Lock + from freqtrade.configuration import TimeRange from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException +from freqtrade.exchange import timeframe_to_seconds from freqtrade.freqai.data_drawer import FreqaiDataDrawer from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from freqtrade.strategy.interface import IStrategy From a5b438e41e5a8a882f4ff9ff6acfe2c7b0db372b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 16 Aug 2022 08:43:03 +0200 Subject: [PATCH 308/308] Run price_to_precision for dry-run orders --- freqtrade/exchange/exchange.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 18598e92d..d50007dab 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1019,7 +1019,8 @@ class Exchange: time_in_force: str = 'gtc', ) -> Dict: if self._config['dry_run']: - dry_order = self.create_dry_run_order(pair, ordertype, side, amount, rate, leverage) + dry_order = self.create_dry_run_order( + pair, ordertype, side, amount, self.price_to_precision(pair, rate), leverage) return dry_order params = self._get_params(side, ordertype, leverage, reduceOnly, time_in_force)