From 86c781798a53d14ef973c3fb84827a42d1007a42 Mon Sep 17 00:00:00 2001 From: initrv Date: Thu, 6 Oct 2022 19:59:35 +0300 Subject: [PATCH 01/60] =?UTF-8?q?Add=20=D1=81atboost=20train=5Fdir=20for?= =?UTF-8?q?=20tensorboard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/freqai/prediction_models/CatboostClassifier.py | 3 ++- freqtrade/freqai/prediction_models/CatboostRegressor.py | 3 ++- .../freqai/prediction_models/CatboostRegressorMultiTarget.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/prediction_models/CatboostClassifier.py b/freqtrade/freqai/prediction_models/CatboostClassifier.py index 60536e6de..31a865a8d 100644 --- a/freqtrade/freqai/prediction_models/CatboostClassifier.py +++ b/freqtrade/freqai/prediction_models/CatboostClassifier.py @@ -32,8 +32,9 @@ class CatboostClassifier(BaseClassifierModel): ) cbr = CatBoostClassifier( - allow_writing_files=False, + allow_writing_files=True, loss_function='MultiClass', + train_dir=dk.data_path, **self.model_training_parameters, ) diff --git a/freqtrade/freqai/prediction_models/CatboostRegressor.py b/freqtrade/freqai/prediction_models/CatboostRegressor.py index 73cf6c88a..a04649d93 100644 --- a/freqtrade/freqai/prediction_models/CatboostRegressor.py +++ b/freqtrade/freqai/prediction_models/CatboostRegressor.py @@ -41,7 +41,8 @@ class CatboostRegressor(BaseRegressionModel): init_model = self.get_init_model(dk.pair) model = CatBoostRegressor( - allow_writing_files=False, + allow_writing_files=True, + train_dir=dk.data_path, **self.model_training_parameters, ) diff --git a/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py b/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py index 7fa4e293e..292ad600a 100644 --- a/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py +++ b/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py @@ -26,7 +26,8 @@ class CatboostRegressorMultiTarget(BaseRegressionModel): """ cbr = CatBoostRegressor( - allow_writing_files=False, + allow_writing_files=True, + train_dir=dk.data_path, **self.model_training_parameters, ) From a9d5e04a4320f321e9f19862e2c88be3c2b05f7b Mon Sep 17 00:00:00 2001 From: th0rntwig Date: Thu, 6 Oct 2022 19:26:33 +0200 Subject: [PATCH 02/60] Remove constant labels from prediction --- freqtrade/freqai/data_kitchen.py | 12 ++++++++++++ freqtrade/freqai/freqai_interface.py | 2 ++ tests/freqai/conftest.py | 2 ++ tests/freqai/test_freqai_interface.py | 10 ++++++++++ 4 files changed, 26 insertions(+) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 7ea2daf02..23bba3f1a 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -460,6 +460,18 @@ class FreqaiDataKitchen: return df + def check_pred_labels(self, df_predictions: DataFrame) -> None: + """ + Check that prediction feature labels match training feature labels. + :params: + :df_predictions: incoming predictions + """ + train_labels = self.data_dictionary["train_features"].columns + pred_labels = df_predictions.columns + if len(train_labels.difference(pred_labels)) != 0: + self.data_dictionary["prediction_features"] = df_predictions[train_labels] + return + def principal_component_analysis(self) -> None: """ Performs Principal Component Analysis on the data for dimensionality reduction diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 5ac7bc32c..62c814c72 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -492,6 +492,8 @@ class IFreqaiModel(ABC): # ensure user is feeding the correct indicators to the model self.check_if_feature_list_matches_strategy(dk) + dk.check_pred_labels(dk.data_dictionary['prediction_features']) + if ft_params.get('inlier_metric_window', 0): dk.compute_inlier_metric(set_='predict') diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index 026b45afc..df61b284a 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -107,6 +107,8 @@ def make_unfiltered_dataframe(mocker, freqai_conf): unfiltered_dataframe = freqai.dk.use_strategy_to_populate_indicators( strategy, corr_dataframes, base_dataframes, freqai.dk.pair ) + for i in range(5): + unfiltered_dataframe[f'constant_{i}'] = i unfiltered_dataframe = freqai.dk.slice_dataframe(new_timerange, unfiltered_dataframe) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index a61853c47..238c0418c 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -181,6 +181,8 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat): 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") + for i in range(5): + df[f'constant_{i}'] = i metadata = {"pair": "LTC/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) @@ -208,6 +210,8 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): 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") + for i in range(5): + df[f'constant_{i}'] = i metadata = {"pair": "LTC/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) @@ -233,6 +237,8 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): 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") + for i in range(5): + df[f'constant_{i}'] = i metadata = {"pair": "ADA/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) @@ -256,6 +262,8 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): 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") + for i in range(5): + df[f'constant_{i}'] = i freqai.start_backtesting(df, metadata, freqai.dk) assert log_has_re( @@ -312,6 +320,8 @@ def test_follow_mode(mocker, freqai_conf): freqai.dd.load_all_pair_histories(timerange, freqai.dk) df = strategy.dp.get_pair_dataframe('ADA/BTC', '5m') + for i in range(5): + df[f'constant_{i}'] = i freqai.start_live(df, metadata, strategy, freqai.dk) assert len(freqai.dk.return_dataframe.index) == 5702 From ec7af83c8733dfa7ff294c041689529f9c12a92b Mon Sep 17 00:00:00 2001 From: initrv Date: Fri, 7 Oct 2022 17:13:19 +0300 Subject: [PATCH 03/60] add tensorboard to freqai reqs --- requirements-freqai.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-freqai.txt b/requirements-freqai.txt index cf0d2eb07..c78b3b25e 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -7,3 +7,4 @@ joblib==1.2.0 catboost==1.1; platform_machine != 'aarch64' lightgbm==3.3.2 xgboost==1.6.2 +tensorboard==2.10.1 From 8fcb80df69f0e898529674be4cf570b189f77a23 Mon Sep 17 00:00:00 2001 From: froggleston Date: Fri, 7 Oct 2022 16:06:30 +0100 Subject: [PATCH 04/60] Add support for dp.send_msg() to webhooks --- docs/configuration.md | 2 ++ docs/webhook-config.md | 23 +++++++++++++++++++++++ freqtrade/rpc/rpc_manager.py | 11 +++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 556414e21..8fe6b7620 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -215,6 +215,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `telegram.balance_dust_level` | Dust-level (in stake currency) - currencies with a balance below this will not be shown by `/balance`.
**Datatype:** float | `telegram.reload` | Allow "reload" buttons on telegram messages.
*Defaults to `True`.
**Datatype:** boolean | `telegram.notification_settings.*` | Detailed notification settings. Refer to the [telegram documentation](telegram-usage.md) for details.
**Datatype:** dictionary +| `telegram.allow_custom_messages` | Enable the sending of Telegram messages from strategies via the dataprovider.send_msg() function.
**Datatype:** Boolean | | **Webhook** | `webhook.enabled` | Enable usage of Webhook notifications
**Datatype:** Boolean | `webhook.url` | URL for the webhook. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String @@ -225,6 +226,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `webhook.webhookexitcancel` | Payload to send on exit order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String | `webhook.webhookexitfill` | Payload to send on exit order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String | `webhook.webhookstatus` | Payload to send on status calls. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.allow_custom_messages` | Enable the sending of Webhook messages from strategies via the dataprovider.send_msg() function.
**Datatype:** Boolean | | **Rest API / FreqUI / Producer-Consumer** | `api_server.enabled` | Enable usage of API Server. See the [API Server documentation](rest-api.md) for more details.
**Datatype:** Boolean | `api_server.listen_ip_address` | Bind IP address. See the [API Server documentation](rest-api.md) for more details.
**Datatype:** IPv4 diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 3677ebe89..2793bd1eb 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -94,6 +94,19 @@ Optional parameters are available to enable automatic retries for webhook messag }, ``` +Custom messages can be sent to Webhook endpoints via the dataprovider.send_msg() function. To enable this, set the `allow_custom_messages` option to `true`: + +```json + "webhook": { + "enabled": true, + "url": "https://", + "allow_custom_messages": true, + "webhookstatus": { + "status": "Status: {status}" + } + }, +``` + Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called. ### Webhookentry @@ -288,3 +301,13 @@ Available fields correspond to the fields for webhooks and are documented in the The notifications will look as follows by default. ![discord-notification](assets/discord_notification.png) + +Custom messages can be sent from a strategy to Discord endpoints via the dataprovider.send_msg() function. To enable this, set the `allow_custom_messages` option to `true`: + +```json + "discord": { + "enabled": true, + "webhook_url": "https://discord.com/api/webhooks/", + "allow_custom_messages": true, + }, +``` diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index e3b31d225..bc13c1654 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -88,10 +88,13 @@ class RPCManager: """ while queue: msg = queue.popleft() - self.send_msg({ - 'type': RPCMessageType.STRATEGY_MSG, - 'msg': msg, - }) + + for mod in self.registered_modules: + if mod._config.get(mod.name, {}).get('allow_custom_messages', False): + mod.send_msg({ + 'type': RPCMessageType.STRATEGY_MSG, + 'msg': msg, + }) def startup_messages(self, config: Config, pairlist, protections) -> None: if config['dry_run']: From fb2f2d9a39fec6388f9c8a2de2cc588a87135c0c Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 7 Oct 2022 20:44:47 +0200 Subject: [PATCH 05/60] Allow webhook message setting directly --- freqtrade/constants.py | 5 ++++- freqtrade/rpc/rpc_manager.py | 2 +- freqtrade/rpc/webhook.py | 7 +++++-- tests/rpc/test_rpc_manager.py | 5 +++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index e0eb5e288..27968bb1b 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -5,7 +5,7 @@ bot constants """ from typing import Any, Dict, List, Literal, Tuple -from freqtrade.enums import CandleType +from freqtrade.enums import CandleType, RPCMessageType DEFAULT_CONFIG = 'config.json' @@ -282,6 +282,7 @@ CONF_SCHEMA = { 'enabled': {'type': 'boolean'}, 'token': {'type': 'string'}, 'chat_id': {'type': 'string'}, + 'allow_custom_messages': {'type': 'boolean', 'default': True}, 'balance_dust_level': {'type': 'number', 'minimum': 0.0}, 'notification_settings': { 'type': 'object', @@ -344,6 +345,8 @@ CONF_SCHEMA = { 'format': {'type': 'string', 'enum': WEBHOOK_FORMAT_OPTIONS, 'default': 'form'}, 'retries': {'type': 'integer', 'minimum': 0}, 'retry_delay': {'type': 'number', 'minimum': 0}, + **dict([(x, {'type': 'object'}) for x in RPCMessageType]), + # Below -> Deprecated 'webhookentry': {'type': 'object'}, 'webhookentrycancel': {'type': 'object'}, 'webhookentryfill': {'type': 'object'}, diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index bc13c1654..9c25723b0 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -88,7 +88,7 @@ class RPCManager: """ while queue: msg = queue.popleft() - + logger.info('Sending rpc strategy_msg: %s', msg) for mod in self.registered_modules: if mod._config.get(mod.name, {}).get('allow_custom_messages', False): mod.send_msg({ diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index bb3b3922f..b46addee5 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -45,6 +45,7 @@ class Webhook(RPCHandler): """ Send a message to telegram channel """ try: whconfig = self._config['webhook'] + # Deprecated 2022.10 - only keep generic method. if msg['type'] in [RPCMessageType.ENTRY]: valuedict = whconfig.get('webhookentry') elif msg['type'] in [RPCMessageType.ENTRY_CANCEL]: @@ -61,6 +62,9 @@ class Webhook(RPCHandler): RPCMessageType.STARTUP, RPCMessageType.WARNING): valuedict = whconfig.get('webhookstatus') + elif msg['type'].value in whconfig: + # Allow all types ... + valuedict = whconfig.get(msg['type'].value) elif msg['type'] in ( RPCMessageType.PROTECTION_TRIGGER, RPCMessageType.PROTECTION_TRIGGER_GLOBAL, @@ -69,8 +73,7 @@ class Webhook(RPCHandler): RPCMessageType.STRATEGY_MSG): # Don't fail for non-implemented types return - else: - raise NotImplementedError('Unknown message type: {}'.format(msg['type'])) + if not valuedict: logger.info("Message type '%s' not configured for webhooks", msg['type']) return diff --git a/tests/rpc/test_rpc_manager.py b/tests/rpc/test_rpc_manager.py index d71f38259..21c8b0813 100644 --- a/tests/rpc/test_rpc_manager.py +++ b/tests/rpc/test_rpc_manager.py @@ -99,6 +99,7 @@ def test_send_msg_telegram_error(mocker, default_conf, caplog) -> None: def test_process_msg_queue(mocker, default_conf, caplog) -> None: telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg') + default_conf['telegram']['allow_custom_messages'] = True mocker.patch('freqtrade.rpc.telegram.Telegram._init') freqtradebot = get_patched_freqtradebot(mocker, default_conf) @@ -108,8 +109,8 @@ def test_process_msg_queue(mocker, default_conf, caplog) -> None: queue.append('Test message 2') rpc_manager.process_msg_queue(queue) - assert log_has("Sending rpc message: {'type': strategy_msg, 'msg': 'Test message'}", caplog) - assert log_has("Sending rpc message: {'type': strategy_msg, 'msg': 'Test message 2'}", caplog) + assert log_has("Sending rpc strategy_msg: Test message", caplog) + assert log_has("Sending rpc strategy_msg: Test message 2", caplog) assert telegram_mock.call_count == 2 From ed12cddf3fc4c5e250fe504b821b50d8b8d190af Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 7 Oct 2022 20:45:15 +0200 Subject: [PATCH 06/60] Update docs with new wording for webhook settings --- docs/configuration.md | 14 +++++----- docs/deprecated.md | 14 +++++----- docs/strategy_migration.md | 12 ++++----- docs/telegram-usage.md | 2 ++ docs/webhook-config.md | 53 +++++++++++++++++++------------------- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 8fe6b7620..e773e1878 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -219,13 +219,13 @@ Mandatory parameters are marked as **Required**, which means that they are requi | | **Webhook** | `webhook.enabled` | Enable usage of Webhook notifications
**Datatype:** Boolean | `webhook.url` | URL for the webhook. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookentry` | Payload to send on entry. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookentrycancel` | Payload to send on entry order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookentryfill` | Payload to send on entry order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookexit` | Payload to send on exit. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookexitcancel` | Payload to send on exit order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookexitfill` | Payload to send on exit order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookstatus` | Payload to send on status calls. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.entry` | Payload to send on entry. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.entry_cancel` | Payload to send on entry order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.entry_fill` | Payload to send on entry order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.exit` | Payload to send on exit. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.exit_cancel` | Payload to send on exit order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.exit_fill` | Payload to send on exit order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.status` | Payload to send on status calls. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String | `webhook.allow_custom_messages` | Enable the sending of Webhook messages from strategies via the dataprovider.send_msg() function.
**Datatype:** Boolean | | **Rest API / FreqUI / Producer-Consumer** | `api_server.enabled` | Enable usage of API Server. See the [API Server documentation](rest-api.md) for more details.
**Datatype:** Boolean diff --git a/docs/deprecated.md b/docs/deprecated.md index beceb12ab..3b5b28b81 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -66,11 +66,11 @@ We will keep a compatibility layer for 1-2 versions (so both `buy_tag` and `ente #### Naming changes -Webhook terminology changed from "sell" to "exit", and from "buy" to "entry". +Webhook terminology changed from "sell" to "exit", and from "buy" to "entry", removing "webhook" in the process. -* `webhookbuy` -> `webhookentry` -* `webhookbuyfill` -> `webhookentryfill` -* `webhookbuycancel` -> `webhookentrycancel` -* `webhooksell` -> `webhookexit` -* `webhooksellfill` -> `webhookexitfill` -* `webhooksellcancel` -> `webhookexitcancel` +* `webhookbuy`, `webhookentry` -> `entry` +* `webhookbuyfill`, `webhookentryfill` -> `entry_fill` +* `webhookbuycancel`, `webhookentrycancel` -> `entry_cancel` +* `webhooksell`, `webhookexit` -> `exit` +* `webhooksellfill`, `webhookexitfill` -> `exit_fill` +* `webhooksellcancel`, `webhookexitcancel` -> `exit_cancel` diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index ac65abff4..b971b81ea 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -50,12 +50,12 @@ Note : `forcesell`, `forcebuy`, `emergencysell` are changed to `force_exit`, `fo * `force_sell` -> `force_exit` * `emergency_sell` -> `emergency_exit` * Webhook terminology changed from "sell" to "exit", and from "buy" to entry - * `webhookbuy` -> `webhookentry` - * `webhookbuyfill` -> `webhookentryfill` - * `webhookbuycancel` -> `webhookentrycancel` - * `webhooksell` -> `webhookexit` - * `webhooksellfill` -> `webhookexitfill` - * `webhooksellcancel` -> `webhookexitcancel` + * `webhookbuy` -> `entry` + * `webhookbuyfill` -> `entry_fill` + * `webhookbuycancel` -> `entry_cancel` + * `webhooksell` -> `exit` + * `webhooksellfill` -> `exit_fill` + * `webhooksellcancel` -> `exit_cancel` * Telegram notification settings * `buy` -> `entry` * `buy_fill` -> `entry_fill` diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 055512f26..db4a309d0 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -77,6 +77,7 @@ Example configuration showing the different settings: "enabled": true, "token": "your_telegram_token", "chat_id": "your_telegram_chat_id", + "allow_custom_messages": true, "notification_settings": { "status": "silent", "warning": "on", @@ -115,6 +116,7 @@ Example configuration showing the different settings: `show_candle` - show candle values as part of entry/exit messages. Only possible values are `"ohlc"` or `"off"`. `balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown. +`allow_custom_messages` completely disable strategy messages. `reload` allows you to disable reload-buttons on selected messages. ## Create a custom keyboard (command shortcut buttons) diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 2793bd1eb..00c369919 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -10,37 +10,37 @@ Sample configuration (tested using IFTTT). "webhook": { "enabled": true, "url": "https://maker.ifttt.com/trigger//with/key//", - "webhookentry": { + "entry": { "value1": "Buying {pair}", "value2": "limit {limit:8f}", "value3": "{stake_amount:8f} {stake_currency}" }, - "webhookentrycancel": { + "entry_cancel": { "value1": "Cancelling Open Buy Order for {pair}", "value2": "limit {limit:8f}", "value3": "{stake_amount:8f} {stake_currency}" }, - "webhookentryfill": { + "entry_fill": { "value1": "Buy Order for {pair} filled", "value2": "at {open_rate:8f}", "value3": "" }, - "webhookexit": { + "exit": { "value1": "Exiting {pair}", "value2": "limit {limit:8f}", "value3": "profit: {profit_amount:8f} {stake_currency} ({profit_ratio})" }, - "webhookexitcancel": { + "exit_cancel": { "value1": "Cancelling Open Exit Order for {pair}", "value2": "limit {limit:8f}", "value3": "profit: {profit_amount:8f} {stake_currency} ({profit_ratio})" }, - "webhookexitfill": { + "exit_fill": { "value1": "Exit Order for {pair} filled", "value2": "at {close_rate:8f}.", "value3": "" }, - "webhookstatus": { + "status": { "value1": "Status: {status}", "value2": "", "value3": "" @@ -57,7 +57,7 @@ You can set the POST body format to Form-Encoded (default), JSON-Encoded, or raw "enabled": true, "url": "https://.cloud.mattermost.com/hooks/", "format": "json", - "webhookstatus": { + "status": { "text": "Status: {status}" } }, @@ -88,30 +88,30 @@ Optional parameters are available to enable automatic retries for webhook messag "url": "https://", "retries": 3, "retry_delay": 0.2, - "webhookstatus": { + "status": { "status": "Status: {status}" } }, ``` -Custom messages can be sent to Webhook endpoints via the dataprovider.send_msg() function. To enable this, set the `allow_custom_messages` option to `true`: +Custom messages can be sent to Webhook endpoints via the `self.dp.send_msg()` function from within the strategy. To enable this, set the `allow_custom_messages` option to `true`: ```json "webhook": { "enabled": true, "url": "https://", "allow_custom_messages": true, - "webhookstatus": { - "status": "Status: {status}" + "strategy_msg": { + "status": "StrategyMessage: {msg}" } }, ``` Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called. -### Webhookentry +### Entry -The fields in `webhook.webhookentry` are filled when the bot executes a long/short. Parameters are filled using string.format. +The fields in `webhook.entry` are filled when the bot executes a long/short. Parameters are filled using string.format. Possible parameters are: * `trade_id` @@ -131,9 +131,9 @@ Possible parameters are: * `current_rate` * `enter_tag` -### Webhookentrycancel +### Entry cancel -The fields in `webhook.webhookentrycancel` are filled when the bot cancels a long/short order. Parameters are filled using string.format. +The fields in `webhook.entry_cancel` are filled when the bot cancels a long/short order. Parameters are filled using string.format. Possible parameters are: * `trade_id` @@ -152,9 +152,9 @@ Possible parameters are: * `current_rate` * `enter_tag` -### Webhookentryfill +### Entry fill -The fields in `webhook.webhookentryfill` are filled when the bot filled a long/short order. Parameters are filled using string.format. +The fields in `webhook.entry_fill` are filled when the bot filled a long/short order. Parameters are filled using string.format. Possible parameters are: * `trade_id` @@ -173,9 +173,9 @@ Possible parameters are: * `current_rate` * `enter_tag` -### Webhookexit +### Exit -The fields in `webhook.webhookexit` are filled when the bot exits a trade. Parameters are filled using string.format. +The fields in `webhook.exit` are filled when the bot exits a trade. Parameters are filled using string.format. Possible parameters are: * `trade_id` @@ -197,9 +197,9 @@ Possible parameters are: * `open_date` * `close_date` -### Webhookexitfill +### Exit fill -The fields in `webhook.webhookexitfill` are filled when the bot fills a exit order (closes a Trade). Parameters are filled using string.format. +The fields in `webhook.exit_fill` are filled when the bot fills a exit order (closes a Trade). Parameters are filled using string.format. Possible parameters are: * `trade_id` @@ -222,9 +222,9 @@ Possible parameters are: * `open_date` * `close_date` -### Webhookexitcancel +### Exit cancel -The fields in `webhook.webhookexitcancel` are filled when the bot cancels a exit order. Parameters are filled using string.format. +The fields in `webhook.exit_cancel` are filled when the bot cancels a exit order. Parameters are filled using string.format. Possible parameters are: * `trade_id` @@ -247,9 +247,9 @@ Possible parameters are: * `open_date` * `close_date` -### Webhookstatus +### Status -The fields in `webhook.webhookstatus` are used for regular status messages (Started / Stopped / ...). Parameters are filled using string.format. +The fields in `webhook.status` are used for regular status messages (Started / Stopped / ...). Parameters are filled using string.format. The only possible value here is `{status}`. @@ -293,7 +293,6 @@ You can configure this as follows: } ``` - The above represents the default (`exit_fill` and `entry_fill` are optional and will default to the above configuration) - modifications are obviously possible. Available fields correspond to the fields for webhooks and are documented in the corresponding webhook sections. From 1aedf08ba52e70963301a27584d587ab44b7439a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 7 Oct 2022 20:45:50 +0200 Subject: [PATCH 07/60] Update tests --- tests/rpc/test_rpc_webhook.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index 3bbb85d54..d06d2dade 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -3,7 +3,6 @@ from datetime import datetime, timedelta from unittest.mock import MagicMock -import pytest from requests import RequestException from freqtrade.enums import ExitType, RPCMessageType @@ -356,15 +355,6 @@ def test_exception_send_msg(default_conf, mocker, caplog): assert log_has("Problem calling Webhook. Please check your webhook configuration. " "Exception: 'DEADBEEF'", caplog) - msg_mock = MagicMock() - mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock) - msg = { - 'type': 'DEADBEEF', - 'status': 'whatever' - } - with pytest.raises(NotImplementedError): - webhook.send_msg(msg) - # Test no failure for not implemented but known messagetypes for e in RPCMessageType: msg = { From df5ae6625295e1c86b2b16b4b938124629636aa1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 7 Oct 2022 20:52:14 +0200 Subject: [PATCH 08/60] Refactor webhook method --- freqtrade/rpc/webhook.py | 65 +++++++++++++++++++---------------- tests/rpc/test_rpc_webhook.py | 13 ++----- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index b46addee5..19c4166b3 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -3,7 +3,7 @@ This module manages webhook communication """ import logging import time -from typing import Any, Dict +from typing import Any, Dict, Optional from requests import RequestException, post @@ -41,38 +41,43 @@ class Webhook(RPCHandler): """ pass + def _get_value_dict(self, msg: Dict[str, Any]) -> Optional[Dict[str, Any]]: + whconfig = self._config['webhook'] + # Deprecated 2022.10 - only keep generic method. + if msg['type'] in [RPCMessageType.ENTRY]: + valuedict = whconfig.get('webhookentry') + elif msg['type'] in [RPCMessageType.ENTRY_CANCEL]: + valuedict = whconfig.get('webhookentrycancel') + elif msg['type'] in [RPCMessageType.ENTRY_FILL]: + valuedict = whconfig.get('webhookentryfill') + elif msg['type'] == RPCMessageType.EXIT: + valuedict = whconfig.get('webhookexit') + elif msg['type'] == RPCMessageType.EXIT_FILL: + valuedict = whconfig.get('webhookexitfill') + elif msg['type'] == RPCMessageType.EXIT_CANCEL: + valuedict = whconfig.get('webhookexitcancel') + elif msg['type'] in (RPCMessageType.STATUS, + RPCMessageType.STARTUP, + RPCMessageType.WARNING): + valuedict = whconfig.get('webhookstatus') + elif msg['type'].value in whconfig: + # Allow all types ... + valuedict = whconfig.get(msg['type'].value) + elif msg['type'] in ( + RPCMessageType.PROTECTION_TRIGGER, + RPCMessageType.PROTECTION_TRIGGER_GLOBAL, + RPCMessageType.WHITELIST, + RPCMessageType.ANALYZED_DF, + RPCMessageType.STRATEGY_MSG): + # Don't fail for non-implemented types + return None + return valuedict + def send_msg(self, msg: Dict[str, Any]) -> None: """ Send a message to telegram channel """ try: - whconfig = self._config['webhook'] - # Deprecated 2022.10 - only keep generic method. - if msg['type'] in [RPCMessageType.ENTRY]: - valuedict = whconfig.get('webhookentry') - elif msg['type'] in [RPCMessageType.ENTRY_CANCEL]: - valuedict = whconfig.get('webhookentrycancel') - elif msg['type'] in [RPCMessageType.ENTRY_FILL]: - valuedict = whconfig.get('webhookentryfill') - elif msg['type'] == RPCMessageType.EXIT: - valuedict = whconfig.get('webhookexit') - elif msg['type'] == RPCMessageType.EXIT_FILL: - valuedict = whconfig.get('webhookexitfill') - elif msg['type'] == RPCMessageType.EXIT_CANCEL: - valuedict = whconfig.get('webhookexitcancel') - elif msg['type'] in (RPCMessageType.STATUS, - RPCMessageType.STARTUP, - RPCMessageType.WARNING): - valuedict = whconfig.get('webhookstatus') - elif msg['type'].value in whconfig: - # Allow all types ... - valuedict = whconfig.get(msg['type'].value) - elif msg['type'] in ( - RPCMessageType.PROTECTION_TRIGGER, - RPCMessageType.PROTECTION_TRIGGER_GLOBAL, - RPCMessageType.WHITELIST, - RPCMessageType.ANALYZED_DF, - RPCMessageType.STRATEGY_MSG): - # Don't fail for non-implemented types - return + + valuedict = self._get_value_dict(msg) if not valuedict: logger.info("Message type '%s' not configured for webhooks", msg['type']) diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index d06d2dade..a8fd0c34b 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -336,20 +336,13 @@ def test_exception_send_msg(default_conf, mocker, caplog): caplog) default_conf["webhook"] = get_webhook_dict() - default_conf["webhook"]["webhookentry"]["value1"] = "{DEADBEEF:8f}" + default_conf["webhook"]["strategy_msg"] = {"value1": "{DEADBEEF:8f}"} msg_mock = MagicMock() mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock) webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf) msg = { - 'type': RPCMessageType.ENTRY, - 'exchange': 'Binance', - 'pair': 'ETH/BTC', - 'limit': 0.005, - 'order_type': 'limit', - 'stake_amount': 0.8, - 'stake_amount_fiat': 500, - 'stake_currency': 'BTC', - 'fiat_currency': 'EUR' + 'type': RPCMessageType.STRATEGY_MSG, + 'msg': 'hello world', } webhook.send_msg(msg) assert log_has("Problem calling Webhook. Please check your webhook configuration. " From 9454fb8f7bccc119dd4127b5c838dd535a7db96d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 7 Oct 2022 20:59:49 +0200 Subject: [PATCH 09/60] Fix discord message sending --- freqtrade/rpc/discord.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index c48508300..f6a044318 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -11,13 +11,12 @@ logger = logging.getLogger(__name__) class Discord(Webhook): def __init__(self, rpc: 'RPC', config: Config): - # super().__init__(rpc, config) + self._config = config self.rpc = rpc - self.config = config self.strategy = config.get('strategy', '') self.timeframe = config.get('timeframe', '') - self._url = self.config['discord']['webhook_url'] + self._url = config['discord']['webhook_url'] self._format = 'json' self._retries = 1 self._retry_delay = 0.1 @@ -31,19 +30,21 @@ class Discord(Webhook): def send_msg(self, msg) -> None: - if msg['type'].value in self.config['discord']: + if msg['type'].value in self._config['discord']: logger.info(f"Sending discord message: {msg}") msg['strategy'] = self.strategy msg['timeframe'] = self.timeframe - fields = self.config['discord'].get(msg['type'].value) + fields = self._config['discord'].get(msg['type'].value) color = 0x0000FF if msg['type'] in (RPCMessageType.EXIT, RPCMessageType.EXIT_FILL): profit_ratio = msg.get('profit_ratio') color = (0x00FF00 if profit_ratio > 0 else 0xFF0000) - + title = msg['type'].value + if 'pair' in msg: + title = f"Trade: {msg['pair']} {msg['type'].value}" embeds = [{ - 'title': f"Trade: {msg['pair']} {msg['type'].value}", + 'title': title, 'color': color, 'fields': [], From 4daf0000c7f3619563dfe640ca40fd9880fe5366 Mon Sep 17 00:00:00 2001 From: th0rntwig Date: Sat, 8 Oct 2022 16:15:48 +0200 Subject: [PATCH 10/60] Move check and add log warning --- freqtrade/freqai/data_kitchen.py | 15 +++++++++++---- freqtrade/freqai/freqai_interface.py | 2 -- tests/freqai/test_freqai_interface.py | 22 ++++++++++++---------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 23bba3f1a..de4a53a50 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -241,6 +241,7 @@ class FreqaiDataKitchen: self.data["filter_drop_index_training"] = drop_index else: + filtered_df = self.check_pred_labels(filtered_df) # 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_df).any(axis=1) @@ -460,7 +461,7 @@ class FreqaiDataKitchen: return df - def check_pred_labels(self, df_predictions: DataFrame) -> None: + def check_pred_labels(self, df_predictions: DataFrame) -> DataFrame: """ Check that prediction feature labels match training feature labels. :params: @@ -468,9 +469,15 @@ class FreqaiDataKitchen: """ train_labels = self.data_dictionary["train_features"].columns pred_labels = df_predictions.columns - if len(train_labels.difference(pred_labels)) != 0: - self.data_dictionary["prediction_features"] = df_predictions[train_labels] - return + num_diffs = len(pred_labels.difference(train_labels)) + if num_diffs != 0: + df_predictions = df_predictions[train_labels] + logger.warning( + f"Removed {num_diffs} features from prediction features, " + f"these were likely considered constant values during most recent training." + ) + + return df_predictions def principal_component_analysis(self) -> None: """ diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 62c814c72..5ac7bc32c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -492,8 +492,6 @@ class IFreqaiModel(ABC): # ensure user is feeding the correct indicators to the model self.check_if_feature_list_matches_strategy(dk) - dk.check_pred_labels(dk.data_dictionary['prediction_features']) - if ft_params.get('inlier_metric_window', 0): dk.compute_inlier_metric(set_='predict') diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 238c0418c..c8444067a 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -157,7 +157,7 @@ def test_extract_data_and_train_model_Classifiers(mocker, freqai_conf, model): ("CatboostClassifier", 6, "freqai_test_classifier") ], ) -def test_start_backtesting(mocker, freqai_conf, model, num_files, strat): +def test_start_backtesting(mocker, freqai_conf, model, num_files, strat, caplog): freqai_conf.get("freqai", {}).update({"save_backtest_models": True}) freqai_conf['runmode'] = RunMode.BACKTEST Trade.use_db = False @@ -182,13 +182,21 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat): df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") for i in range(5): - df[f'constant_{i}'] = i + df.loc[:, f'%-constant_{i}'] = i 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()] assert len(model_folders) == num_files + assert log_has_re( + "Removed features ", + caplog, + ) + assert log_has_re( + "Removed 5 features from prediction features, ", + caplog, + ) Backtesting.cleanup() shutil.rmtree(Path(freqai.dk.full_path)) @@ -210,8 +218,6 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): 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") - for i in range(5): - df[f'constant_{i}'] = i metadata = {"pair": "LTC/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) @@ -237,8 +243,6 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): 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") - for i in range(5): - df[f'constant_{i}'] = i metadata = {"pair": "ADA/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) @@ -262,8 +266,7 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): 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") - for i in range(5): - df[f'constant_{i}'] = i + freqai.start_backtesting(df, metadata, freqai.dk) assert log_has_re( @@ -320,8 +323,7 @@ def test_follow_mode(mocker, freqai_conf): freqai.dd.load_all_pair_histories(timerange, freqai.dk) df = strategy.dp.get_pair_dataframe('ADA/BTC', '5m') - for i in range(5): - df[f'constant_{i}'] = i + freqai.start_live(df, metadata, strategy, freqai.dk) assert len(freqai.dk.return_dataframe.index) == 5702 From 8e3a4eca4198e157e794d2d2b1ef936764c9d615 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 9 Oct 2022 09:15:11 +0200 Subject: [PATCH 11/60] Remove unused type:ignore --- freqtrade/rpc/discord.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index f6a044318..8be0eab68 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -52,7 +52,7 @@ class Discord(Webhook): for f in fields: for k, v in f.items(): v = v.format(**msg) - embeds[0]['fields'].append( # type: ignore + embeds[0]['fields'].append( {'name': k, 'value': v, 'inline': True}) # Send the message to discord channel From a4aa1b972c543b0ea256bb521f3c8d41a2585c80 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sun, 9 Oct 2022 21:11:37 +0200 Subject: [PATCH 12/60] isolate and standardize location of tensorboard files, add doc, ensure backtesting functionality --- docs/freqai-running.md | 14 ++++++++++++++ freqtrade/freqai/data_kitchen.py | 2 ++ freqtrade/freqai/freqai_interface.py | 5 +---- .../freqai/prediction_models/CatboostClassifier.py | 3 ++- .../freqai/prediction_models/CatboostRegressor.py | 3 ++- .../CatboostRegressorMultiTarget.py | 3 ++- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/docs/freqai-running.md b/docs/freqai-running.md index b8994aed9..f6aa7b2e1 100644 --- a/docs/freqai-running.md +++ b/docs/freqai-running.md @@ -142,6 +142,20 @@ dataframe['outlier'] = np.where(dataframe['DI_values'] > self.di_max.value/10, 1 This specific hyperopt would help you understand the appropriate `DI_values` for your particular parameter space. +## Using Tensorboard + +Catboost models benefit from tracking training metrics via Tensorboard. You can take advantage of the FreqAI integration to track training and evaluation performance across all coins and across all retrainings. Tensorboard is activated via the following command: + +```bash +cd freqtrade +tensorboard --logdir user_data/models/unique-id +``` + +where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell if the user wishes to view the output in their browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard). + +![tensorboard](assets/tensorboard.jpg) + + ## Setting up a follower You can indicate to the bot that it should not train models, but instead should look for models trained by a leader with a specific `identifier` by defining: diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 7ea2daf02..b7473eacc 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -120,6 +120,8 @@ class FreqaiDataKitchen: / f"sub-train-{pair.split('/')[0]}_{trained_timestamp}" ) + Path(self.data_path / 'tensorboard').mkdir(parents=True, exist_ok=True) + return def make_train_test_datasets( diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 5ac7bc32c..58d8523a2 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -196,7 +196,6 @@ class IFreqaiModel(ABC): (_, trained_timestamp, _) = self.dd.get_pair_dict_info(pair) dk = FreqaiDataKitchen(self.config, self.live, pair) - dk.set_paths(pair, trained_timestamp) ( retrain, new_trained_timerange, @@ -267,9 +266,7 @@ class IFreqaiModel(ABC): ) trained_timestamp_int = int(trained_timestamp.stopts) - dk.data_path = Path( - dk.full_path / f"sub-train-{pair.split('/')[0]}_{trained_timestamp_int}" - ) + dk.set_paths(pair, trained_timestamp_int) dk.set_new_model_names(pair, trained_timestamp) diff --git a/freqtrade/freqai/prediction_models/CatboostClassifier.py b/freqtrade/freqai/prediction_models/CatboostClassifier.py index 31a865a8d..0565b15b5 100644 --- a/freqtrade/freqai/prediction_models/CatboostClassifier.py +++ b/freqtrade/freqai/prediction_models/CatboostClassifier.py @@ -1,4 +1,5 @@ import logging +from pathlib import Path from typing import Any, Dict from catboost import CatBoostClassifier, Pool @@ -34,7 +35,7 @@ class CatboostClassifier(BaseClassifierModel): cbr = CatBoostClassifier( allow_writing_files=True, loss_function='MultiClass', - train_dir=dk.data_path, + train_dir=Path(dk.data_path / 'tensorboard'), **self.model_training_parameters, ) diff --git a/freqtrade/freqai/prediction_models/CatboostRegressor.py b/freqtrade/freqai/prediction_models/CatboostRegressor.py index a04649d93..46f33a142 100644 --- a/freqtrade/freqai/prediction_models/CatboostRegressor.py +++ b/freqtrade/freqai/prediction_models/CatboostRegressor.py @@ -1,4 +1,5 @@ import logging +from pathlib import Path from typing import Any, Dict from catboost import CatBoostRegressor, Pool @@ -42,7 +43,7 @@ class CatboostRegressor(BaseRegressionModel): model = CatBoostRegressor( allow_writing_files=True, - train_dir=dk.data_path, + train_dir=Path(dk.data_path / 'tensorboard'), **self.model_training_parameters, ) diff --git a/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py b/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py index 292ad600a..085c13b86 100644 --- a/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py +++ b/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py @@ -1,4 +1,5 @@ import logging +from pathlib import Path from typing import Any, Dict from catboost import CatBoostRegressor, Pool @@ -27,7 +28,7 @@ class CatboostRegressorMultiTarget(BaseRegressionModel): cbr = CatBoostRegressor( allow_writing_files=True, - train_dir=dk.data_path, + train_dir=Path(dk.data_path / 'tensorboard'), **self.model_training_parameters, ) From 3e8d8fd1b08e28f8ec231de9ee3be57a539b266e Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Sun, 9 Oct 2022 15:04:52 -0600 Subject: [PATCH 13/60] refactor broadcasting to a queue per client --- freqtrade/rpc/api_server/api_ws.py | 24 ++++++++++++------- freqtrade/rpc/api_server/webserver.py | 1 + freqtrade/rpc/api_server/ws/channel.py | 32 ++++++++++++++++++++------ 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/freqtrade/rpc/api_server/api_ws.py b/freqtrade/rpc/api_server/api_ws.py index f55b2dbd3..b60210143 100644 --- a/freqtrade/rpc/api_server/api_ws.py +++ b/freqtrade/rpc/api_server/api_ws.py @@ -1,6 +1,7 @@ import logging from typing import Any, Dict +import websockets from fastapi import APIRouter, Depends, WebSocketDisconnect from fastapi.websockets import WebSocket, WebSocketState from pydantic import ValidationError @@ -102,7 +103,6 @@ async def message_endpoint( """ try: channel = await channel_manager.on_connect(ws) - if await is_websocket_alive(ws): logger.info(f"Consumer connected - {channel}") @@ -115,26 +115,34 @@ async def message_endpoint( # Process the request here await _process_consumer_request(request, channel, rpc) - except WebSocketDisconnect: + except ( + WebSocketDisconnect, + websockets.exceptions.WebSocketException + ): # Handle client disconnects logger.info(f"Consumer disconnected - {channel}") - await channel_manager.on_disconnect(ws) - except Exception as e: - logger.info(f"Consumer connection failed - {channel}") - logger.exception(e) + except RuntimeError: # Handle cases like - # RuntimeError('Cannot call "send" once a closed message has been sent') + pass + except Exception as e: + logger.info(f"Consumer connection failed - {channel}") + logger.debug(e, exc_info=e) + finally: await channel_manager.on_disconnect(ws) else: + if channel: + await channel_manager.on_disconnect(ws) await ws.close() except RuntimeError: # WebSocket was closed - await channel_manager.on_disconnect(ws) - + # Do nothing + pass except Exception as e: logger.error(f"Failed to serve - {ws.client}") # Log tracebacks to keep track of what errors are happening logger.exception(e) + finally: await channel_manager.on_disconnect(ws) diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index 53af91477..4a09fd78e 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -245,6 +245,7 @@ class ApiServer(RPCHandler): use_colors=False, log_config=None, access_log=True if verbosity != 'error' else False, + ws_ping_interval=None # We do this explicitly ourselves ) try: self._server = UvicornServer(uvconfig) diff --git a/freqtrade/rpc/api_server/ws/channel.py b/freqtrade/rpc/api_server/ws/channel.py index 69a32e266..8c6c56d6e 100644 --- a/freqtrade/rpc/api_server/ws/channel.py +++ b/freqtrade/rpc/api_server/ws/channel.py @@ -1,6 +1,7 @@ +import asyncio import logging from threading import RLock -from typing import List, Optional, Type +from typing import Any, Dict, List, Optional, Type from uuid import uuid4 from fastapi import WebSocket as FastAPIWebSocket @@ -34,6 +35,8 @@ class WebSocketChannel: self._serializer_cls = serializer_cls self._subscriptions: List[str] = [] + self.queue: asyncio.Queue[Dict[str, Any]] = asyncio.Queue() + self._relay_task = asyncio.create_task(self.relay()) # Internal event to signify a closed websocket self._closed = False @@ -72,6 +75,7 @@ class WebSocketChannel: """ self._closed = True + self._relay_task.cancel() def is_closed(self) -> bool: """ @@ -95,6 +99,20 @@ class WebSocketChannel: """ return message_type in self._subscriptions + async def relay(self): + """ + Relay messages from the channel's queue and send them out. This is started + as a task. + """ + while True: + message = await self.queue.get() + try: + await self.send(message) + self.queue.task_done() + except RuntimeError: + # The connection was closed, just exit the task + return + class ChannelManager: def __init__(self): @@ -155,12 +173,12 @@ class ChannelManager: with self._lock: message_type = data.get('type') for websocket, channel in self.channels.copy().items(): - try: - if channel.subscribed_to(message_type): - await channel.send(data) - except RuntimeError: - # Handle cannot send after close cases - await self.on_disconnect(websocket) + if channel.subscribed_to(message_type): + if not channel.queue.full(): + channel.queue.put_nowait(data) + else: + logger.info(f"Channel {channel} is too far behind, disconnecting") + await self.on_disconnect(websocket) async def send_direct(self, channel, data): """ From 2f64a086238b383312dd2db9aea104690aac5a8a Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Sun, 9 Oct 2022 15:11:58 -0600 Subject: [PATCH 14/60] set channel queue maxsize to 32 --- freqtrade/rpc/api_server/ws/channel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/ws/channel.py b/freqtrade/rpc/api_server/ws/channel.py index 8c6c56d6e..91875abfb 100644 --- a/freqtrade/rpc/api_server/ws/channel.py +++ b/freqtrade/rpc/api_server/ws/channel.py @@ -35,7 +35,7 @@ class WebSocketChannel: self._serializer_cls = serializer_cls self._subscriptions: List[str] = [] - self.queue: asyncio.Queue[Dict[str, Any]] = asyncio.Queue() + self.queue: asyncio.Queue[Dict[str, Any]] = asyncio.Queue(maxsize=32) self._relay_task = asyncio.create_task(self.relay()) # Internal event to signify a closed websocket From 2c76dd9e39c8742dfc39b82eae407f11c9be7c91 Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Sun, 9 Oct 2022 15:23:56 -0600 Subject: [PATCH 15/60] change wait timeout to 30 seconds to better support reverse proxies --- freqtrade/rpc/external_message_consumer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/external_message_consumer.py b/freqtrade/rpc/external_message_consumer.py index f5ba4b490..a182ddc57 100644 --- a/freqtrade/rpc/external_message_consumer.py +++ b/freqtrade/rpc/external_message_consumer.py @@ -62,7 +62,7 @@ class ExternalMessageConsumer: self.enabled = self._emc_config.get('enabled', False) self.producers: List[Producer] = self._emc_config.get('producers', []) - self.wait_timeout = self._emc_config.get('wait_timeout', 300) # in seconds + self.wait_timeout = self._emc_config.get('wait_timeout', 30) # in seconds self.ping_timeout = self._emc_config.get('ping_timeout', 10) # in seconds self.sleep_time = self._emc_config.get('sleep_time', 10) # in seconds From 71bbffd10a0fcac0ca5992d7ab4c62e0ed6e9bf8 Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Sun, 9 Oct 2022 18:49:04 -0600 Subject: [PATCH 16/60] update ws channel send to add data to queue --- freqtrade/rpc/api_server/ws/channel.py | 12 +++++++++--- freqtrade/rpc/external_message_consumer.py | 5 +++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/api_server/ws/channel.py b/freqtrade/rpc/api_server/ws/channel.py index 91875abfb..7cee95e6d 100644 --- a/freqtrade/rpc/api_server/ws/channel.py +++ b/freqtrade/rpc/api_server/ws/channel.py @@ -51,12 +51,18 @@ class WebSocketChannel: def remote_addr(self): return self._websocket.remote_addr - async def send(self, data): + async def _send(self, data): """ Send data on the wrapped websocket """ await self._wrapped_ws.send(data) + async def send(self, data): + """ + Add the data to the queue to be sent + """ + self.queue.put_nowait(data) + async def recv(self): """ Receive data on the wrapped websocket @@ -107,7 +113,7 @@ class WebSocketChannel: while True: message = await self.queue.get() try: - await self.send(message) + await self._send(message) self.queue.task_done() except RuntimeError: # The connection was closed, just exit the task @@ -175,7 +181,7 @@ class ChannelManager: for websocket, channel in self.channels.copy().items(): if channel.subscribed_to(message_type): if not channel.queue.full(): - channel.queue.put_nowait(data) + await channel.send(data) else: logger.info(f"Channel {channel} is too far behind, disconnecting") await self.on_disconnect(websocket) diff --git a/freqtrade/rpc/external_message_consumer.py b/freqtrade/rpc/external_message_consumer.py index a182ddc57..88ade185e 100644 --- a/freqtrade/rpc/external_message_consumer.py +++ b/freqtrade/rpc/external_message_consumer.py @@ -174,6 +174,7 @@ class ExternalMessageConsumer: :param producer: Dictionary containing producer info :param lock: An asyncio Lock """ + channel = None while self._running: try: host, port = producer['host'], producer['port'] @@ -224,6 +225,10 @@ class ExternalMessageConsumer: logger.exception(e) continue + finally: + if channel: + await channel.close() + async def _receive_messages( self, channel: WebSocketChannel, From db8cf6c957cdf56b3c1bb7ec8f27c445a0933070 Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Sun, 9 Oct 2022 18:51:52 -0600 Subject: [PATCH 17/60] disable ping interval in client --- freqtrade/rpc/external_message_consumer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/external_message_consumer.py b/freqtrade/rpc/external_message_consumer.py index 88ade185e..01bc974ad 100644 --- a/freqtrade/rpc/external_message_consumer.py +++ b/freqtrade/rpc/external_message_consumer.py @@ -183,7 +183,11 @@ class ExternalMessageConsumer: ws_url = f"ws://{host}:{port}/api/v1/message/ws?token={token}" # This will raise InvalidURI if the url is bad - async with websockets.connect(ws_url, max_size=self.message_size_limit) as ws: + async with websockets.connect( + ws_url, + max_size=self.message_size_limit, + ping_interval=None + ) as ws: channel = WebSocketChannel(ws, channel_id=name) logger.info(f"Producer connection success - {channel}") From 337ea04ba0dcf92e758dc082e08b1126a6e0877b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 03:02:27 +0000 Subject: [PATCH 18/60] Bump nbconvert from 7.0.0 to 7.2.1 Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 7.0.0 to 7.2.1. - [Release notes](https://github.com/jupyter/nbconvert/releases) - [Changelog](https://github.com/jupyter/nbconvert/blob/main/CHANGELOG.md) - [Commits](https://github.com/jupyter/nbconvert/compare/7.0.0...v7.2.1) --- updated-dependencies: - dependency-name: nbconvert dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ebe278e10..f4120dc5e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,7 +20,7 @@ isort==5.10.1 time-machine==2.8.2 # Convert jupyter notebooks to markdown documents -nbconvert==7.0.0 +nbconvert==7.2.1 # mypy types types-cachetools==5.2.1 From 40afa079b12f01810cd9d48caaa416caf81801f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 03:02:31 +0000 Subject: [PATCH 19/60] Bump tabulate from 0.8.10 to 0.9.0 Bumps [tabulate](https://github.com/astanin/python-tabulate) from 0.8.10 to 0.9.0. - [Release notes](https://github.com/astanin/python-tabulate/releases) - [Changelog](https://github.com/astanin/python-tabulate/blob/master/CHANGELOG) - [Commits](https://github.com/astanin/python-tabulate/compare/v0.8.10...v0.9.0) --- updated-dependencies: - dependency-name: tabulate 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 4f4b30d0c..cf2f14c77 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ urllib3==1.26.12 jsonschema==4.16.0 TA-Lib==0.4.25 technical==1.3.0 -tabulate==0.8.10 +tabulate==0.9.0 pycoingecko==3.0.0 jinja2==3.1.2 tables==3.7.0 From dab2759c2194f88f03cc1bab00382c0c756a8217 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 03:02:43 +0000 Subject: [PATCH 20/60] Bump scipy from 1.9.1 to 1.9.2 Bumps [scipy](https://github.com/scipy/scipy) from 1.9.1 to 1.9.2. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.9.1...v1.9.2) --- updated-dependencies: - dependency-name: scipy dependency-type: direct:production update-type: version-update:semver-patch ... 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 efa31272a..3e76a6c22 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -2,7 +2,7 @@ -r requirements.txt # Required for hyperopt -scipy==1.9.1 +scipy==1.9.2 scikit-learn==1.1.2 scikit-optimize==0.9.0 filelock==3.8.0 From 8bb7b94f8de4326b0ca7c4be5e2db1d3dd7d2e0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 03:02:53 +0000 Subject: [PATCH 21/60] Bump ccxt from 1.95.2 to 1.95.30 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.95.2 to 1.95.30. - [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.95.2...1.95.30) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4f4b30d0c..73ffed8d9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ pandas==1.5.0; platform_machine != 'armv7l' pandas==1.4.3; platform_machine == 'armv7l' pandas-ta==0.3.14b -ccxt==1.95.2 +ccxt==1.95.30 # Pin cryptography for now due to rust build errors with piwheels cryptography==38.0.1 aiohttp==3.8.3 From 9d2f281ca6c89b79f766e6a9c0658b15e7bd577c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 03:02:57 +0000 Subject: [PATCH 22/60] Bump pytest-mock from 3.9.0 to 3.10.0 Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.9.0 to 3.10.0. - [Release notes](https://github.com/pytest-dev/pytest-mock/releases) - [Changelog](https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.9.0...v3.10.0) --- updated-dependencies: - dependency-name: pytest-mock dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ebe278e10..ed0b9d73c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -13,7 +13,7 @@ pre-commit==2.20.0 pytest==7.1.3 pytest-asyncio==0.19.0 pytest-cov==4.0.0 -pytest-mock==3.9.0 +pytest-mock==3.10.0 pytest-random-order==1.0.4 isort==5.10.1 # For datetime mocking From 935adc99aed9fd1249f077a3408993275f51bc8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 03:03:06 +0000 Subject: [PATCH 23/60] Bump types-tabulate from 0.8.11 to 0.9.0.0 Bumps [types-tabulate](https://github.com/python/typeshed) from 0.8.11 to 0.9.0.0. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-tabulate dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ebe278e10..27a4d83a2 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,5 +26,5 @@ nbconvert==7.0.0 types-cachetools==5.2.1 types-filelock==3.2.7 types-requests==2.28.11 -types-tabulate==0.8.11 +types-tabulate==0.9.0.0 types-python-dateutil==2.8.19 From c1dfa837bddf6c98007a82e1c307692da5536d8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 04:56:43 +0000 Subject: [PATCH 24/60] Bump mypy from 0.981 to 0.982 Bumps [mypy](https://github.com/python/mypy) from 0.981 to 0.982. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.981...v0.982) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index f4120dc5e..f8238a07c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,7 @@ coveralls==3.3.1 flake8==5.0.4 flake8-tidy-imports==4.8.0 -mypy==0.981 +mypy==0.982 pre-commit==2.20.0 pytest==7.1.3 pytest-asyncio==0.19.0 From 3fcba2fb8d82de03fcd84936b7b4d45222bc42d8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 08:03:40 +0200 Subject: [PATCH 25/60] Remove hard-pin on python version in ci --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 195370339..034c5352d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ] - python-version: ["3.8", "3.9", "3.10.6"] + python-version: ["3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v3 @@ -121,7 +121,7 @@ jobs: strategy: matrix: os: [ macos-latest ] - python-version: ["3.8", "3.9", "3.10.6"] + python-version: ["3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v3 @@ -205,7 +205,7 @@ jobs: strategy: matrix: os: [ windows-latest ] - python-version: ["3.8", "3.9", "3.10.6"] + python-version: ["3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v3 From 13529fabb19a5efaca61088c886228a261b607a7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 08:16:26 +0200 Subject: [PATCH 26/60] types-tabulate in pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2cad0a7d3..e20f0916e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - types-cachetools==5.2.1 - types-filelock==3.2.7 - types-requests==2.28.11 - - types-tabulate==0.8.11 + - types-tabulate==0.9.0.0 - types-python-dateutil==2.8.19 # stages: [push] From 5218fb1df5e394d791d0d1af0721451adb831180 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 06:49:11 +0000 Subject: [PATCH 27/60] Bump types-requests from 2.28.11 to 2.28.11.2 Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11 to 2.28.11.2. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests 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 7ba4cc8d2..015f4509b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,6 +25,6 @@ nbconvert==7.2.1 # mypy types types-cachetools==5.2.1 types-filelock==3.2.7 -types-requests==2.28.11 +types-requests==2.28.11.2 types-tabulate==0.9.0.0 types-python-dateutil==2.8.19 From f120c66987bc1cd892627c3c4861fcf1d271373c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 08:52:38 +0200 Subject: [PATCH 28/60] types-requests - update pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e20f0916e..7abe5659a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.2.1 - types-filelock==3.2.7 - - types-requests==2.28.11 + - types-requests==2.28.11.2 - types-tabulate==0.9.0.0 - types-python-dateutil==2.8.19 # stages: [push] From d0b163764efdcf5dca79af47108cbf3f88df02a4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 07:41:38 +0000 Subject: [PATCH 29/60] Run coveralls only when needed --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 034c5352d..f7bbf23d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,8 @@ jobs: if: matrix.python-version == '3.9' && matrix.os == 'ubuntu-22.04' - name: Coveralls - if: (runner.os == 'Linux' && matrix.python-version == '3.9') + if: (runner.os == 'Linux' && matrix.python-version == '3.10' && matrix.os == 'ubuntu-22.04' +) env: # Coveralls token. Not used as secret due to github not providing secrets to forked repositories COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu From 6be9b81f4cddfff670767dced5feb3db8b74f807 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 12:12:30 +0200 Subject: [PATCH 30/60] Fix workflow syntax error --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7bbf23d5..47b9a9279 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,8 +74,7 @@ jobs: if: matrix.python-version == '3.9' && matrix.os == 'ubuntu-22.04' - name: Coveralls - if: (runner.os == 'Linux' && matrix.python-version == '3.10' && matrix.os == 'ubuntu-22.04' -) + if: (runner.os == 'Linux' && matrix.python-version == '3.10' && matrix.os == 'ubuntu-22.04') env: # Coveralls token. Not used as secret due to github not providing secrets to forked repositories COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu @@ -442,4 +441,4 @@ jobs: with: severity: info details: Deploy Succeeded! - webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} \ No newline at end of file + webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} From d3b2b2972e9b32ec193f94b1b7c0a19b747a6658 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 11:54:13 +0000 Subject: [PATCH 31/60] Update pairlist docstring to be less missleading --- freqtrade/plugins/pairlist/AgeFilter.py | 2 +- freqtrade/plugins/pairlist/IPairList.py | 6 +++--- freqtrade/plugins/pairlist/OffsetFilter.py | 2 +- freqtrade/plugins/pairlist/PerformanceFilter.py | 2 +- freqtrade/plugins/pairlist/PrecisionFilter.py | 2 +- freqtrade/plugins/pairlist/PriceFilter.py | 2 +- freqtrade/plugins/pairlist/ProducerPairList.py | 4 ++-- freqtrade/plugins/pairlist/ShuffleFilter.py | 2 +- freqtrade/plugins/pairlist/SpreadFilter.py | 2 +- freqtrade/plugins/pairlist/StaticPairList.py | 4 ++-- freqtrade/plugins/pairlist/VolatilityFilter.py | 2 +- freqtrade/plugins/pairlist/VolumePairList.py | 4 ++-- freqtrade/plugins/pairlist/rangestabilityfilter.py | 2 +- 13 files changed, 18 insertions(+), 18 deletions(-) diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py index 70638936a..7c8cdb5ab 100644 --- a/freqtrade/plugins/pairlist/AgeFilter.py +++ b/freqtrade/plugins/pairlist/AgeFilter.py @@ -70,7 +70,7 @@ class AgeFilter(IPairList): def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: """ :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new allowlist """ needed_pairs: ListPairsWithTimeframes = [ diff --git a/freqtrade/plugins/pairlist/IPairList.py b/freqtrade/plugins/pairlist/IPairList.py index c02ba5ef5..60abac6a1 100644 --- a/freqtrade/plugins/pairlist/IPairList.py +++ b/freqtrade/plugins/pairlist/IPairList.py @@ -69,7 +69,7 @@ class IPairList(LoggingMixin, ABC): filter_pairlist() method. :param pair: Pair that's currently validated - :param ticker: ticker dict as returned from ccxt.fetch_tickers() + :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ raise NotImplementedError() @@ -85,7 +85,7 @@ class IPairList(LoggingMixin, ABC): it will raise the exception if a Pairlist Handler is used at the first position in the chain. - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: List of pairs """ raise OperationalException("This Pairlist Handler should not be used " @@ -103,7 +103,7 @@ class IPairList(LoggingMixin, ABC): own filtration. :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ if self._enabled: diff --git a/freqtrade/plugins/pairlist/OffsetFilter.py b/freqtrade/plugins/pairlist/OffsetFilter.py index 149befdeb..c9531ece1 100644 --- a/freqtrade/plugins/pairlist/OffsetFilter.py +++ b/freqtrade/plugins/pairlist/OffsetFilter.py @@ -47,7 +47,7 @@ class OffsetFilter(IPairList): Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ if self._offset > len(pairlist): diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index c29b4f337..4cc92175a 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -44,7 +44,7 @@ class PerformanceFilter(IPairList): Filters and sorts pairlist and returns the allowlist again. Called on each bot iteration - please use internal caching if necessary :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new allowlist """ # Get the trading performance for pairs from database diff --git a/freqtrade/plugins/pairlist/PrecisionFilter.py b/freqtrade/plugins/pairlist/PrecisionFilter.py index 8f1c9b839..98cb3ba46 100644 --- a/freqtrade/plugins/pairlist/PrecisionFilter.py +++ b/freqtrade/plugins/pairlist/PrecisionFilter.py @@ -49,7 +49,7 @@ class PrecisionFilter(IPairList): Check if pair has enough room to add a stoploss to avoid "unsellable" buys of very low value pairs. :param pair: Pair that's currently validated - :param ticker: ticker dict as returned from ccxt.fetch_tickers() + :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ if ticker.get('last', None) is None: diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index f2952001a..a6b400a38 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -68,7 +68,7 @@ class PriceFilter(IPairList): """ Check if if one price-step (pip) is > than a certain barrier. :param pair: Pair that's currently validated - :param ticker: ticker dict as returned from ccxt.fetch_tickers() + :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ if ticker.get('last', None) is None or ticker.get('last') == 0: diff --git a/freqtrade/plugins/pairlist/ProducerPairList.py b/freqtrade/plugins/pairlist/ProducerPairList.py index 50b674e60..740cb4ec2 100644 --- a/freqtrade/plugins/pairlist/ProducerPairList.py +++ b/freqtrade/plugins/pairlist/ProducerPairList.py @@ -71,7 +71,7 @@ class ProducerPairList(IPairList): def gen_pairlist(self, tickers: Dict) -> List[str]: """ Generate the pairlist - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: List of pairs """ pairs = self._filter_pairlist(None) @@ -84,7 +84,7 @@ class ProducerPairList(IPairList): Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ return self._filter_pairlist(pairlist) diff --git a/freqtrade/plugins/pairlist/ShuffleFilter.py b/freqtrade/plugins/pairlist/ShuffleFilter.py index b6b5fc3c8..6eb4231bc 100644 --- a/freqtrade/plugins/pairlist/ShuffleFilter.py +++ b/freqtrade/plugins/pairlist/ShuffleFilter.py @@ -52,7 +52,7 @@ class ShuffleFilter(IPairList): Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ # Shuffle is done inplace diff --git a/freqtrade/plugins/pairlist/SpreadFilter.py b/freqtrade/plugins/pairlist/SpreadFilter.py index 1f20af305..1f6d4f687 100644 --- a/freqtrade/plugins/pairlist/SpreadFilter.py +++ b/freqtrade/plugins/pairlist/SpreadFilter.py @@ -48,7 +48,7 @@ class SpreadFilter(IPairList): """ Validate spread for the ticker :param pair: Pair that's currently validated - :param ticker: ticker dict as returned from ccxt.fetch_tickers() + :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ if 'bid' in ticker and 'ask' in ticker and ticker['ask'] and ticker['bid']: diff --git a/freqtrade/plugins/pairlist/StaticPairList.py b/freqtrade/plugins/pairlist/StaticPairList.py index 83a0fa0c8..5b1337754 100644 --- a/freqtrade/plugins/pairlist/StaticPairList.py +++ b/freqtrade/plugins/pairlist/StaticPairList.py @@ -42,7 +42,7 @@ class StaticPairList(IPairList): def gen_pairlist(self, tickers: Dict) -> List[str]: """ Generate the pairlist - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: List of pairs """ if self._allow_inactive: @@ -58,7 +58,7 @@ class StaticPairList(IPairList): Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ pairlist_ = deepcopy(pairlist) diff --git a/freqtrade/plugins/pairlist/VolatilityFilter.py b/freqtrade/plugins/pairlist/VolatilityFilter.py index c9af3a7b3..c06fc09ba 100644 --- a/freqtrade/plugins/pairlist/VolatilityFilter.py +++ b/freqtrade/plugins/pairlist/VolatilityFilter.py @@ -66,7 +66,7 @@ class VolatilityFilter(IPairList): """ Validate trading range :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new allowlist """ needed_pairs: ListPairsWithTimeframes = [ diff --git a/freqtrade/plugins/pairlist/VolumePairList.py b/freqtrade/plugins/pairlist/VolumePairList.py index b290f76aa..bfecbd62a 100644 --- a/freqtrade/plugins/pairlist/VolumePairList.py +++ b/freqtrade/plugins/pairlist/VolumePairList.py @@ -113,7 +113,7 @@ class VolumePairList(IPairList): def gen_pairlist(self, tickers: Dict) -> List[str]: """ Generate the pairlist - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: List of pairs """ # Generate dynamic whitelist @@ -150,7 +150,7 @@ class VolumePairList(IPairList): Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ if self._use_range: diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py index 1bc7ad48f..ca844f003 100644 --- a/freqtrade/plugins/pairlist/rangestabilityfilter.py +++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py @@ -64,7 +64,7 @@ class RangeStabilityFilter(IPairList): """ Validate trading range :param pairlist: pairlist to filter or sort - :param tickers: Tickers (from exchange.get_tickers()). May be cached. + :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new allowlist """ needed_pairs: ListPairsWithTimeframes = [ From 60de192d47173f60dd666bf5c47517bc50c09bdf Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 12:13:41 +0000 Subject: [PATCH 32/60] Update Classifier docstrings --- freqtrade/freqai/prediction_models/CatboostClassifier.py | 5 ++--- freqtrade/freqai/prediction_models/LightGBMClassifier.py | 5 ++--- freqtrade/freqai/prediction_models/XGBoostClassifier.py | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/freqtrade/freqai/prediction_models/CatboostClassifier.py b/freqtrade/freqai/prediction_models/CatboostClassifier.py index 60536e6de..9a77644ed 100644 --- a/freqtrade/freqai/prediction_models/CatboostClassifier.py +++ b/freqtrade/freqai/prediction_models/CatboostClassifier.py @@ -20,9 +20,8 @@ class CatboostClassifier(BaseClassifierModel): def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> 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/LightGBMClassifier.py b/freqtrade/freqai/prediction_models/LightGBMClassifier.py index 3eec516ba..e467ad3c1 100644 --- a/freqtrade/freqai/prediction_models/LightGBMClassifier.py +++ b/freqtrade/freqai/prediction_models/LightGBMClassifier.py @@ -20,9 +20,8 @@ class LightGBMClassifier(BaseClassifierModel): def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> 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. """ if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) == 0: diff --git a/freqtrade/freqai/prediction_models/XGBoostClassifier.py b/freqtrade/freqai/prediction_models/XGBoostClassifier.py index 8bf5d6281..3b14471c1 100644 --- a/freqtrade/freqai/prediction_models/XGBoostClassifier.py +++ b/freqtrade/freqai/prediction_models/XGBoostClassifier.py @@ -26,9 +26,8 @@ class XGBoostClassifier(BaseClassifierModel): def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> 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. """ X = data_dictionary["train_features"].to_numpy() From eaae9c9e037890d38b5a6a8b1cc9883296285302 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 12:15:30 +0000 Subject: [PATCH 33/60] Update docstring format --- .../freqai/base_models/BaseClassifierModel.py | 2 +- .../freqai/base_models/BaseRegressionModel.py | 2 +- freqtrade/freqai/data_drawer.py | 20 +++---- freqtrade/freqai/data_kitchen.py | 60 +++++++++---------- freqtrade/freqai/freqai_interface.py | 10 ++-- .../prediction_models/XGBoostClassifier.py | 2 +- 6 files changed, 44 insertions(+), 52 deletions(-) diff --git a/freqtrade/freqai/base_models/BaseClassifierModel.py b/freqtrade/freqai/base_models/BaseClassifierModel.py index 09f1bf98c..691c27e23 100644 --- a/freqtrade/freqai/base_models/BaseClassifierModel.py +++ b/freqtrade/freqai/base_models/BaseClassifierModel.py @@ -78,7 +78,7 @@ class BaseClassifierModel(IFreqaiModel): ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: """ Filter the prediction features data and predict with it. - :param: unfiltered_df: Full dataframe for the current backtest period. + :param unfiltered_df: 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 diff --git a/freqtrade/freqai/base_models/BaseRegressionModel.py b/freqtrade/freqai/base_models/BaseRegressionModel.py index 5d89dd356..79f6f0d3c 100644 --- a/freqtrade/freqai/base_models/BaseRegressionModel.py +++ b/freqtrade/freqai/base_models/BaseRegressionModel.py @@ -77,7 +77,7 @@ class BaseRegressionModel(IFreqaiModel): ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: """ Filter the prediction features data and predict with it. - :param: unfiltered_df: Full dataframe for the current backtest period. + :param unfiltered_df: 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 diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 31c76a68e..465ba27f5 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -412,9 +412,8 @@ class FreqaiDataDrawer: 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 + :param model: User trained model which can be reused for inferencing to generate + predictions """ if not dk.data_path.is_dir(): @@ -532,8 +531,7 @@ class FreqaiDataDrawer: 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 + :param dataframe: DataFrame = strategy provided dataframe """ feat_params = self.freqai_info["feature_parameters"] with self.history_lock: @@ -579,9 +577,8 @@ class FreqaiDataDrawer: """ 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 + :param timerange: TimeRange = full timerange required to populate all indicators + for training according to user defined train_period_days """ history_data = self.historic_data @@ -604,10 +601,9 @@ class FreqaiDataDrawer: """ 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 + :param timerange: TimeRange = full timerange required to populate all indicators + for training according to user defined train_period_days + :param metadata: dict = strategy furnished pair metadata """ with self.history_lock: corr_dataframes: Dict[Any, Any] = {} diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 7ea2daf02..0a4dd960c 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -107,9 +107,8 @@ class FreqaiDataKitchen: ) -> None: """ Set the paths to the data for the present coin/botloop - :params: - metadata: dict = strategy furnished pair metadata - trained_timestamp: int = timestamp of most recent training + :param metadata: dict = strategy furnished pair metadata + :param trained_timestamp: int = timestamp of most recent training """ self.full_path = Path( self.config["user_data_dir"] / "models" / str(self.freqai_config.get("identifier")) @@ -129,8 +128,8 @@ class FreqaiDataKitchen: 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. + :param filtered_dataframe: cleaned dataframe ready to be split. + :param labels: cleaned labels ready to be split. """ feat_dict = self.freqai_config["feature_parameters"] @@ -189,13 +188,14 @@ class FreqaiDataKitchen: 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_df: 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. + + :param unfiltered_df: the full dataframe for the present training period + :param training_feature_list: list, the training feature list constructed by + self.build_feature_list() according to user specified + parameters in the configuration file. + :param labels: the labels for the dataset + :param training_filter: boolean which lets the function know if it is training data or + prediction data to be filtered. :returns: :filtered_df: dataframe cleaned of NaNs and only containing the user requested feature set. @@ -285,8 +285,8 @@ class FreqaiDataKitchen: def normalize_data(self, data_dictionary: Dict) -> Dict[Any, Any]: """ 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 + :param data_dictionary: dictionary containing the cleaned and + split training/test data/labels :returns: :data_dictionary: updated dictionary with standardized values. """ @@ -516,8 +516,7 @@ class FreqaiDataKitchen: def pca_transform(self, filtered_dataframe: DataFrame) -> None: """ Use an existing pca transform to transform data into components - :params: - filtered_dataframe: DataFrame = the cleaned dataframe + :param filtered_dataframe: DataFrame = the cleaned dataframe """ pca_components = self.pca.transform(filtered_dataframe) self.data_dictionary["prediction_features"] = pd.DataFrame( @@ -561,8 +560,7 @@ class FreqaiDataKitchen: """ Build/inference a Support Vector Machine to detect outliers in training data and prediction - :params: - predict: bool = If true, inference an existing SVM model, else construct one + :param predict: bool = If true, inference an existing SVM model, else construct one """ if self.keras: @@ -647,11 +645,11 @@ class FreqaiDataKitchen: Use DBSCAN to cluster training data and remove "noisy" data (read outliers). User controls this via the config param `DBSCAN_outlier_pct` which indicates the pct of training data that they want to be considered outliers. - :params: - predict: bool = If False (training), iterate to find the best hyper parameters to match - user requested outlier percent target. If True (prediction), use the parameters - determined from the previous training to estimate if the current prediction point - is an outlier. + :param predict: bool = If False (training), iterate to find the best hyper parameters + to match user requested outlier percent target. + If True (prediction), use the parameters determined from + the previous training to estimate if the current prediction point + is an outlier. """ if predict: @@ -1118,15 +1116,13 @@ class FreqaiDataKitchen: prediction_dataframe: DataFrame = pd.DataFrame(), ) -> DataFrame: """ - Use the user defined strategy for populating indicators during - retrain - :params: - strategy: IStrategy = user defined strategy object - corr_dataframes: dict = dict containing the informative pair dataframes - (for user defined timeframes) - base_dataframes: dict = dict containing the current pair dataframes - (for user defined timeframes) - metadata: dict = strategy furnished pair metadata + Use the user defined strategy for populating indicators during retrain + :param strategy: IStrategy = user defined strategy object + :param corr_dataframes: dict = dict containing the informative pair dataframes + (for user defined timeframes) + :param base_dataframes: dict = dict containing the current pair dataframes + (for user defined timeframes) + :param metadata: dict = strategy furnished pair metadata :returns: dataframe: DataFrame = dataframe containing populated indicators """ diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 394b98e94..40fbd798c 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -603,11 +603,11 @@ class IFreqaiModel(ABC): If the user reuses an identifier on a subsequent instance, this function will not be called. In that case, "real" predictions will be appended to the loaded set of historic predictions. - :param: df: DataFrame = the dataframe containing the training feature data - :param: model: Any = A model which was `fit` using a common library such as - catboost or lightgbm - :param: dk: FreqaiDataKitchen = object containing methods for data analysis - :param: pair: str = current pair + :param df: DataFrame = the dataframe containing the training feature data + :param model: Any = A model which was `fit` using a common library such as + catboost or lightgbm + :param dk: FreqaiDataKitchen = object containing methods for data analysis + :param pair: str = current pair """ self.dd.historic_predictions[pair] = pred_df diff --git a/freqtrade/freqai/prediction_models/XGBoostClassifier.py b/freqtrade/freqai/prediction_models/XGBoostClassifier.py index 3b14471c1..67c7c7783 100644 --- a/freqtrade/freqai/prediction_models/XGBoostClassifier.py +++ b/freqtrade/freqai/prediction_models/XGBoostClassifier.py @@ -64,7 +64,7 @@ class XGBoostClassifier(BaseClassifierModel): ) -> Tuple[DataFrame, npt.NDArray[np.int_]]: """ Filter the prediction features data and predict with it. - :param: unfiltered_df: Full dataframe for the current backtest period. + :param unfiltered_df: 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 From 002a46c5a0036bcc1ff05bc27bef4296e98afb54 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 14:16:37 +0000 Subject: [PATCH 34/60] Fix typo in docstring --- freqtrade/plugins/pairlist/pairlist_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/plugins/pairlist/pairlist_helpers.py b/freqtrade/plugins/pairlist/pairlist_helpers.py index 9ef3e4614..93d4fc308 100644 --- a/freqtrade/plugins/pairlist/pairlist_helpers.py +++ b/freqtrade/plugins/pairlist/pairlist_helpers.py @@ -12,7 +12,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], :param wildcardpl: List of Pairlists, which may contain regex :param available_pairs: List of all available pairs (`exchange.get_markets().keys()`) :param keep_invalid: If sets to True, drops invalid pairs silently while expanding regexes - :return expanded pairlist, with Regexes from wildcardpl applied to match all available pairs. + :return: expanded pairlist, with Regexes from wildcardpl applied to match all available pairs. :raises: ValueError if a wildcard is invalid (like '*/BTC' - which should be `.*/BTC`) """ result = [] From ee0d90d1aac8f2ac3197c6214b6353c20836157f Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 18:03:55 +0200 Subject: [PATCH 35/60] Automatically create freqai models directory --- freqtrade/configuration/directory_operations.py | 7 ++++--- tests/test_directory_operations.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/configuration/directory_operations.py b/freqtrade/configuration/directory_operations.py index f70310ee1..e1313749b 100644 --- a/freqtrade/configuration/directory_operations.py +++ b/freqtrade/configuration/directory_operations.py @@ -3,7 +3,8 @@ import shutil from pathlib import Path from typing import Optional -from freqtrade.constants import USER_DATA_FILES, Config +from freqtrade.constants import (USER_DATA_FILES, USERPATH_FREQAIMODELS, USERPATH_HYPEROPTS, + USERPATH_NOTEBOOKS, USERPATH_STRATEGIES, Config) from freqtrade.exceptions import OperationalException @@ -49,8 +50,8 @@ def create_userdata_dir(directory: str, create_dir: bool = False) -> Path: :param create_dir: Create directory if it does not exist. :return: Path object containing the directory """ - sub_dirs = ["backtest_results", "data", "hyperopts", "hyperopt_results", "logs", - "notebooks", "plot", "strategies", ] + sub_dirs = ["backtest_results", "data", USERPATH_HYPEROPTS, "hyperopt_results", "logs", + USERPATH_NOTEBOOKS, "plot", USERPATH_STRATEGIES, USERPATH_FREQAIMODELS] folder = Path(directory) chown_user_directory(folder) if not folder.is_dir(): diff --git a/tests/test_directory_operations.py b/tests/test_directory_operations.py index 905b078f9..8e49aab10 100644 --- a/tests/test_directory_operations.py +++ b/tests/test_directory_operations.py @@ -25,7 +25,7 @@ def test_create_userdata_dir(mocker, default_conf, caplog) -> None: md = mocker.patch.object(Path, 'mkdir', MagicMock()) x = create_userdata_dir('/tmp/bar', create_dir=True) - assert md.call_count == 9 + assert md.call_count == 10 assert md.call_args[1]['parents'] is False assert log_has(f'Created user-data directory: {Path("/tmp/bar")}', caplog) assert isinstance(x, Path) From 5ffa3cb9ba4dfb448fb42d21eb8efd0b585c4205 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 10 Oct 2022 18:11:32 +0200 Subject: [PATCH 36/60] Update docs to mention `freqaimodels` directory closes #7570 --- docs/freqai-configuration.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/freqai-configuration.md b/docs/freqai-configuration.md index d24c60057..737f64824 100644 --- a/docs/freqai-configuration.md +++ b/docs/freqai-configuration.md @@ -206,6 +206,9 @@ If this value is set, FreqAI will initially use the predictions from the trainin FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag `--freqaimodel`. These libraries include `Catboost`, `LightGBM`, and `XGBoost` regression, classification, and multi-target models, and can be found in `freqai/prediction_models/`. However, it is possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to let these customize various aspects of the training procedures. +You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model. +Make sure to use unique names to avoid overriding built-in models. + ### Setting classifier targets FreqAI includes a variety of classifiers, such as the `CatboostClassifier` via the flag `--freqaimodel CatboostClassifier`. If you elects to use a classifier, the classes need to be set using strings. For example: From 724be0afefce0fd8b696abd7b221dc1271fe717d Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 10 Oct 2022 20:39:31 +0200 Subject: [PATCH 37/60] add tensorboard asset to fai doc --- docs/assets/tensorboard.jpg | Bin 0 -> 370209 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/assets/tensorboard.jpg diff --git a/docs/assets/tensorboard.jpg b/docs/assets/tensorboard.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2aefa869dc475aa007fb4f1fd4dd52cd0b9cbaab GIT binary patch literal 370209 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

F1#i1AmU@L`9v)2Yd4cD7wj{2MC?jO->f ztShW4;73k33~Yk0nHNeGGl%@Cs4_k-=8k?D7)`fvFm&TyYYj!;_+BCBhDy@j#n71X z7ycVf3}&*U6J=@s_h~fYqscUU|4&~a?ByRO8S)cnnX0tvwpOJCP=Vf@Zyy(l3lv6=`x9A~ztKIh17*j{=br?ns``Uurw zt;ojjA5=j&?_%c->8{{RzBw{ZDmaUOF>H*Uw{b+;;EL!{5PQDG^4q!gVSKDO*)Gv^ zKKpgYCkh(a-VF}2ly4DfMz$9O9!*YV(IJ&-4X{wl=Y$i2`H(Gpxl9g2XW~NqPziq_ zQkqB~I?Fk3A=vebgZ+rH667Aetpah+7U>y^^{qaO3X%ZmS3dhurmt!JxrPFDIwKaLu`7| z4_(8#Rsk*u2TqOv6IYR%Z+<#0-!+hKOm4Zd!)K81{$0CC z0u^sag|EV|EEmwKAirUEI*e!^Nxcifs}a)eKu48z{LRi^$N%HKbQ{Twk>Sn1_(F;J z$J-~`)o3^H!-s!MHvh+e2HnRp5kzQnvM3vybRK=Wl=aeG5pak4gsYB6_W%Fze?JBp z1D4BrViq5mA#c&{x2p?y&KADfM)6{mDO}zR1cxT(jO1~1CS$IkRrTdp2r;BX%d>l8 z=_Uo_G%Sg(3-BRNRtI*oKkg8r!-F5yXBjRhj_NcOv#m-YF;VY}AXLAIyRttE<3J!2PO{^h6*5MIDt9D@ z9B5e*FL=2byHdjGg~IM`kDO8nA?usF`aynU?!D^6w$m}C2;<_6>9ATus2<$JniG%D zDWWdNPu!Y(`r2h{jkfd>ZYL9wYzlQwx>Sn>094+g6D5ZYcSW4c_DCzyY%hYcv$S<% zu`^2{TTe0qLTOaP!(@c||5|TEnV{ES@>L?+dxPlQ7{I1}y9Cyg0dj|!VZqW?7dmnJ9Zr>-8jKyp_4{ng zvUo~+ZGhcAbQXUwiBho=K7)M1o8Dk(K*$SEsYAc z?u+_9Grh-YpWG{A&tJhnTLu5)4*jz!b>{a2HX>Q^AVHN_hZVpi65+Be#9Ifmnw|;r=3?6ywGO!xvhv1dtQ&T- z58J2)RVcf%n|*io%MfPL%)Be;>H0>t;**XDkP4M$Xc>=Zd1K%q@j?s%nZcSOMe8HWvKphTA*HvWm+6aK9yX_x zWs$$Kv^9BU@K9hk{;Aekvc5$JxnhdE6(yix3aHlN4LZqyX(DK9B|*l)l5#3;mNta} zIg%3EY`v968kMTUlz_438-u!Y_TYLXNd#tUE zmm*`n_Bdo7=r{ex9RjKeUS?+F?Yf@?SS^FLXPXGQT#zckTm0ybdDXPnpmqXE*?E-< z2}QOiLv62M8Ra^!rErZuX=)`Y*~-2wUd(`Tv2!D6Npr zB2#?=Cq(o8fEtP9ykarIqLpQxk3o?Qx^43_xk)M>(KgW+0>!QeH_TlhwPD&vlz^hV z06z!Ah6}kxKEcLmp{%HptcK@fg_sqchLN(>*VLT6 zw2YKD0eWY=7&FJz!3T2n7CZF;SS{$BOv_Rs=+MAh$9cC4&8*~M!PPm_qABF8?v5;G z4?wmbagRIp^hNYjtB_ ze9d%inNMI|k5oD|kX9>9x`M7uinw!=l4d)kLS)O=6I2whOJXub?rPI#qw^+Qu(WJ8 zkiPHzkakuj86^@SRBdZ0_DJhzEV-@)H|Eo%p(1$XIn=QCb$i^(xU6c|H1|r8WsFU^qu?V83z+103O{7>dVR`71LeRjX2mp+ieEIdSHK~+&ced7nZ{5d zPtd;LKCE@!0_cV}Khn5&m*uJXu#z@rI@m+Wb8`5Qn!Ketn10pF-#v;C7GPY54E5mo zx^l=W;)_|oF0ShzO1e5lc`}>~IW%B}w=M`0=92yrTz*FDeR{*sDPhjp zjm1P2ZX!)s%TlKG!{G20;CaC}_EQcVx6HCgg~^%l`lpolb%b;*FKu-)jqB|xjybb8 z!Q7yF@HQ6-oskf{mkE|@%1nSG@A^nBa$T*i54Rjq?i@yHI~Ar1I6L6vfR4?y>EQDl z@lMI^sdxE|Rs@X{ecv(iM|rzY7Oii(FHQnppPB=rbF$N(;f*;K0Byd~ca+2)(iN`K@$7 zr*)9s9p#Mo*gwQ@2X z!yk#{!>v|12w@)8@lG5|a%2nelz7DZ#Ye096h!w|6}F9)hbBw@tTEe6 zxhMLvavg+M(=*>7=@1$H`otpK&p;HTSz=#(GOtG9LylUCB2CMjOv5l%wajSbn}~X0 zwJUi!vdlErCUj`@QJE~Aj6$Lo9N8}#fC;z&SIY@;`B-?5pINFw;uAO56(Z5wsiZ#LRKwf*^B^2k{s|;*eMr;5f0&N~)LvoszU5d1cLhiAEc_GU^ zkCah`d~y2cDCP)0?*`VSDth4`@}d*QfJ55;1pH#|GF6jJKTT7x`&cWc67$A$$f1eI z9oEt)6-P}c^GxS*`dapJ0p+bKTGqlE8pwbvQgyQU$dHU0KS<8PPRdLDpr+a2dWQx!b|M z$CfIFwSq%_$zees(HmP)TQ-4c{#b|d`0Sne7c4p%oNJs-^0!M|pIV;5r;*1B> zFTXyVqzj}DqtP_3;r1b_?NCRBl)qUHuStOL(1%MUs&0C4kwU33w+M>gJSnX=NclFG zWBcHxVwT&+3t2;NEMu*h6fD^FtXcZQj38WhJ|}lvQ-J^-+3^~l6Gvq##iE|D!5o8r z3m9$<1+v4SLh?)Hq>4mIcQx{^!1x7thWgnf?!GR4TUCQu`{$SxT$davvHw@KJ7 zNTMstV7r@{uVJpwq>I7DCIj#D@wfPxjN~aP5hw9>*Vh^C6&GS@KOzZB78l@Sxht55 z`(*O8-y0yjlXg3->6-*<`3>ypk~@u0J11cx08(GOF?d{IDc%q9RG}S~3OhRcQYJXQ z{Vbl=Bp;PF+ebl8H?E^c+m0)`@qsJ*s|`&RYZRqkY|B)7p?kt4d)o0B8P|k|?5|YL zIU1^+kL|+VJsPc`=M#H9Bj2p-lGRlyl%=PGxrAXQyb;u?%w0KermCt@9G^r$)(bXUNP_DVM& zH@V4bZxy|gg*)bF&C(_I<*v4#T=Tz-RrqYC%$aw(vB8!paPv_e&06>$e*2C_Gm%v???HVX32CNf$8mNY#F@ zw8CFSp79Y?jtG-^K3WwvHL?;Qy;$(+3R{3V zn6n!!BbIZgfUC0;Po{`)gbn8$yx6mv040}D^TN+p8gD%L6a--g>>=U|`0YKE#oMJ6 zUYsJ>uP`nv-{Kx0jYCUSIdYBGUx9i_ofm<`weKC*P}h7?bFu3NB&R#cFTapqxL#yf zIQH*PlwVD(FaRXlWpAxuunte-vl?C%9uUf`8**kj>Nmtm1oE#n6iF&ZZ^ zXMX)AES?Jf1u2~QY!M+2lRd)y?;mto9?wa7q>4r#O7S2bst;JD%D_1J-0fbJZ_Q|p zk(jZ6C)}jfXE(@ZpoYdYw`%*QS3#?P|dDNlQV3S(Kbe;sLA5b42HGdJf!1ns}B zs`Yp|>1Wtt$4vTgmulqRiUL%?aimx;J)7_w(^rs$q?IFQ5}jk3v|AW0f+EhW(6zKy zR{N>>fd1UY+Y0?w>MYx_)Y0-)r<*VdD9o%pM(M!#Q^=ZPJ|{k*lyjMI!<*A7Ql|%2 z4#1gGA)$qup!+`^1;W6-j`k$lve+u3-RdvJsEq4X%{mQ@q+QUA zz|B{3cH@VQU@jYdbhs8Sa22k>6@2mlE~i+ikbsEL6SOUQgVWu0kXZKMvrEAkwRY(6 zo;?ivxoN~>zpI~_@DJCh)P?e>{A5e%PEjqd`?`kw@-OJbj5(MC6mtcM$>g=e+qb% zgG|cqlb|?0ClNI0=}*!1NHWuziFQ*ubV0$3%IXj#D6*7Nj%v5UVT~5}hd=J%J>EHP zT0V#i3{Tors;?Hzj&WoA=-5$VB+0;N&Z1`_+r)scewQ@1v9Kt6_*cU1`sV}(6|3b& zl>)ppL$U7@sj=~Je9vzCwR=l~`x+j{;+Bq%TO-)M>A^G4HBxP|ub`m%^2SZBCm+@3 zH+G`xT`n7S1jE-)PYB;r7O@DKT}4N)+Qd8^vC*EQ2y~|sbYO+S1j72VRyAajyzQs* z2w3pwv>cUmy4hJ6vf}8P5^iMO;pqWM92@I&AEmTnud?#?La0qDJG>jmrvjXe;3H<+ zMf&1w+*6zWv#p7Gn<$wyI0e7Di|!;ww+`hb*$r6ZB^79X48r)+ff7@!@;Ptw>mMXv zwjD1gov|%4bs;r-*4^qg_Jy<*@_Ue)YxSvSIdKPc;MhOzm@R#{Q(pBx(My>t#)x(F zo}AKcrNx(Y{9_qVWlo#fdY!7s!yH{9 zR7i5@CGRe;2oX@wk%1Cq`F6AkxF`O3ren3jw;f~NORE2s9O+|O_*gtU%m_?dgT=J4 zXw;T=jc_xoWZBd+H$*L`+Y&{ufQGosn;{4Fpme{Ds1#v=LPV;rVWEE%fTh+O+-xRz zR_7y{tge+_9l1-Dj!CTr$$`q&V`Z#o6H(w~=;5?u4f=wI;;xl_s+rjqasv}&bmu8J z;*CM)^!Q{KRkOe3Zv#{_-zr(}i+mx`u(bRsO$#+(6UXJjj5ZpbGa{={Mg}^4+O0FDcO+srUxLD}1~#ad=) z)zvui%J#D!(X{L8m&-3s!}SJl!oqsg{3q}|&&z}4BC%e6PQadn9mI%{-faW;_+9>U zUfZPqE>%W?)_BXkuz9IW(`&pv8HCd7{uQ=_be_-d??G~!nIEWRvEsjfjP+IL<0|qK zOn0M;x=Hy=O$LxkNN2E+N53@D5{BE7rf$WAu~+oKozGk8hk?J!a;+6p`UdC{LojpVh8kb`MpVsrWbCdo~GUbzJBei6KC5605@D zbaS&Bd<>Y-mnzN>AW>30N6E)JgeTeZ1CEM(TouCiTk{*0es>2rY4bv}AY>*Uj``y$zWqsis z*-I6a3ozd1GrOWCXyTh6m>PK@JScoa?PCQApz!KghCxyb~U`HJqEdyu$ zY)*qQRG^cgzF-4DSy;cJ$x+?%APf^F;mH;AbuCxj$o}m@-LHI&Cj72C9Fr>8O!i^vl_M{Y${^8x1FSjbmeKoL04-s$Xb8<{CGf$Lz4{x!* zh2q!VxR1|qKgqfB?eO27=2+^Wo4Xc4eSNBW@GgC(3kz`jfA(Kh@tVIMCf4Bzgj>edO*zy{Vz~-86AYhLi~$y~ z`tPQgl!1oqU)HkSY_hHykjl{fKS$)x-l$W@sreC$<1hSI3w%i0)ISI4&)&(Yf8s5I z#zPnXT_}GA<*EAL#*X+*yRz<|K}RO}-asIm|BKa=I%Fgd!;Lir+z17k< z4;+~}I{s_qc!0Hzy-~j=51t89Tyq-16N;Oz0qdkHm*g(cmgfX8exa{SY@UCC;D@>B zRUK#tPX4>4@M}W3|L)3n{^{qpR`-(iKQwspppG%|R?*Nv9J}Ew7JtDWx0%T4{wYh2 z*?LlRki!U~W9CnlpXV;soKg5t|50&16$`^$5IU)|pBOMypz!-XWn*^;N?%YpoImAY zo_0mJ=_l;r-Sbufi3dz23ZnC7io)EK6C#jE4|0u#Nw3ZK7s^d2=qE)vC|fCej7pd} zm&?F{4eQwetEZZYJ_iueNa|`M8r=xAB6FoGC|cIjO%s0yN&*#fMgqHdace;8etYvk z7STdEg)wV?fufO?f$oMJn_mvmyp*h7`k-pH#L6fldFK3VjWlK zA9or`w~ndP=*2%hrA*pqrpZmRwAsMn+u~!f;|O?@xaLy6%I&!3YnTl$&#M{7lRtV{ zmf(2)MVgy)<%Z#vG~-)AhdfwK2jw4k`sM83b_(X{2!(16Rx`%Yn?q~3gLt3;x)5De z+QiNVB*$LWvL0=XcKJS2_5-`g9p&UVz9Z=z1^R9u+l@7U$2g(2N$=pM`skuV&)_{@ ziBQ!lH0?IYc*ZYtG)7Qaxsz~xyKj6smS)Nwy}R1O;PTAO*W7s8v}xJemm1|C+)Si_+;{ILA1HAepV%o&@C{ghJ?6z`p`g7uv?K_{#hRpB;^J`utZAhTpvX|5%!dw*a( z$KT0*2KeG%IyHa*=^STyQ~l0GAp7gl?}QAO4@fmWygbg3Y}4;)D77#b&MP^n#EVEb&H((AbMu+wztQ0NQ4e&(UFb5GGf)9=}hCdMi5L- zt>0c&ihHhhd#*O&j7)?}algynxXF8p2;5#$p9z1Lj6AXpveWwfS7AT)ZxB29+f1Ax zG?JK4tWx%>{$SQU=FiIHcNR%GsWzXx9qW7*;S03(LpRIzjs+jnmbH?wF?+*Iu|~=d zr-5B68+KVoZ)$5I9*-IG0@@#gnNZjSWE22EpHO`$1E zwu;B#Ia$ZpV~UQQ1yWdT3VXkHO%2?I1(UE#Nt|%qs}m8nGL;gCY|&@ykILCFVWh?G zvA91qF^X?dNoxq|rOC`_;i0v&)4{aKqs`1z7>rh%n!Mr4%=D^aIkk-lx3eQu4a>|_ zr6y`w@tqo5=@gDM@mw8px2#ot=(x-s&01{9*#U5I4-(+tXhYYwPMgtwlG*r%F^?=| zu>Y9NI3pC~j6Q$6n2Fli89Au`UeUVWwSYO1bXMv!%(pfIMQw>Ct)Fd|I5`&mSUQ(h z@%GMjUb1oM8PJByEMV~xE zIa{BYxd`ffI5u^is1i6w>j>(sw)}a+e<~#%;(^lhZ3`(j(A&QiIE|ZxW*mh09UML! z-g)99Z1iaCozxaXoW#rOZ@ELfH58=vWKynb8HGWCsTc8%e2u78Z+<=3vP!UGwf4KLiPu>w&!~CR9RQL z>~Zyz1W#>#2C$ppK2l*)p<-c_`ai8XTlc;Y21`=mKkqZ((%3d^;(b5)CT4TdH-MF? zX;{PA-uEy&vvkYhHaQTZ`SbV0RGW@ua$mH)4Vb2S_3`#@9@t+Akhz4Fi;Sm)n55bA zQYsJvA3eJQVWdn!t+GkQ6sOLhV$`p#nIdaQ_6 zc$%WoP!x}mdR|Ec1xnT0&r70AJkVO!kg(Z0F9*p|C+t{R{B+7=C-O6eb7Yach{=z) zwglor-6MhGb;LG9`fjGxd)bKJ*%ti#z6D~Yn{fuPY|om|eM>z3y78PPV_-}J#?VEz zwchnYuEE!{=776ugPuNCv&b)>YT%`_Y3ta_$c#pP#CFPohJFmqvhv7kRtxK_w>^nB zsB@+rRVUB?gaVYQ8}~5IMB4LhABVw2Ss|Hi@qsP@o}}yv9GSU$)GNR`vj<5-8BTmU zzj$iMt(s0Z+F=P;+DFIus-IA{v=3?HKSBpYg-3o&tHW=2>;Tmo<+)^h zapoJ9OmL6+V+IJJsQnJ6!gj5S27UZIZ7f280yJ7}#*D(Ju&Jwe>Z z!lB?f=EGJ$Ef$ASQNctNtzFSj{V@K$N>*cfoVmTnIs1m}*g^1u8pqI1ngFbhL~Wek z=&o=KRv7sjkl{&exS(xmq~%LIHwc*~yFje7>ygYNI;pBgMKo%$;5$)J^$*_~8#k9& zReLul`~St>dxk~PH2=a2A`+Io1PMx(C^?90AWF_zB?=M*Ng^OBVaXXJgGdmGk`WXY zSaMpjh$vCS42xOR)3XbR@qW(pzt8#bzGtr4*`A)B`gK)TcUM>U%y>EOdph%qj;7Sa zq~&9LhJoVa6K{N;NY)coxim4V#V5NzG!|GW5Rmo4kK`u&mG{SPtG2>EG{^QOOUcylCgBqW{vD(38c_KN3l1+v;?xVyTn$w3IUQg%OE&bcio%dEfd3 z_j`QhBIon#E|-fs5A0YC4cf);zNaXKhS!1?Db4pt{p2%=?3d1OAq85yrqCw5$}!mG zCC&y9lXueaW6mqvNg1k`8^3fyj={PIidKZKbMw^@dc^8M(YWjOyMi}v1J|o`W#-P6PW9yW0$d0b_8{`%G z8VQ3s0SG>m3VlKin<>r0a29fEra3CLpF-T`U9GFFCrg^G5RbyR|e?wTk>BeesA&yXYW)1uWfJ>b{?f_ z4)T8~XkK(U$*`ng)jB6@^g>aY6GgGjnpZ4OwZh@C-h)UncF!PHA0abGm_W?jxfI13 zDXA<`co^ILVlcGPK<3~rK9knbOhL=$gElN)A&d+58EF}Yrp=|;+1Nr?Wq8zJJ+lJw zB{^=fCp|pY6CveK=O3)jzVuW{e=P7I;q)4UH|AWvT1WefmUs0Nm11S24ysA6vwLmF z#v0w5bYe(tZt$eWR<)NbztdDcNx9LTm@NeK*f+A|-u$=sgGt@-RJ%F^;uuBCs=y^U|x!s0+$HyS=TRroTY4$)Y0^xyg6YpSVkC z87R`6IwO}Se8=GoH;*24qOr{LfhuPx;sO!=@`*~fU77i`Yoxe{fOl{5@HgSonG4}> zpj{)rMnQi+w#$v@13oE1jhAl{hFh$D;YF@UTk6c=cXa|)NwQ(7@$tpBEG;LX+reE; zXQuEWh&(|l+p&$aZI;SJL(7}6AFsP^hTqs`;htvOS&EFI`clr-1^M9<#NXO+=IxIx znRU%L#?h{3+Lc*qB)H4QbBJvCMpfdzu(Fq&LeU>RJN6WFuL=D;{@m`_493ue53dPV z-`X}LQbkXH`_USBAXJzuB&3o0aqaMO#H^s1*cflu?XN`224hve(Vn`CX(65&J$HNY zB3D;vP}6AlxNOfhnl$04cpP1`&~=+ATlt=vfF|ox(>+~R$V{g)+wcBnP^!&zaEhCL zA1!y819H&L(<18X`Mu&`pHy&x&Ut18^TGV8KbCY>Y%0> zMqi{NAzE8H`bY>QuH?_&hNCdQS18g7M`}nxKF|xH8>G}5c?iKCQOQe-J@5WOd`@Mo zphRny=~w_BMqlX!KF}M*nZALoJf|9!)AE~|+}dGMIiH3~d9=pBvoOmO!RkpsArz7x z_kd(%`FG;N8)1Wm6I1dj3|BEtRv8 z`+A#0rDp|AuZeTm+c}?xMP?qQw_F;hI7InNi>S8b|8*rS>|I-t9aYu%Y?so#R*7fa z#i&G2`pS}<6$JN$LNvL(o3@9FIiC?LRB9?IB1J@LSnD^{9iyHZgO?2>X(pHVpPELY zrEd~a>)T)?DaowA&`NP>yUuOtbFWc)Wwtp;8kUHD7>_p^M=WA2@xk&a};6-rRuZC0) z#e8{X@7QuYiZf_rGJ8o^L3bLC;t&}EpA@4#oD@I6q(Gf?tqlxo)K8+q6=*9ILW;Ul z!%>d@fe9_VZ+B70W<1-u&EOTQfc#hmfrKdH1x+hRdtJ>RdOMbf8V7Xh{GTP)3l!6JmBKkXGjmf>f(A&E^+9vgD zp-p(wj%BOu@w#=)jKHhhLsQkt?4fb{L*&-S|%OKXKYl@O|( zJ)Ao*T70C{$;Ck_X6VF?hMS{N9O7g<%KX_Fr-&@L)S^_$bb3^W$dsI@cJ zmb!U0ckFPXp5wJ_gUp5$8lxwft8e1|&?hZl_wlLnRds8(d1J9?RmvEL^91+^$0&u$ zbdW-Q5z*m%P&2k7OQgT!T`n-&4h7$Mf}UKAk?1kH!8!ebPmB4z zN>Y1)@>L-VxN=59R%asPIhVqFai)@Maz9%bkN4z$gVh!IGW^bEC_2U4w#?$Esy)oL zYme}YbuU|Rs&QSQs--141(WLvR`XHSEfcC8G*(N5+rtm;se1C4x-iQ=c9W|yd8TND zC9PMd=lc2fWp!E;5jLyev?-UiG{MCUGZC(&7G0F~la=+Q%A6lP#S~@>%=Yu->ocX3> zpr&wKU;?$$fznvaf4EOel~8&{lEs}p>Ex)jeg4Y%fS_5Ba#ci9HXg-6r;sP;D=y)c zLn!!Q$nv}6ukFd3YgepI1`)7f-j7?sG);M+aj5aA=BHhiZSLcl~?4LxNo#{*|r<7P@c?* zG~rtU0cL{Rl7#&BdA+AN56ihuw#igX8 zTy0ga$TQB#g3s8+hbP-iiKXGMISEQ$9}C}aWFyN%QrAbIYpMQ~^)zk_@{5b=Xg?Wa zLn^Bhe-)|ervWvJ1BKq!?`>YTlBd$)W>DOfI9ylYS2@`e#hB{qmb__Lqv;2c++oHF zj1;FYon|cGm$q2wX%iozdomd*hZ`IwXSx;Gno;@E*G5R(ZoIKnA|=EsTj!}{AG&_kt;X58U+XKyf5w7TBx9%;JNAMVfQqW)jT}y z)7$}##P_0kEe2^5T`dK2r#@=s7Ylnd(nq)m<$Z!@P(*~QrsRnz^@r{=G6<8cJS;28 zdWOyLI_*ouCCqPNUUweYcr`nLT6JfokOr$Wh}*>h9G65S1BnGE}7 z+R9TGKJ^v)X>9>w3Na31@3{5UEk#9DE55(nR=Q3teKD8RgboqJNO~;h8T*QF$5G~V3GDr9W1!C zqvFJJTtbwLOQ!WN<-K+FkB~x*GlYyA_!?6f4El7GNEMq2nH_mQ8!+mSHe!{nWZE;+ zG~CZJ$tCg3sJ;bWkaODHd8?lSGb>a<~Fr33hHMz27M%Livn3}oI z8_CIcX)8aA{1T?O(DGo=%dy)Fb@fhono8K~1Wb&uoL=3iez$^Pj1R}-Smw6flSX0T ziy7z7>4{W7{vs0v7JVJ~c{WGS!c3|1qOGPFpHh9hjBwx^ot#}Q5m4_I)0%3{ZLQj~ z>I2-bEX5^-vTF97p056D=n$5$)3^qqS^{#@9W}8IOG- z3M@M&l5bYqq!scyAV69}>p z(AwcKS+m4%)2iEo%h)^ns2r#zpUv_m=WM4`*Wy;1;vS;TCMAEDY_ z6zgMiny9x&+=VGz!SsrMZ@VIG76IeJV26z&Sfr|YUS#Ur;K#ZRM6~~LfD;t^NZt(Autg5 z1+8_Od7PS*6QxQSbv9JN+4yCkm_=O*`CY#Yt!9Fp(UvnMhLt5BPaK#b?e&8X_c2=} zyWJeHkVEa0u!_(rOe$PejVEXsKfe^F)rx!1 zA5tRc<V707@d>0Cdms-({54Z_u5-clM8Po9f}La*N*5X=9444F z69<^`K5c8=N2WgMIM%1t`ta+ZiBOhKMaY(UdhW`$1un~XtlRem6WH~iwDs{g2K7Rr zp9&KjnW}0zBP7_4_XvycHTLLC*=yT+T=-h4jWXD#rZ;DElIRBP}DK&R*MKQ2xE|+$0HMje7Swi-<=JSw|_^V`(Em2&JO>lPu zvv3L~?$xJ_TI9ALYfZ@K^uBe4zO1_9YUV-^`OO+kuETBBB;(OLL~1-_mOuIYX0yJ* zaIcn0;Hi>jC3iQereAuSdFsW@Zb8AJjKr(%R=jlSyE9JozPqWfrDND( z!gr}NJghAkEpxj@FS(>$ zZpnV4PRin_A?81KqN#g1Gj)ndlxC`UyCsi@crtxNFAddM(*9N4-4J5_$9w<Dx39HQaxK0cW`Zb}1cBS2rPGREUd1&LR zvHs<#yk~W;_$!att?*9QB~yNgDNl zBKP{cSk(xF3-i6%-tJOD4~Gk4cRs8PDPvNnm5h6$B2z~RmZ&W7dC|YxV=J3TVnmoq z&zO|PqHf+3S)qqI6R}_PIv@l7MpB)3-dXcC<-i?g#YGroAUKRq@#o^5xW3s~qmdcH?sY z0X#&TgvNSkV3lWo?|Qgv$0*sMs&zthl@{y3tO8eapwFVN*?9jv+*Q_R9aS%QEm@x~ zxT}5{k^P3P{ZxmFYVBJtN5d+iJU4r2&?ubmpo$1jRzSVBXlGn`PEqHUF4vyyZD>$^awVb;Y#m-QVk^{uHs89b&s#(pzJ_!)Z{ecaLxBkV0%@f&hnak74|T)}@-q zE!0*FWeYf;^T(l>mx@v9?|ffsrW6e>=TXd?pe4jtS}!%`@&u{Rrl+Ut%@*3*i7GMs znA_WX4k+1SCCtHYAVWB)5x;xNTZK0>1k(6yy^*X-+|oBUu8x)xbg0YtWg1Zw2dAbVl`3_j$!N`!F44n2_eTiGT=*yMZRz!{bF#S7oEkYuA?{I} zM9g*UvC{tdjMu42Z){JKq@sp6q_YC3ZVg@$H1*!yl_v0%oWxH1x!!KOoH3Dz+?&Oz zA~NSV$PO0?d;o8jG(WPs-ubOQ$huM4!&l+&V(ZLeI*GRCnKp}m?&4MoPCCY=Z-niu zizx%wXw!U%Cl<%0tH7z`fk_8NUE+66?IbRS5o(#jl?zM8>MNH>A2-}3w#TPAk?kbj z8Ib$9nDj0yM?8-+_aTL*-Pqo<3g$6~1y5iX&DaWV>tr%MiwJ%Aubp4}UPLcX`Gh!iwmrf}ssFBkxen=EZ zjw1D{-P1j${(QJiiSzcm`&YpG@zocUNNpWr`)TzJv#+V=3+}z!ZCed2b0BFzM6 zAQyxwG(7FN0S9o+LV`DP0y0>27|J3puQfV)HjnZ*uIcwjZ3IEG8V!{#dG78sKk%c2 zdX^_eE#0>MBjsf)rAC=qPI#)zorpk}>sn@$Z**gaj0NtWFTfcxd%5jrLg8NMypUJn zjZ3v_b>QV4@BEHG(;`9dp}w~eN+U9sdv<+1{&O?54QJJLzTL5FTc>%(0eC<)`QU(3 znd620rCdStW47CqPtS7?j`J5)ntQ$4$@&Q{87h0wYNEWNS7y}yQ}nc6<}+3fo>%gV zzNan(WT-8EHzgDswSA1~ zt>wBR;a1KjyKp^1`O-EuE%i=DnwGXyW3_W(^4Y=yPXw9ImaU!pzH*0| z^)6g(l$gk2Z+?-{1yzIoXS)I^y$CN532|yNGOIm0!YD?@Mx!>2^)M2+rz4h;B*Jy5 zs5ZTHjBW0~F&&;i#2x+?p-X9?Uk)!X)l%|$oIp!UCoOQm|J3){ zJfCEawg~fwE+=X-UlUdpJ&;utmVW={Gh;xpi8QCKp>Q{6=3Cx;`|biSW#s|zK&ufV zNr>+vNxQJ4!u9c64qR^=a!fZD)2=Pyeb~s*L`D53lIfnr1!Zo_>kgNr*IMH=Oh&Ki zXAg|-qFV_=FiE6JK>onTS`U2VCvMV~qJWdqm6(IX$w(p*d9vh8xI(&#y1}y8-CO&q zqpO`3KEC=}lNoB=Je+)4lQu$)L5 z+s1v8fkyDE)G7Tjo(bi|7B>HCL6WhxK79qQd~JgC&hnEC-nX}9SkxN#yf3i!SC#TlrNc>Ai|ZY&;B)*o-3xQC3WMS&Tvv*#${uH{8Bpy4!=)#NEsp*8*aW z>lfUR-Y_kEx~k#4S~Z4+Y=_%- z@(V0pTV2mnzx*nT#`?5cKz0{z`5rBS#bb-s zbN%!qUDd7}C$fF_h}?-@tKB(r!VQupJcmI&g99HsogjougvPel$R^u zC>)N+9S+Ijh;+Qx+lrp!pK@bM+L8DQ9&|g~xmz|e%)l;gR=OV`fO2yon^UkP~X ztH(=@Z7WPGcP#IQ)2VRlx&65Idee5er%M@2FLHc@vUk7Gi<;`*)?yp>xVHDiN@c~z zbQI21J*>GDQE`ihtGeTUP~A~&C{=Zz{2fENDr{4%F4MRa$r}omK2F-uUgl54;{E>4 zS3^E6m%U-od#amo|D;`Zinr<4GE!-_6mK(dnzSgKoXn_tEq(pcHLEiZr9m3#TGS4D zhHg4GedG1>q&ef1^LC@V>tB*}=a40CliFz5f+Qbl-rdA9RTv zwy;@6f)J*!8M-K4ZZfq86b%$z*_JbPI8(|G4uGeKIUJd*YwJle>bq}slQmY z5|&(8yr62T(2PU$=CCWxP67esMg9x;`8c1mUOW6BDetJG+qpBlA03e0bw&1F()=bZsC6`M<`pd6v#?vAbuUO9Zg~BIzRcv#KlirBuH>g-{qf6Z< zR9P?C81d?D_PynX>C^QEdzDnDbgmfk(bW`oY=8TS@Z^O>r$np#-nif!TH!M;#7-uN z7h-|6Eb?GC>D@c;ARP?te4mXvaM{{!*}a{*9v3Haj*;TZB-qL2PG9>?Lr=zKKjH(||TU&58kw9@lv!Pcnyp29;5XIeET_|GXx8(*rNNkp*>u~jucb>9omMR19#D0#3Ua!YQNG=l z(p!*6xaHmX6A>j<;h_~wmsh!;d$MK}G|?yD731%D`hl~X$$ch&pSrD0_^ik* zVl1h*kPETmmBd!O10k)zgjnN4c~muu`wzPF>IdDi4}W~MsUVk`PVR^q6SI5&JK zo9PkmVVz~~E#8uEu;j@M zd`X0=G)T2jhQMWV0QYGia;fcJ*GKuO7oDdFq1B_%;UqHHRT z2td=ko%|H|JJqkTUCO@9w86;8q9YxBysf09b~)W1T=B_^Bm{qk*#-Lb0K+7Z-tQX> zdLZmW2hK}!ix_-BdU4jd+h!+qe#mp~YdW;)Jl=OB%DRV+!1p*)&m{pID?e?6qD$Nj zx}ixYE;~n>@QL1yuK>d^3 zO_ZzpkvpXd*T|+u3&!5gIvFT6Yjux=EJT>-(6wnDj%CP5o?jFaq(l@8c)d=ajVX5` z7RuN=t1+o|6+>&3loHE;O42Z)8y+QNBp)7Xx(FUJS@%=nU$=~VllMn^3nN?ok2Dvv z9Z$76)?vCmURPG}J|Jp17QQ{h;q(~I-sC<`?23Y#7MV!F%ERDYSEU4WZ zOg~|BNj>_(;nzj)wSqtFHcg?uVop~!ClJm};H`q+B|wDeCc_lXT3n%o;tcGaqj+Rdpp-$nQWn9b)xR9rjl$T{3y8Y?z>9 zs82ODXH4Fp?!q*v7Zlp4PrGo;mN3TUOvRPi?t)2=+lq=gN5dZ3z2#0Vw>8O**%mje z8B`_M)gUEc{oqR(F}!ui_3_c%1LupRa$`R?McF$z(H~H}d7F_e(n70UWbb{gOoC_W zrjg=(zKwqsp(edu< zrzzz!rbZv@zd((yvPCSMq0YX0fvKb^JTXy@nNj<3Xl$uNiV%apr%rMT?am!XGHw!_ zXc1ht6O5Y`m*9TFSabb^7&0#}Nu9?RF=YX(_zHCkqZ^-er7VwX14LU z)4sY0>GR~1vb9MSDQOQ^TnjbQ_673wU!{GgEMMIC4c5M?k!uxJeEW+17~{n(5I045 z<&&?!JUe?-8Yw7XbPjX1+e&!*^F(HO=GMt;!St|n*~eiP#}ho~^XoW>uTMs{x{|gJ z>}S66)T@5%L{>)0Nk`++sffg!OGb#sNI!&_bSY_YjNElma_c&Ol7-~7_=o0XYI4U> zIrd==kFH2F7e=tAXVg_5SUaVLJWFVGQldJ^s8LPoNl*9_dL#?rOGCS5d@ zp`Cqii~LA$;Fyp(SqGjsx3ne_j61Adk+`Zl+!5AgXB0@YJNp}K>fM3kkvmF{YrOHL zkQ6z&a3`jjV%|2dl{Vi;ozINEX`VvF@U0S07jNFH>*ViyC0AsRs)W%t+rKeV+}}zh zwA-^fD}+PK$}Gfjkx9KH??{dUO$tk~|5?A<%dF1B)j1+!2kq$h67%+`7YB8n#9q$j z^vmPv-No(FQ>0vy*Z6K5<-Q#2z?-d=EfE*gC3eeooB2@iTgh^zF1!kT7H6*$uj`@c z`nhcW6%%oc-B{p>rtKUdr6tThG~F*cZkGAvtG?4W2rF>dcc<9w8;oVM@?rDyVhqqU zH%j)tA@e{qB}eG_?lqTJ@kvs5rgJ1Z>({JgpuMN$rCI|Ou|i_>c_UTNGo;G~v>`99 z35O+!2K1DuW|i_C7RXz*-D|5RAD#RFc1 z#MO>@o}Qdp+=*)46wS*E4!QAjAH*?_vh1ho9aA2@DDBRU5=)D5y^<8^X%IoFbWJ6F zKSNcR&;6a^EJfoIo&zpfZ6;Cs1hr|Z7X@oIq@vBl_uexr9*fN{c5g^XbrR4+^jRf& zKdbU{Y|YowRUhPUZAetx#|hqPim(?J({|dKk&`%9c$DEF>e35Sc$*)J6y4|krTCWc z0SaezN4}zw%Cq^;kb-<_Jc$}zwmbB@($CPma*~vOiR?6^EoO<43O3`IXFgV=8`00p z?s3LR_{59)D$j;1qu9BamCBTyvrhS%d;H41F9%0n((szd3}>J~SsO*kMHJc|I^$Yd z%voLHJ+@LUI4VUSK|B<#HsJmoO=EBc@qsdMQDFr2QhCgE&wVE~_u_r0Wap-_!mW}+ z{o>hK{iWdLj6tlb*6^zMRb3_03o+52`_i7$(7B&3jX!0z1HS0qHm5?A%cLhCN^tXQ zoz+N7Au9G+q@5Udf>a(m?2?L-hP9?eZh~HZ;Y$hgp3m?+X}fM(VX~yKw7Hy>GaCz` zpf@i9N2<%#*WlyYnwOmNO%hr95?1 z_c(^gu;#k?$PT3-dAm^^N4LQ87kg^6*S2-W$(~2O$-LE`VT%YdY!N`EasYw>zMQ*m zlU8^y*zfnColrX2PTzkIdPVr54(NL^7i7FWT6re8)J$wt?~*q+G9?tyxcYY8y)cY8 zwu36TRQ;F~{gYNbWqQc~UdO(s1_2k|OJfs9+y-Rq0e#Zw%o=+P5 zeX&AsZ5no6>yFf|G{4-CXB(19dP@5hVWhx_wVq(pnH*a~{!&V1t;_sMbBEuyHd?8t zWz2p(Q?5FAF?tf1Bx^1ODYGPM+Qt?P48;eJk@xPF%2Qvx@l|{JinmVFoN{S5|| z?^cl>yda0ET#&A~k(MwRa{ds*=;%ypTj^1W_1Du6ltZtlzj}@+{#a?zBh|P78#)A! zpec)QT z{c(i)wUR!oz&ZifiueGhQiM`njcu1SM&eQhcK22NlHRdVROg=?tn#G>|iZ!QI&8btK zgs>z^9PUPC`aI}(M4QM3f*&3?=B^B>bMi;|ez4?!7mtZKJG@s-GRa;8uO)WSC>DAr z`|f#h$UTj>J~E*JKK_;OANnEDt-m$XW*oSGzQLfkW_}fO25wS(6#-9K*XTvEaT>@Z z`ToECzmNcRu!kGIF zOH5Dp8NRp9+?AuB99YZ%?enr=6_CzHDu6}_hi?qYqQENUr9|Haxda`)O zxVBS$#%(lJ|6 z_`0jJjN#rl7?m|%0J+b1u^a^+8NR;%J6l&!C;vBC)B&qnnM^Ads|Umr(k=BAl`g@j z{@=;}SO!5NW%4|F7lCx^@4hwtbf|3tD)6urNYxG75(bf~66^yX$aYQ>DDI!(JL$8X z3?Xr4Ab2y}L>NN0bMT~mHnG>1zjWx#UOtD|f9LYamjCLn(j4?}md$~LL?qPghyTMr zN|7~IR#~@MbQtA-_}3Cf3}+IxY5^~5{M#QjJ1ppL8QFpTIj1mUQVTP4UunH-Qb)2w~g6S5&CsqUiriyA;9yB_P0&)a`#2Yp`||gT(Leei4^cG+cCm1QKH_ zH#oZek^s8&x1FR}p6CiGY$MJ4iIF2YYtt9xzQHEZa7;5?R8ds4oq8D!AMS>WwZcWm zB96Yy8na1VK68^A&>cpc5+%G+jCKg7kev9uBkDaA`N!Sj*-7KaO*pVt3wHGT>3ESa z<~ynsHIrzf#piHQnIh3kiRilGt3hXy0bC|1NNt zTApZghjnxcRrlg|!C*L25l@qt9StYi2A9JAcM$*0U6NpcF(3P6Rjpf26e-$+mXSPLV=VBS{Te=qlfr+u-ZZIO#LS*ZTokzFvvdv zK{CX!w`~7c#3=Ge8M)dcj>GzWJ>7;OxkCA`U>)@6UB|NRr*0+_5>?0XNJs>=61eSO zmSHa?pc(|H)`e4VBjN*L0yHQ-5&(Av$T0e^{pA04B?B@f0u*6TorX5hLB%l0pmB^upaRNDs8oKVbn~Cu-d;G~Yp@ z`wQB4J=~~h^Axf`<|A+KU;Tg;@`rYwfDkmtcr5l_>S{DxEL~HK4lY`XxPJsLo+Qb> zav1)6O0)yQ!nQ)knt`AvJ(qTTHb6fL@a(mI4)Q?kJ+hTA6x1HVz(?2CO-gE*Kl1g5^1{L6%d0gSHll-E ztr=SdU&`r`tUYc9uvRWitq!nl>PALqn)9}$>Xe$uvunh6FB@Per*Avn&^hoU7O-vp zxZ$xXF>t78x@cdz_ya~x82YYQPG9TwUhN%UFE21)1htOAFWp{7EEujFy1(Ybh*8S$VAw!T1sNkxrHWyh~N?Hy7!e* zp8K?GZO4F{0frh|&tLZwUjbr&O|J`!1oxy&m2`9BGeQ`m7&nv<2#weqWZiQ=;P5i&hc0wF#zi@0f{IP zyfP5Z{v$BHz^XObA*I(v&TIL5_OPs?IP)EtZxqz8&_0; zff)?kU7bc=Rrfc*p+JHL6hhnpc|sLQ&RC&kEy%dpy5X_bQ<^*39f9~7zWllzOd~(Z z(TBkB`rZzsr48ugYtaR^gwoRwFoFOghGJb90#y?L+rn4?1oo$G6YMaWRrKiP+mV{_ z9h@}}!aty4E)T5bx`IS;?Gr%sbyTyx$V&$?Hnr!q?8RPRPfH}@*Ka=<>exVF-mH6G zW`4ok1Ov>?#_}-S2b_rH#fhLXh>$qhqY6q8V?9hm>d3Hx(A^lp5daoxf%*nxf6!Yv zmUH0aB+_837*Th?SOt0!k+=1IJr~|>phICr6p^P`P&hEXMiuVKz9hMmv5#YxeVhA zQm3{CM&ibX$Ew1muVW#K8F>HtliY9|G6{oVe7y&|yisC32gT<3S228mPb?m5z~OyX z*6mMse&8$QFoXrn7YuTlh+TmQ*1W~M-zvmv?PMthjUv7;-f_qW7{q?e&eiq}tZ<+L zLh~3Q&}?BboT(Vmupa;MPsm%J&UkK>VF19Q28|5ZXExZ`{NKcatc}TUFt-u^8nO@X zkbB3K7LKw#x*=egxzHCZ_2n*}ESY3-I40{cB(YOmwy1FV1pm!oux{ zOou9ah!|Y`97dq`@fxHZ7}*hZyl&&M4u)aa?=>q7>mc*Ydw#$QT=^AZGiC#ey`|UO z{Sy)k=4dQGJ-K`L8?53RY_Oig@Den;2UH8*uoXBUf~Qngb00r=XZ|k@y;oKdy@r$u-Sb+Ifj(8d-XA`Ulof zcX70duC#B_iw(FdFT{}*o8Z;>j&~GX6KE5Wcf7mtsIj9 zzD%K8kl29R8-#!JzlpViqqB@bdP3R;#03W}FFq0w!KomK#Oop;yB@&DKnd_zfjGP4 zH#kt#CKjN^g+W@!BC+j4o){7uU@F2ySJABTaqDzeRY8E;7K6;~12tBN4sg){EC^Pc z%>*C@6#xNckaz{d3KD=AaK!J} zz(2s?q5;-7*c$kKgS~(Km*EH%a#d$-6?15l?4JTyR1m&C|9Wi3iSes~eM4OtVJCV2DjP( z1X%NN{~l{SUjSj?NQS|wZAhpCNkoH)U;*E;NP^nf|0DVQgVqaSQJ}>h*zBZ#s?^Pp zLlNl#HM#$D)`V7|MyzjxiQoMH%jJbx1sDbFp{-X)fKMJq2nUu3bubY-;0gxg`gip( zQXbGOgI%J!LOt8V#NNT07l{ZU5RGqz?C*cMexWo0%{KOCO?L4A^Y$-e1walDgc$6% zV_SeVGJu@#1E!1Ys*db$6%z8_fDyT-=sbn!$X~Sx8v;2YEQ80&0)XF_nmv%oBa$_d zf+$xN;t@E*X3^|~%CdPxe6uiw=kG`bc9J9xz^+6ib9-fNf0tl0hu9DbK$EsQRD2Lv z^#Pju4_>Oo{^(xMmmiU#g z7U>*l2q3V@6bNAP4n+!+AW`bPE^0jj?pz&F8!dKxzXGt9A&=1(zJeCbEFpGcrzF!O zh1W@;K{DWWfqZ5)81~hEu2O;4j1}nrJQ&NgUWl0%0^(hcg9aVz$$$(|7XcQII0K)7hLXWL6C=E`3eB`1|ADe5KTfI z4(5!Ib6c=*x%$r6)6OPHHxQ3zz{DM%FK`6PhT{vw%wtGa-?c%5b{t=z)Hai01HW!y zLA-3;@O-UCgXaA^RwfqG!*4Lh3!d$pRDP~tog%mMf6G`1WTwS`uk`CJ1gP>=o+KPqUT3|hVmYv8>bADOZETD+* zw-#6cW`i)`kNtZX7XnyVVj@srAbUWevCUU&dXYUxX)c1?hO7%}wTD$+<9lV!)0bN9 zlY6&c7*a&4Exd!<1A~8}zx5PgEu%pxtSbk0s(DrJ%?s@@NP6F8C>y8%$#4W}uns*^ zRbB0;Jv0p|J>cuRoFOc{_hBo-_wY|L#6AzF@L=sbyY?d%G-d{klmTey2hg4vzS(Gt zO+CbAU>y+~@=xAowCIQqpXUIO;l7E}wWoS)&R{^7FS!~9WQcRw03KU$x-o$4B-MJ- zXMbmP4PU`PBjvfZyh09qXXBR;;A5$O!n;_Ja%~QIn)aGT%GP?_~jIJ(l65mtSk23*aC} z7Xb-x%J7Hs3IM(EA2$dqX1(!Ujn_4r-r6yL$65^+ZAJ|$k{)=mYcLot1SSEKKx;`N z+6sYD*b?vJSeb%eJ3N{bRN8&^u_79`AQ8) z@N0nu;+I+cp1aKgV?kg16bFI+1`7j+3XHTI@$SoVFL=IVdTF)S|Mw*p_)l67^%Oz| zKx!bbpo`xyIe^a%Vh_J}K@}IT;Ex($QAIXZKJ>-u~b7%BeYDwtrLmug##~N^#)TQ9>)R{DF(Ut zSOLFP7^L_*ryE!(Fg*X`2C!b=Zu$m;BVSW)tfts1L45eU|0?{@H&~nu!2J7;4fxvt z9iTNWBk#fw6@DfE6CJ3mvSiA4{Lv-1c_TJp`Hy_z>hoNsf92{_^;qxbEk6ZT;@6hZ z(^bcpev1F~6dTy`cdTD;`LAPeHpd^)Hnig(3gSOR$A)aN1Af8$x3PeI^T!RCXrR0L z*Y;5CACX`%#eY)c|4@4C$y&Akg0<~0Ui1GV8$FQY;ZNH(3~~_68~zt$f4zkiG@pO7 z0|1uT))xI&3jcdCf8q&>-}dk61*BpWf3v0jmXH79nkM9w`qTDr>micJfI@PG3iJzb ziGJiD&Kb3V&GkDOj`**>ZhDXL|BN}fsWsp+PB7W?4R#(2*3_fn?wzdeozw2$3-f|6 zh{1`m=35&~h=u@0K)8*VcpCu$UR?-iU>sud*3^3Lfw@EMx(QXwD~H`$W<{;QqbMW< zAlV`6p`rZzBPy{mY|L_!UJgtDKR#u<)jDnyD*pNl$LP7;pRyk{&*dTuW0se1lK9bM zb6)yi`)tYo^>14i0 zq1Uo;sNhq5v;LglU>~Fi%Zp)#Y95QLzG?x5yssqXf*ERL9;&KG7v!jalJScP*9_&| zyMvK46UN}K2tO}zg-V9t{5RN>d!JcsVXX!P)9Tz>+(kzUl}~DO1i3n@4HG^;Eb01u zf2l_x%rgNdg3zCA50J&s`kl*SCsD^^Qz+`R<+&ZJ*q~a ztb0oLQ_&*(6<4wBsdo*g6mQxGw9*1%SRDc~(=lgv!`un1m<7fXm>Ir?z^5Jn{uqcO zXuIDKmn(ZsRlB7{OJr1jm|J0Qk+t=^1m{cjjh;?7?Al(%XJ_-^DI&!xEzQq=AiG;Y zgsG1On>}`dy55R>`n-jIQi?H~d+L{~pSjaG*&gJ@auV?{H$2sMtX*iO&FLW^xbjdq z*0@M$VvZLRPGBmPFr#qHZahlY)WDi#k>YaAQxi3Ke3Vn#h)HtLO3xW#y^A!OX)|`S z@^qfJM_d@f^IemyX>82yk_is@@bZ3MK*yLz2uAv1WHa>TDGOtFralncO>B$Y!{3^q zA3dz1VivtTt4V5YB$G;G^HBw{ot34n=#=dVOLZmthdr_0sT^FsvEEl z5W93{jG7He))3Rk^&*(|D3fX6GK~!?h$)FbCM|8cBa*$Hnf8@3&GnnQG#Ym=4BVY~ zKou6kK(I~o_`bc*V!y$bs-J7p?VeS#K2bmST3w1fx$#Q$S&JwMv7s5Jh=|G>ts(8h zri7K|@)dQw4mK0o5(NgQS@X#+SH%VT^Gh~(P}kQ!z7y7>HO|Vl*RT>n#5Z?AWwf@F zNXD}aemL0usb&B?kg1{LWxcy6fzQX711sz_vf7@`V=t&vo;IxT5qY#feAV8{L7a%f zW|%Qlut=XC>qr~#x<0mt>%xcP7@^peqlJ%ZCYB2lG{iV-{}+329TmwFrHK{}g}Ynh zZjHM)?oQ(r4uv)D*0?kdjk~+MyEWdpyF=ss_|43lx3h2eo!xVG_n$YJaVoMRD(hxO zMr7WM``zzu?R$pJSJYAO(ldXLHjA>uSI_b&JYu50DF}{$p_DLppNA((1(~`{sh>mB zWm{8Xz|sKL)QScZ$td8r9c1;{@L-3aK0>X@g8u@n|0LA5Bzmc>d2F)c>)w|6e62g~t{h>>GC~{KYl9fNy$^*y0$a z{w_@CS-j%oA^aY9;`hasMC~p141B7!pP*nyv0zg5N9MWe$MRpmR7(Ef{FA~~-TH2J zr4C{3B9$Pv5B&tsv+=P(s0+pKzX1M3_vh|8;;+(2@6~rFZ{$nwai@O)Up^=V z3;3R6XW#tZ3&-|zFl^n@q_CQx40tq|Wk{%qv>;@x`j%$`6~2oc)&N5duORbT22NjR zVXu~jG8EnO!(9@2;89EY%_U44NE&nQE8!|F1#Lu6<;Gzsg8Gih7!Lng>CnvZDuNm= zt26&~&BIgmB}4dDfhnh(1e?%K)n(+EkH5i7{}KCL1zIPN#k*R*&t%cUlnn}Jp${H? zqRbkCoSizx{zF9|!hq!oVTRns`7*U4#q}!GJvoYmE+}iO!8v+Ps4(f}?k}#!4pnH7 zUI7vLt|ApfKJXX7wK61tr=^*JLiiCW5_ne_BMl(#p|<}`AEP<~#Tsq#_9{}c?-}ro zRss2Qh18X&E#-|~w86@|Eez|-BFF686MKs)hnf2frvs}q2i@R?n*WZ&_F^hwdkH$zI0C->S+yp4x-l;_S{rzv070g{0XZsaJnQ!rSVprfm-*)%Pir z!u1>%4@{ML#g!n;6->K96vK-Ux)K2Lc6;ZHCSN1@!A3EjG_qI^^qaN;P&x z+xQSHK66&y+5E?1Va9OCnUANQT0wy!`ulWTi^eZ%-qMHPA-R86X(&T=FGx8Hkv9bM zg;)v!Xts@y%AK1vU$|}Sqt0urf@SCPlfXNiX08u8@vt~CUK_%(VEi*%{s$|`Q!{!j*AfeE-WH5WL~wV0$%BteyhY{M7>7dUwt@%-Cz_h0v&m#G(9#F^{B9x8q-helCOAbJ7$|*d)xxP!Kbolz-Pa3+XtO8*@j; zdWOtl5Jq+agITqCaQLua86vUn31&6;9&Np12BqZFhhBYG=v|x1V`MB#GzcgZpaf)! zr?jYHjJJhROX)JhJEJ<7!U#GaXByY#GHh$^ zmW}ppv0(@Md4;Q!2g%eMgIxu<84UX}EDs{j(4^w=@ickR3wb&sdfYu*J618pGc>3o zJmJJaq>x=y1`X01-k(sz0+A3Zk0=|X=ma8_XXg@p4*UZk3`QS)WDcIxwMC>$v04TU zX&P*^SrMOA@{s~srz3Aku{%H+(FDzsms*ZL)A$IniCPJ{g`f^JI1YABW=(2IQ7Fp) z0yOs8L|n@WmBY^lWtQ`PR*gjssz#_j&g|C8H0|4Yz$y zld%?UJ+B!AHPGyeYxVd&LyRIV&&dB;*W3Db9ouPRQQ$Z0B+!|b*A4YFgwh2Wtv}XYQ9HFP%EOBiZ(j~dH63Om$l1BTr0GJ{kn+;PY=>f)H=;TDiNgp z*{@bxN?D)t{pUXyB?N9PASwd+!7Zd=^H~ny>vCX22B~PNh53`Z*|AvvuZ<}8a%tIa zNloILg~L)Q&PdIL{7q8Gvp!BPL&;(5(An5tqG*v~hFQ2vzPUaE3CZUeJ1Km~9j$xx zjUNcq41+^1;0iGY+}ik1NoyaH`F){6;fb|yLcXt=BA$MU28EyO*i#7`uLLPJjpG(G z4p2T16WMAC!8tVflB#-it^pfpe~)C|oXYHPZQ|Sx0RtHzYhSfPL(DG;>P5=?q5?Y~ z16g@nHCe6Q@rfdBdrs@_wd}BzjYuEtt{aUv#X}@brh0QTM)K>U_^Z2C{^WA7;cAgE znP1R;j;EDJgT0*owBkhI6=j6)L!O^wnj$Z8t+79^v+UQHusyy4QWCla$piVS$hFa3uUp z6E4d)J!15J-g5@7KyFD2dy|{R+C}aZRjAYjaZ*KE-;QN+_eu?kkaDXIGj+a=R?^o! zB1HudI5tmSGAoU1b**x8-G%j>AraW0J*>BMvwuh}@m_t{)?5hDjT#0~rSp$IVT`rY~)hc&0WjQ6JvjXm1O9kW5Kz$VBVq+{D^ z-$qULoMu&ta~Aqt2L}`e;ekv7%V&U$hIzWS8~iCQHDDAVid&{gL^@VN}$^8 zGG$}o{6eHoI=^h{5{TlOTi2uOTc!5%uMlNR>haCkU?q&iG1Vi&C09t_C6Gm&bLK~2$Asp~TX?GQ5Jw#>dMLm2@79tx`yR|IH(oa<F9xkBy z=di|4%M4&fmk7NGMp!fT#!OSeTZQRi>PH5MGq@+uR36(VHSFQ%GlAHR%u3UlYkYG$ z*{Oo)MSb@_6*QScNLy!HYHO7Ye}0C#&tKb!@hq4gH@L$PvkBGs{E9aA{dB6ty)Cg* zE3yLx1s*7JfIQb5gXg)njK7qK7b2@^PgasYvN4mmN-Mp@b0sF!cPya@eq^!7c5Ue* zu!VQxNu;~nIN12*w$b0&Gq|T>=uh;aCzX%+u(jPajjT%Y>=@bf)s8Al;K8#e8-9J! zgyU#rXihraanR8#lMNMRV^S&to$Q>YwRGpHLwO42oN=htE=D<)4Q|&>u&=M-bwo75 zD~2*#2_(qk4xMlKv4I%{koEtFN?lX zv17}D)7$~_W$gqXdH#OU75b`s3Owybt)};07zS3a`5(G9LOFfbU%e=MjWDVkLvn;R z4WJnFuZPzBIk$g3U<0WK8`Q3~pbv0B5R{=q4>LJ5^Q@J6QtO-cxH5GM3vdPzll+qQ z_xB`36e6UQ@ACWw6F1G}cY;7p$1a!O=p)`Jn!5oZjTofrcdJXd)0Xcbu`~c3zY=bF z_KqFK$!Uq;!oIVu$=bt>gqpS(2UltRLn!Ajz@~(ulEVAxX&|+2ZhSH#pDZ-y3D)&lsKp#v!0e>C4%{}r(VEwI*s-`@7XNSLpQ|X2aDJt zKme_@vSef2Z+BXK(8PSx*|i2I)v7eNTzj_?HB*X`WVO+SwV49(`)drLZpJZ|A464D z`_=R9WP`1b)2S*Bx4;K0l%-t0vz#~Ut@*KLHn7EI#Yj;a)~S;^L?4c6PJOEQIsV); z+#3!X1!-WWZgk6eYhnXh=<;jRZPWHw!^th&jn2?D3#k?Y&mVPz+x3WZwYy5maMg__ z?hMlwI{NaRU*3N~Cs`XL4R;t%Up?^q_)q{8bNJ$r3h(NLJF^i zzt6M50At@;c6v=bY|7`@Wx-TsMR;ZJV)P^T)lQ;8!bF?CDf?d)(uC4 zUQ0TIKlfN{?MhA&>u>y44zboOH1f6WWPUZZCzRc?yAK`b8Dx$pm;z+aMJQE@Xj*w1 zR6cB7SEn6>*(L~oF8)ES%bGFX?)#x-o{puYRU}qoLv9u7d&4`@L(vE3l+XkJpO2t^ z7}2Ngk%Vt|3w?wTVYF~KIg_mOR44sn+wf5QxIu0g>D$A=$rkn3Wn;Y*i7V#2l1msk z$YJrT=baC{yzU*0IAsPOa3}P+$>_A0s%_BpB59{yK@o;XPC)97&gs!Ry^l z?OS28A8MKK{UjLEJ{{;z0jIFW#h!}Cn%KOA9CC@D&V^^kmTLiE%A=)To~)znCLK75 zokJ-p6_&o2R62SuxhaHh3{`@)Cc<^eK$F62S0O2th)E1L(%L+|yr-2S``*8&W9=sM z`Hp;ntAUQGmVgLv&{%bwX(zPnFF+Il3nS3Y!%y8ql{N%bl{SY7TH#kTtPz@l#X)?Y#(c2E#%Sso13_fk5gAC}NZd?~xT307frOjg1acYblH1S)aQG<6OU zlqxrc8~e#KVF&Fq^H6eOue%9+=SY1(w_uYIRm1X}$*au;mZHKGQ|BjyUF{?@@F#Xz zH*iG)S7fDAGva(`k2c0iGb+nTEW2pEu9EDWrzRklUh}AurVtn>&|UHI@*8%HQu8r| zL0Z7qe;20x@j{F`M{NA@5-cEZAcId{op>o$5lT(io6D?PtajTU-CukIuha}{w31mb$R)XojW6^exY?q>PEY(E~P0W2L zWJF5MfF(nsL;*6%#1!8;=04+A2q-Jdp@vv~C|YDzNq+(DSZr^|^VlS4fnun-se~8y z3v-$C(S7}4Ko!+gM{T}Fl7m4lVk9URWr1ED_7eGe@&xc3;yej;$zyu6f5o90%|=`E zy4Vl2`c`Iv^gzH`P#GLCxK!s8F5ym8jsHJCrPZbg4!SgyJy&IQ0Ne>nxWa`;LgVlr z8tSVRs>CDBj3ZeX1)hQ{ZWXy_4clUtoo=!fD59K_WY~ih03n-VuOuJ;ANEk3i8%|7D0B!XeniIf6)@vgm>?<4pT6peMLS zwIzbJh23i=)UXrnh?`MSar;(Q0(OvE&Gom=Rj3d!tqt8DQqryP$K>BTZg1q)FrqwHR$u&DU^_YQ6?neX`PxlCX zD>1y#mc*hSIk7b4@$d63SADr7kP`in3L`rn&jCy#)v6RMH|d}3g^YhHLK1sSgGpHw z%g63@<i2l_HI;yzavI$8v%*N|l9Ey%PoLE`3c`Mh<~I0lfARS4VBm4z+i`Z_ zN&k2_JhYuU8<(@g?25#L^j@kQcuF>SE&+@5QfWxZrjP1rmP1uSj<~_ooxPOhW4Z2$ zw8u19yIAkojd5vjK*9ctA!0r|}G?dKX?!_{ymJp0$6$P8& zo+18^8m=x*L-W_cMFQ$ zh8C3~SBjrJaN{#*(@<{7aC|VhA9Q6X4g36q+2f~5{91%Z0g}_)@WUBqthzO>w4)K> zS|d3e@{!l}s!{s78pi})vs$h=$f%bIv>1!#FiyWG-LX-q{{kp}?KU9wh9>zTpZYuK zm>k1PHKch) z6%4UvHAMw)jlu4$x^|f3E!1(r3RxvyiS$4wsn$Jx(qj4&p1(_AXse^m!(lBd$Po~* zRh#@i<_0}za>QYSj3dRD>@D~gAY3YN@F`l;h|QX=FUeHKOdB8eL3LlSB$W93gW~<$ zk|&}UC)l80q^F$K@~aixLji)DP(FoH8z)+izz=NIRHn2N@9S(W;E(HJ%oJH}cq773 ziA`9d4lUVY{thC`j{7~Q;ux?nLEj) z@k;4^WU|l!{9W^hNRL$<;`9XKs;ASVFiFZmUD|hfk`A65MFpriQ}#@vk29;}NArf4 zIefcgvE-ocDxjGHe-%$DK|+`Kd=?myY^Wfb3r0`6e8-E|0!K&A{v)=O2<(SW;s7Q> zLQbQ44XO*1X&5xV_#5U;SyYFGE74xCJgT6#v#VNauw)NAjp$nFUOp6Rl*RyF6>k>dmUK< zMsCyvuLchBn*8>LkaG$M42bt;bN=`XvK`Afwx^QVNCQLgHi@+w$*;-cwQpxHkE*;L4%Yl#$`WLA%NA)L$T4gb)uN~sQd!>0-0%1`N1k%Y%NEVzxreR zctx+&n_Khv^>gL#6ZMuD&kWq#N>D7GYIQ4YXPNPr<}nuGDZlLbEVKLIv^GA|sTL91 z?$e>F$?Kq*%P(JWb$m_$p}`(%-Uhwnk=d2R>fL*qlJ4afiwMUh0)n{K&&}3|s0yn= zt;hVzJf1KR0eAF7SxJS;?!-hf6!Im_c*4S^9~xNkF-pUS2KHfv_%-&k1A+xISxkye zS!&bvJZ2IEe3A6YtN8}KH9MaRjaSxdNSRwmgONuWN<1BJ_B)T`=K@ws+_^6XUFgY+ zBn>?hyCfr~S}WMj-6Twfu2dA2hf$)-a4}0=mJK?KQu*}@WDg@~AwGu;amuD<>SUwy zs_``Xwy$MVfPQl0jRa-p+}%%N%O4oFV9RWq68kN{{XIGBG2ya3Su0lcU<&Z3bi2gLsa zcgd~oW!?T)zzgI*fR_z952n55g#X`VpUMV?am4neQR_&?-QJ5MO5GsTrpmatkr5dt zv2V5B>OqqkT(&F!WUNS7@Yax6e06p8&#~t1Z5{{#HNM;N5C#yjBu_hYHD-$yEVet= z)T3dp0&HN5P`5C{R{}C7qmsa4IJltRReF(;MO0=s5wY=s3StkD37m$dDz&xjQAb%i zCnpXMf*MI$75~;P&sN8%0ZwJl;-_~wdx^etVF90M|@nwO~aaW9Rv`w~wHL zP@JJO&PF3`!=XGS2s5~u)pJh-AKO=&ts8nzQ+@^!R+;s^Q2bbQkh`;1qGd#K0Lli?p+%s5E&5zi3_!>U@l6QeT} zs+nX`b!}O}y10vCmHO4VFY`&3R~?^}3V+{~ezo58Tk6r)x24~Mkats!6{nVrY#O3- zd13Mo#*RP$9uYcXzTUJp*FKLO1RH%M3Skcs+mYNOOt7v#QaO^bH>tQ_3}_Y%2;4R? zHqpe@|4wVy);pb`q9|Y8`?ed-6fhphlkr_h#jT#tJk8fVhYInoLbEe2Z^FC?UL$@K z5i&v|9SpO2s<5G~G+l#gNV{B@)f2<`^~FBgUc1hzzbgQ%rF6Tu?SW9h$ML%riZpWV z*(=JrO?MdXzAMU>s09puXe^H5K_n%6qMv2dV3h12md8X}o{2W14yW-#7J3(V+NWBJ z3g&yO%x~?M>{wNU#zSb=bse_iA(mX&eUMy>O$-7y*uMPf7SJ0a$f+5X?ove>{_P~( z)tL+?CxbVnRe}Z3UG9!IX@&JRT9c6zK+OrH>R4;+GijK<)9VKI?>hEnzhsADjnEtM z){R1r2IBLsIP$}cg{>NPrLtUMx>EIs^jVk3NU1-;*h5imm%7pUU<;tf9+G@?sM&+(|QLM_xvRkH}r*y&FN*d7u_?m1uCf~zFL(M8~BI%pGcB9Z2 zuls6my9e}Om}b+jLG(m{s~c|9q?(YkR3$4J9|SuHtt(<)RzQ>7WO!U#6GLYWa2#3KCMCx@%cS-uu&z<{)^5>ka#)^iuEma4l^Brs*kLj< zP%Aa@5kc`w<)NDey!ojgLeH; zGr`jA&~Ql;J!J5t3^5C>h&}p88?>cZ1sYY+)n8gG%gUcFjx(3lbvwS&3-s3Ds_}jH zSd%Wn1xl-&(_Yj_Q#zA4>d}?H&sb&;56bS=W;NuvZ4>IeXE)t9C&=v!#z#0;A`s zXAfZyUg9r;xo=rB@6(ok77fDntE4OcRmA{b4=$Q|&kU~JALhgpBHRyUeeAk(YSjBU zT)AQi``{1Dx+9h!x*p2@+aJN?%YU907GrHnNiNy+$3hx&-sJ^PS~53PKlZ=U{I4!% zo`KDjJlamHco4)~zEd)t6^xbmuQx^V(t|xX|2H4V|IU;A-|*iey=?SIt8Z}=vM;2m zFXS0#p$>KUvHwL1_cOgE!F+YtzkQV#rdzGPLY?n(G~Bs8G^oGzyDjbGajVDZpilVqVHu3-J*DJ!@Et7gJS9b;ZqCM`M3Ge1gQ*3=H z0zfv!gWWhKLwfNC_PQ59@yEIVFjC(>(esO~rdmKUOMJsoORhU#6{aj9La;-T4(_V; zmOaB5oDnPIZ+gZ^HkC`@&lK*>E=U4F;4%Y?9&EKo96LBIw0Y6KGg_^H~x$u!?n z|Mxb7pX_Mc@P`_nRgDND_kMc0y77M{=vcaQG%k8sn2dDq zOdT_Splhy~Ts4Ug(q{fLxxYU|W2?XDcYA!5RBRjpKGSU3W@aXLTA{1>nG4W^V;IWb zm@K@lU4{zCb!Im5hJOb+1=pXeYctVc!TU}jISv^1R(I@ZqFP0=rdK>Ta5(#rptEeq z_1XD&7A-B6{f}k&eEcr-wrSf#+IfjO3lSacw9~Iq+qxg;p+;1kK`QXI?dJ>Ll^;jI zTUZ@ZsI=qgm<@N#57zK?P1~IB%WzDd@N1SR=RTx+f{`5B4P+|ujtL9;A~UJF^yMQS zr&v4Mdf0OunoIj*dOC{&YX&`r^{V_t;_Z>nHE$4oW}SoK6$D{Kj<-bSPnBaSQi}3S zWCE)bYn#%ksgE#qn}s~&Uq|~FN5U4FZUtEZMk0j1z;k4bC+ucFnrQs zcTjmv#G*ECcBB1$RDxj9U#o3gv6P9Q(A{$jGC$qAiHX9Z1Q#~P|5kUCi{q085 z^fMnYFxLB8OUS|~tbtXj$LahmFwl*&5b-VgnY9iAE^VoBkG=D=OGn(P&C)<4jVIbl#i1z&?lE84}fy}08c zBO0r`XDDpJP}o6D8|G5Syjk(s2mZ`Y59S_|2c+}0=UA96L3H*BQXwEksMv& zTD?)$NAyoNY%r4FxAq8+_pySUNgoqOzP^60zF zcryT_ z)wq74!5kwl8rLu?<31hXDr&-=v48oFbqDzp3*-HwouJGxsw#j=fbeW`awW_kb;4E+ zHwC=V4RWDhbOwN@%z589Q&V=9NqNI5LOv$;Yc=9JreQ1Dm| z-`}K({7lnaPnDQHA2Mn93up}9Ugfw-#Tut>b`zhBC}ntzeba|}LY5$$0LK!nx1Plq zdyY3I*OK(l%$^bvQxn&cTJeB3QJ_h&Oq}}-wugNuR^n+1(-i&W2{AU9QnGlmrVzE? zV+Yv(0)RN%`OI1Bf2J(NZQ>O@@6M;c;ZIDhb^qz%X$L=jF&%|d467PW{2YUbNd;kK zT=5q$n`Y#OkBO101hysiN;{*uU1M*5u;_0$dm~XlytajyGVw_b$opol@KP~;2G<*- z+x0^*E?hI+78CCL0IK29I+6T_VTqYGbM~@1E-o+nkPL@zW z?95FZ8#9=~kE3#dBi?x6vm+v+-#eOEn&9`qHq2V0)AsAD^NnTOd4x2fwZ&w*gsbP~ zcB5eTV#`u`7IG#_M%TG?6ekcxtQ*EWXf zQvT_uGpi=>jFPsyK5ro+;}RX1gbQ<6+L)L@J*J{J7rY*QW{3xKAlBwnT7wvtKL;@= zKWd;jnKj9j#%2Gcd{|)1cw5j~(4UrW>Dc+GO$)}*mP7~Aldw2loIy@Yxj9Z}>Q&AF zui=g(R<-nlF#Zk<*iR!JS7&+WubEZ8?HpvI4I^nN>)^1okx-S=(Tl^$8k3vx+uzaBqztVun2?SnlP?%;31k99 z0z{;nF#~HJ`|+oENWb^rivvvk_?h8pwQuC7^bel2G_Lo)y+1Ob5Wi`cHBCs<+9;8Y zoaGN3GiLZ^O+2z;(llDuCSL@bry>6Q3;0w6G8=ssVBNgd|Dr^P;!bw`v@@Tljzf}J$a2fKb0mdoqBByqM!VF)BEz_NiY=&HRrHA38xvOup2ck zlBvEw5F>CxaAU{be*co<@eN2|iv3h8(f2{AU zE##~7C){glahW!`af~@&xJ@_@rq$qSAXUI=Cg7FUbmu4=FkV){HVY2TkAfiZ*pkrclA41Dc;pr7NipD@lip_%i|Hj3}#JK56kw zKx*5uXMy2Jd#GC;2iHC0*O*}UU;*GdCV}&Lnl#bG^cR!+d(Z14wXp5*r&J=ud}>{d z0ZX+to|l*)e&N~Q&%~`k4wVCLFfY`Y145~8T=tgcsZi6x1LFXOdOpwD6DeeK$I_31 zfOXKI^9H(IDzlkKbK;8Ns+KNbnmig(bAlV2BZ$5n3xkf#x&%T#!z~gu0mKtzIdz&mZu}L1>Mvdx&`m`V|k@5}KN64!lexzAS5G!JL%9f%`*aQ~Yxp0B;QSJerKLfVg2ONdNui+nq zEuB_bV3(=|O=)*XTzXaS1d(g|w2>Ipd}RRox)tDxt8PfX#G`M`U>0wqEo1Xv?nWEb z4#@nDWR^pPms(+T*YL1Wi&8>=?3~gtvB2<&Gd#EH1&$p!tGm+(qIH3@!{RVk*Om&^ z=vV_8(>fjZX@Re_L@?Z0wb%^XPljgfT_fy;KC$YXEAZ220of~1!ga7t@52c%xyz%2 zO2!yqQ{W8+cFthfPDQZRG)BI)B9B?7lDkhd_u+d1ja_fm=V*_4vScd0LQ^M}{_ z9X&>LB|6zW4z$jDChrI!s}ZQ1lk1ir%DM8;_UXIk0>1rPE(jfdKd|O^EJ---y3IWK zD|ym{ziWyQAk@*(A45jfj1W6FzTjHewa`6hGoLc(ZD4DB+^y{pMN%eW^q!t=GZzKy_A{z!pD3kFJ?p8IdV45bjSBG++z)GmX}L*j}{mv{o-nOAY{r; zyw|IX`|dlzTSJ@2qYIx*T~rzRyMJ4BE9S@_Oi?J9!=0+5nSOC}?q;TjZ^!y@>+px6 zENzcp5gDnjZKx{;k?F)B9?4K7gn>yJrk)y0yHd(gCBwx7?m?@qDSi^X=Hl&*3;C7W zlvXhZlO$~C+I@V&KZIVhDF}~A<%&{Wid2_Re#qZ77%qqB;&QV=_wCDGNCmH`hhM6f zDGCtq7T=wZnH27;g##b@rchTeqenI)$9o}M;Fs8&*lXT0SF%6$IMS8kfhGnJbpD~y)a|mf>(5|C zCF6m+U;NsJ|FC8MvIqx6g+jE9@t;E=;+Wwj7*t&9A?g4xe`*>))PLX%Q$!-KU21y* zg*)IY=dfv!g@PMfTDnJaaJu1eH0`Pw2Cw8fOrPatawE2^drh@XUp@k7LxZ&?j|Z(; zG``lp8FR{w71iE;5sH;4nb|@ispoK5DW2tZKPX0-uy~C&Jak>h*nl9^tJ3jX(RGze z-?{tFO-go3Z0f+RaU~jc6M!;b_sw&PC}wMGsg8lEC$(u<+jXu{D!|S^BDb*_m1jNz4+YL~9c?HRw$ihT*kHheT2bos1;XH& z*r-8eE9L~@+nz+M4XVe%3%`c{7T?o+&_^#NI_j0$R-e)jbG(*1 znRkd#9d9lbLm&JNZ4wp22|4}tP4<8@{os*|LBb_@T4)N6i(gNOq-xhbs_<;j`X;D} z)NKa{M6GnX?m*Mm=l3vwN{cLyfn&kf-GpZfY@k}=&c#$_c6}5@eCTDgPbAWj zs#SnMOl)HDg>A4QIrSKypLRiB@h#t|M>`~fnl31p{{t1-JpgKIyps1%W*Zh|As_5L zvY>xq`tc=+$<<2=f|8y2@-b<`CjH>{3Mq@d*rWD$$ZII9>Qn4_#rFl6dP8>+;-qg; zwauAE3)bvNF&DMZ{aZ$!?w_!zTA5*mYK!8xhG*o9tFkFR>6fja>sIUU+v0V94{Nxh z%C$FhB7>0j-%HuK!vgg*rdNz}Z)hQJWN0(H`;9L+x|$1t>jl;}CdE-9Ayk513t3(` z-bHkt_p~mkiq^VAF=jF$4FB9>Yc}=Z43(F0#~yS*eoU~_#<-BtKfp2;L2Z&kk34qP z5QfLFkY~S=ZIxyO><*w#G!s89K^bFmR#gYK?GfG^;EsLWT@AHG8A-NdhTPQ8+0^_C zi0k@*CW_%oI0=wa?8q9i&{730A~QmHC?;_fA9%L<8VwQ8c54D|?vnj8D}7ZGIhaTM z+#mS|QF)*7YDY=zCe`-lF>le%cMd9W{Oz`NNHHi_fAK`Tvnvfb78raA7->&cI@5lw zDC0WxeFN#0FJxqEGNs>V%&nPs_Q=T4!W5HMPrQ()J&5z4 zg}SXET>^2qDv6d^Yn)omKtwLX%#%e3SK(LT8LYAFf+9`78+Vms&l|sl4hrB<*krgJcAzEwhm$UVae-A8N`EEf7vra<#b6ei{8^PY1VY&vQ zau+6+F@qLxhM(B63W<9dVdT#tFUjj+#zv95an$&O(fD^uqX9PXO@(Pv39d8~1Fd)j zOqxIk{E7#@Jy32>7mptum+mP5&BE9j2~Mh zllSpcPhYQIFM(rNxTARG7|bxHecg3)Rhifz*RTGM0drkO!_CdcL~I7AWXFBvXrlHo z1qAe7=UiWK{FsK~tRlv|fwit0+Rcl=o~pnaDjS8JhYHqy{@2Hrhi?EF0<_zjA$p{7 zpvFQEzUB-}WOQn}aePNjDdf<4dH-$Kh=otw)C>8~e`#Bb6{P7p{A@E0-x1JT+~miM zFtd88m1?1E61{rqzhzecGs}P6^}qG4`o7g^e>{a*|KGBLe_sY3{60+eOlbcEK81#c zh5Uz{;vaSjh<{A=D%YaMxmRdpjsfw#wX>`uMquS_|9>H;_@J^7M!Q5U-5^!#5Gr=} zQM`KoxqZ*yf8rK4|DVPG*(U$lA^zK=AqE8QWneN+yl^O8+f-}qDt7i!Jb3;&dC#A5 z;>JDypT+;#CjZ$X{@bG=Bw!h3`Jlx7FJSwkzXFByo#ZaNiQo7yKslFDQ3ceAkl68i z>a!Jh=7zJ!_vRQ16>#(RLE7R*Y`XcL8_ep?K`7ig$Y?bc{NcqTUUQ1~ z;VobCO+kr0mnS)LcDTc+UX8%dzt?#P_QtCEd*vVZONIApqxsvs{8=oXvS1f$Vp#&| zzW{Q8#lv8m$KuMgwn)o%Nbf3BfD}>NELH6$);Hr&;jyL%EA482vcySpiem`Al0x2y z-s&A?ZhAT1`F}5VAg`_lM)xEB`>qg?xYEozn<5Vq;t4B`Y zzOOcu1AX%`-gidP@LP23oV~XJ-kcD!u0akm{YDhN*M4$Ih{06r<0y<(mXOKXm#}dx zVD3*py*g_T@YXhqbQ``zZqanmBCkg0C&11vx@kb6j#4Rd(G1o*yC@>HH{9A4EuyGc z)U|(2emlz#D9Tau-xCkU&Ob-29s)!!ia0^;mSUygCECQIcvXGNy$|C|2%)awCPg_SvlTNCF{c6s;@cg_;g9$XHBIby5M&Xx_kshN~ zC+ckyn+coI>Y&)!%dZ$ia&r(Ic;t^6aClOgIfqqnkhb-oWNpTJS`mj689=t$+w!R$ zny^OOF4ttn(17a|5Ujdp-A*wevci458zScvKk$d`r!}9i=06Bacy8buBSZLZ2qOwLiAjOyRCq^eyL`5V6>I)upjawO>$b)FttuA4reZFES^PIMzI%bye)K~S2 z;w|WY4j}DAw6O#p{e6Z#l2aw$9!6ES@4~uV{s_WIQ$#GLqmial-3b>omR%7Rsr!(_ZD-L@}LOmY%E_MJO6TC*dQI^*)Xz>>W~h$QJz9O%jBzmx$4vg~<`T;sHz8(?Apum(nICq40w@SP36f%`TlPL9K2y)Jdu%C4? zh;GxqO|p!=RtP`qO}Sllf*b%uokVB%2UU=5fjm=LgfLQ!_$l+)Uu>bd7+?zgx?1Ro z6uombTVL3tB9;8$uU@=Xg0fc};p;Bh*eI1WH!PTl|wc~G_@ws@#A_-DLi>QxNF;-tFv z@``v`{8_h$OGu!x?CgD6>c~$;9R4RtoPN_MhN8xlv3qR~mF!!5GYSJ6v3dL^b*Lds zdgJsOvy6dN|6JGov-B)YLZst-?eH=UXYFDcTwJ`ZDNHghsj~ytshgAvP?A-F(H_Ge~XBIq{xs`3IEc^`sVA#SXt% zpJrh6(7Wjs(mdFTZfN9}ByMh~ffH&>D0vU6x{(<7HW(6N9jd||ww_42aEXQ@J9CoG z9+H#CC)*PDQviP6A*PYP@~jvpx_Dq$VjX^sAi{)|Acc$SqRRBRW%?ExTq|7RkY@z8 zM(WL|ey)WSN)@&0DQDuQHP=lMBK=>$3(_NJC2W5hEbUPQ>&nGH!xBk2sMCfod%&NU zg(wM51p#?PZdx)_r9(SFv~M|8Cj~E@7OjxJJbmDRc|2!^==&LYczE9lDI)q-k^e9* zl82m^J5{y2F%wTzK8!ND7`<#s3pd=%DToUk#YlJ3Lk5Yg@J_M5Q31c$nDhAaMT)#e z1e<5!^Z?&QXAl<{RuMNI+<|b6-t*^GTB=V68DdOmgo70OX!?N3;uq}#1XIrRr#z&9 z9Dyl@OptkrqdIPsifnYsR3RGUMK#{Vq66f$+Tydk6GR4+s}=u6_5Nj>;%J%Mxr&~e zxblY)n42iXR|2j9$=%F6l>1;`Hm5o~h6D>iRI+C7t4vQ#Ymt0=Nwg3w?ul35xFnT! z?c*2rBHH#TTRzO1Jv?-5ZA%1ip&IFt@p6{na}RM59Tq^N?$om+r46u23erG+L`*8yEtCo*8g zx{aeuT;8Z1gx0m()AS?jfouL88xTu6)VbM)4dR2aLwe-VT+;AMufDWEp%UzI7{skZ z2mD_^7mIwRjT4BTqE2VUS5GgzRC_(|ckr-;jM*QS*nULWZ4fd!x4c3AyI6UXW%&S` z(3F|-58iL~t!!=jNzm(A(5y?}Yr$M*TYZS&j+U{de8BSm#ok*-#o0UygToB2gAD^r zaCc`QxCeK4cNicE5Q4kALkR9pkdQFAyAy&t2|)u1gm-!0-@Uv0?fL%L^X<9!p8d|9 zGv~BCE%j7aKiyT;T~&EU5>`)idiPQv*bv)8CQ7zlK(PCKqa*GZJ zAy@P0cnW1>n`!K*S)xOs?8_kmRa`BmjK+3rl=gefS8-FTSqR%MT&8R-7N4yRx3-bT zY~O!!iIbQ|n{hLoH6!e`ry@F|QRZaHxDnODr=)!XWYOf6OR{i|(pU5yZNJdwXA zkx3d_%XGHqI75b7Hdj{v%)L?X7!2uJY*>V+*`J8veI8XOjsPl5I>sb)Ty_wl6l&Ap z-18!Y>LjxI@Su+L)oDNP7D9a_ffS5QQ-T;q>C^-^W}!?$e?^4lmnw-Qiwvj|@L&?i zHR;y442dDN#zG=9xd&*2NLVYc(60KSdnwLt7Hm1X{$=laIid*l*V^O7LP_Fd*^RC6 zSi5N|s+0G0iH6W+qECqwp`31Y;$jE)>y{&r_&2pDK}3XgJiEyO9DNGC)lDCw$Jc7W zUA+c?D0do~N^z3CkuyueGaV{nqgV9A$6h(+8O&gF%*}Bq0wvJS zAa*v2g%+Xf(|B&S*=n~Pzc6>fCgg1tY)sKn#K{u?janLR;vjp3d)FzwV7VgHQt&C+ z&bk0o$bgQsT05|RVtQ~9J@7IXPKV#sJ#U6`uURsS(9<4SwSW0(iZU;<`7(%o3*XY% ziDMi?cWxD;GDGgxa-CFX$(Lp5yFzGLuG05zLdj)_o$paeDR_y~g5N60Yn^^={jd{- zxwH|7#r4)|$8!f;Jo?q3Zs?|;@E?N`@72nB*s?Hh#LuVbMIL}qgz4d&C(RVJ)1Rp^+pO9bXlzihRAO0B0U~;j`FUO0kgdO1t9<`-CCA!f`#5?9S}faPPpoQ-)4zmVuB zJ1`prdei>OYlH)d^6LO(mfdwei%2)Lg%-PoJ1$y1#W zM>BqGul;-{U;fb+q9Sq%@YKCh}7FOr^+ zdP0<=P*P&1MClKXbB7q)vXXK#CX&0$zzih8FL9Dk>mUuaX2sqQ#NqfsWp_~77g#dm ztW#K`bRUb~N7bOnS+l2cj8ttLLx?9d`t8v3_#@+$*(*i{a|eyD=WHn#SxBBIRwze* z$pnWcg0;6wqzo_!uwM-VkzOAwM~jM8$G*MH%5@eqcr;oS6kBO+ApJgPqy~K-FemYB z9Po1z>d%B9^2fZlYF`U=8m~2>2OaRHEIb_SiLdzX!zpC>QFnmW z_hgaH?Mbcr;fve<^xrmN9CeaGa(RjHWz1~>-LE^kwlwP;f+lzBh3GY?bQmt+EH#I} z{bX}_AdUy45wd;g@_8*-K7HU%eJ+yhV$27t$R+;exG<}x}+*9 z#%G!fbW3*r&kO^{QCe4DR;5!Wjc+J6JVv=KvHk@(KR@#wqzJlu(|St!G%wF@-!5^M ze$jDLYZF@dFAAgw`L+Dw`5I3DAGmYvT`OL)G0pfd1MI&DAODfvYO1writy+WwhIp& zd}bEB5NU{+3{ZF3@wOn&y~|(z@67*3$p3c4AS+b2JDS2SGB%~})sm54yYIj*V)WmM z|G(pajMN(=>n}i5<@-$nz(w~e2@KKOUFud+Y_H|a=OH=F%diI z?Y8)OzJ2H=tRq3MA=u*?xqmmqF^WNIi_h^H`!&g&(E~JQtVqHTH548*{1-rE%ifZj zBf$1xDj#_M7a;ryI=sm^@-W`g%cC8}()`L{{o8a0mSqj{SE7<7=F=Iv*n!$<&L>+8 z7X3lJS%nYWqd{|?=p70As%hjC!HpmeCtqW(_ANsrn$|M^D1I3LO~;7t!yV1TDr$=s zLVDtPQ)mXyw4P-<9wz5kD~#RX(psM^0?*_Mz9!Z45Ef>aJ;KOZ6Ak(LPms?8&%>O< zH04DWRExXm(Oi%_$x3TXl+{uqBBrqIc6M;layPvdX8;=E8IttitUk|t0Ok}+AB$O0 z3YxaV;5OI7&IhBl;&^fC_OOHHgNaFVh^V%Kzo#nQydnv7kTq;=3BN7SQ+`%{mv)v# zd!bk@Lo;*d35I+yVB?Jpu;LNRgjF=p?_iapNs4GTbeZ(H{4|RtY4j|8gRac!etz!R zah`z>pV2f=Bk-9smM#Yuf&pvw+FPdk0fw+Mlqk-19@1C(aJh{6XJHzc79^Dot7%$e zmXS1r=XmCFPI(@M>6yP(RT5Z$sV(qQg+%O(IslrvG$xX$VTP<)*?)zyL>}dABFXZ= zEGA#tUZuCrQQNS9?8VJ(fe#;Xt}I6@vz z-f#{4l*Q(>Qkw{{;W-K_2HNTG@0}*rm9%(J?vP zkL==TvIm;E_>v5fjc~23h?1|GE8NzHF~x#JLb}d{1bW$9N%Bs7@ZF%3l^McWS2u;`LE@sc1%}N zJcpR!NaxeovZd6v1lvOm{&G&DE|GcaBz#SOct$|IrXDFdqYc_+8#)#K?l50@4zFp5 zUiK+xxS^i&T(W1`>6i_pbpl5TjH5k_@EKa0N^9@$EzcnXX}`|iCpOus)usakdD9n0 zh+?}OR_Fnt*ff*@41;mTs6LZYkoLe)>0Kf3330Z6@YkJ`LCwhm0mIbrUW{fKbTZ!T*ZFUhuH?8@Um4n#N42j5&$zp`g%Ft(a}-T&vLuH?taoJp~MaiOAYDl>X-x%Qg-`xAd|BjzzrGMS~a)Q z!ON`z01|X*Zo%GV67p<MU zmESUFe%_HRSTLt4da4)A2-DsIQZ*j7VY-Co6GjcnvEnIrWOCI|Yer9*_G=F!So`zY zUA?Fi-f9=}Y^*t37RO7$cxd`7(e!g6?Fq}>6;yA$P;v3-kP?1N!@TXS=rg2wnZBTO zQk*U0h>E0VmIHplWw2Tl~xfi{q`jm~rBL8A~4u!^u+LYQwN_88v9*~~i+t-u` z42FW-e)X17no&q`EmQI>88lU8M@#8#z*biU3%(dRyQzA9aplHDK)V!iYX8`+PY5** ziS|kNRt^A%9(@O1))+%RgNQ7pIpHS#>8&Z2vTga$>bX6FF$ka(ac%ARY2>36k7q`d zk5p3w)GH++xfkQ4TrT6Qlz!~k_ed6PH<@Ajgs(1~QqnTtwPHrIKL!vszBL>%dG7T1 z7l5QZSF-nO8P0yMC~5MxKK>UX&yIE@+<;+0o}8vM&nMAW!0sB zCPQN7`*a))_d^Z9v?S*OOI_79!DyQ!zhjZ8yOvJ#~JlYqEPvg~V(NZqL*D z!dZ<@|85s7)dzTc2odJg;7urod-87Ec44DwuO?n9Xk^7xj~F|I`MaB{ zdl2BhsBt^d6?vOFzDM3N0AyBKrK` z0dI(QA|WuxMwj)c_%fwMpMQ1*jytt%Y`-a0{L5v>p_9hfYp z7`u_RHpb*=Q>9Z8wm(3Ocw+%Ygf52 zqZH1^Sc$=5Gf8qCjDdm9LZbPEn6)=4Y^{*A4Tgr1HJWRGFb|$BS&Tm->Lp%hR8V?x z(Hi%jr`_3Nm0?z4KtfMf0~+YO9GNhHBSkSzp%kK?#A!f7mykCbdc8({ zlqIdKPOGT?nn?=VL*xkCGP!25BAPyXQpjhR+3LmJUw~j1KFP3;&Z-*^VsHCj%-^{z z?`S1NJNJ#S&#{M9uL&B~b<2ndnE$f3cZs&wTM)QDIUkS`r>z)Fcm^UG`(SB(l?{Mb z+PQ5&d%K-4rL%Y7Zx*ZoMVz(VE`;wD)5tLe;jMYjY>bsd1x%DDG1E|k(PI@-2sKsM+z5Z_gvQEoYz^er7v4yI>} z@@^z}=94%=1ztI=ba_GQ*~zwRhxYuQF)#M!8HxjGi!y$`V;c$<41yZ-yK#S*>M)s<4(uzoH@!YD(Rf7ZH0fn+#`Y13P=2J!AN6@?mj~v>LMY$4|bz%p_5jf#*UF17eiK+J%&*=BAR# z;hB>7@UHkW5yLi>9dDDMEo@ctCo6a#mA z4*qjcAQhi-WQ4L^)cbVa=>mdyL{0t0U;LyUnsCl+$aH|FTT4A3svF=t>^k<_ zC!PljucbB=v+{np)d-!&WvM)VkeIL6`O{QhUuMwVmIo81pit$Zf>|Y@+3+v2%!Rj2 zTWhKXDaH zxI?Dave=b^MrfXxBApG@!=Uz8W)h|Y#_i;|Fz!0P=VbqX2mj$H818uY86JW=%=bJWo%)Hb zqFtF!k5ua8wg*fuHV0cHqA#s;;95q$qCo_$rwKIX-=Qj(yXsc zqWY-j`e=;a=sVHVrE65K=(^(MKI0$Qa1s=V7EL12qn8ula>ZgS=4@5hG1g*2w{D!d zpH-QIoLaHBc<;(S&k8ZUc#iLd66p424#Z4G3W;Z(4sp71xnISx!gCHmRy< zLb|cD&#|B;iYgF_aNG{*In$hy#&+x+Z;^dIEjU#DAv%QM>#R`}?WnrfKf>NnC*!`t znXid}@eETAV=YRu2(Co-_^~K-1UtuCI?0^ZR*OH`&J2-4;_?w!JSr7!%5T+PHW5WL zCfvX%yc|l?;%kx=aZF8Dhx@Uy5zt?zUY@^nM)I{W59Jfq+uxxGDwXZ^y;lU)T6xx{ zBy@OYN9KWb8_h}6h%P$qh?7_6K2bqm*LgQO$MSKgo>P1CPsm8abP_sC&DvhyiKh1Y z&L8+__*36VDzVh_*gcRu!{kJWamJRmsf*kdy>RiAPy15o%P5xR*h~DvUllD#C?3bR z*YN^fL{?v)qk9X6h50^Hy*WSOCboOhH?g+p&Gl{}1FvV!igeU!c=`Q}oF6*NALGtO zz8E_Z`6;)oXYTLuG`C=YoC&MXE`nX5jk3X>K+OQhA6>Ez>k8ih3)}co%RH?unDe-1 z#O!Ywds9QF0<4e5K!e5No)ceKyw@4qQ;Ub5vJwFibcSis?+_}|h;a9g%!T?7PAyeKoS>aDQU5H#iKg6n`8%0j~B40A#4a0?ph;iSCjM$-A%RWn; z*ff0Bt?tjss(R??JD+@&13naM_8=SBk0l?hgj)bd0*yl+|B)-@u1Wj zb~dt_!P~z8UqyExD;5H9sdu7GgQ#?7LG%1U$Ildzy;*l9^$$q6SUwP5r zN_0p5nUQ-vRfOXQW_rT(&7lY9c^Cdl+r^ zDASPE=jIW=WZRNw_mSl^iOsG$?-V53{c;~CiOWtC%-u7xO+xjG|4rqp9n$*!YJ+J zP~DOsfSY3zyacs&;vBHc%yX%sT3_ZOxf-gck60Lg5u2;R@fV-~D&6riTlvdWF;4aD z!FnOuG0VAv^mwM{IYo$+a`tm-rFj#Xe+4*41pK6sLUSjpWa%j?2qF z)D#m79ZAB~>{1RZzWm5g3Q#`Q!#KTh4iF7G%L6C@Jti##z-%6{l;v|+wbG`T^)Uh; z%wt7bS_NhDb^4Vqs-i9Ws_)CbleSeG)~j-m9>Q33MFw-(tjyEa>9sS8KFkcdgaG+9 zm}Cj{eb}L6@CfC1EIiW?(&BZn8Hz6)83HgyS3>W+GZYB^G|F~g@sWdtfOIq)w7NRi zzE4g1R+S$ojlJTvhz`-rwkmyK6aYK*Wokc_q`Vg4)boK_o`^zJVu)vEhZ+##SpmI2 zZ;7)duaGghVDPPhxEkBq5HB*NSGEuYJ(Sc-p1f7;9TfcwKt$z5+JvD*&Wt8wG{Djo zcCs>hhtz$!MAq2nY%yAfJO=JuiWKp5qurtY5OvUekhY#4RIwhrp;4yImNRO1d7#2< zvcWK1Y8e-1m2p|G#OLVUX)G0y9w+HrL$UvGkqu88s{;Y&!*P|I%aMXE2@c@^E9sE$ z;yrRWgr9b4cEnzoP4mK$NMwHsP&V39UtLr-h67y}U0HeTHK*jbZDPM!{0}z13wsq# z)HW-WY3w+};*WhVaT88?s(PZ77sjau?&wC1P9`@bL$1A1CImT?V8L3n?U7mc5o7sjutTB+O7uD z>t@OTg+a^<^f}yxRD+Jnr@606ss5W@iWfK|M`nic^VSeV(k7`HLFs=PhKFJ;B`-q&zj#Tfh0(*8OF+D9gx6!diSbeOL>KC*0fva}1EIju*-j)6Z0oyIFFBM#8gY zFY~DKCUXbI-zh&5f@zooBOL-P1n1SXDc=gv<14WDooQ}b-suBbU>+0Y8iTpwxB*r& z+i86mdy?S}OOhwP(~>u00uks^B$4YKe*qZZ?I?3(yenny)gLc@+U(@2mUq)>PwuQ;G?T<|*m+e1wr z(aOcr-QeO_^)q~D)c&I&NwD&DPtGCo2$dC<9gkgfutO0@*G@^wegn93WFgoRQjo`0 zwL4l0Z=v{|m+S7-S$^=}!G8h@lJv-dL(yMAB8pIFUi+SjxaW~+Ai*p&Wc?B!8f}`n zX4KHs2}`+vXX3szTVFkF^OW*KZ{^@kKjz^JcDe}#Knhf}!;%W_T57^R>P&ODPSFA* zbmI?=1?I?Wkx7qDY@NBuYiBrT@o9_H1LzEE?>N*Ovr()Mc|e)?d`n}#*k)2V7-H-D znm1dxF)}PGc4BoRTKyr8obDQ+4+oZ5hPgBP;%1&1sIqip9oh=&Fj-vk>W3{Ptx_ff z`cM&zWb`}f0^z;C0F}3#P=m|f2acDRNGY*ec^H5j^vqI(u5lU{pbyqOq?UIM#=-Gx z$jAP~>8V>IeLRJ!RMPfjlC`(n#Itx@WNI_dy306!)08Yh>H;V0LtYJIo)hm5T{Rzm zXJ2)<@=FmJ(T~B^!jwUV<5W8^X>u$NwAp79=4`Fw(l9kc=BZA6bTR^EzrO${*SN<$ z%zqR+9jEemE!SfO9`VbtGPu$m$Z}9}$M8W$P&{?3K=u^W126-0)`j3rY;J6NR)_)R zjY#kDU}%W~H2wp_Lah@S?LHKGg}Yswh!FTl^A-_IjZTzRwUmwKdK;QN--Lqr1;HOa z$#;x#GN+K%v{QX&_4wqb9_fe;J(%kMT@ZEioZ#dY^};vFs+Ay}#>Wb)KkEPQv&;SL zpGQ2IP%{q<`FHe^&p)k{kL*PbYQH2;#K#qURud8GJv&|KKAUNeCF`vYYLN)_pns+B zrsF#on%--T)?N!%AE82=D-}F#4I|&p`rC-f%Vqa4WP=S7W*GF z{eNQCI%Y}BoR`X0{&14Risr1`apei|=%R{(7mP#}f+z6+njtbHrJ8N3_$;Ro3a=3F zrlVy#LPjNLp&HV6wH^#<+0`E~aCoPs*a|6i`*c*)4%v6Z2Ad)nYqCjwC*RS)3OtFC3is;6$Mwe^vsqm{0mxGLVq zRd3&unX((gHd_+oyjMxE95NlY>RRhtSH6t$C_ZunkbBnN_59xIdlqA;K2FEqe2TzDJTpBP%hW6Lsg38s?$BUbEuG6R=* zefh|-CSP;-I^d)Fx93`VgOhGNR2I$2*ds1<5Ptok(9kh%N_#w@DW1%GJ#8aXmX6ID zN9Y#`a*W_r^BMH3n)02F0UG3jvt~J=(V^00IS%G|5wwJg6#|Mkie!B>`Fmpi&Hd@Xefv$Hzn63;(e;j2PeYhJFk&%<2gF!O=iKre>VmMK!Zw zP)2VBkZDm>ExS&cgV>}sH?gfow$M-5V0;-tT|7}PBMT-=#1}NRA}=45Y7cq!RRGRK z^yCjNHTJ~;j5FAREu|)S%!O}CfNZ|6U~e5r%ef3?XjgW@J@OsoYq=h4B+_o$H%HMH zq7h(r$cS;=-$2q0Aq8w+$x9z-@o0?^`#sDQt9_)veFS;qyg53g^Ow-Vup@W z`?Wv+1Vr)jw>9Zj|MA*K3#tv*&j8>RCK$isGvsRf!8f_iP~Xwj4fYcAKeKK|RA(Vd zQ9To~s<7$ru*h?KrvC zPl|Dh?f9TApi&aNV{9fsGu1Jfyi_(}LBWXKR3=C9v5GCEpY-jv4;p$qPvvkrs(6yI zof{!?R)KJ4JHsRydA#{v)Ts$>&;jLYjCn=fE|nrsKL*w#0)VG!UNBLqs@|pg$iP?moxh?qF3U5 zG}x)$ox)Jz2;Pb% zf1OVd{qdWW>D-A>v=A_!=#=s&4G_g>mZCBFqZP`r_oc)yEMOPN6wQ|t{1b+*qI&_g z|0xJ4!UOWz_xVShf|Y}5Szi`~CO&Ic^BjtE4lEc~BIU+Qr6_vgZ;z<(J|#2qygD zi(_m|IG`$-<5`&CQ+b~&HX6(fTtpDW;&pRU&4`6ll}t8=ujKyor{%NdqYJu%H?TcQ&nl8wNmDVvVV7&YtMM-7_hot3VKAt(MW^9@p zzl$!Xq;HSVgMC$LGFhLQ=Zgb*4pkn~DM?{<1>&MOz|U<>^)uEXXfm+4Bk;$B5RfRd z%+j3^M22PRZf|TE+u{f{=_`@{!w<228_M(>+Qu4v#HiT$HHvPDqoYE!cM(J4Yh|<{ zJv251r`Q_>ttEZP1MN@pqS}`AzNIWfGyY<^txLX?xDA8Xhp-r4fI~mY;3SVHUK5DW z`aqT&E9Z)3RwK$|Aw;pE=}GyELMuSD;e1{cyCI?vKR*{Gu_|KxCMZ|uE==u`TMefJ zq!@rgbYn$uC7;&dExo4V1if04jK&&Bv_nE0ySytWPFpnxuFkv18lNR^!Y)4A5+k8) z2rpKBVO#Y=2fZ?}z7@%uRV@V*79YETvdXILa2#@ew)j@>pyoz+SQQ@(>aAagFxl?u(+%iy=n2$U5crXTqW4maqbMS_NGj z%5MY~Co*VFwT&LQypQVVAllCW@Ne{${VcG5eIQ9hs4B^Mb}(oPJ>JVl6>a2Wuv77! zGC(;dhMSFJv@6Fo40pjAIYe%ip@*^~2&JdM>80=ZYJ$skHbH$SSObxkZcpOS+U!HO z(v&6D+f!{ebG4u=p44wYUII|FwG*s~H+&t1gkzjb4gDazJLv zQP%A2VNZVih7R2J2y+BgHf`zfcvG9|loY;KOvdm0ma|3W#T>>gL<|fv7F`&y1?yW* z$|hS35cwQ#3ytf((Aklvk~c1WTNg6ml-^9%G>@iLtl@3sv#u=jFi`hm) zTN^tdfB;)TpbIcUD_*;q{7YM5(p_e3t(CilU_vpE}ANq0XJG1gt_5}7K8)qjhY+X+d>bx&saLq02iMT<@#VlAcVTOR&u3 z#rEt;XJlJ~ZyjUrabP>}Kr*E^6(dH(<%~cizBx_7RH(K5ved#u6@+sJeM{ceVhdE4 z>tTUBZVL1jAz}0n22xXbmwxKQ1 zbXK-2Gb(hDkrtjhHmiKE+Sh3@wHO^gSfNRftTQ02B$akb8)2%UT?;* zz%WBq)6uw%ZkMG{MJov5=U^32P3c#!O+1ze+8d+TNW?}{KlWjUymu2B9<0utZUd1T{El*&m`n6jTeDX+L?o>5Hg2-{HO^^pR=T?;1no~RnaF)=lxSApcnhXjMW9t-Kd~8e0GQQ*^zd|<8Z(ZBVDp0}T zm#oLOWuMcJt)%8@F#HacW1Fl~Zw2Bh!HDVdWP=-zbuC5M)+kJ6b*vMl_@A}u;dF4cgD^wS zg2{^@T~om(%V_j?-@M6CAzCg;|4srJ=ZA4%syH%?x>nZD#X*>yyj4#JQloj`z1Q$) zilJmxDqeTX&edw9xMfWfS+iWPxa5uK|HV6=^OywzrDg=2$FN#5L;>Ta!D%G(JtaA8d3tnv$gi zHk{*IXLnJ-*tLB4Y}?u)#|WS@T84ZF8T&xau6Ft~_aFTKJ1fkAqIfRKG6$J43D;N* zFhlR{n;5CofTbdKta+zl)eLiG&{R{=ui3dbu=mNJyQ0-Q2}U^@qjlMWUX4DMlJ(3N zE^za;Yw<;5bPjv=TmJ0N6b+y>psM#w-!1T$%7brtjZs?_Pk8c2I zi`CFWnSJf0EI-ac_f?j{!63)#G=fxT$-eEHfYQDu9{W{ApRQWw@PqEIk zouiJucVW$^V{K1Gc8@j+^`4$Ha4cC|TBN=Er<%+BzgG)zndbhxT&>OPgjrar<1355 z3m7cVzV*|uGj0tT=ii{1`ik@K+{+)^*Nc9cPi?qR89L3(>$1)bf4duE22*-aJaoGm z_kQl;dw|qC@13x+%jl@|VR6t(>dwO4ElZxRy^M7Ik#pnb=>}1mCOAXe0 zClo2#r~StLGUoU@C2jLuo{ygHfel$emqUj)`P$I2M%P|VSRLr~>U)fab z1f5W?yvfJ0B_$P;;S`@A(t4-?e|4PW0f9;5GL{=vyaP13eai=#e!2?s@A18ks$?#B zdGuM!(e1P6OwA`fc-`980{7g=j1NgiO0@D|c8WH0uQzdOB5JGXu5>svdfJmkoPWro zX*q}rYpK%Lr%g;6_}r);46|SX(?|v1r!{&h#vELPa$@XB<*G-?tzEfHHVAe1Y&p!o zXggTWGk5c|Dl3Q4)(eKMcGXyc7Ue=dn1vvVU!P^%~DX}R6 zZ^i<+0TzEF_PlS2+hC2Vg*|I9nS48{^t(TmdCo7%PyY;UlfzGzSiGd{v9^v^c1p3= zk-@;=CyUoJ|L}I-UTzLYs27zluRm?px^VbSq4LwL?XvEXUqKJ&I~1l^ZiaqrvSohV zJ|xS5r2+wXr61{D$$g7i1w+M$`(LaQH#6I+k7QDqmRS3m3dU&pKC}g+x?18V#Dz6P z1ujq7*~s5TZl-Ywd)qTjsD5-xDV-SlMZq+omL2wt6N+;gaLr1*S=#TN}Rb}aBm^f3Eig%ySq61&EM^KG33=U(}4ZcCpDw^{{GSj z_ebts^u774-j@;Hw{#5aMg6cE35qcx5A^Z(NT>d+yeDr5(r39n#aA@!!78HKx#Ubd zJ8?IcOK;x)&c+BmtO3AKSqgSJj0>NAQAOt>zUA$Y6OP(`+ivyC2^(Y-+G`WxL_uc! zpo(E-i8Iucfl(0PLG8GajCQ8aPsspOG``B*mgWqQT^+*a#KzpgC%2ihWsWjO4)fpU zi3$aV6LQK(wlsvOdDdd3DoVL?(5DP`c!iMTR&~`5{}|8t8aBBuSRi?^edZo*U0wEM4r3uwQz{RM#hL&}G$ae0a87tYJRDpdPo zrkY4|ZXj=U24=+-0G#?K#%5z8re?simR4TFSXu#vLZ9Rqtg}PXc99DP0&hMA8#&YB ze^ZHz246Js{*!bwdfhu!pY~MmpBfsfoF(I@LbcMU=hWG1*xfB=tCVBn%H2yM z8?aE!?1mRNP{&?O+j=^qe|qctj8lPQ_hCEcsCwc^?WqYf_VJ_shZnO?Pn#BK&V7iT zCyagK%|hd%Wd7+tKc|~VD2ct+Y@tTfrs5Of&Pl=RjGh!ick^Z(_ND6ZfeeSD#j*pa z&D6hv>twT{f=b|J z^R?*u{A|qzBSu;r;V^J1zx*4g~iPCrK6UOuspSvzEvpimahUo{Zg*ic`ppd|a^41l<7CuyMw&MI18T(xHd?_*7B0~r ztD^(Kc$Ox#F>m*N@jq|$`xx0$@hB#a;zOJ-bF~#fFH&_Nbi{Fc{`fx*fBcg^;$Je( z1Lgt8E`t$BfkwjMaIp02NuLY(FP^%$)Vy&P zZ@Z@Z&SvOAf0W3JyN_=tfzF$o{^5<#uSgS8OKt<9XK}?%0!oRax!e_?4CQ={kRswI zu>bYC6l@8Ck3L8Sy4G&;xEXFA&LNNEp7O`M-yX+aGnrNY7VRlZN?EHGzTTVsaHy%aC$&7vt!6&dwf9Aq$?MC7AAq&d}c-O&L*~oa8;l10JF)ev^ODe^see)|*P_ zBT`~bx0QEan%e&ZQ%_0XyU<$Wgk-Em&+Ks}1F9@^8-9ix+P){KOTe;lW2S!*d7|(uMtF=S^tuZ9)fnFEWL^2;jM5KDRcmg$q)AI1m|MnRgFJ*0ca&#BtSs* z@$T}rARvQNm&}PNJiPCVLW%eIY1>Kmvl~CNFB;$kwerpS!i#{VSO)KjPB3p68ESXY zS5!Q72^^VY)&n|f{v4EaPTDMp>itmR$M2KMR+%Nb~;Sv{FRluy))B*I1<7=-cgOc8o{U-2P{DYB=?fGdW z3{hz&#-hsm(u4m=86G!+wRdnpt<1#3ThWjH7r^%~z+v1EbfTzgjZRBw8I>ID3x3nq zdma)lky>#ka%FaI0vb62zhmjUf-L5K)E$FDn=ShlZAJgwi19SiSAfqon0>)Tm+z-^ z0{3MkX$X8Xu}PyJsSs+z@`>%L!96)zOEf!G3Sy>pG;I~%i5*kSgG9PfQR~``sUB`}_J#Oa9IE2iep=ihVk?U{usf7kPy*@a4gp zXH9tKmn+V@Id523q51bxHcmI`dq26!%(hz7D2e7LCFwrxFER~7hs$I0cwlfJK^6?t2j*ASjZ|Wd68I$rQqUUYx((}m%p;7Vae6@#&yQQiF)d#hJ4o& z;?qZi&cNs4GnxkogQO-!?k6_w%3^m@{xR&UV372I^>?Q_-#)5v0&F&-(rmv6jMlaeVs1za&VeXs9L{Qi=PT5jIBz>y*Bnfo<{h%){f@Nm=yyO|6sF2u043 zWluN@&BzI*b-m@^Lz-?P4*D^upuIO|&2D`)M(*dA*R{O9Q|8n7`&}$W#(=;dAE%BEsm0zDQygPRsBq2O}Qc?xE%v@ei zkN!D(lB&20to?A23$M-RkxY@&D=J93eNKJ$N^<>MQ0K~D0Pm*9Lz_QS!}tGd`2hbd zi=mZi4M2y26A?zPKBni+(yQC`?>{=fY67VO3vkt~d?bB6_MJ6Eu74QZjoGydrr{_=-+E2lk4+;!-gGq2Y=H}M3lxL zC+>_-Qt;Mw#rlu6I}k_c%D01uFip`vcGS(?Z$8KWpb!&*ePt9KyOu;;{Vt+Avd-w9 zr0xn(Spatv7UWGPW;~hJwxtpWJwNCf{v7wu2H8|t#!|<2c)l>-* z@G6ysKCO-iD0SxuL+H<>_l_eJFEa;wVbZC)HyrsKVvxv>+`I~Qo=m7^vc0XAxeilo z6tk`{*YUhO?9J!o5@$RsSBhq}hjydquB0!zhk^qY?z6VIRPxjSa~n4 z9zziqs1@<5|9|*4SgY?se?6*tR5MQfyf65E`~1t<>-O~@9-SMT-k&}nzIpqr^P#XHx0?9nDkZ|lH=fj^Tm_j$y(Ld<9IojZA(Ky{imN25$D&7v5waR%Z|zFpeyh)Olj=>qxVB zLforO%1AsKM|$9|rsT|H45C94cRaw1C!(ak{9g)`-(%T*xXUlr(qQaJ>)M?4v`%I( z^}UEA?m@wV(dVhJ88rX!V-FN(Ueccx?#-+Z3fvx3VTGT5iT5F>EX z>MOJ4p;ecAJobO^_7rSYEzusjyTe0CcXxMpN+S(=5JgJ5Q>42=LOP|p8$m+4Q6wb< ze4FsTd*2UuALsj+GqKj1*>h&E9`n-Dr)v=a2!QmbEbp)3oeV}d9tdc)vATo(FsJyE z_3&%t*0?Sd=`bCrG`2kUAo}jsI_%uQfGJNT^Qy{zDaezV_vC?G5I#s*9ddHm`#hYJ=IVzwIZD7 z>`V;O$6Sn>We5PlgZii1F-#53-ur)Z3e%Bv)C}7yfg(|Yib*@Cwz5BIfB_wjPKCb4 z9!q+AG;%=jcc=Y+^7d%+r@$o|1s6k3I+Qx!Q6>Y4x|e3rf}&t>ylZ;6q>DAdFU3Vt zhT)GZ?j3xva8R4~FSx+ii5U%n#)21b7y!MBASKCF8nXPcv83Sa`ixo)OkdN^=uvLF z>->AB=Y}R7_Bf8SQmr(>2xWTil4hok@13U#9~nRI38w8_Z`zW3A!W%3kyc z{O_*P`b0^Ucd8f3M{8Tyz4WuYr@}0#kjZ`GWjTqYaXs$LPfZozmRtby#~%pPLRO zJ{z7_WBjUQ;Y!5T_@PQItIC$RL;7X-gbk$mdIMq5Q2_8wCVBBRYWOiLkeq^;5M0a- z7Fs(Mc0qH}mH}MhIf6$|NrP^uG4FfDt*hL506`I96jT?PUhiZJ6)6}Xchv?5j>J+7 zq*0S=0oJ@Hb_n~!8v7XPKNA7S1_n~w^H7=S!D(0VhK@YcERZ$Ui8}clX>d6QOVEqs zY!Nu@Sh&ai)-o~wHg5=VPGmZr7aDPAPhxcScn$w-7n1BA#%BB$vXbceq~IGhZP_P= zL>slKfZnnXNn3B4X};bJTT47&))G?Ml06`GD7CY32A1(Ju7=Pj$Xw>mx96`W(s|xG zdY=!*e;y(lxvoyVwB|h?eYqJ#2<7|07T+nA5}Wro&gXWSULXsIIX0_*#2CicYB>{% zb2RBR{mJmLR46+G4W}R7p$qb&os{3bwOJ4Ly)bB1ur9-JOn&ao;Tbf}402besOoJ2 z%K{m4?ay}LE|NUU$)q24uBmIHnY3>w($}R(M$C`Jd(35{Imr%0fS@8I{b!rd-+p$r z>~d{Zc?jKaBxSP~3D>`O+Bz$1ca=CNKa{Y3VOSb z)lD9d%~4DxrmOA~uZ?2Z>`_p@594LvE8KU_zErPHL;z0 z<;h&~mQ^vYkFj>K=IDp#YGPuuJscP={HLlM4|=Q8=yx!^Td%8Ew1afU1VI^J^l;PR zhsz2F$MWnM{HOFDuI4Ni-S4wzi>|4fUsD>+LtnEs$9CM5OAbwm(w^TrkyY0NmdHP# zlBnN-KIUsp;PR6g|}lTngk`Z?KPx|(b^hfmWJ zO;G$bRP_wB@XbZZibhXXE-L-E|A0bw-iTu9PkRX|?-29@I;%-0WIAqLP{!rUu#uJ1 zocR?QhDueu8O`JFOV+zbC;J1ea>wCPd}r;;d}LItlaG+UiXf6c2{#D-Vci-{=_Agh zkUXl+HJ`Mmh7An>I;bJPEJot*eg|l)bTTLD ze631e^|Qgh{-xd<{Z^{^=qZ@QN-4c)I!kPcO=^ey($^H7xF@SG?rD!4sjOeJC(-3M zY#s7iOT1@N#Kr5O*tzkFU{ZEHU7-Qn_TyZ%#@?>L-z*Yt5%%$}539bZ|I7T1Pvx6n z0h5sM;;%LMXUEPUFL@WAyjolxGs~aXG8Hzo#G5;oC+pv8jvtsq;@zC%QMtAtr=t8r zh|<*2%i(&lZ61u!mTwaq2UqL_L3%4AjQsT(m~ELTNru|Vse-!Id_=O**?^o89B39k zi5Hw0EjD^t9((M(4xG7nyy2m(8ll0bga$48@?~_$Re6AD(z_?@@-0j)lrKsfe!VK1 z%TyOiojM!#pAvHu0rE6C7uj8-D*isE7OzA2C@lf*^BW4PY$#&T6m(TItzfb}R*w_c zA=D661EJp>#RZ4y50+!$FX;woe;H#d-op^32+&EO(tC^DaT)f>amv|(g>%}~2S=yC zUCBSH%zLdF0`?C0-Y9~**H*2x;DrxAU{*s8n_K>x-bc2PVN@pBWaWnY~f|i$ULZ_eN?RN$t%kfDv;>2WfK<4<;CScNe?VOn!Rv$)bRE zEzWIJz_jp?ZQI_0hC3g=Be zIZOZkVpz&Sxwq`rfsy^L{X|ud;gCGAH5B*bshD4qx@7bTlei74pI*TN3k|F|DIq#B z@VXJ+4`kKuM8ca?F*QG^5V4pgtl#JtQPqR5BuKB1>CcV(?v4eBo?#A97#-~>U38VG zr6C>xeBVRpkF?g?Olgn=bg5Xw!-hXHs29wjiRVG_L5Z*b99tD+Q4K;}LL#ipJw#9) z1Cv>?4Gk@E$J?h)3R-z^P6x$BL9ck9tqqip@>3#>LWdm0IM=U)yl0N}Zg8a1d^v$g z-HT!{iiwH}CE&e2@B_pD-+B(~7c)@$e{BctE0QHzZ0}Yf^Wp=akjpU1jmcLR_(9cNMCm;ieF^Zo4|FVJtNhzSnOO%{GAah~=t|*+? z-$jmYffGnTdiUq3leQqVd{;VyG#NFk#aMoQ4jY|F$jT0Gy6!0nO=X0?QXrR)=;+M~ z*$+QByfUQQ1o(Bft>HHmcspQ%7&#_GPs$7d zY=}~xAHyLSpy>=I9|rvDLjoyblx6p%oA)2k?K)i%oYEiAz40x*Ne>F+;fT43de8*= zhy4MasJ+S@U@<5)?+qKaxuJPJx@gaRI9nggoJPD6-~{{f$4mFno%vi6NJj2)Mu6tP z-*evYR09r1!Z}Ys;q}m$1m-82>9bRNn!-kwX1Pba`7ck_-Qjy!toPtyUvPx-dXyQhNM(^77^v*zZEML{4FM@GhY6E569XUD^U2_q-}o-H%_fV% z^so4&Mlvaw5;=!{J||smq3n4E0#=3wca%zi>7`br$i9r#&o35&_sSr)w31`j^A>8!;+-+s*uE@l&)MGJ zz1_3a*Wh=jCOd$fd@LGFK)JqlJB7u*6MZ|1nIlpgQCkp!tXOSeX{m2Q6XTBIgwO+b zRgRoWqSJI14=;Ww1VJZjw#{;9odd6BHTYg9TT&g<~_Xg50RREqqFe?WS3H{}?c-9-Djq z0f}P#$8=rsTxBJ_L(uOn>;cjuP6I9E|Mlw=*vT)+4-(Bjdkupdc7|wN+X6SuU~1iq zxhAV0esZ#7rQfPu`XciC@`O?BMJoCY?SsaVwpU5&xMbp`x!w3zp=%4yy`Ht~Abbb92<(vg0Bv%t{s56wMbv_XlpC@LS2k4k$EP8g)7eHe< zFXjSGla}QHEMXlW>q(@LknI`JxFY91ufw-W0h~VA??##WKx+s`Z^Tsx7oOqOpb3=o z$O6z@?J}|ehJ&7L%Q{y!>A&t$cB`VHk945>-Ed10rwn7$k7|mY!4D*OUtXVtYRZKZ zQW1yL!%e&!mOs{sa7y~I9%Fk>n7sVa%2*s(p12Vt%-;!_1mR+Do&+t2>VEAy?kU9I zHbuO6U+_dgr;5+7LqS|sNtMi9)pFqImzlk{1T%J-DU!0Q@rM9ZxTjecW_JRT;6(gb z%B^Qc*Og_V#$LNdhktHq_Z3~umJ&_D1>|RD5O3@I0Bgs2%ETqnNzRyr?>r1L6!*l%l&digQvpY2_|Q6Ye9%fB0N9cMMmdi-7shwm=LG`P9nqsoV8n3E z_cK7FMFsAm#E6Wt9!AL2!^{Ar(0J{P7nlx=nqmqgb2LoQ=&vAmz7iwMh<^F92~WJs!;j?R ze?XI#baMr4R0Yp|V*i*zw?rqk$1o>nJ-Ydbw^fHPxg1eRjZ*v-BB--X2hqy9y%LY`Lesggns0O{ zcKsc%U6!wSSZ#Zf)UNxRpB{ro2R)1=PEFy#rIr_lr<%u-tgNmxgrns%uhuTP%Esew ztxHx?Ee$shF8D_0akiBd$Rf;;keo!PW@4IyYnIfyf30%ofA`%ho>gO zelH3!*u<*Io`8y#LE#uCov@0enndqHHNO|Aaf>AD1h&z-ObsRP3bM2k7L-MUdyDzP zpl@8S>i&R42;71tF;|Exa`}k*LWFI(EA!wxv*<9;@9lIL5>B3Xhp}vOB7TO*opek5 z#zcMz|L!Ojj5vHJH;y<%98COlGB9pCg1<4y%@pdpM2MA+pGAD_KC}$B!oE9`94&fa z{bsucIuk1)zmMI%xMwrrT-Fj&CZakmJG~>%_SrulvTj$>3L&oKFm~G;<;MSfB)Vdu z%9v^NsXK0zg2XD<7CN~ZOw>>evkd*&!;5S6DxI|`R8hIYsX+!_F}ZQZs(Xe!r=};i zgQ7?!5ZCoQ$W~3tHYztKD#0?#RT#J1$qH6j3L$)XN%%k59}4ht&up(GC}J@S&!8_> z5d)i}_!T@UbG?!~Qk}2DX|MEOnY{(N~ zn#J3Kzn|=da`OFMlw3Xm_kR{eEDNksP8WglA#<9Jmy}lWk(dXP!0jM(=CrnZUM_^& zgqWCm;Qz35?~-WCwbRx`VwUsQ7_Ts}d@>G14!@%^_b^+#>jA1OSQqzqm;Y$BzB4V8 zpe1P>7}iHWEni*TXM3GYoo&O9Az`)oH48$PSbeV|&0$8tAnNM=>8=o!Kat_rrV75> zFC?{gqq;bSnePZjH_*SRs{7(Fc9oVzn6h(nN1?p0SsjS;(Q-wnH=leuFhp&DuP%!c zED}W7k6W42yLy~A=~pV{>+VXU{7lP&y zHpemyj&C(ID<_Gsn}I&WGEOxjg?{_oev@--fluJ6p_YPdDZA-&4f^$$utP*skR`_A zY{ZRsvV?HenX-YINT9coAP#86L#}xo>yb&u&Zz#GXOLH_76Z;t#0rv35|7AI-uNT?@gK1wQs3C^Dlb zd_^!5$L>A+kxT-=KDsFFYXRjugh!1I=xBObFoU5N>DiARa6w|-#D9IW`XV3Yt1bL5 zfmw8D1|R8&J?my5T5BVk97E!c{G7z78(ZJCEQFXAt>j1K?M!Oks8CM4ax)FGEbD>R zK@9}*@M-OQ)x}OCUVBvBtQ$CCG^(seJy;X(WQX=B%xWak*|KR77l$7(}3EdZ^ z`l}~H-!54%&NR1EJPk<;1@c*&=OaEbZH_n}p*U%y4gM$te&OCxml1?{5#jmcmCiEwLvz2kf~AzaOBaZjU#MsUHXrOgH(xh2fq5+ z8ztVZbQ@-#eT)x1$M?H{j!;?_hH@Lz=XN7|*|5AC&iBt1M;tKK*i5fHTJ35Uvp(fU z^on}oE2$8XeaP`79oDyI)(lJ|bTdhbvfNEfzci}w zBs45I!ZYAP^0C8Y3~3NDu~5ZODxK1LYkmeEr=EUTjUI2%MQV{bBbk1w9)J6!+Hfh? z-FF7XNsL*|4o*C(K*_3}nbVT@qxY2>vP;}DUTgjp(~Lk)K0DWZt^~!400frC6y-hM zk4w3jmRGiM!01TeTg~JQ2f;e0;h+|aQ}1BV1b_h5an-!{vTH*KB$n$}{CN~oDg1+S zR1-EG@BQ>p*e-UEoq!g(YtqOb2)V(D7iuq?u-PG`UhWX9SS`svOH?ca3_U|i4P7AS{c zJ=I&M&l^`h>nIYCCWxO}l_0k-A2Ikt`XGB)_Zu$P3w3uHH2T%=PL}EhNwRRSIW(i# zK%lIn@9y9iKMK3V!aBK*kEGe@AkAqvQwZ~@#ttqimjI(197S}74)`VD-dMrsi*in{ zULK2VcWt$&R{)&gk=7NRlUJtKe|8+&Aaw9y21)~T&>X4R_24%4A}T?P3X~j0xE;Qt zVWls=kbo^g5MrxZH&&a1VkiYP@_g7>nuXK=5^$d+(P@*NX*m4n*2-u;2IibCEdmAs zd`(v0BgAy30iV!FuHR3Qp3K0qqm!>~V+5%qI=BM)g$bz~Vf>Q=j2J%Te_E(CVZ-wI z2ru3_ez67B-__u}8ji9Uga@9ljTZN?@kehL0Z ztOilF=gh+1D67Nb32*;^Fsu3xMU&^=sEp(gE-uIZRY#O=O1#b}C|3pFl(Ls`lC$f@ z!!r{63gl{`Viwna%DReq3~&=9-VowVFZS;dKoy6v^%*toS7%6 z8-LUy+|-7tW<5@z+8GJ5W!GWaX#+zw@by&a+k$E^B~`~QT*`XoFK>=$f{oDVVVBRB zk{!F5&0sP}|M4+9wL#cxQHUp*Ua1{M*oLV8R%dHw!0sPVG@k0%MKDS7f0@i$dmsdE zeWL-^f=39c*H7P6F-!~Jf|R)vmS(F`4dOtHQVw;XCe~vQBGv9h%K|AYYWm+ao9kF4 z)gs`srsRE+d?ihHm?s)fz}MJ&bYEkZiD=CwW;qqa5?0R zWe~Sk-IJuyRAKLXr(% z4tBi6&LZqTupJDQfbyMxP06XzWwPXde{-7 z!F)(>o7J8X5a>&aFc4w;aruWPqm6||zDI?LoAIl&e`eBL7H$e3Do!lky-K%q6wlz( z*(mk1vYuxRrr4F168$4`V+}m}6pp=z!9uC{2MUTxabinF9R}j64#of$YPokHm^G2$ zdRZZ{cT*t=R#!*h!%h-)D`&emQp?4S{Nqr#kdy_kunKm@_K=SlnEFz5iF(!edcD;= z?^|De7mP%A!5Bdv$x^8shl&ug^;;a?-}b&Vy0bt2)rq~y2p$WhiX!NuN0;@>??JCl zV?Nf`?^Lz@BFGb({j>jI-pyH<)^bMw-4l7WJwVo?(4{&wD6c8mxfp0w+FJ#IaETE7 z_^{NDD8kv%l?T;S2(lC3>?$c0=E@<1Wgj+~dr;^;>;-%W&8~#+DB!Q2+l6WFk%Pn{ zB)!2ONy`>VLbF!Ik1Rst_2ka~KqTR}?%_+oS6<*&DX_y7vaQ0K%aN$r;SH=XcT z#vAu7&TS&AlV7&Uw;#~|ty}r3Xk|SJ&;z#^wJ}mhW-$YlLDD48^gRffk6|maj@JEu z{%eTSBI9B&@hqs3^%ALka+2@ZXETmFl7m);~z0sHGyJln>RmYul$Lp#u1z{<7iu3AWgTjN@8G*pp+ts ztgvdAYJkhXrA#Dt+64awMg@a`b#10-qIm+|jTXK_%pK@Ilg>IqGm~lnjLk2|2qAgL zT}o&jq%21kRT8UTn+;gSb3OgJPkll(D@cV=PS{G()m&ML??zCg4A_zcXz_qDYCTev zUR9DqiFsgB?cWhIKk)~I0mMmJNYO{-f3W5$q^Y)-q*4CRrK)AMY{87G>e5m$6OhGM z=fvzxDrZy+4G&)R-yLIWq|fjFmK=+Rzg|Om?|SMs;htZc%ej)8%K?(Mut6 zIlA&b!l0LY=K!h=bNTfhuIXIyB5LY$G=cnr4g2pE*MDo=9DW*fynYm~_OTKe_&LVD zCAQTSm}$Byukr>gVW~{I)uwj7MDn6ug8=`Usl8r*Ikh@WSmxQYzBGTmEs zwhIr(9m%l{v7505p*zwXrgoyB@UBe)BksxuHg=K9@m4d>6yIBIgMUPxhzDTTe;_=j z&J>QOvm|BjW7-}@g`LH}?;cVH(}V587_P&2nZ!B*5P<{Gf`Lz}6Z5H3X`V(PI8w>O zTHqxju`gk~pGD`_c2i4ETiyWB6|6cbwzVLK--38T?p0!B28%C57LgfhEz}V}{Sqkw zsj((mOza~!|CebzP+348qFNIZzbV1~BMROC28}|z`+%EfoAYq$5!F%M+_hyJco3JG z|Hp-&D~FaL@kq{e-$_f?3!BA`wD{5>Yc;D!$k^`>1X5xN(wL6iN#Twl!Q_O{tJe4p zM0LHk3VMl2u3%O5(oaTaUS!VkD4Q%Kd%WYW{#=2KP>EGxN_) z-Pt0t!0wNyRuv>5!ewt0(_H@I9XKKnv36t8gYi4@WlZK;cOt_V0=-z3v!}f+8%q zW~%+7gzy2>Y=V~~#uN5Kcl9ZfgL{#h8w4S@H>{@oh{@m<1Bk6l`el((l+jj|&0?4H5UF7po6`CjzFmnMU3r~do!tHv#c^-GoW zLZ6b(E<#NuTJ8=$s*p}^JNR|!)%ONYCFqd`h?Rg{^KdgZ>0tA_{63!DnVXHm(;+rnV`#q8qyK#M1b9Zjj%GjtOnwT=c1I-)Flc zFze+ znk6kE@)XX12)~T$C>~4Nr2hO#`8y#a_n+O|BgX%co>om2ZsC8vAWRBAO<+LMhxPz@ z@4UWC1@=qe=lamnn?p6mmR?7`GuZ3w<>o%zp{4>;+$sfZ|-xMJmh zIxS;+xmfwBcFFWLntmu%ow)Z^2$SD>h2yC1u~gI3kHsnqq>UBZax7e1#0`osS)(6S zu2tz0?y_`U>X?Y6%YE{@4q&E=lV0Sd)IzGRXEEM_Af--`S7+;5* zCq%#532tD}<}zD2rIq?W@G5NtNU%b1-$7o z_QF;?5@E0!w9m;;;QbHXT90Xl&(Ceyo&TL3-iHK~kT!#HKJuCTsM0>du;CQpX+OEK zTmUaInOb{+;ZAn87%>~PuYGj%>o4m8>vT@6xb9@h8Ai6sY^=4HWO2X2@7I%CQPzoe zHG5E7bf|whaT~B`dCZ$}^JO$PfBB{s#;g1IoMEd(ocy=jO=vPImzi%ajWM{olr&Q2 z-wi)o@$%ig3KfWrX^)q$;4(2LKqFf-Dmiwj^C5tl+5KdNqXfoYwxEik*QoS2!00Bg zx`e(cPMaBU?jg=Lm73e%z>JC%6kP+~WNw zFGQ1e(y()AHtwt%X?B}XAC9URO7aypwU9?wvDGn(N%svL2}zE030NMeQuFw|D-${# zvF~{A-I=$YnkbM#wf@}|qeNj_>btuHC8ai6pmD^AF_g$7&m@``YV3@YDQAH?JGJ`S z`6`s=Ns%`+=11Fx=60}Qodv~+AL1^ZF)x0)};n2 zYNM*iO5VCorc-n{3$?M2wrqc6X6JV(K2q(JgF=#m7PEbU$iyEl+ zliTNl>jeIlX{GCFhnYG%zdcT1La2$PiW=Cl<>Ag0}m%zYSFKHyPgelI4 zNU5dTTLPEq<0NAtNpjRVi$l4%?_U&(HCEq5We;^S3R=L!9kR!!xJu_ebFW!w)th+= zG2r};WLe>gw-bH1#f^*KoX!7YRy?mkqoGuMC$3xrZWAIlT!~Thv!|Qzr}6kMn@y0*UlD{)7hutnViqP z!?M1DI4LDZNNka83EZyHbgw@d51A)4dqz$}SE~C4{`_Y#dk#v?q?RNB-X>nsL`F4@ z;Q-?r$LD91iw3>E2k&_qGs$pI6=>{mrPw}d#A}a8Or}X1BKn_sJA<*b8#$at9m^LN zOd9LjoE^PZ7sQWm%7Dep>Fqi;wpdH?*+SUV1D@m|^6U znByv2oRJ}Ee#;iRNL;VE`Z?R>jHyvbjqN^vV7pmxslJ-eaBq!ML)2>wpW>e+45Jtf zrdc4EaGyTd8G4TfkdP9?XwPv+{7;Hl^*-1EQu(?zCob5o{04V`fK>Z)p4kI{w5o}T z-~PRn754j>a}HRMSJ@s=dPjwwWRNU)gkgYg&v6Ht)@nzut@#^ZSa1}>%FQVAwLj|R zpm-zn=syhrJQ((*k5e;GzDb)-jAG4d`*ELzeQ!{bEN%KlmhIBK90eeAgsz}}0R{%G zub0Xmuo8ELhyts!P05OIz$xUHCq%o>jsw%sxN2o(Jo0rB+9^1!*VR@M%m!22O($$M ze>246w{|z;ftZImF#HO{E4oEps}J}}15T&aU}DhnIz&yEpLavsO7R`QV^!u$@k z*#`rN%J1x%e(A@(w+RhWm)^+vSbXNG!{n$Fi#-P29(C5~B<&U|lV%D^5KwuO)@a(r z6$iV=`X2UqB}!q+>g4s7dx^l;BAdU5F-}fHs~OtWjNk^NH{1h@&Kk)j?6Y zr9*2$h(u5juhvcgUFA5Ud(Gce5R(bRMEK<6%Q6@yHj^flTgNz!I3d$oIodF87h=xV z-Bn@xbkp)%0fj0=C8g=D#GkN!Wl$`QG1vO~>| zyVf+7?RBX6==8$na92aT-`?k5NY@l7&Cq<^pTMZEM0doA6B4R*8`L<1k(@sm9l-lE zF>sx(>ZeIOsD?n3_`7_k9O%>Y83N`A4)PqniJsBr$B;-?V&7w=gWsd$L2PeMx zL12EK`$RENiGZD(N=Qf5oQSBqV;32bpd6g<6E5R;CpX)e7B_lPDVLwXS_?p6~|dnmIqTtBDqbO?Q*TP_ZI;hMQ*8;?+E!%Oj!zpbj-b8 z!1R1lb|^gx%4MEJ;JV%aC!Ggih!3=vp1I9oHT?Q<^|&p>x_TP7{$%xsWR69BayWY7 z%TSXIfngLq1YEt-KK-~LrDsVb73 za%Gng6jB({txwoB@K((1Q+;hNwe2t!AlMrPbAhwuu<2)42dv+nefcfQiMwAs&8BA5~?&u%r< zAN0x5Pcyrig#x(Tax13>nb1ujE=*I&;oS9S$HgLWOma88?Vs#4r=!X5Zfe2`GD=<` zn5Bwi54Qw?Y08YGEKk!K5mt}h412@k9eA1i$1N&7T(2$@xTHcTdkGoyd1x$GAe`;u zsL9~4O!2mWegf&>%IX{J5geT20i37|ocNK%sv_g;RV+bEBa^jZb0&IPZplEvS^K5` z_5_S1mFom#p@ck>h=&GEv7feVWq2B}VICJ~b8_aIj8xSS$zr^5IF_sExTe z4u{0=2JE%n6HJqo;FLN$dsytYdl9M&^(@+LM~3~r_|fDU`qfpWHQ|?8CYRhS-7}Vb zM%Qj0qpf&*C=(GQ4(5!%{O3_lJF+ZSy+U!`MPYQGQynj!gRc9eoakzJf70vYzf!+0 zw3^_L`vby3ieus6gP36Ohb-5B7xZi;go?-#jj;SFfgv#N)Yqvsm!Pe zPk-f~Vj_qAqq`ZN5$}-OcL^S}5t__-r#cjhXEfP{aE=p~f{p+I(T4ceLOAQvXj$fM zBqlM$))bsin2%4$O@bLPLEG>I9yGjxiErCzf;jX2@<_HA^$D*%VOs)5)0oFDyAi5W3gD z6E@Ed40l{&_qPZ4#2bzcz`4KN{*R1p?LLE??2X_u{Rae>`kx<(K)#o#b5eVXNa#_s zO<56eyMu~i*@txPR(P$e_Hi%y!F_KeL7otYT9c3)rR&O!q{~wo)6$VIUd~^F^Vp~B zR_O~d;@t-)OHR?7y_n+lpn7tM1KD69D`bYRtsKxwNljj9qE?#eA(*%HCwOEWbq+HS z6rpK!uBizGFAo5}mJ?qQTRLUW+@T&$IHGS73o zNKNSe$MW3!S?<34q`T_-8q`_C*JdOf4*fI*LRfihy8VcYiukwzxVDIofS<^9;o76c z6;N2w#j=AJD{-NGB}4A;Ra4>5cNcsB3e*DH{e}+xL3I^UG(&1?xK)>RN|Kn(Z06f) zn9%6B_nj%^BCzzSsMTu4f$KjV`h8zw$KWdJLp{NQPzu|vYDzp}qeF+zR(TA(X|#ua zbqn7d5AT*aN&VdCwV{{j>3s^Yt3h@j(kE8!NjpYRwbndRb2!hHV~E>_3aX#W=wpey zVYq})HS0MQ4ha|Zr&1a)wAe=BFx_z2L(}C>;3+Lefa(ON^O>_${p|Tx+at`7;kcx8 z*(R7bSScbLLaWG4zTkA}r-ZN+_-wvtFyqYZShFJ~R5nJWd&h?vdH#%QQedQ(%1Dz& z`wwV>ybI6YGiSbq;kA)_8|pnF>=k^V%EfvHSnr)A39BUKI8wGE&^`+Z4#aiToyt1 zdwi0jpO$GeSFpXV1GXI$>}cv??$8ov3L4hotP)<Nmg~@!#l70 z!x_`te@>^a5m}4zledl{N-Q#MnYY8n{=yNzk5|-v1z+gKlH6+D#1j0_-uCaAoA9Ej zZ+jUfTyk>gl^{btIK#_+e1*eG*Y@l<4Gr$Q^@!<((KU(~ct3(vfV-%Nv_*ppM&p>Z ziRRz=jXK`Vup55H7BS^;xbGiUu5@Etc2{ieWOrD= z=yz^b=wm(Jz#%Cxdmm5Hh zVF?Z~u>2vp1$Wb)^OQJXkhRrUBebxWh0!LAj{+&_oLoP2N9((uvs|&!hm-E`NoNzz zl*_c);Tn%;u5LrhU}pv<9U;ANLAY1Nsf!G~V^WJNm(YXJgzbV~JN1F+hARoWXNw34 zZJdR}7e=8m6m&+3o%FBy4R4A3BP_))t*q^3yv)+J$rZXsBL^+;EP2q1b-NH`KpbSv zp6NeTu_oyYTSo1-tgKWC72lGGIN3B>y(QIGlo179!`EmGBmP!)llZZy)oPqnPZ$B^>+L^33`s=_b--9YL+BEIyehN} zbH3O$^jTyquP?j^h<$v~d{oeM9E<9|BpNR%qdhE(9_kMh8dFJ+v)y50o(pMDi?Eci zrI4y`dYQDG?t9rSrqrc@}B(DyYjmgl0j+z1BfHg{ZB1K+)r4*>p-} zQ0sftUU>{Ww!lYP zEBlrHLuL~=KIlas(~_x&q_N%_i$@h5;)WG4C=G9Ob%U=qKGC9(Q^G39M$D-jR5uELNY&B;}Hop0o}t^pd%q>zg+?!hb!2@ zb+c6uers}B-Bp@Se^;%WAff}Hr(~&^vAIkI1~>GA5=TRH4|&0Jhhyo6Sj$0A@}gz91_g)w|Xn}&6I8xdQWO6cxd>IyfJJZeH9%?N146^I@9>h|%$ z;y7f7(jjX&dvW|5TQZXA5a(1O8TI29(Z$hOztlT@0{_?NHhy)i=8?4NtfFWIF|lE2 zHlFTSWyrWbBvRl$#0Jtq4X)f_y1Udey?rs4Nz#(FvTBNrp@r<%%RyKhOv9`bJdyJ} zG*HLQ|B3L_YC1s1vwr-|JxC#KecN|l1<|a3{kV;9%8yd-GZPFgogUvsM*&{r|73N1 z@P51$N1#C$GZfL@Y=33e6IQp8HvSgAm3uz|*?4F>B2+6c76<7a?yp1ic=Adt25^Cn zNzRPcD`F+E4=HLW5RW>{#7~wSCJ{cN+89AWJTnF4+w3;$7cfFRWFrFomvw1fDp{f* zy3A;9j1h~E`?e20s*rkbki2oCSHX>VQN71 z_atY=pMc>Ju7zq>vfxg^xGnrQE3`30sXF1!dj-g1GcM2Fz2`>sNEj4Pv&PYd+& z@UO@c?(#X2oJJ4pJ*h}Bk6sZk&Z^yHCxh+*70wmr;gbIM`MmvMT0C&;fF;%-9KA)W z=a!rz{4AnVmyZh$rJc?S4a)E*nN2onsB#Ft!D^{uw<)h;$S;Rq>0?SiudJ1>z4!iY ze7Y4Cyi*6bdDK0m5I8>n;T`eqPQC*hpBE$-uChYjKJEHdGq57 zsuc7Rk2*9gz=LG$TqJ`t{$nr$Zs0KGxHWxkvJ{dD*&ml>D}6Pzg`ILv=(U151EycPk?{Z=sY1bh%#f7}`UK~Bbqki7Y{L;rwdG`?l9cEprvv=Cc-e+WE z0?gqb9eN?#&cH10n-wLFh6-W+_p2@{^H%vI+43!va3dtOmAe0Yr^2L83AAvyUj$%y zjDmZICU-O2{k-q6>%blr6A3(m7ANNTro(aZta)pENs2g2M~9m|lO(aUmIat8bx+h1 zPNX624}=#!_Q;H-07M0xluCURc@#z#b3DqJ(9{q03je@mS@L7B!0_kv#JKHYV=Ex5 zWu@0u4K)AUhioBLobAfhB{>g5&`0G&oE9c$;q&{%i1fIYPov7FnT8%LCCjzZFCT+L zgIJ~Ir8|yu8aDgUS(9e_r*rXyJo8Ck)jIl;`HJOqMojtFQs6G*ud{wQ`C@B82{+eB$+=W?i&G^{Z0e2T;x|0F*mszH za|-8ueEm&(07)q-bsZy&)*o+A`u)~t$f=|{SRiRsLft$X$EFLFnpfQ$_cDY`6XXX0hBo9z=5}AEh%4X> zD9;eN;gqWwj>u`9;}77g-72@!pin2Dr?~mzi#v6#(ZCfkR|nYr?sw@@gD%OlQUt51 zJLaitJJs8Drb#gbS_TODP||E{5sZzDtV>)N(%>^1O+XZ%M2JW*o6a~eO#Kgg?-|zA z_pOU2fzW#ip-2Zq57kgadKIMC(0i4t0TDw9z4zXmH0e!5I!NyzpwbaUrHFzeo~Xb7 zKL7nZ`<(OP-g`dWXY(albImd4$YQR!));e)_q|X1QR^KvEKEq(9S@IA{DA!UX&^{8@GZo{5ISc#%10(1EFag{D%YXe8Gu%zv{o%l%Z zpac4);wL*9=v)a#vrdY*iy$EyO{WXGn(SUov26}Fqsi_kK8mfFVk~Q_Z2zPk=yBU!1I_M zsu_m{jVr>ve&XBJ_nFWDKrb1~(nkg*%;|X{br~>=fZkfwxdBGeXpGjh>IKjWZ0Id> zl8Bz=4(j1m+4^?4d~)p6&D!za_1GZ8hg8};$KWXz5#iiXyZhDK3y(QR#^T%c^>Ti$Dlgd-%!VYhZPcB7^vjB8$U}|WN zIVflnPZF4peRLPUpyf;OxdqprHTnxfohXTwTELkBI~u|K#6~!w$)QnM$K56)-v;ww z5o#y=3@{>-*yf90N@kK+&{3V*5>Q`_s9%qw7&78VU(@`YRvWzH>HY-(=JjZ&qxP6* z9V1487e1sFI%^qe$^e&t&4@LV_J39^Z{G_(JQKrwOtu}qGfkhMZSsw+rp?qwI42yu z8e)m73yb2?$tgmE;WhvZViYghx2*qg^`+?9^cA0(32QSrP9n5|qQghn3!wtEo_fF= zosz)iJ@W2cKW-R=lQXPdKW=8AUqGjxXa8b0BpZ!G1)JG;m-VhKq(onUmwjxO(*;dT z;z$W(FnE+hASt=Y%wBjc=MScHeHK?yr)F_ztDOI4Q@EiIp<~_5Xtt=v9CVK>jYCHO zR(F8M+gvnQPxwG8JfOe8v(LW9nKzHBO+1&EozZqx16g^e%9@E%!I5K1VF%dIbTdCT zX@rT&gvPceoQ$a6jUW8et4JAUHe64A`9>GOIzuNX6i0#kmdy((?5w*pyaKldZjsWR z?3w+@4~fB{G-%YC1pQ6cf_honsF(eb}{t2!KQd0nCZ`^%^W`)g1XHb%y(3YUeL>byb zd6nx21hl&NI}(^u_c?y>Vujt(qAT7v6g&Za6Idr@XozUAEFxl00CeSM$RYidB9;d* zZ_Q*3%*yF>N%%d(bbNrsP>iZLyNP}QH=W7;KHY|0nc!F20N6c>u@@*N*YRshg-Eg)$b)PmjClwV0a1kKN;8IwD7mTxY27!s0&sDsaucAfLg zdYg#w?~}SnV5p4vg-Mj|!BFIb7&x|(MymAD4GAAS6r z4yl1;_nW-Ry?+o0uxahTk;$hwxEUzcYPN4_@Kmq7jn*`(K8hHbwUN0D502Cs!M7!V6ot~@(lo6=ov zX;ep93P)K@hIlddK_sruO>8-xsZeRL@(}4EB}7N6{LQX5Bs~I1&rm6u&iB`v z_O9aP!4)i4+8pL_5|ea_US`E<6V;3Q4}XYXW~^sYHV{>ArL9avE%JD)^bz5dNGg;2 zZ#d4>`LIg@>hW9ww@omKxwXT@D(gTUJk<+Dv`VUV8xJv2--*j3WJ7j(Ze|(KNzyk?0 z8DitBBa7c4^egAFg?~B6rd-j>OS`548XK$l;xAFW`>y+Xm@hOv+<{$T`5bT_gStz> zXuc)Jl4hK@4}Jj_K4KA;*02ak?bk&Ky~+%XeF?!FV8u1f_!PODan$LMydiZ6)%d>j zlf!>TsEPqq<(WX1P^hE~_+H%8YKcW{*Uu-%T?##N5sAd9#43sa9sG!oo8@2n;K2KT z?<*Vd^?TCbUx2^A>-$xLDhtW~w6^m8Po)S5QNj7O?(+xtS^V-}p8wl;7(O`N_Fpv* zK3b1oc=#(02P#?{Aa-br8clwFw)eGaJolq@Cbm}(O+<#j@sn0?X4 z{_9lZ?vec^X%}mi{mIxj0{4FYL2&qIwF;79>6d#eY$q>j(dojkv~iaNSv}0n{3A$~ z*u>pdkkoWVKZfh}iTFNcBy*B>J{eyzlcWv#qkCsG?|ZwTzW09toc`Rle<@y9TEm1k z-AQ|y1r(|GZirX`boz>o&IagpynAtPgCL9D!94Z@1d%tjGRn_u7!m|(IC+o+@Hh^g z+F_lYGc6{zgv&c$|BWIRi}`~W_j2e@XyPwLuJqSNMfBOrzpmati}18JD-jllPqk>E z%8O94FGHhYwX3J|#YV!=m3MTj}>$ z`~CO)+4KKy{_kt@|6oFZ`J$?J^|FY3##9>seeBG1b+-MMz!-= zD92z1!Qn+Be8KvzSXs-$2fQ6;X2_iSAcA{@VKjY%BF<2@05M!m)u{@!IgDS2B?3i$ z9&^)>Bu8-}TO)!%{3WV4qwKes_j!2dl zXX=PiLp2lDeBtU^4CA#$p*@6C%!dYq2y$kf$;TyCWNMR%1Y0Ajl@@f2#K9Tx^5NCt zU5n>hQ4DcZHE)@ul#T8R=1i-ro4w_8Q(wM@i>vhuHS>b2})P{v`i#HfETuplfUh7LPX+@?ysc@z9XMyh>R`a$Q)mkF6m{~X@Huh4tWW2%+@RT{HX zpzk9Ca&N6ZDSJl}0<-${07j9}PdUXmm95Bq#LXq;b4jI6GCoBV2U69MnrBfVs*{N} z6`ojsNZe=zzYlRc5hm6UttJzh?&9KPKP$KU1yDZ}edz|6y%MXu9qrZT1TmXL9w);NA%)%gGP~9%R+eVk`h2f6f7p#4OHJKnV%TxMSu#gCqQ8VcfY49n zSngw`Q4+9=l^$kBH`IA9%fk7^i{%-aJ`?(5G5d&M?X0&eKR?Vl`Ihyu;L0onGm!Ry z2F;Pbad}LvR%}v^+$LpvP$YpLDw0|LkcUis%C`M_(ji+(mvT@@%KPn~#$pH}4li7Z(|tY<#A2TS}Rxg!o7b1ayevi3>Wt>I+enR z0*)$-FnP-@ZoCIfzW`xXQ$K3yovc>u3llhRi+v4K=kYx7mHED{j}OO!q!AK--lS zP{-ccAyN_J zl+c`BeW_SGv~zSR29?%Le%bobGe#Co%1hCaAz9%bB$y)Rkv+c=;qDNYl_a|2N@f{c zO8cOrFOxj+L>2jD;d|UsS6}iq>_g)BLf!mj6DIP%&9$Gf`7IP5=cgG2{387GG?KQ4 zQi3jlSWd`ZaiX*cI;W^{S-Xv!FMeFsyM-YY7p8v!kg7{}usE+Ww|@bkmB-(11p9oB z@!8CCD=qn85OS{X zPJ|F>R#*avalq)CV9FiJP4s9;F&f~==uy-0lETJ6J4k8!2Zs5Sux+mn$>CBZ z?-$GD7g0cZNzsZ@HYLpV2xLMk#@%L7xtg(6_R~x@t%+s0+mo|zuwl2vd@DYOWZhWp zt%qD~YK;8X6P-K~J_ujDjn)Sy3R%2H&f_@tFR*Pt~Tp{6h8f{;krredZzmC^KV%w|Rtyouz3wz>4uP zW-+?D!B2Q~P#=6k4Gfe^Okf1zGMR9g^)Fy-K)PAh$W)agzQn;cV3}@BjR-t~&{z<*|^4e;wjDpNShicLqO6UG2Wp z2NN9QsJ6+LPz>4_I7SpeE+*vQeA7%^PMn<|Znjyz6?-M=B1SqA8?f4&1(FcK78Tam z0kwiCJteQ2t}GlhH3f}p75Z-5#H`&ts@mr#r{WMd6&b_zcp;Er`>ckRtYQE-xEa?r zHqieR_m!q6J0&T&tXMQ+cz(K8kq&I+(Ldfcj!ZN-%?+q_Y< z!YQf}VpP6BS2S+euhV`WWR0j}qv6nuZO(|}KXEj8BjEo?D&paWyFp5?PlH~I?L*gq zID+;_S>dsVp*eE6FOl50+4~?SXh$ zBCEksm@xQ#$oHroGJY+|O_8jv=>>pMTb>DuJtbP(qt!fVx_|w!Yg;NJC7;C1Fub9^ zluJ8?a+Hh-8cOq;6h;!a)psRe4zjQ`W+YE{(aET9db$0FW$=6A@1Wy@7q%}W!c|+< zSY4_=CID^}vau_LtxLudwFU{FxL&P=c8|Wk$wkk?;vGYVI(YAO{tK}DZ{iPc+ugYH zpCSaZ4Oag-AZxdL5veM`Dq!UtsRO;?;{GlF`8Vl@pB{W(cMqmLId$)oEMOf2Oxoys z@V$h)Hw*m?{+(%my2T9YXlH-z03!)AcwVb^qwr>8(-=eXYpi+D6Kp#h2zA4NPsO6ar#z3byGmSt_8B8h zp6!xUtd__aTHBx+#CT$EtuOa8peP~lVv&HYI$*V&#sJ{15N<%aB>kbMdf<$(daJr( z^{RM$nj+pd2yo;^y*2{)DE>?XnqG6^bsTD&OBsAzjH3_>epZOcVy2N;$HDXXu9##< z1ei1}sC^8lbxn{n&|Z2-CC9z43m;?JeQpckD3KE{eMK7k?`u2>%#FpYUQ;nELMSy@X0(saanIY`T@u??j~l-HyhsUR$;50nQ9yDZ6nc2e}uG zAZ~X|KU>BZbhPcl=PuUe7w;PS6P)`M{fLEe0A9x3t~jdjdNZV?3c@D;gW_}J{_m(~g z<%nDCE5B#)Ly^xhU7OG3v^wgJJT;7WgJ|f5!x^yRIoW;6=jDSjcRh)FYsI|J!}YYh zWBKU#qeHi}>2##hHF<(GnxWtGilgUd&p!Y$OBfpBdf}$3{{~f=1p~zpo)_K=5s)7GBS;z@Xrm^THx0i z>9=lS3 zGKr%G%RM};$Ywox6-4I-4k?T&{DATs&O`Wk<5{?0qNkQ=Td7xyM~}-rt6NF4G6XqU z_&ck2cbIgFm0)M=?;hM3?1+ZzrC;pBGmC<%XrFqn==KvwEp~hQZQ?jmI+!%njV{g) zBN1i30B0P#`ldXHFS<=1A`fHs3Uzi~eWWtbnpU34jZ16CKbfUX1QL~xiSDtla$l?> zb}H(P3O5EIG^$Zs<~im?`w+LMw3^P&#?J_??O_?Nqb8lSLK(2o;k^UxX6CnaF_a?u zWW;dvy~+C_9>@K%{iNjwHKDaYGnxf!)|s$@+v&Z8S+zkfu`;)Mc|nVs2;qtT2ObS+ zNl))@TKB%qlu;EH(aK&g^w+p7+1@p^6oT+hhf8l3A{2NpB`9H@Gs6i}3A`>mgZagQ zTQa5btQeYnfLK%g(WS;@HG#}9WcAJ*G>Le)grMP)reiyHS6|L6#_7jCxY?kVNp*Ih zk3Qr)e_IusKZ%8dNQaQf*qcE@X+lp2S@q2rb_H7*H|Z?cJTp~v^K>GT%vNg%+K!4B zn#?`H&|d9ZnrQx(X*~g5Mcvr}M9;1@TeImK+@ZZWmH;!suMO2;;_bUs3vp>#z#89- z3gceSWw1+8T=!5uTNkOM7H5AA7_#j)Cqf*gCO9u76bUm+BgFCUA1AY68g`Ls$i1z~ z&(WcTgc{l&ZaOhUiUA$`6634d#$fu{!l3Ks29xv%A(=fgkz8WkVii=mjSH_UI~@aF z3cG@Vl+L`#X4qzwsr6z=Q!74W{5$7(d!UifJ(j`psMA=S;ywesoSJ>2cc3C`6kfc; zg0_N}wlOGM2)vOEu_s*cVx@md<}XG&=xXsu&NGClW8ry!b7#!ph#^02AIr}Oz#}CZ zy`-ply7C&+ifX6l{XC#b_E6TYu}O(V?KmQ()e86)u2sb&?(kA=6Cez)e@?>LcdQA%&Ai^JvSd0BV?O zyQ_WdSfA|J6Dq#4p|<67a}^W!N(6(*IH_|>Q%xtW{hlW(p711<@lJxfnx=^9a~OF> z>9fEG1OQn5V&Bl%KE1AVQ4AFEa_9MPE~ADIbXW3;q^o7DRi!wVy@#ranLCQ$saiwc z>aAyqja`C{R4+(B!@rb!l+u>SLPBM|?AboVj@o2ey1-dFEU(4whs5=kM`=$0gj~J) ziZOW-0_@?lmH`V?l2u~7E$WKNj;tLP-Uq6 ziB@gNTGZwMnTcIi=5C`(649KGeD3}?=G(MG`&v(i8mzl(CuGQ}QwH*N33P9pt!vny zhQW7ClX1`SSML|D^8^F~6}C(FR4yz#HM^to*h#}|?fO^&c&eB6fA)i=hGc#LFzgJV z#Z8n&E)T)CsB}Xt^|K$(L%TB!h2bZU5N*Vi}2yb&XyUG-d;vWC`2 zk0lvUBzET{H4hg!p(@(@G4aBCY$oITFTkxo?-ypV^0s5bnl}hB;7J~$N^0Ec3tHeN zZ~b^z6c=UmhV^3Tc~Bfpo^N@hn_?kG0<$!#E9PWlylX?mUkV?rgTJ_U94FDn5f6Eb z>3o7mU;!yH8dG3op-iYV%!QsbEX$7yK9f2X70&nOZ-kN@DH-2Qq6iHmMjX)JDqy7O za?$+qWcJ(dhnL+FUg9Qkv0Nk5u&t!^FF=vp4zucXp>1HBVKv=47AF1A-eLMQyw}sZ z!3jKus9&f}B>N8#NK76P3t&Ycp+-eH85-&+x&9 zp@ii$Nhb2>{e11koN@SV1;^9b!{@>G%C&)npOmv&1?>n$hwe~lXh@aSUZi{9@XnHF zQ`m5G6>JR$$0+nNX|=tBs+V;>^rrUkZncF_S9e=MRBMOWD$AtO*z-!<$H5$O0G<0H z$4$*%#H_7+vlNvC#W)4HycDMCz#NqVf2M|b> zbb!*4ma@mI+$;UW9!G5$&%7yeFo)$HP8#>QB zV79{tgKOB!pnK*#=ClNdm2SAiUc;7C4DAJ#*G(oV%ls$NgU6pSiiZG}Sk2-z+$+>I zfX2F|?JX_%aU*Sxyu2rw5IYIv%jQM1I1X$SAC96Ro7S>n$wvtwZ z6bmddhQ^B};c7cQZd-WY2A1z%$?S(%QH92ojD$pPadj5jNWkI*>+zv!FHA{&l*jZY zPdgfqk)>V`2?ykdkj_vGm`^fQ(ux6_Fe5Ieg~o>dMq3Tx;E*#dP);Fb6|NyaoN}(( z`ynXwDR|ws7(52z-Hgappm}m0JkTRU)}T(uZ}4bLV8 zYI`s(o}~iR!&%;Q6sXD=RACkAWw#V##UzeFj)hjp_fhniaw%X#%0auhjEKHG-M+L2 z4#}>q!tWnKulsnf35+S)Pu@@IrD?$$GWX<8+c1E&>9Fb+K#1tonHPy zQVA~;pXydooFQ;$g9;39v6l-!VzuQ2Opfx;>SiG08QIQLF@n0-f)bR(%F#=QH25EQ z&Uh#>BY>WD4tBORMYXXEMVow?&{x(@RJ$wuZN`J)X~jhfO!LBu3?7Q3`{0sZ^E4(x z(-SU1`YIDAfKLLz>%bD}ETo`+ZGd6jA!e|X&qCk(JA>B!L-=l87{&TzNVl*kxyve! zBsv}GSVk58$p6DLh%4`=(sJoZQf-!T>)|U;fuGp;xSCa4?)&Z!gI5Z2?Gm+gr9iYo z@~gzPI&}-vehDAfS_(7JRXR)ZauuXdje1=sf?d)CTW)dD{ttMs#J#I zYGE>_oqQ6-E)E);W&M!@U;t)DbPyXG89XyAh=kd@p+>woiS|NV64q*|q*61JpkSIr zXh^4m;iPFJUvgJ57`tBnanyeSOqlLqUUm7U5bm_5GI`>~#XS+ildNU9fXY_mto5>r zU;vJ_(gg6ANcm6L$T!60oq*3`*I0-@%%gD^ z9xkyAtLcLEIjEIZRbPQ@0q!FmFDU~DKZR_iesGH|H|qua>yZ$xhKw;kas8MBhDR$9 zdQe6VXk1TkLAe{Cql6mz4UgH62$1vh>0ceDwCqx92p1cEWr9fp8gE%AYQE*KunuK- zgIj}nrzv=;1}Q6l)U-Q|IuLK3Jyt?PYUJ+PvTgV(%ITf-SpDUpK4<>@y#4&WFYF>w zS7oRhQIEE52bFEJCLCIY4Q4tIkwsZJJVZ6e-V-k;y($ z-DY|(M#5cRk+~81n==Q~eNgO9fWj&n!fpve#tJx?0(x7eZ#8Yd4x!#CW@Zh2;TKCP zClJGp%ctAnYnwq+g0Rqh8u39Awaz4(tuU1!l;ika^Rqs$?4~?T1}V-XGa`pLnGuH7 zSYzsJT7jD&p`5Huc%lwYGG!kNj!A}~yO+NRWy!U!;?y+EHJVyBX=BkZtd};h2!<14 zQWCRq!)|wcRX7oHs&aMxc~M2tiZ9ThVEem-w}a3 zV3n)aNE0rwiCMih#$#}nK!Jq zqfUjmd*t#vp5MFF>(YPCI`9+9Eei_>SGrg z*|DZJ+L#tuu5}bTl6WhZ?zIiNB)tDi9((P*+SYH5g6LpebC3{JBGUf3qHvKhLx?i! z;p01ne__%i8jP8~gld~o2Q(<9QO^K(v5Bf>)1x9O2p_mM4PO7V&eO4UUY&tP$Mno> zY!0hlX88Kqo(8s8$$TZL3^wsp1MW>u!#+`9+VeXNm44l>Pp+TZmDv#6S(Q6(xHcfA zTqB+5^t7txk63x+F-YW(oLaMyCMd>rGU&Gwk048;ZGwz>Y8R0Z6n%psO^-ZycEkDk z@#zn9C^0e9i=a8I8s5&++C~R!CgaOj;pV;CO1g0YFKXO&u_tuoc_E}EFLYGHqv@~) z8x)UEr$jLSwuluHI{2C88?M(WRsrn2?{?*%-%<0~iStj(($=UKOPVDw=JdB6Zf-bZ z?MJ_Vvu=DjHuvrHENkl$+n)BsR=a@|G%K{fbNP?QM6L!~;ikZH+QM zQ3}o{i71v=n$uP^Pt~72??c)sj{R2o_=`{O^lzK0M}&opfBZ@D{P?{u8S@K3|3QUV zm~&%W7fo7Ye7-}MNgr)HlEacRC5pcizhPP|3Cr7ktoa1RS1apOL+f8^8Zln(#i{`N zLey@!buq^W|2nq4Vu#1e)HRnZ4aRxnLg3s;Ww1I2>1;ajP1&_u@Xj-T@j_wWOPC(} z6kv}!?;$ygJp;bMdx!+7m#0C( zsw7vY;p0lGG>Lzn;ABbx$T2M90iXbbJM0*1Un&M(`*X)7$OlWDg$0;@ImZJ!c+MO} z1V3%WNi~8Frg~?_FsiSwqr^}p99XeRgJn$nQ{#C@=@)=4lDJD~dvf;b&ApS|PhH*b z-im4GUCTbY?(zIKKEAZCehgg`tB$Rf!n1XvX!4d z6XlTKgz%o@{R}~G%X!$P!f)Q}pq&tsds3^~>9*_lL`-nJGP6c|=vij*<#RzxR}04R z8JYT5Wrt5P$KQ&DzEN(Et}JVZF(-12JQFcVCtwbohigD&Fmm~;_*(c1NiF=1n z5{3L1_pVP${Ps`I-kqO4?6I_Lm%2MiD;%4NGuXSbG+1jb2g$RE6X*+xp#=^pex5fV zS;Rmgs#ovwF3;a(->gy0TObq~p%hJpmW0kn=V?9&GVXzhOY+%guS>wVV&s z&sUMtW+%)#VZN8>vpn|x+SwxWo{&*~td)@B*#l(vLf5U#q5z9jbu65ZP+C2xVdH5; z23;b4=tNR4lVMbTsHN`Imk^x8UL@i%34L^0jj0SL+jGURjX1S(SRaSy?Ie~fw7T`z z8EE!%gicEZDRKt6PtDcR%=+4NozIY2#0C zQPN}TEM;#`o4htLAz5^we{K)_2&y--5exW2D#m;}(Q1!9aLAvCP?$%07jLKfeQE+& zw>^K5AK*6pGnA;MZ%|s@S+x9Mi*f>w)>ktdEV`qy_5*Ei&1x0Os;HL7p5&Z1ABSZy z`^}pM^K>Q}wQ>uO#`39&Vrk5vS(2^);#Bip*$h`Z?fS#oCh9({(}DUe@kcPi{=TaE z9|ay+cznh4lKfu(bQ@wn;ZVC4_JeQsbDhHu+I|cAi2%zddU+mu_ca| z&CJcLMB?P~P~Mc?q$^c1`xdldpHh{kvaNpgxCN=ixs}P6f9$jdVBf*@|5kpkoriJ! zQ)%>nymiMymSX!-LI51oyQz!7Nq1u&eeCJ?n7Ghox(5sE}A zXNiPGZHSc7bdb;-`#va|^o_b1VnRpSzx)=ufrQzN{S{!9ui)}g#-bTvo7cEsBUs{%q1aEXkP7>J z$e3(Sw_7guKvAIj?xozy#IsxX)O4UL#;{4gi=wSgU>8Sxc@qd~vu} zJ?bBmJVGeOssH{b-kgWvh+b$Y+N6}yetu|w8%KzJoPW!{Zc#5Y!BV2FlV!XN^!*_0 z!`^h}og)(W3|oh%cn$W+N4F^AbP4BXnep|6cbIXW zYWe4_gXD=R8&4=+sB0QbT>shDy`~1MTk!$v9JFkn)lyJ|a><)4$R#mznq&!q9KE1XgacHPTa5I>CZydK>o1v-cvVp_%^&J#)%q#m=F_+TXJx)!xW#n_qiFP3a zl)pLl{)5Z@`3Kso+s~22&O_OXtRWwb!^^BoGPVM{?uTE6$Mn7=DpbuGM*P5;18o@S zUCahKB#0{qDcnlcVCLi`vOLmZ__NHg=u+mAv_L8-`^Le*ZUj=A7J)cM4Hqk!q z)Hd?+XIr!gpx|MwA?~Vzj2;8t5;Ai$tfqOOgwjk0CyDK|YOE=h7jh*dA`Q5R{2fQ@ z=UVv6mnGjuL4`Sd53VN{Mh44JF0 z*Qbm1(X=8+FRMLU4pGKHIRZ+^uJK-roym!IxI^gWx4)l*<0L2s3Wbj3v{n^?%hFg%3B|NAVI3sa- zyjS<7G<=JlBa7lo%Qr`9$Bs<$vU{Mnt{jK8n`TQceZ>GyV$ky3ZKm70{6+05=3Dop zd$=#+F8F}xZ73|jz!{$VPgDBb)|Y?2=Wf}*)O+R|q;+y@@Evu~UHgxS+uRp_PO?It z+$a@LMGF4WlepnRL(7T2S&{ zOI+`#)$F$_pFwZxn+R7~jQ^-{^zM##R?s{gILLZ5`PWvh6Cz!``X`E?%q}fhCW)I4 zb`R$p-FDvxdyZ%3WU8EgA?Isyk$SfqcL2eOlz`FFT^0~#f7#GbvQ0z8S0u3$5lZe{ zG0D8Bv=V*ITp%~wneUC|{}sA>^|z*e>T@j~%fMRe1dY;^1d_;i>5S+`TH}~yB#)=( zCa({f%sRVzAY;e=mQVM$wO!i&v4-Q%UW^A44f>z1ydIoJD51T?MI$^=V`knT090?a z05}MfZ-7Qnw-?STyZ=z}bFU?l*9UTJ+Fwh$ykhB(czH-L4A#f-bt=lHvPOn5)X}kR zg4bry(60WlCwqfYO@u$w!=AEb_#Q&;pfUZOj%A)uUI{{{@7`R&NhV@FgYy`}md!}A z&IFod(7SB@1&Fv+eH__MY{I)pV|G(i{(XPG5*mID1BK%0i`<3rjn0nUsHav&-^`Up z!q}zg8R|GAy8}#>ORF|E#7o>LUWCrj3{IzeId;em-7G??k5n$#wOJEtH(v5zk*@N+ z(j}!%t|M9z&zBtT( zA{)b;!<73$O#8Y-PvvWUI^&z19>KN=RCd>&9<5*z_ANNc_?sECroMdSeh;;zc-=t| z_>NIHYv%ZU;SPNBq4HHg*PYy_*D^1bjdM@VRW^%a#j~J|xrIg*OQBrxg?-acmM7m{ zqWIGu^uK_^+-5R)*JtlglZ^z9(1@o5L{h1V$Vx`cCLmV4C8{M z6eqmD7ooIYf6s3|mv%aQFugz`M`Qef;sZ%j<;s7weJre+nW5eJ{_p+vCD(L{@TMQm zVP!rRK3%(`-xgd>A!h9OZ^xDHKb021k);QJRsZRxv%wpdvWqKo)8pT@^|lcPS=s+f z4^~c*eShOI$1O2Z#RR?Xj!?JU2;a8g5_KLEQ6$&IH#Jft+qcqBqm?$!hwhL>{}~)B z^j9NqQu}Qy^?z#%VJ&^slM<%cPWW$)(ekbZ_saflL`w z#eVc zz(#I~i=H~|SVc5)p%;g1TY?#g+VEm^-&2@~11gU-Y!d^k;3Em}s!L%U4{Yv6wm}a} zJRb*nmf@ZHjy*dft}heKXAHF#siH4;Nc0ckN#y9S^QvUn^)7&QogBmztKa4rJ|u~V zpXhWwG!k+z)#}WYhNZP4=)zG}RCC`*hMi30UcO9&=*(r(+)~nUZV_a&Xx8u);AZ3v zEtg=;dCRrwo4N(*wHEfth*~7wJ2EDBesu08&*X5jsWS>x+et=`z3FUk=+UJ)u0((H zFheg6RD4H-t}L3cUTE`E9luiFFnS=?4pt>6o+7m4p^i!}d7BammxyGG0k{{`LNl%I zksM6yLlDh^#d8H-I`GVd%D;iE|H9+iJyT@u3>7x6iNUw-eO0wbtqlp(gbIy5Ii=n9 z(;eUlCSqefmiZErQ)~Ztn)&Zr$+5#h3F75d_*Wb{V-t^)E)H8|`CupYw5*KT@A^Uk z1y1J~lOk=RR2Fn|LPH8l*A9j0Do0>CuEC4~8O8JR=Cn~7l+i4Gwj*JQW)_5tDZxaJ zM&rN+b+UK;ls4D!iwZ-ZE^^yJD_z3iwJt7qM|jqfZ;JcVri!s#Ucc3rT;4z5^FDR3 z*K6yW{%Llv5}@nDcGv$SWh^K5Pp8leUBP=u>c6`5GQ+e9{^_EzQlBFiY!lu$RN`LM z%UKP~X(lBapcuNFh?6*2DoJSVeQ#q!J60w2uc*F*s>OQ&N2~$Zv5R{o++Zz!f9%tD z(0JGQuhAk(IX4!rzx}CpevGYWlAE(hDpLOb2F4s6CS7y*(0Jj~v#Kq4yn)etMDVQ! z`dj0*blFV{ys#+=pO=3V1FwUluNBGY{H#WDOE0?$x5wZ32L!JTNmW$cD*B!;xfQA( zE#U{Xe$VMD>}vM>#z`V&ou-j_@w9bDCzdY$AGZ*^93i%tP&_0AkD}tsB(&Ovi^Q3D z0dU1&CHh47QrTe}FD(ThnB7Kdpx=MEi~IgY(4&GLB#Vt_*=Ot~tjYh{FGgjSOjHOB za-pp6lqqH)6By**0oQ6g;p8#t*nm5`J1+*Q+3O$fHT0dbXan^yUgpi;C**$$88|Hw zmHxvgb@h|_DuPMy{maB#s%QRpMl!n&Pk-7^y;9GpyU@-%r7nh-7X;mYMOrfXbz;GO zrpc7gnH(VZC3=D3b_1?$u`z<6i;Nce?)SXR8IQM$BD-bXviU;}Kmwvn>E%d)HseOH z_5chk!kLN_c2&t#Yx}SWE-fg@y)SWkjvMX8Xd7=d0E{QUy?%c7;P#WOC`UPC<&<5> zepjt1=JVT+kdSO2GG0m-4AVLsFl3uR`QTUq)W%wDQ%!GQ&5lNn+jKz6Gazp&Eeb&P za~qNWn=41^hLlu{u`O|V{6wc{Pd;(tC`YMYtO~T+uwr&f>sqjR!TbKz0_F=|!R_sP zw_KJdzN%LK#sE7gO#SNsy*@`@gXFr952L&c{?If1W=8rC_M$&LN&l}MQG^Q7bg1s& zUSp9qv3%_R#hiRXYG)AC-0hq%xnXriX*pc05vD9(eS98m<9(BO`fK!>8i00l1JlBC z6Z=T@{6w%Ftu#bPY}Rd4nq;!J+MKe%WXzhNXjyXd4s`Ja#7$u0AbfXmF&gI3IdzNU zRxvmR&NCf+!2s|&eRw74hy+?OoATRS%z+FJ>IbNG32`x6_35`ZY< zX=O*<%IFEIuaZl36F=m0VQSvCp*UtJGB8+)29%-d{j=l?42ZAwv)9a5~ zq78HO;NP|3!DBm)`762y@pr=hlsBW3Z~^P#$Tu7@m-Xwe>)CdYj&bRB2{TObX~TMU zDO))!LR0c=TH6R<$Y@fO{Xe|C;ywYTzcVs-ox{n-dpczY1!*ANpLi(w=?bi;w zpM?E(DAQM3BbvcKP(O|7dg-J+-bJ2ih$Y;mr^Iov5lUM^j2A^8uPC z$tx5Hm{G&X$p0b;IhNdCeawp5KDk~I(9uCj6B*)&+p6ps8{SWkXI#(Jym%sOc~Y6% z@?q~0$Nc!4meViOul@ox9)0igv%4mKu2R_dXP=<&37H5Hf4hp@EulWVHsDqtPmo#1 z-Si++k188_p4#gF(cX6lMfEKI?gG2y49kK@l$@5lAUS8rStRF-0T6M?Ip?GxIcEVy zV97`j5KvHb$w`r<0;0Yp_`Tly4Zm0KRlTZLb^qCOW_o7&GiT4tnd$E7o=MEW>+-X3 z;_=L0ybNc#@kqwTjGBX2ZuOBs)?OpHnWxI&whiTUJrB)GkHFP;-$$Q)%eng%aNLS- zS!Kf%r&OI@FK}*z2CYLc+Z%GfY ze4_DtdM-+M_WQo+MHQv;=R+3%Zjp5R87lTynniqME6&QI$@P5}^lh4Dw)n;bL*CYc z!*^|Hw0FW>s=c;(m5BqN54sAN0>6A*k|6o5ZxS z?`dFjc=7Namxys&0u8~1%QUckoCF?zJjUdPo6!_C+Qmacnyi96Yfy8~8^)UEpnaf~ zu{7C_TKPhlrQON*!fU9r(*!8%6QJzi>j{X z6f1UnxE8<3c!#V+Cw(gSY!DG&k{5lQf!Z-pcj^w0sW%bWW4s=M39A0ebCAb2 zeE#M8Tdl!RoFQcdmTtOi0L~6pzrG_*hN*Mn@^#y#P`+L+dUH>y?c17cdM6!!GitYw zyM!}7f2-Tf`w0+>66ii!cy_mI=j6N7bsN>4zRfrrM_j!eV|++1uHL%KoT0nRdlFhy z)X7uDHDf6naaIg*4}5;|(Chvm$88fXwXWku$h2bf#xffFdfqE8E1!OUX~MV^9ZIu0 zP>N}p(vhtV?#4X`Agv%&Gih1V{d8c z*FMtR$NpQj%)Q;N%CDB%G`@VGQ0HR09WhfJR90!pjREu~u{U`hJ6C~@(eL4RU%`Hw zpuWR!LN!}H*_QXIg5L-L+N3@c6in0BdN8ZVOA+mN>5?Oqj{*6AJnaev#4%a41wqG@ zn?{&Kz$22-$Lj;K#bENTX-SDkBw+#G8|!oqjwJM|dM>Kx zIU|l1H##1ym3c;_TfG-e!>+t$}SX8fFmc49}S10xsr5i*E@6nv5Fo1(P@3H z9-joV0N*z6+e|u&WV^L{sT%Vk4?og_kiP>!=L7QbK3prQ3vTvxB44>Eq%$)^*96sz` z@e;dVlN-5?$5QQBi>h6!n*KNW%_g08luj+u=DwDb}BSIpvB#bR~ zh>_i^m`wF*^uR<<%($@@@oO1vTdN=Z|6$!7W9O!J%c@phRvZgM%%rb|Z>rOj0qDd> z9^Ju5O!rHtw|_e?;DxRKsasWxtfTX|!aq-@1%$b zb%o^tpY7|gJZ0CJ=kvr)0=|9^AU(Mmpp_yrGE*DOM&G(1WzN#|H0DvZ_|`|1N`_>g zCw9AXa4i+X7pI{B@wXdN7HhRR^;_SqC5LZt6&@AbzAo|1^fphxGvd)%?|t3%cT{8@ zMmL;1X{dUTCC`?rHH{b+>o#-guDBkWWv^}#+Qg%M)D56zZx2`YzW(L*;eNN|AH6|g zSdJtOzAgz>R&Vd#Va23{E2}gFI91x!wcQ#mW6n3b4WX_LhS^7V#|LsS)ge zp<2d&h5Qj!K6NE$L$|1fG(%T}xg{6i#q^8!J=J3=E8G4@PtiIarGt0t7~ACdYp+6G z*;5rStJ7*wS$V=Ho~j}>>?3vVuv^Ehzo*>5uNk9uYy?YO`x^rMT<<=DqgnZ>JseXLlOI(Et zo7RdXtXd%9UXx6Gl;1l(71s!akk<8h-19o?6f(^vq!;yDieuBVmt2`91aTii+}7!y z+ZkajW)mAh(&COVFV1|-9n<|!wX zXmtT+-8s}8+;|T2rH2w;@R#h-^ZsZ)W0$OS?L^)DI9k-f%UvI7{;?PwY2xO5C%|y<_gNp4~lh;7XvqPM!Shobbfzld%i!yx@5~{+n0&-_u?c zw3&ee*E5Y62lze_Ij97f8|>O|WNZBdNPIylF75RqRn6lE-*@k-CQp-(IOY7S9c=)~Yu(%b zO6xUs6l)yjSM6G<<3Mdpp^1XVH%aq}Xi`l^J|h?vEUXvnjiN_Wj?;|Y_?n9C67RN! zGE zdI_FOoUawO@{eoFQ(0BanFap-!L>c8=hH_&BYWKxDGsDv%wFzZ z@_gfcK?-N46U3}svRR)f>y9l0kg~52hU0WToQmtypE0dm}nE z>S;alF_5_{*Pqh(36HfubHDkJ&*#-B+RCK&q`KN8bs!eFdhc8167)~xMc7Xsj}~RYB2S zkkix3*UI}C=FS_5yR9HL^Kh<{-7k7j^O~OO&~`giL8=PcfC7s*wEC;(_l{%W-L0=* zp|bOAj_etlgrv(xAF$Qz>EkK#^Vjh2RtvlgA@Y6S#G_lx%WY;PUbZyMx;&->zy1n8 z6{Nwc#p~)4^{IX{fYq_S7~oqr-bym_I>Z#*HsvbAiX5gWowX)`6cO0MQ}El2tgE(G z5GNIMPFh9Y6?z{U`l0UYSYKfbMzq)p+N&m#G*~rPl%Mh-Wq@Ym6`|~xOecqfciLwa z0v0N~xKJ`*LX|<3M6T}K5c@4a=~Y-J^&kZt>?gMxChJ~?)ihy5I|Cta!wnpNJ+}K+ z!^>cQr_wQ?MB9aXFSfonB%5tnkvaVN#vSXu1tTgYdO;SAaOQ4-by>&@aOx2PNMW37 z!vdW=6a(8!bk?5DEdRL(Eu8pf*)R&10x=)^xYs-ANkYFlF=h7AmB zm(=wN*aUbIVJA>X(g@=ri22O^*e?9_=1ew|%aBE#6=hlL>+i`I)f21DIqnr!X1HU} zB2a8-?A^OpL{OX%f^ej}jQRXSwpQs;Kn9gpx4AZtU1IsjmgpY8y&UZ`W2Lf6i?Ehn zfI0??UoCcV7a@$Sn!;cJn9WfE##``We`Ss=03T}+LDGglSrU;wY5!6d%vr)t_3?@n zAcE)$uel}*b1dkv&{$zvyCdM?A3D&(dmhrL&CbYT&0->~jhIj`RP&e^c1d_*M7V!2 zWq1oFV~6>w1fkgQg9SbmwOLP!YFHI-=B(=$wr6oSpLSq|0bU4qxg9@V zuV}y+SM)(wZ8yEni-A*V?CLT#JEZEV>sHTn*7LTuK3^$&3RXvC4tOD)PNz$Pm@3XG zGn;G?dN5$V2-F=WV=6`*qzA;*XoI*V5vTwnUU#vIu9PP_wpgD6exLEmX?RXDYO_X<+4uabCODt9`@}PNpCrqWIn_P#W2jh+ zP6MYAy{b+1#5Gmtr=IsB2=1P79dFnbXZr;U-9D%qCGjAIiW+4(x`IwhE=SP!X{da3 z`JfNkLq#*p3)d2`F(v*`WbH&d%#ug=sN?fM*(r}dx=|W;XwAJcE2k0n;ylx_J8Pz&EWWKRCQK}iX6X?27m9#% z6ccEX2e%|0MMX&@+A?;8&&qp9V1Cm1hAg*~8nq*u$5$C#B57<5C(K^1SDPtDHWZk@ zG`tUcj!*E8v5NQb9T@HjlnIygzEq#Vp4t_ZyRP8kRmm+n%s%(xDHCLMs~Raw(Lroy z&hRLN2K^b85K0Rsy@_jX6?Xg_QHc*Sg!eD@7?~O|i*0>=S>S1`pI(mWZdJe$=iyOz zdVaONR0iM$+e9jwZVOgxHM}}8L3n%T^gg=lX#s5IT8MSwWHnCtE5#P1gc;v zcIdyXi_Hjl!XG!-uHxba=DKh5mxIE27vommE2D^Li5?%mfM=^k2mGYtrOyse4XPyG z#;D)?3BZvnj2nvvnGy+Xzln-oUTnv)P9Z6$XnW%&>m?)~A-Cae*-y=~D7-uP877mJ zo+16?3NBYMM8@~r81;YHsjKaW-W!m8+1}Hg=4)YAVL%^eOh_&=wWK#7ACZ#phlgjn zix@P|^jz#!Q(SN}dE@<-t|V|5Ap$<*dxJpzzrrLz{`i$X^7DY{S86lGN zeB5$p3AOk?NgpZjJ=u8ng?U+zwYDlC0%4gu3KkiM6Sh~WGZK6!#C@Izb37$Wwe-o< zk}ADC0mY`I%Tax0WoY1ZN=`3#CwKnUdWPy7x0=|_N*|^i-u1k?~4b)jnl06t`CkMz- zK>t#H{k}@?!deu=pT*duF19^2lJ}XR(*pvhg4lqV9er=aC=XbPN1zaYFs!RWf{@Ny zFa$VDvlc~SZ7-5CW_Dc|xN97)C7M3WT~|x1Zfod?`1nRODA0_%p?{oa+R3k~VVJvd z`Oxa@h9{``-7Q}eHB49{j0pG2%V{QEeh)^(JAyi3=H?3Fj_0~Wx`~ZrE>W`gi0_Pv z#sD`<>M>d5)EiRBgflW}h|GtE78Qnv#fluc#eb{W>Zr}qN=A%kg{%*G_29!%4K|0x z_C9{!F#(~(jEP-3WH!t1wV!LlFbu_Wi_sL%;K&6H>lFdsSf_A0ntq2d)8yzBpi89} zMa}&k+-~LW8E|UDQFpn62St@|7z?DC+K&@S#o7HbS00;NDz_`2HZf7T0&%A&*aceP z8Nu?J45v%RbaVh|&6*Vzs?C{g6YJ*Jy!tA~LJ;AIF-Uc(tc5jSnXyMBx@rh$c_4g%wc3@3~vc2U!pz2m^at|H8z%p zfH|BZ0SgDvgL_`t&!M}N07TQQQQuM#Uqf>JvlHQQ9fDB?z!+T3XFAA#L-oE22}Wy7 zNW8oF6)~MG=INSLkfCRudT>We;L<7Ef~BGh-g7&Tso1J65^iqKw>X3jPLZQ?#xiPB z&U!Jon=hzLRQmPo0Db2cXyd~28zFUNw*f@5r1O{{{2HmH1}rP8dbA*jNq4WsM7Oqx zKX%qe0s5uB!70GOP>`DW%ZQsYC1+)J?SG267L>{YMRO~$gLLJx9(vxb3tX)_L8}h5 za(COJr4mC%Abbl8!wjpA?U#W>Vb|F;6lo(&lyk8!F?07vumfN^*kKQ;i>^Mpf|>g1 z_~_|-zTZ}*nUO_`eVNhL%Y@F>(%)0SsW%G5)V~kLV{oAGOk!_gU50=V4xTw#?aR4X zWjkca7yfr(ZjhfdBS?0l-|3q%Wd$q#=v#$!v_tMhfD(>HILVL z1>xE<8+t(~uOLemP=0XR9g4HcrMDC&NIAPb6kk6cHZ&((va8xI&t9fGU`(kJ3!OH+ z6&u;a+P3}H(B%w9`Mh?1*KCX`n(H}E{^i0^bd9sLLN-mK3y0VR$UFLKmYjV>7c{je zfVk#!0W4bWVJz?yK>1g@317|=xvH;0GRi_^89}tg<>~yNKzF+UmY99bm%*+TgqdRW zz7Y2qOH`1FMz_^v{CN4D=U;3MONot@s4MQ;a9u`;bxhFS91zmcQVMqsXo;CRA-r`z zjU%|HV3+bIV3Hg{!L@&%PctIG8DuAXt+&IY6g6ol+~D_E2HvZq68HmuCth zl>!{JpkC-lNCM^@J}ICBH@4?bC$#3%U*g0x$a==Q5XLr|QPuT$y|MN)W|7GQXW4;NqPXRSZur<#WXkZNe|*x-dE zwEa<|Qj){Nv<3`9W49VsxZhG#f88Eh7%rV09G|Hrez#NaQWsZtx7y@mF8Szn4GVJ2 zl0)y$q2f)^&h#-rC-NW9<7u0gN<+MK4B%>;x5h*vu- z$YZe_wA%Ceml2l95Co4;gs?9T3`)H1FbQtt84eCM#i8m}CNbb=tc=)H`x<0Bxh$&O z8xSj~_cGKA>`iuSbzK$W+GC1CzjML>iSXc$;k;?J23w#BjaDf?rEm}I5||- zutFbPcc@b^(Eeof2tm|cZ>!|0Oq#PVy6Q3VKJxZENA2i zMoSWYuXk*bK9Tv#n=i2^^*m&uK$`Sck)a#k-C@O~mq%-IU-gB|bAhpoHIGi)WXC|6 zl@M!q*`IV1;u~0XzmG|(ts)yotq}-d!!y0b8X2h`8xI~)Kt9E6;$}CZK@B9?7ZwR) z`I=RpA$3`0>NYG5kH9K>?OL*2&#c6*>8sc(x|hxK)amg72BMEvvQnS|zCOn&U+n zxbUOArO%8(PEQwnZkr4^xA8bGGGG-cYblZuCW+>c|8Sf)`}u0)<{gJAiVx#hDOZhv zCi4&Vo=TP8zNhu!I4yuS+iByRzWt&cO?mLuPO11-ct^^wB2nqDX1m4hETNrc;A;MQ zBRGnIbah0BW@txnyd@Q8BfA^5YPZ2#S&1FPHlv_9Y)a#gZuk$bn87>X2YSh0?bILI zDA$l&c0ZsG7bGeU{9>Hyy)w*R8yV|UqC3;U!6e1q48y<6gv0=*Y=CDL_83~ z)XJGnibqhN{I8Km4Zy1*znO4}(Prb`JPtGs9%kDs#lVi$if@*UjdRe;9|c5&T((Mz zrDM0Mml?#F)OHNs%8M9O#F&X1o~grSb4dH9^Vd za6(Oxg+$hT9>G5WQArueRBCA}1wLGz-HQD8j*>M4&p$JzGPuH1hKfRK?C*RCQyI56YAtznk7+q`WWp;fbGr(+AT-pCr5} zPba~MVcrI$2G;5>+DWr*+~%?ZZy8t2BdVRKM9%j$ox~Ak)IELqG5dn^cNx<`Kp9{3 zsXfC;$H$g5@c^8v3|PJv{@5X@Y-{TB_Yp%@3}4`8!5AdTZWD&TSIGr`9ze@SMb7Ti zwUQ2ewVYuhm%e)J{OPCBZ9|bxzKAke$bf(H0SFv!X5Qec zB|5%hocx*P%MeA78Y+dFaz3wdQ`Wi)_4l4A*?Y zb;`m0-q_o3d2L^>`fNieaTX_Uuf6@P;28FB_IXa0@m=W4S?~n2F#j${h`&Xpjl{n4 zEAJNg@~bZbpIfhoj?lak-nVKSfcNbU%F@lDbd<4?CJ_P{GG63gv|fM90Hwj?HM}fz z>YOQ2G?>|DWnkx+r<4O>YSv+mpX`6fK~>QhjfV3ZlEoW38m52XJSW&ykW+E|>JXY1 z8`d4nxqRFFH}w7W?5i`sHFMhYXT!TL|K9jgWyNHTG;(RhR>!oE3Ny5(WAdRC(-@Ck zDwu&?r#ul_ivy#O^3sK=yKb8M5BWh!)HrUMyU5BgT3eRL|88j}XNs_qs<%Ca*aj}J zNJNM)%ey{KJ)|#7=Q#ozk#1-QFp?yUy@FtRb3gNh-(}p(4GtNa^^VbfH8GN4Y%_ld zrzacaS55iI--_VS?@N=yw|*Hf6Zw!EN0?O`nBmQn)7STr^DagT`aA)hk?rI^tXghd zgl+nPMWo-h2`ppIl?YeKgtE`qZOjB~WQEgZ!r0XGP>d=7ZEerrEq&s!Y;Cy5oW(jH zu`xp0{8?qY5Qd!nCc`-Gd0LS<>2le=ZRuO#RB=58+8BsH7H*TGKvsW;=lT$1d4A%| zF>&1k?;aex#qv&xN;@-CJ`EePXd6L!woYpGup3;S{^X}J!ZW@8zkj($6uU@@)afw} z34Kif12g&66S7%yU*+FDL*2`9X-Ypz3gMEHH=S&-P{G;$|CB|0UnRmvCo_U_c z!WJtI?mvR0_P^Xty-O+su=2iW)BSaPc}D;&=x&UP8Gss60-hhzou{K)mzhuuK;?tJ zA$@|4U~7^)5euK=wfqD>8()$t|73Z_)BajB=hsW8IP5=$P`7I(j|lD3Rn0fv9(^O~ zYFcVA`HRJD3{MBqMS}2U)#p@G@zwJV*azftZHT&_)xl&!G|xDk?aw->vhGKpnRESa zMG;me(3}|-6_w}j8Oo{e^P+ty=LNV^$@Q*)9_=N2vk7DwW6Yp{7`+5zQgCJ;a zB}Cm^Wro*7#bKD$tweyr;4sRC4BuIOohoBW3FGf>y+apFihCy*Y#1&w%A^o(crGJZ z!eM~q=y_5DM$K6=^W+}FykoSjLM<5Vuu$?xbv;(xE~&(PET#}TW)HS-AI`>Sn}?*f3w zg4Flrvwe=c1h%BluGDa&Jc-=vr>z;BI~qUoh{oV)Xz^K#$mu+x*2dh}aRePRLsPN#p}IeeB{`XKnzZMh|_4jLMfO^CcZuMZ2NM1~7)ws4-dSOiWj-j9qF`;G@genlp0Zl|lh5N!ZAR3svrp z+gGhVj~VNlcqMuq1>jPV=5DKw}WWt zZU;L`7L$DjI^vnyqKrq&-)DVz^OsUM^aTZyE5*d4CZfIDh4allp~Dzv?6{50X9L6B0+M!X$a(Qr=a_-SHF~~@gVF&be1gQ*J1jw?=F0Wq?m8Yyi9iI{!eXm(^!wio z%mRox7|+y#&@;^tavf4HoR@Z$^S1tna$Q3n%fkD@K;dZN>()M*CGcf)+`e7f{C+U0 zhpzEXX5ME1fl{fRS_TB|x%bO?t+Af~W%|A@?dR&j^`2Z2Ld`*W0s&5Zsz_IhM}3DO zFuK>Z_ZLaG?XjMf@1|8p7tK-JGNx{LRtP3)S7s`#%S%xZ^6U-H4dAf*X` z>>0bhhOy0`_it7=g0wk<?aG{LQ&JVEq6_VDF-X&z+=+Ek zvnWRu%JFCsx*(ElTR$0T1vg9%T4Tm;(C0=atr^pOfYzQ6%)Diqd`aF}w!s6^f4n7s zX|YjajW-UPM8=+k?7J^*EbHXyNmVfPv@sDh8(E_OK_$E!CSB*rIn^qxf=AxZJ>n>ASMPsHJ$)?6vX|4in~?ZEBvd~rX9+_47MBkg&a(fVF03{_2e^*Dbr450(99?nd6fvB_FNy~e?|&qh z=vR7;_FskbD1W8uIr6;>i;ee+3XEOZmVRMa$Tlu73QE}b5+ru*6|3*NuY>fF*h^nR zIOTe;tcU7uFdRtupPz#I=c!6MlpFP>xmpIJ5;w|sZi*#9Ds!}LiX(!k6+7W?oO}F@ zq1?jmzXVQ*p0Ke{sExD|-?QHREq$v^mJ@Ysm$G}Xx7@Nh&&D?+;Ex~gh^A#oj>|+l zO64=gKc`e~8P9AZoAfi4vaz&lNg7>yPTXIoTvqpWseoJN(qn`#^#Pv>u|)*Wl6eC2 zWuxI!bCrLZSFE`urlu^}Az>v=)=}SVb=51$a&55uFEQL9km0Eu(`ifLfJErWu)nRq z{?w$~!IOq6_oi84&AI{!)>HnI81D}cCyI%4keWsqPKAEe!zt3b$4WgE7_S(oGot_Mo z-*j zx>6AM)`l5)?bLjva!byYbhajJqJG3@d+$+`9@*%@uFYl%t8PRu@XG*lP`zRizgvI( z6Wly{uesVej^A`@L770@L;hiio~cq*q1{Ud3ibs%fYoRg<^kU>r^?>7GCQv0NLGhW z-@8L%9fFRclDR>R_Z%d-f`)r_9xqtNJ^U6umn3(st8q7<)>g_DX7ir1yx&M%v zl5#7!qQ|)Mb3O~4(+b74DPnr*TFMf#HMkR*t76)5=lM+Y6KJhRR<(=Sh-k-sF4LJs zf6ulR$ivi`=2j!&y8+cMruc+v(9IWT6Yl+f>0e^zF01Yj1qPhFa7OHYj^ixcm?U}B zkK)W5l*(0DU9{_dHcaeouOGBuw%cS>YAld^6OIK1U4NFpN1v8#b}_2;BLGl?}B-5|!8QzoNK# z1S4rQI|(AaY7vyBXlMP;*&Lm*r?|{vL=d_}aZH)O;`^l{H#cOA!cONn(kz}vY#mfr z{^-g*h&Ff_EgtxX0}399ckj;wXQI!>9umOKUk8mUR+j~6Vh*>bQsHry!d&TW1sK>t zSihf9+`oUS@;p5HlTPHqQU}M_);;>TPKwpw%;&~Gd1Cr2tL+{Ci>Q=;vTOUNiQ>=l z=>PQX@po%2n_p|Ko~-rJRmK?+8nVhVvUtJmH=jfn-Fn|dwU7X>V$~^h`r5n@hy;jX zp>xRHS>GxJ=4n=ptX-5LcW3e(Uq(%yRX8KFJ~E=K6+0`c*&5qeAge`0HnYo7t8h_Y z)}I(72ijX~2-W$;=O({8X2{GRO~~yVJI4&=c>N-mRi*ZN`PjeJY(33mrQo0(B0eNh zTV}n;A)h9s;Cfj82O?(SI?e;t3j{e{z&9RZCtFt#OkvAvi?8wC${ze`T3t>oBu;9% zZih%W>lFJb1F})Z8Qi3;U%WZ)5m9I$t{Q~oUci^x?6n&B7cW*U{>v4k7Y#Zk#D&`{LcHoh(m^C z1?Jz21$TeJquvnWzx4~h@`?@@X~?-$GPM83#Vg%csB5h`ojT`xe5ASuc-I)4%u%%L zr=+1ZliS|YyO0$#BJIG6^4V*Y!DutpZ`O-9dj8|y@C?pQ2CJ2YehbU6C*D3RE)43^G*~P;M^o8PKCKE zE`{EDi_zRhMAJMYddFHjo>pllw&@$k!#ujY&Y-%6Tc&)FcecuOwoxS(BoaKKJ_h48 z_7LV|T2~md)_F%DeQ&9ev>}HhEFrhQqW}-kl}J^=Y;yGtfkwe#CUNQlVo56(z@nJ> zg(50Tq_ygnRSrNtreY`4`1KRDYa;iiIl_XrXvcG=o9^qg_f8x4UN>bgzyZ>Out^lX z)o3QwIzTf<=5|*N(1%21ScqU^)jsw$hGfvDnJEz>o`xYSnr8`=r{)HjL6 zV;kTz7PoVvmEt;bX_9D7jiTswo27Qji;md<*-tcaJ|5&aTfrv}GA^4}3DH4AM?%&L z(<3vWpd^QzsdNB+DmsZ`SLHl1^KPHVl#fk;vgXE`%n6EFZBZ$eV_6KcR<{x_xzMWk zc$1>Ik&Mx5k7H(scOPwZ8%*n1+a7VNEh>UUJiB(yujAVh%Lq;SKQLp+U3A7bp_Vl# z!x$!j9HjZEU|Tftl*f_N>|7RFHRfa4;{O`8C02+*ZJ-8^{%8l*zf_j&0DsHNb7!w1 z{Sl3mq7Ew>sD>k5bfkF zcT7YN+I$qi6+l3>Kz&mTrm{oAKhe4qJxfkO0Ucv_$J1dWx~x>T&i;fCKGaTTi2s1G zdvZLz_Is3fJ)t@VV{>SudPcs&c9E}G`0bg#F6)6eEcuSuSVOc5%Jf$wRzs?=;hw{^ zDv>ESpJH+rSl29;W|`>Sd)3CTW-Ua9tp%So%n}ImKGWYGcWU;B23@_+S>J5!G4kLcAYM=ct_w4YiofmMV zj7s>Mx$F@)^aGj5UtW@6zZYt=$?Y6LRIFr{?}cLxfWN~G$Nm~r-R%|cZ+f60SOk82 z??%j_@~$3IcXyiR&kzZ`)L`K^?=L3S4V8M(;!GQufX!<>n?E z2!#I{g^V75Q_$j4Eror!AqR@>i^2taH4@w4hs{Vyf+GhBK zo`ijn1rmP({B3xWYqRBpt?C041 zSfZjHS)kBAGB^ajit)-YSQU?w%Eq_vdR0E$y3wvVD2Ob6Qa!5|;`p-oXtN+#o1%EP z->9y&t53#A7`ut-kT`mT2ZS3$3xEN;th`(N@4nnWxmMl|(F?Fsf zHrpAmAOK)lUf8y`_E4X;akJ4S_juZ-bdG{qUdXb==EXpy2<=h$ z;T0)7HcoL(`o7tqE9sCRIo zBMS#Tpc5#TjH@ino?hUh!wD}aVtR0A15?*YhO+kIj@{+r8pdd|zHXMj^j2D>cSNKC z9)uOK6yiNA!xk0|Qv&(yEXUX>r|m9`>f+#~-zYn*SIkdfTHH4XMoqw|XJ6+ zMzNn@kz$id2vr68##Ii}-KSr>ijFzbamlFm{JX!Ob9G!37SCmeh0MAIV3b84BTOVM z(3NR~j*fhea}=U+Y#ih;*oX{Q{j#@Fk`2F=O2**}yFs^G!45=FQBATB0YrBnQ-NXR z(}GF?ON|gt?fYTxd>}$a9~BMsm#7+zvzXF7yAI=Tgd1pN+c3SZ=13On&}#~0giH(& z1!@XSxMgMcW%3VXBv?%^;6?*Mx=bH7|gmD{0 zfBtec34;1&uMH9bEQku1{AvkJ~>mz@uP?MO%V2bZyagtU3k!CKCzo z-}Fv1+s{&(JJ9VIVo=eINiPuLTMgj{=wq3e@jagfM(fbH-aVpV*A~T%CN<^$=KJL` z+7}UKMQei)FBK+q2A=mmo}Ge^Lih<-pprSB`o__~=}Xh&)%D`SgaLeKV=uwdO{<~G zxLdcrls4JAGdbL*=h1e171wer-=kybnDX7!;<-P5A~t~`)d39-d!JQAa*Eh>GlaK$&dSQ8Xm&9qE*Yvs-)c!k zQD27|8=Hy`@+ux~zPvNTb zR&47ByA3+tv+sS;aP*LgZ~X}<|9k^$fS|MQGI~hqZA#(3;zNg$_PcQli%Oq>^3INi z&E#P!K6U#_LpuU(Me`F-a*H18!%qOkt%20qT;H_h#^ytL19Zso#v4#vIAc{~Prfp4 z&#`P*C4rHn;#&qE{k}T|&QG*7={8(CrjL1{KLIa%p%mA1Un1f1 z`g9d!0{S7n#CmezPfETxs3(5M35UI7t$WEi?4yGIDUUaH5)CfJCXvG|w*0W zebf6~*$VAY&2-M^@9N`W*Lhr}lz-ec-J{Y|vVaIKBs!vyvj{E^;_JkyP3a{;@ulIQ zSt|zK%s47%3t>Ky9tmuqA3>sJ+{A6;x1NUTOH`YrdbC?cMn<1_4F+>ZG~(R371$3h z9pfzYQCijULpW}>PQRf}xxZ_4Bl9QVq0K@#qLKCC!lo4U`@_N->CJmeHX*g=p|}&m z@BCnw=I1qULmO&k{C{`Z>;Qhd9}Tod5!?>?B%0N#+3im5nG^b!bwL#Ozls0rXFv&* zgc1xhdF{l)&|`@yqiQ5$DzMb=p4Ri@ytL0(xi)VbO?{{>pS_{i&{1ml-|YWBlmEjP zqOPMLRr=ZlP8SX)ATxjCW$9r-z`%FSfY-blT@F9kw-SyY8tiDG-$C)EAEi?P;64)> zbNQ3ow6Gmy4>kc5hWw%7yVKJHCXj$xc0IO?hp9#&2g0+0XRPA!O=4$*efxHLf;U2r zH_^-N0=Y2sGW}nd;P>d1-)T+@67P~V%s8wu(%0<9@%KWdI2s|xiT~Y;WRwF^z}49G z24f1V#!CW)*B$b#8d*`%0pS{1A{>jhLpj&@(UdF^uJ48Di-7IWY3jENxIcgZ`s5PL zB^v4qsH3X~rc!@6XSnl@kVChS!y)rInuqKEj!FtxNFw48R4Am5%dN+4^8M-Uk8fJs v=l^txSaP4w9DlacsBwSO Date: Mon, 10 Oct 2022 20:50:54 +0200 Subject: [PATCH 38/60] revert syntax --- tests/freqai/test_freqai_interface.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index c8444067a..445b718d2 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -182,7 +182,8 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat, caplog) df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") for i in range(5): - df.loc[:, f'%-constant_{i}'] = i + df[f'%-constant_{i}'] = i + # df.loc[:, f'%-constant_{i}'] = i metadata = {"pair": "LTC/BTC"} freqai.start_backtesting(df, metadata, freqai.dk) From 5ada5eb54001724775cace6335fd9be64d4ec31e Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Mon, 10 Oct 2022 23:30:43 -0600 Subject: [PATCH 39/60] fix error message, update exception import --- freqtrade/rpc/api_server/api_ws.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/freqtrade/rpc/api_server/api_ws.py b/freqtrade/rpc/api_server/api_ws.py index b60210143..46909955d 100644 --- a/freqtrade/rpc/api_server/api_ws.py +++ b/freqtrade/rpc/api_server/api_ws.py @@ -1,10 +1,10 @@ import logging from typing import Any, Dict -import websockets from fastapi import APIRouter, Depends, WebSocketDisconnect from fastapi.websockets import WebSocket, WebSocketState from pydantic import ValidationError +from websockets.exceptions import WebSocketException from freqtrade.enums import RPCMessageType, RPCRequestType from freqtrade.rpc.api_server.api_auth import validate_ws_token @@ -115,10 +115,7 @@ async def message_endpoint( # Process the request here await _process_consumer_request(request, channel, rpc) - except ( - WebSocketDisconnect, - websockets.exceptions.WebSocketException - ): + except (WebSocketDisconnect, WebSocketException): # Handle client disconnects logger.info(f"Consumer disconnected - {channel}") except RuntimeError: @@ -126,7 +123,7 @@ async def message_endpoint( # RuntimeError('Cannot call "send" once a closed message has been sent') pass except Exception as e: - logger.info(f"Consumer connection failed - {channel}") + logger.info(f"Consumer connection failed - {channel}: {e}") logger.debug(e, exc_info=e) finally: await channel_manager.on_disconnect(ws) From eb8c89fe3188fefc284d0c825ab29e98c59096ab Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Mon, 10 Oct 2022 23:32:10 -0600 Subject: [PATCH 40/60] move send delay to relay --- freqtrade/rpc/api_server/webserver.py | 4 ---- freqtrade/rpc/api_server/ws/channel.py | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index 4a09fd78e..c6639f1a6 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -198,10 +198,6 @@ class ApiServer(RPCHandler): logger.debug(f"Found message of type: {message.get('type')}") # Broadcast it await self._ws_channel_manager.broadcast(message) - # Limit messages per sec. - # Could cause problems with queue size if too low, and - # problems with network traffik if too high. - await asyncio.sleep(0.001) except asyncio.CancelledError: pass diff --git a/freqtrade/rpc/api_server/ws/channel.py b/freqtrade/rpc/api_server/ws/channel.py index 7cee95e6d..e9dbd63be 100644 --- a/freqtrade/rpc/api_server/ws/channel.py +++ b/freqtrade/rpc/api_server/ws/channel.py @@ -115,6 +115,12 @@ class WebSocketChannel: try: await self._send(message) self.queue.task_done() + + # Limit messages per sec. + # Could cause problems with queue size if too low, and + # problems with network traffik if too high. + # 0.001 = 1000/s + await asyncio.sleep(0.001) except RuntimeError: # The connection was closed, just exit the task return From 16c0fef72edf529f34744552d155ff15642ad64f Mon Sep 17 00:00:00 2001 From: Timothy Pogue Date: Tue, 11 Oct 2022 00:10:57 -0600 Subject: [PATCH 41/60] update timestamp calculation to correct int, remove internal ping interval --- scripts/ws_client.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/ws_client.py b/scripts/ws_client.py index 83182ae9e..23ad9296d 100644 --- a/scripts/ws_client.py +++ b/scripts/ws_client.py @@ -82,7 +82,7 @@ def readable_timedelta(delta): """ attrs = ['years', 'months', 'days', 'hours', 'minutes', 'seconds', 'microseconds'] return ", ".join([ - '%d %s' % (getattr(delta, attr), attr if getattr(delta, attr) > 1 else attr[:-1]) + '%d %s' % (getattr(delta, attr), attr if getattr(delta, attr) > 0 else attr[:-1]) for attr in attrs if getattr(delta, attr) ]) @@ -170,7 +170,7 @@ class ClientProtocol: def _calculate_time_difference(self): old_last_received_at = self._LAST_RECEIVED_AT - self._LAST_RECEIVED_AT = time.time() * 1000 + self._LAST_RECEIVED_AT = time.time() * 1e6 time_delta = relativedelta(microseconds=(self._LAST_RECEIVED_AT - old_last_received_at)) return readable_timedelta(time_delta) @@ -238,7 +238,7 @@ async def create_client( except ( asyncio.TimeoutError, - websockets.exceptions.ConnectionClosed + websockets.exceptions.WebSocketException ): # Try pinging try: @@ -298,7 +298,7 @@ async def _main(args): producers = emc_config.get('producers', []) producer = producers[0] - wait_timeout = emc_config.get('wait_timeout', 300) + wait_timeout = emc_config.get('wait_timeout', 30) ping_timeout = emc_config.get('ping_timeout', 10) sleep_time = emc_config.get('sleep_time', 10) message_size_limit = (emc_config.get('message_size_limit', 8) << 20) @@ -311,7 +311,8 @@ async def _main(args): sleep_time=sleep_time, ping_timeout=ping_timeout, wait_timeout=wait_timeout, - max_size=message_size_limit + max_size=message_size_limit, + ping_interval=None ) From 5b5bb8aab5046c5ea6c3de01f4b319433997e76e Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 11 Oct 2022 19:05:46 +0200 Subject: [PATCH 42/60] catboost tensorboard bugfix --- freqtrade/freqai/data_kitchen.py | 1 - freqtrade/freqai/freqai_interface.py | 2 +- freqtrade/freqai/prediction_models/CatboostRegressor.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 89b8f2b95..4b604e281 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -119,7 +119,6 @@ class FreqaiDataKitchen: / f"sub-train-{pair.split('/')[0]}_{trained_timestamp}" ) - Path(self.data_path / 'tensorboard').mkdir(parents=True, exist_ok=True) return diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index ac980f5f1..9907a5f9f 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -201,10 +201,10 @@ class IFreqaiModel(ABC): new_trained_timerange, data_load_timerange, ) = dk.check_if_new_training_required(trained_timestamp) - dk.set_paths(pair, new_trained_timerange.stopts) if retrain: self.train_timer('start') + dk.set_paths(pair, new_trained_timerange.stopts) try: self.extract_data_and_train_model( new_trained_timerange, pair, strategy, dk, data_load_timerange diff --git a/freqtrade/freqai/prediction_models/CatboostRegressor.py b/freqtrade/freqai/prediction_models/CatboostRegressor.py index 46f33a142..2978f6679 100644 --- a/freqtrade/freqai/prediction_models/CatboostRegressor.py +++ b/freqtrade/freqai/prediction_models/CatboostRegressor.py @@ -43,7 +43,7 @@ class CatboostRegressor(BaseRegressionModel): model = CatBoostRegressor( allow_writing_files=True, - train_dir=Path(dk.data_path / 'tensorboard'), + train_dir=Path(dk.data_path), **self.model_training_parameters, ) From dba1b573bc773eb952c0830e52b4bf85f64cddf0 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 11 Oct 2022 19:49:24 +0200 Subject: [PATCH 43/60] remove tensorboard dir from other pred models --- freqtrade/freqai/prediction_models/CatboostClassifier.py | 2 +- .../freqai/prediction_models/CatboostRegressorMultiTarget.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/prediction_models/CatboostClassifier.py b/freqtrade/freqai/prediction_models/CatboostClassifier.py index 6dab012d1..2aebc3ebf 100644 --- a/freqtrade/freqai/prediction_models/CatboostClassifier.py +++ b/freqtrade/freqai/prediction_models/CatboostClassifier.py @@ -34,7 +34,7 @@ class CatboostClassifier(BaseClassifierModel): cbr = CatBoostClassifier( allow_writing_files=True, loss_function='MultiClass', - train_dir=Path(dk.data_path / 'tensorboard'), + train_dir=Path(dk.data_path), **self.model_training_parameters, ) diff --git a/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py b/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py index 085c13b86..de7a73e3a 100644 --- a/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py +++ b/freqtrade/freqai/prediction_models/CatboostRegressorMultiTarget.py @@ -28,7 +28,7 @@ class CatboostRegressorMultiTarget(BaseRegressionModel): cbr = CatBoostRegressor( allow_writing_files=True, - train_dir=Path(dk.data_path / 'tensorboard'), + train_dir=Path(dk.data_path), **self.model_training_parameters, ) From 1e31be562e92a3e8629e918c285c4543cb7c0225 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 11 Oct 2022 21:05:42 +0200 Subject: [PATCH 44/60] remove whitespace --- freqtrade/freqai/data_kitchen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 4b604e281..52261d341 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -119,7 +119,6 @@ class FreqaiDataKitchen: / f"sub-train-{pair.split('/')[0]}_{trained_timestamp}" ) - return def make_train_test_datasets( From afaca2167cce2531817e9f65bb0dd0343d331083 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 11 Oct 2022 19:33:02 +0000 Subject: [PATCH 45/60] use Type Alias for Ticker result to improve keyerror resiliancy --- freqtrade/exchange/exchange.py | 6 ++++-- freqtrade/exchange/kraken.py | 3 ++- freqtrade/exchange/types.py | 5 +++++ freqtrade/plugins/pairlist/AgeFilter.py | 3 ++- freqtrade/plugins/pairlist/IPairList.py | 11 ++++++----- freqtrade/plugins/pairlist/OffsetFilter.py | 3 ++- freqtrade/plugins/pairlist/PerformanceFilter.py | 3 ++- freqtrade/plugins/pairlist/PrecisionFilter.py | 7 ++++--- freqtrade/plugins/pairlist/PriceFilter.py | 7 ++++--- freqtrade/plugins/pairlist/ProducerPairList.py | 5 +++-- freqtrade/plugins/pairlist/ShuffleFilter.py | 3 ++- freqtrade/plugins/pairlist/SpreadFilter.py | 7 ++++--- freqtrade/plugins/pairlist/StaticPairList.py | 5 +++-- freqtrade/plugins/pairlist/VolatilityFilter.py | 3 ++- freqtrade/plugins/pairlist/VolumePairList.py | 7 ++++--- freqtrade/plugins/pairlist/rangestabilityfilter.py | 3 ++- freqtrade/plugins/pairlistmanager.py | 3 ++- 17 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 freqtrade/exchange/types.py diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index c41a84450..3b59bdfa0 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -31,6 +31,7 @@ from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFun from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED, remove_credentials, retrier, retrier_async) +from freqtrade.exchange.types import Tickers from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_json, safe_value_fallback2) from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -1420,14 +1421,15 @@ class Exchange: raise OperationalException(e) from e @retrier - def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: + def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Tickers: """ :param cached: Allow cached result :return: fetch_tickers result """ + tickers: Tickers if cached: with self._cache_lock: - tickers = self._fetch_tickers_cache.get('fetch_tickers') + tickers = self._fetch_tickers_cache.get('fetch_tickers') # type: ignore if tickers: return tickers try: diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 6c9b88eae..f3a9486f2 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -12,6 +12,7 @@ from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, Invali OperationalException, TemporaryError) from freqtrade.exchange import Exchange from freqtrade.exchange.common import retrier +from freqtrade.exchange.types import Tickers logger = logging.getLogger(__name__) @@ -45,7 +46,7 @@ class Kraken(Exchange): return (parent_check and market.get('darkpool', False) is False) - def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: + def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Tickers: # Only fetch tickers for current stake currency # Otherwise the request for kraken becomes too large. symbols = list(self.get_markets(quote_currencies=[self._config['stake_currency']])) diff --git a/freqtrade/exchange/types.py b/freqtrade/exchange/types.py new file mode 100644 index 000000000..6504381dc --- /dev/null +++ b/freqtrade/exchange/types.py @@ -0,0 +1,5 @@ +from typing import Any, Dict + + +Ticker = Dict[str, Any] +Tickers = Dict[str, Ticker] diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py index 7c8cdb5ab..f9c02e250 100644 --- a/freqtrade/plugins/pairlist/AgeFilter.py +++ b/freqtrade/plugins/pairlist/AgeFilter.py @@ -10,6 +10,7 @@ from pandas import DataFrame from freqtrade.constants import Config, ListPairsWithTimeframes from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Tickers from freqtrade.misc import plural from freqtrade.plugins.pairlist.IPairList import IPairList from freqtrade.util import PeriodicCache @@ -67,7 +68,7 @@ class AgeFilter(IPairList): f"{self._max_days_listed} {plural(self._max_days_listed, 'day')}" ) if self._max_days_listed else '') - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ :param pairlist: pairlist to filter or sort :param tickers: Tickers (from exchange.get_tickers). May be cached. diff --git a/freqtrade/plugins/pairlist/IPairList.py b/freqtrade/plugins/pairlist/IPairList.py index 60abac6a1..660d6228c 100644 --- a/freqtrade/plugins/pairlist/IPairList.py +++ b/freqtrade/plugins/pairlist/IPairList.py @@ -4,11 +4,12 @@ PairList Handler base class import logging from abc import ABC, abstractmethod, abstractproperty from copy import deepcopy -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional from freqtrade.constants import Config from freqtrade.exceptions import OperationalException from freqtrade.exchange import Exchange, market_is_active +from freqtrade.exchange.types import Ticker, Tickers from freqtrade.mixins import LoggingMixin @@ -61,7 +62,7 @@ class IPairList(LoggingMixin, ABC): -> Please overwrite in subclasses """ - def _validate_pair(self, pair: str, ticker: Dict[str, Any]) -> bool: + def _validate_pair(self, pair: str, ticker: Optional[Ticker]) -> bool: """ Check one pair against Pairlist Handler's specific conditions. @@ -74,7 +75,7 @@ class IPairList(LoggingMixin, ABC): """ raise NotImplementedError() - def gen_pairlist(self, tickers: Dict) -> List[str]: + def gen_pairlist(self, tickers: Tickers) -> List[str]: """ Generate the pairlist. @@ -91,7 +92,7 @@ class IPairList(LoggingMixin, ABC): raise OperationalException("This Pairlist Handler should not be used " "at the first position in the list of Pairlist Handlers.") - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Filters and sorts pairlist and returns the whitelist again. @@ -110,7 +111,7 @@ class IPairList(LoggingMixin, ABC): # Copy list since we're modifying this list for p in deepcopy(pairlist): # Filter out assets - if not self._validate_pair(p, tickers[p] if p in tickers else {}): + if not self._validate_pair(p, tickers[p] if p in tickers else None): pairlist.remove(p) return pairlist diff --git a/freqtrade/plugins/pairlist/OffsetFilter.py b/freqtrade/plugins/pairlist/OffsetFilter.py index c9531ece1..8f21cdd85 100644 --- a/freqtrade/plugins/pairlist/OffsetFilter.py +++ b/freqtrade/plugins/pairlist/OffsetFilter.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List from freqtrade.constants import Config from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Tickers from freqtrade.plugins.pairlist.IPairList import IPairList @@ -42,7 +43,7 @@ class OffsetFilter(IPairList): return f"{self.name} - Taking {self._number_pairs} Pairs, starting from {self._offset}." return f"{self.name} - Offsetting pairs by {self._offset}." - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index 4cc92175a..e7fcac1e4 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -7,6 +7,7 @@ from typing import Any, Dict, List import pandas as pd from freqtrade.constants import Config +from freqtrade.exchange.types import Tickers from freqtrade.persistence import Trade from freqtrade.plugins.pairlist.IPairList import IPairList @@ -39,7 +40,7 @@ class PerformanceFilter(IPairList): """ return f"{self.name} - Sorting pairs by performance." - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Filters and sorts pairlist and returns the allowlist again. Called on each bot iteration - please use internal caching if necessary diff --git a/freqtrade/plugins/pairlist/PrecisionFilter.py b/freqtrade/plugins/pairlist/PrecisionFilter.py index 98cb3ba46..478eaec20 100644 --- a/freqtrade/plugins/pairlist/PrecisionFilter.py +++ b/freqtrade/plugins/pairlist/PrecisionFilter.py @@ -2,10 +2,11 @@ Precision pair list filter """ import logging -from typing import Any, Dict +from typing import Any, Dict, Optional from freqtrade.constants import Config from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Ticker from freqtrade.plugins.pairlist.IPairList import IPairList @@ -44,7 +45,7 @@ class PrecisionFilter(IPairList): """ return f"{self.name} - Filtering untradable pairs." - def _validate_pair(self, pair: str, ticker: Dict[str, Any]) -> bool: + def _validate_pair(self, pair: str, ticker: Optional[Ticker]) -> bool: """ Check if pair has enough room to add a stoploss to avoid "unsellable" buys of very low value pairs. @@ -52,7 +53,7 @@ class PrecisionFilter(IPairList): :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ - if ticker.get('last', None) is None: + if not ticker or ticker.get('last', None) is None: self.log_once(f"Removed {pair} from whitelist, because " "ticker['last'] is empty (Usually no trade in the last 24h).", logger.info) diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index a6b400a38..f007c52d2 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -2,10 +2,11 @@ Price pair list filter """ import logging -from typing import Any, Dict +from typing import Any, Dict, Optional from freqtrade.constants import Config from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Ticker from freqtrade.plugins.pairlist.IPairList import IPairList @@ -64,14 +65,14 @@ class PriceFilter(IPairList): return f"{self.name} - No price filters configured." - def _validate_pair(self, pair: str, ticker: Dict[str, Any]) -> bool: + def _validate_pair(self, pair: str, ticker: Optional[Ticker]) -> bool: """ Check if if one price-step (pip) is > than a certain barrier. :param pair: Pair that's currently validated :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ - if ticker.get('last', None) is None or ticker.get('last') == 0: + if not ticker or ticker.get('last', None) is None or ticker.get('last') == 0: self.log_once(f"Removed {pair} from whitelist, because " "ticker['last'] is empty (Usually no trade in the last 24h).", logger.info) diff --git a/freqtrade/plugins/pairlist/ProducerPairList.py b/freqtrade/plugins/pairlist/ProducerPairList.py index 740cb4ec2..882d49b76 100644 --- a/freqtrade/plugins/pairlist/ProducerPairList.py +++ b/freqtrade/plugins/pairlist/ProducerPairList.py @@ -7,6 +7,7 @@ import logging from typing import Any, Dict, List, Optional from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Tickers from freqtrade.plugins.pairlist.IPairList import IPairList @@ -68,7 +69,7 @@ class ProducerPairList(IPairList): return pairs - def gen_pairlist(self, tickers: Dict) -> List[str]: + def gen_pairlist(self, tickers: Tickers) -> List[str]: """ Generate the pairlist :param tickers: Tickers (from exchange.get_tickers). May be cached. @@ -79,7 +80,7 @@ class ProducerPairList(IPairList): pairs = self._whitelist_for_active_markets(self.verify_whitelist(pairs, logger.info)) return pairs - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary diff --git a/freqtrade/plugins/pairlist/ShuffleFilter.py b/freqtrade/plugins/pairlist/ShuffleFilter.py index 6eb4231bc..1bc114d4e 100644 --- a/freqtrade/plugins/pairlist/ShuffleFilter.py +++ b/freqtrade/plugins/pairlist/ShuffleFilter.py @@ -7,6 +7,7 @@ from typing import Any, Dict, List from freqtrade.constants import Config from freqtrade.enums import RunMode +from freqtrade.exchange.types import Tickers from freqtrade.plugins.pairlist.IPairList import IPairList @@ -47,7 +48,7 @@ class ShuffleFilter(IPairList): return (f"{self.name} - Shuffling pairs" + (f", seed = {self._seed}." if self._seed is not None else ".")) - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary diff --git a/freqtrade/plugins/pairlist/SpreadFilter.py b/freqtrade/plugins/pairlist/SpreadFilter.py index 1f6d4f687..ecb21593b 100644 --- a/freqtrade/plugins/pairlist/SpreadFilter.py +++ b/freqtrade/plugins/pairlist/SpreadFilter.py @@ -2,10 +2,11 @@ Spread pair list filter """ import logging -from typing import Any, Dict +from typing import Any, Dict, Optional from freqtrade.constants import Config from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Ticker from freqtrade.plugins.pairlist.IPairList import IPairList @@ -44,14 +45,14 @@ class SpreadFilter(IPairList): return (f"{self.name} - Filtering pairs with ask/bid diff above " f"{self._max_spread_ratio:.2%}.") - def _validate_pair(self, pair: str, ticker: Dict[str, Any]) -> bool: + def _validate_pair(self, pair: str, ticker: Optional[Ticker]) -> bool: """ Validate spread for the ticker :param pair: Pair that's currently validated :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ - if 'bid' in ticker and 'ask' in ticker and ticker['ask'] and ticker['bid']: + if ticker and 'bid' in ticker and 'ask' in ticker and ticker['ask'] and ticker['bid']: spread = 1 - ticker['bid'] / ticker['ask'] if spread > self._max_spread_ratio: self.log_once(f"Removed {pair} from whitelist, because spread " diff --git a/freqtrade/plugins/pairlist/StaticPairList.py b/freqtrade/plugins/pairlist/StaticPairList.py index 5b1337754..4b1961a53 100644 --- a/freqtrade/plugins/pairlist/StaticPairList.py +++ b/freqtrade/plugins/pairlist/StaticPairList.py @@ -8,6 +8,7 @@ from copy import deepcopy from typing import Any, Dict, List from freqtrade.constants import Config +from freqtrade.exchange.types import Tickers from freqtrade.plugins.pairlist.IPairList import IPairList @@ -39,7 +40,7 @@ class StaticPairList(IPairList): """ return f"{self.name}" - def gen_pairlist(self, tickers: Dict) -> List[str]: + def gen_pairlist(self, tickers: Tickers) -> List[str]: """ Generate the pairlist :param tickers: Tickers (from exchange.get_tickers). May be cached. @@ -53,7 +54,7 @@ class StaticPairList(IPairList): return self._whitelist_for_active_markets( self.verify_whitelist(self._config['exchange']['pair_whitelist'], logger.info)) - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Filters and sorts pairlist and returns the whitelist again. Called on each bot iteration - please use internal caching if necessary diff --git a/freqtrade/plugins/pairlist/VolatilityFilter.py b/freqtrade/plugins/pairlist/VolatilityFilter.py index c06fc09ba..401a2e86c 100644 --- a/freqtrade/plugins/pairlist/VolatilityFilter.py +++ b/freqtrade/plugins/pairlist/VolatilityFilter.py @@ -13,6 +13,7 @@ from pandas import DataFrame from freqtrade.constants import Config, ListPairsWithTimeframes from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Tickers from freqtrade.misc import plural from freqtrade.plugins.pairlist.IPairList import IPairList @@ -62,7 +63,7 @@ class VolatilityFilter(IPairList): f"{self._min_volatility}-{self._max_volatility} " f" the last {self._days} {plural(self._days, 'day')}.") - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Validate trading range :param pairlist: pairlist to filter or sort diff --git a/freqtrade/plugins/pairlist/VolumePairList.py b/freqtrade/plugins/pairlist/VolumePairList.py index bfecbd62a..ad27a93d8 100644 --- a/freqtrade/plugins/pairlist/VolumePairList.py +++ b/freqtrade/plugins/pairlist/VolumePairList.py @@ -5,13 +5,14 @@ Provides dynamic pair list based on trade volumes """ import logging from datetime import datetime, timedelta, timezone -from typing import Any, Dict, List +from typing import Any, Dict, List, Literal from cachetools import TTLCache from freqtrade.constants import Config, ListPairsWithTimeframes from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date +from freqtrade.exchange.types import Tickers from freqtrade.misc import format_ms_time from freqtrade.plugins.pairlist.IPairList import IPairList @@ -36,7 +37,7 @@ class VolumePairList(IPairList): self._stake_currency = config['stake_currency'] self._number_pairs = self._pairlistconfig['number_assets'] - self._sort_key = self._pairlistconfig.get('sort_key', 'quoteVolume') + self._sort_key: Literal['quoteVolume'] = self._pairlistconfig.get('sort_key', 'quoteVolume') self._min_value = self._pairlistconfig.get('min_value', 0) self._refresh_period = self._pairlistconfig.get('refresh_period', 1800) self._pair_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period) @@ -110,7 +111,7 @@ class VolumePairList(IPairList): """ return f"{self.name} - top {self._pairlistconfig['number_assets']} volume pairs." - def gen_pairlist(self, tickers: Dict) -> List[str]: + def gen_pairlist(self, tickers: Tickers) -> List[str]: """ Generate the pairlist :param tickers: Tickers (from exchange.get_tickers). May be cached. diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py index ca844f003..546b026cb 100644 --- a/freqtrade/plugins/pairlist/rangestabilityfilter.py +++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py @@ -11,6 +11,7 @@ from pandas import DataFrame from freqtrade.constants import Config, ListPairsWithTimeframes from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Tickers from freqtrade.misc import plural from freqtrade.plugins.pairlist.IPairList import IPairList @@ -60,7 +61,7 @@ class RangeStabilityFilter(IPairList): f"{self._min_rate_of_change}{max_rate_desc} over the " f"last {plural(self._days, 'day')}.") - def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: + def filter_pairlist(self, pairlist: List[str], tickers: Tickers) -> List[str]: """ Validate trading range :param pairlist: pairlist to filter or sort diff --git a/freqtrade/plugins/pairlistmanager.py b/freqtrade/plugins/pairlistmanager.py index 5ed319e93..1e98b8485 100644 --- a/freqtrade/plugins/pairlistmanager.py +++ b/freqtrade/plugins/pairlistmanager.py @@ -11,6 +11,7 @@ from freqtrade.constants import Config, ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider from freqtrade.enums import CandleType from freqtrade.exceptions import OperationalException +from freqtrade.exchange.types import Tickers from freqtrade.mixins import LoggingMixin from freqtrade.plugins.pairlist.IPairList import IPairList from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -76,7 +77,7 @@ class PairListManager(LoggingMixin): return [{p.name: p.short_desc()} for p in self._pairlist_handlers] @cached(TTLCache(maxsize=1, ttl=1800)) - def _get_cached_tickers(self): + def _get_cached_tickers(self) -> Tickers: return self._exchange.get_tickers() def refresh_pairlist(self) -> None: From 35f3f988d45463e923b333a2a5a34e9442929e87 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 11 Oct 2022 19:33:05 +0000 Subject: [PATCH 46/60] Improve price handling in priceFilter --- freqtrade/plugins/pairlist/PriceFilter.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index f007c52d2..da41e9239 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -77,11 +77,13 @@ class PriceFilter(IPairList): "ticker['last'] is empty (Usually no trade in the last 24h).", logger.info) return False + else: + price: float = ticker['last'] # Perform low_price_ratio check. if self._low_price_ratio != 0: - compare = self._exchange.price_get_one_pip(pair, ticker['last']) - changeperc = compare / ticker['last'] + compare = self._exchange.price_get_one_pip(pair, price) + changeperc = compare / price if changeperc > self._low_price_ratio: self.log_once(f"Removed {pair} from whitelist, " f"because 1 unit is {changeperc:.3%}", logger.info) @@ -89,7 +91,6 @@ class PriceFilter(IPairList): # Perform low_amount check if self._max_value != 0: - price = ticker['last'] market = self._exchange.markets[pair] limits = market['limits'] if (limits['amount']['min'] is not None): @@ -114,14 +115,14 @@ class PriceFilter(IPairList): # Perform min_price check. if self._min_price != 0: - if ticker['last'] < self._min_price: + if price < self._min_price: self.log_once(f"Removed {pair} from whitelist, " f"because last price < {self._min_price:.8f}", logger.info) return False # Perform max_price check. if self._max_price != 0: - if ticker['last'] > self._max_price: + if price > self._max_price: self.log_once(f"Removed {pair} from whitelist, " f"because last price > {self._max_price:.8f}", logger.info) return False From 52e9528361b73bced2f34c77d7bbbebaa1b7fa23 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 11 Oct 2022 19:33:07 +0000 Subject: [PATCH 47/60] Improve ticker type --- freqtrade/exchange/binance.py | 3 ++- freqtrade/exchange/types.py | 15 +++++++++++++-- freqtrade/plugins/pairlist/PriceFilter.py | 6 +++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index a0d4b2d82..6d818bab9 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -11,6 +11,7 @@ from freqtrade.enums import CandleType, MarginMode, TradingMode from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange from freqtrade.exchange.common import retrier +from freqtrade.exchange.types import Tickers from freqtrade.misc import deep_merge_dicts, json_load @@ -59,7 +60,7 @@ class Binance(Exchange): ) )) - def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: + def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Tickers: tickers = super().get_tickers(symbols=symbols, cached=cached) if self.trading_mode == TradingMode.FUTURES: # Binance's future result has no bid/ask values. diff --git a/freqtrade/exchange/types.py b/freqtrade/exchange/types.py index 6504381dc..a60b454d4 100644 --- a/freqtrade/exchange/types.py +++ b/freqtrade/exchange/types.py @@ -1,5 +1,16 @@ -from typing import Any, Dict +from typing import Dict, Optional, TypedDict + + +class Ticker(TypedDict): + symbol: str + ask: Optional[float] + askVolume: Optional[float] + bid: Optional[float] + bidVolume: Optional[float] + last: Optional[float] + quoteVolume: Optional[float] + baseVolume: Optional[float] + # Several more - only listing required. -Ticker = Dict[str, Any] Tickers = Dict[str, Ticker] diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index da41e9239..4d23de792 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -72,13 +72,13 @@ class PriceFilter(IPairList): :param ticker: ticker dict as returned from ccxt.fetch_ticker :return: True if the pair can stay, false if it should be removed """ - if not ticker or ticker.get('last', None) is None or ticker.get('last') == 0: + if ticker and 'last' in ticker and ticker['last'] is not None and ticker.get('last') != 0: + price: float = ticker['last'] + else: self.log_once(f"Removed {pair} from whitelist, because " "ticker['last'] is empty (Usually no trade in the last 24h).", logger.info) return False - else: - price: float = ticker['last'] # Perform low_price_ratio check. if self._low_price_ratio != 0: From a6f6a17393b069153a8e88966a8ff6167c9d639a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 11 Oct 2022 21:42:48 +0200 Subject: [PATCH 48/60] Type fetch_ticker --- freqtrade/constants.py | 1 + freqtrade/exchange/exchange.py | 14 +++++++------- freqtrade/misc.py | 7 +++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 27968bb1b..2fdb091a7 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -656,5 +656,6 @@ LongShort = Literal['long', 'short'] EntryExit = Literal['entry', 'exit'] BuySell = Literal['buy', 'sell'] MakerTaker = Literal['maker', 'taker'] +BidAsk = Literal['bid', 'ask'] Config = Dict[str, Any] diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 3b59bdfa0..8cfe90272 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -20,8 +20,8 @@ from ccxt import ROUND_DOWN, ROUND_UP, TICK_SIZE, TRUNCATE, decimal_to_precision from dateutil import parser from pandas import DataFrame, concat -from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, BuySell, - Config, EntryExit, ListPairsWithTimeframes, MakerTaker, +from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, BidAsk, + BuySell, Config, EntryExit, ListPairsWithTimeframes, MakerTaker, PairWithTimeframe) from freqtrade.data.converter import clean_ohlcv_dataframe, ohlcv_to_dataframe, trades_dict_to_list from freqtrade.enums import OPTIMIZE_MODES, CandleType, MarginMode, TradingMode @@ -31,7 +31,7 @@ from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFun from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED, remove_credentials, retrier, retrier_async) -from freqtrade.exchange.types import Tickers +from freqtrade.exchange.types import Ticker, Tickers from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_json, safe_value_fallback2) from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -1452,12 +1452,12 @@ class Exchange: # Pricing info @retrier - def fetch_ticker(self, pair: str) -> dict: + def fetch_ticker(self, pair: str) -> Ticker: try: if (pair not in self.markets or self.markets[pair].get('active', False) is False): raise ExchangeError(f"Pair {pair} not available") - data = self._api.fetch_ticker(pair) + data: Ticker = self._api.fetch_ticker(pair) return data except ccxt.DDoSProtection as e: raise DDosProtection(e) from e @@ -1508,7 +1508,7 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def _get_price_side(self, side: str, is_short: bool, conf_strategy: Dict) -> str: + def _get_price_side(self, side: str, is_short: bool, conf_strategy: Dict) -> BidAsk: price_side = conf_strategy['price_side'] if price_side in ('same', 'other'): @@ -1527,7 +1527,7 @@ class Exchange: def get_rate(self, pair: str, refresh: bool, side: EntryExit, is_short: bool, - order_book: Optional[dict] = None, ticker: Optional[dict] = None) -> float: + order_book: Optional[dict] = None, ticker: Optional[Ticker] = None) -> float: """ Calculates bid/ask target bid rate - between current ask price and last price diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 56b3fef0e..49d33d46f 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -6,7 +6,7 @@ import logging import re from datetime import datetime from pathlib import Path -from typing import Any, Iterator, List +from typing import Any, Dict, Iterator, List, Mapping, Union from typing.io import IO from urllib.parse import urlparse @@ -186,7 +186,10 @@ def safe_value_fallback(obj: dict, key1: str, key2: str, default_value=None): return default_value -def safe_value_fallback2(dict1: dict, dict2: dict, key1: str, key2: str, default_value=None): +dictMap = Union[Dict[str, Any], Mapping[str, Any]] + + +def safe_value_fallback2(dict1: dictMap, dict2: dictMap, key1: str, key2: str, default_value=None): """ Search a value in dict1, return this if it's not None. Fall back to dict2 - return key2 from dict2 if it's not None. From 96e6c1b190e1f6285ecd8bcb6482ec83e62cde43 Mon Sep 17 00:00:00 2001 From: Joe Schr <8218910+TheJoeSchr@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:05:50 +0200 Subject: [PATCH 49/60] Docs: add `ignore_buying_expired_candle_after` and `order pricing` to summary --- docs/strategy_migration.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index 471ffa601..58f6b0d23 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -43,12 +43,18 @@ Note : `forcesell`, `forcebuy`, `emergencysell` are changed to `force_exit`, `fo * `order_time_in_force` buy -> entry, sell -> exit. * `order_types` buy -> entry, sell -> exit. * `unfilledtimeout` buy -> entry, sell -> exit. + * `ignore_buying_expired_candle_after` -> moved to root level instead of "ask_strategy/exit_pricing" * Terminology changes * Sell reasons changed to reflect the new naming of "exit" instead of sells. Be careful in your strategy if you're using `exit_reason` checks and eventually update your strategy. * `sell_signal` -> `exit_signal` * `custom_sell` -> `custom_exit` * `force_sell` -> `force_exit` * `emergency_sell` -> `emergency_exit` + * Order pricing + * `bid_strategy` -> `entry_pricing` + * `ask_strategy` -> `exit_pricing` + * `ask_last_balance` -> `price_last_balance` + * `bid_last_balance` -> `price_last_balance` * Webhook terminology changed from "sell" to "exit", and from "buy" to entry * `webhookbuy` -> `webhookentry` * `webhookbuyfill` -> `webhookentryfill` @@ -443,6 +449,7 @@ Please refer to the [pricing documentation](configuration.md#prices-used-for-ord "use_order_book": true, "order_book_top": 1, "bid_last_balance": 0.0 + "ignore_buying_expired_candle_after": 120 } } ``` @@ -466,6 +473,7 @@ after: "use_order_book": true, "order_book_top": 1, "price_last_balance": 0.0 - } + }, + "ignore_buying_expired_candle_after": 120 } ``` From 39c27cfc37650916464f267c4b814086c5f0ec01 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 04:58:02 +0000 Subject: [PATCH 50/60] Don't fail if fetchTickers is not availlable --- freqtrade/exchange/exchange.py | 2 ++ tests/exchange/test_exchange.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 8cfe90272..53a3960b1 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1427,6 +1427,8 @@ class Exchange: :return: fetch_tickers result """ tickers: Tickers + if not self.exchange_has('fetchTickers'): + return {} if cached: with self._cache_lock: tickers = self._fetch_tickers_cache.get('fetch_tickers') # type: ignore diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index b07892f72..07aad80ff 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1834,6 +1834,7 @@ def test_get_tickers(default_conf, mocker, exchange_name): 'last': 41, } } + mocker.patch('freqtrade.exchange.exchange.Exchange.exchange_has', return_value=True) api_mock.fetch_tickers = MagicMock(return_value=tick) api_mock.fetch_bids_asks = MagicMock(return_value={}) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) @@ -1883,6 +1884,11 @@ def test_get_tickers(default_conf, mocker, exchange_name): assert api_mock.fetch_tickers.call_count == 1 assert api_mock.fetch_bids_asks.call_count == (1 if exchange_name == 'binance' else 0) + api_mock.fetch_tickers.reset_mock() + api_mock.fetch_bids_asks.reset_mock() + mocker.patch('freqtrade.exchange.exchange.Exchange.exchange_has', return_value=False) + assert exchange.get_tickers() == {} + @pytest.mark.parametrize("exchange_name", EXCHANGES) def test_fetch_ticker(default_conf, mocker, exchange_name): From 75f1a123ebe5cd4b7907c2feae11f64ec4b98e5e Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 04:58:17 +0000 Subject: [PATCH 51/60] Move "tickers_needed" check to pairlistmanager to cover all pairlists --- freqtrade/plugins/pairlist/SpreadFilter.py | 7 ------- freqtrade/plugins/pairlistmanager.py | 9 +++++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/freqtrade/plugins/pairlist/SpreadFilter.py b/freqtrade/plugins/pairlist/SpreadFilter.py index ecb21593b..207328d08 100644 --- a/freqtrade/plugins/pairlist/SpreadFilter.py +++ b/freqtrade/plugins/pairlist/SpreadFilter.py @@ -5,7 +5,6 @@ import logging from typing import Any, Dict, Optional from freqtrade.constants import Config -from freqtrade.exceptions import OperationalException from freqtrade.exchange.types import Ticker from freqtrade.plugins.pairlist.IPairList import IPairList @@ -23,12 +22,6 @@ class SpreadFilter(IPairList): self._max_spread_ratio = pairlistconfig.get('max_spread_ratio', 0.005) self._enabled = self._max_spread_ratio != 0 - if not self._exchange.exchange_has('fetchTickers'): - raise OperationalException( - 'Exchange does not support fetchTickers, therefore SpreadFilter cannot be used.' - 'Please edit your config and restart the bot.' - ) - @property def needstickers(self) -> bool: """ diff --git a/freqtrade/plugins/pairlistmanager.py b/freqtrade/plugins/pairlistmanager.py index 1e98b8485..20a264fd8 100644 --- a/freqtrade/plugins/pairlistmanager.py +++ b/freqtrade/plugins/pairlistmanager.py @@ -46,6 +46,15 @@ class PairListManager(LoggingMixin): if not self._pairlist_handlers: raise OperationalException("No Pairlist Handlers defined") + if self._tickers_needed and not self._exchange.exchange_has('fetchTickers'): + invalid = ". ".join([p.name for p in self._pairlist_handlers if p.needstickers]) + + raise OperationalException( + "Exchange does not support fetchTickers, therefore the following pairlists " + "cannot be used. Please edit your config and restart the bot.\n" + f"{invalid}." + ) + refresh_period = config.get('pairlist_refresh_period', 3600) LoggingMixin.__init__(self, logger, refresh_period) From f8331e0326e12cee9ec9a84fc1c5a7ba76731ab9 Mon Sep 17 00:00:00 2001 From: th0rntwig Date: Thu, 13 Oct 2022 10:53:25 +0200 Subject: [PATCH 52/60] Add model libs info --- docs/freqai-configuration.md | 38 +++++++++++++++++++++++++++++----- docs/freqai-parameter-table.md | 2 +- docs/freqai-running.md | 4 ++-- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/docs/freqai-configuration.md b/docs/freqai-configuration.md index 737f64824..2d40918e5 100644 --- a/docs/freqai-configuration.md +++ b/docs/freqai-configuration.md @@ -204,17 +204,45 @@ If this value is set, FreqAI will initially use the predictions from the trainin ## Using different prediction models -FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag `--freqaimodel`. These libraries include `Catboost`, `LightGBM`, and `XGBoost` regression, classification, and multi-target models, and can be found in `freqai/prediction_models/`. However, it is possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to let these customize various aspects of the training procedures. +FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag `--freqaimodel`. These libraries include `CatBoost`, `LightGBM`, and `XGBoost` regression, classification, and multi-target models, and can be found in `freqai/prediction_models/`. -You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model. +Regression and classification models differ in what targets they predict - a regression model will predict a target of continous values, for example what price BTC will be at tomorrow, whilst a classifier will predict a target of descrete values, for example if the price of BTC will go up tomorrow or not. This means that you have to specify your targets differently depending on which model type you are using (see details [below](#setting-model-targets)). + +All of the aforementioned model libraries implement gradient boosted decision tree algorithms. They all work on the principle of emsemble learning, where predictions from multiple simple learners are combined to get a final prediction that is more stable and generalized. The simple learners in this case are decision trees. Gradient boosting refers to the method of learning, where each simple learner is built in sequence - the subsequent learner is used to improve on the error from the previous learner. If you want to learn more about the different model libraries you can find the information in their respective docs: + +* CatBoost: https://catboost.ai/en/docs/ +* LightGBM: https://lightgbm.readthedocs.io/en/v3.3.2/# +* XGBoost: https://xgboost.readthedocs.io/en/stable/# + +There are also numerous online articles describing and comparing the algorithms. Some relatively light-weight examples would be [CatBoost vs. LightGBM vs. XGBoost — Which is the best algorithm?](https://towardsdatascience.com/catboost-vs-lightgbm-vs-xgboost-c80f40662924#:~:text=In%20CatBoost%2C%20symmetric%20trees%2C%20or,the%20same%20depth%20can%20differ.) and [XGBoost, LightGBM or CatBoost — which boosting algorithm should I use?](https://medium.com/riskified-technology/xgboost-lightgbm-or-catboost-which-boosting-algorithm-should-i-use-e7fda7bb36bc). Keep in mind that the performance of each model is highly dependent on the application and so any reported metrics might not be true for your particular use of the model. + +Apart from the models already vailable in FreqAI, it is also possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to let these customize various aspects of the training procedures. You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model. Make sure to use unique names to avoid overriding built-in models. -### Setting classifier targets +### Setting model targets -FreqAI includes a variety of classifiers, such as the `CatboostClassifier` via the flag `--freqaimodel CatboostClassifier`. If you elects to use a classifier, the classes need to be set using strings. For example: +#### Regressors + +If you are using a regressor, you need to specify a target that has continous values. FreqAI includes a variety of regressors, such as the `CatboostRegressor`via the flag `--freqaimodel CatboostRegressor`. An example of how you could set a regression target for predicting the price 100 candles into the future would be + +```python +df['&s-close_price'] = df['close'].shift(-100) +``` + +If you want to predict multiple targets, you need to define multiple labels using the same syntax as shown above. + +#### Classifiers + +If you are using a classifier, you need to specify a target that has descrete values. FreqAI includes a variety of classifiers, such as the `CatboostClassifier` via the flag `--freqaimodel CatboostClassifier`. If you elects to use a classifier, the classes need to be set using strings. For example, if you want to predict if the price 100 candles into the future goes up or down you would set ```python df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') ``` -Additionally, the example classifier models do not accommodate multiple labels, but they do allow multi-class classification within a single label column. +If you want to predict multiple targets you must specify all labels in the same label column. You could, for example, add the label `same` to define where the price was unchanged by setting + + +```python +df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') +df['&s-up_or_down'] = np.where( df["close"].shift(-100) == df["close"], 'same', df['&s-up_or_down']) +``` diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md index 38d7ece94..7d9864fc0 100644 --- a/docs/freqai-parameter-table.md +++ b/docs/freqai-parameter-table.md @@ -42,7 +42,7 @@ Mandatory parameters are marked as **Required** and have to be set in one of the | `test_size` | The fraction of data that should be used for testing instead of training.
**Datatype:** Positive float < 1. | `shuffle` | Shuffle the training data points during training. Typically, to not remove the chronological order of data in time-series forecasting, this is set to `False`.
**Datatype:** Boolean.
Defaut: `False`. | | **Model training parameters** -| `model_training_parameters` | A flexible dictionary that includes all parameters available by the selected model library. For example, if you use `LightGBMRegressor`, this dictionary can contain any parameter available by the `LightGBMRegressor` [here](https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRegressor.html) (external website). If you select a different model, this dictionary can contain any parameter from that model.
**Datatype:** Dictionary. +| `model_training_parameters` | A flexible dictionary that includes all parameters available by the selected model library. For example, if you use `LightGBMRegressor`, this dictionary can contain any parameter available by the `LightGBMRegressor` [here](https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRegressor.html) (external website). If you select a different model, this dictionary can contain any parameter from that model. A list of the currently available models can be found [here](freqai-configuration.md#using-different-prediction-models).
**Datatype:** Dictionary. | `n_estimators` | The number of boosted trees to fit in the training of the model.
**Datatype:** Integer. | `learning_rate` | Boosting learning rate during training of the model.
**Datatype:** Float. | `n_jobs`, `thread_count`, `task_type` | Set the number of threads for parallel processing and the `task_type` (`gpu` or `cpu`). Different model libraries use different parameter names.
**Datatype:** Float. diff --git a/docs/freqai-running.md b/docs/freqai-running.md index f6aa7b2e1..9e2b13c44 100644 --- a/docs/freqai-running.md +++ b/docs/freqai-running.md @@ -144,14 +144,14 @@ This specific hyperopt would help you understand the appropriate `DI_values` for ## Using Tensorboard -Catboost models benefit from tracking training metrics via Tensorboard. You can take advantage of the FreqAI integration to track training and evaluation performance across all coins and across all retrainings. Tensorboard is activated via the following command: +CatBoost models benefit from tracking training metrics via Tensorboard. You can take advantage of the FreqAI integration to track training and evaluation performance across all coins and across all retrainings. Tensorboard is activated via the following command: ```bash cd freqtrade tensorboard --logdir user_data/models/unique-id ``` -where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell if the user wishes to view the output in their browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard). +where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell if you wish to view the output in your browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard). ![tensorboard](assets/tensorboard.jpg) From 20457808100159f653b05b6967f18c5e9d099bfe Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 11:57:36 +0000 Subject: [PATCH 53/60] Reinstate default of 1000% for roi closes #7583 --- freqtrade/strategy/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 8f803045f..96e3065c4 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -49,7 +49,7 @@ class IStrategy(ABC, HyperStrategyMixin): _ft_params_from_file: Dict # associated minimal roi - minimal_roi: Dict = {} + minimal_roi: Dict = {"0": 10.0} # associated stoploss stoploss: float From 28be784c2eb90bcb814072fcc1b5a388944b941b Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 12:17:53 +0000 Subject: [PATCH 54/60] Fix kucoin live test failure --- tests/exchange/test_ccxt_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 9ff65cdc4..9f9866aba 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -56,7 +56,7 @@ EXCHANGES = { 'leverage_in_spot_market': True, }, 'kucoin': { - 'pair': 'BTC/USDT', + 'pair': 'XRP/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, 'timeframe': '5m', From c71c0e8da0e3326c9de12e97ffc36333baf00c3a Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 18:16:39 +0200 Subject: [PATCH 55/60] Fix some typos --- docs/freqai-configuration.md | 13 ++++++------- docs/freqai-running.md | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/freqai-configuration.md b/docs/freqai-configuration.md index 2d40918e5..d162fe373 100644 --- a/docs/freqai-configuration.md +++ b/docs/freqai-configuration.md @@ -204,11 +204,11 @@ If this value is set, FreqAI will initially use the predictions from the trainin ## Using different prediction models -FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag `--freqaimodel`. These libraries include `CatBoost`, `LightGBM`, and `XGBoost` regression, classification, and multi-target models, and can be found in `freqai/prediction_models/`. +FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag `--freqaimodel`. These libraries include `CatBoost`, `LightGBM`, and `XGBoost` regression, classification, and multi-target models, and can be found in `freqai/prediction_models/`. -Regression and classification models differ in what targets they predict - a regression model will predict a target of continous values, for example what price BTC will be at tomorrow, whilst a classifier will predict a target of descrete values, for example if the price of BTC will go up tomorrow or not. This means that you have to specify your targets differently depending on which model type you are using (see details [below](#setting-model-targets)). +Regression and classification models differ in what targets they predict - a regression model will predict a target of continuous values, for example what price BTC will be at tomorrow, whilst a classifier will predict a target of discrete values, for example if the price of BTC will go up tomorrow or not. This means that you have to specify your targets differently depending on which model type you are using (see details [below](#setting-model-targets)). -All of the aforementioned model libraries implement gradient boosted decision tree algorithms. They all work on the principle of emsemble learning, where predictions from multiple simple learners are combined to get a final prediction that is more stable and generalized. The simple learners in this case are decision trees. Gradient boosting refers to the method of learning, where each simple learner is built in sequence - the subsequent learner is used to improve on the error from the previous learner. If you want to learn more about the different model libraries you can find the information in their respective docs: +All of the aforementioned model libraries implement gradient boosted decision tree algorithms. They all work on the principle of ensemble learning, where predictions from multiple simple learners are combined to get a final prediction that is more stable and generalized. The simple learners in this case are decision trees. Gradient boosting refers to the method of learning, where each simple learner is built in sequence - the subsequent learner is used to improve on the error from the previous learner. If you want to learn more about the different model libraries you can find the information in their respective docs: * CatBoost: https://catboost.ai/en/docs/ * LightGBM: https://lightgbm.readthedocs.io/en/v3.3.2/# @@ -216,14 +216,14 @@ All of the aforementioned model libraries implement gradient boosted decision tr There are also numerous online articles describing and comparing the algorithms. Some relatively light-weight examples would be [CatBoost vs. LightGBM vs. XGBoost — Which is the best algorithm?](https://towardsdatascience.com/catboost-vs-lightgbm-vs-xgboost-c80f40662924#:~:text=In%20CatBoost%2C%20symmetric%20trees%2C%20or,the%20same%20depth%20can%20differ.) and [XGBoost, LightGBM or CatBoost — which boosting algorithm should I use?](https://medium.com/riskified-technology/xgboost-lightgbm-or-catboost-which-boosting-algorithm-should-i-use-e7fda7bb36bc). Keep in mind that the performance of each model is highly dependent on the application and so any reported metrics might not be true for your particular use of the model. -Apart from the models already vailable in FreqAI, it is also possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to let these customize various aspects of the training procedures. You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model. +Apart from the models already available in FreqAI, it is also possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to customize various aspects of the training procedures. You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model. Make sure to use unique names to avoid overriding built-in models. ### Setting model targets #### Regressors -If you are using a regressor, you need to specify a target that has continous values. FreqAI includes a variety of regressors, such as the `CatboostRegressor`via the flag `--freqaimodel CatboostRegressor`. An example of how you could set a regression target for predicting the price 100 candles into the future would be +If you are using a regressor, you need to specify a target that has continuous values. FreqAI includes a variety of regressors, such as the `CatboostRegressor`via the flag `--freqaimodel CatboostRegressor`. An example of how you could set a regression target for predicting the price 100 candles into the future would be ```python df['&s-close_price'] = df['close'].shift(-100) @@ -233,7 +233,7 @@ If you want to predict multiple targets, you need to define multiple labels usin #### Classifiers -If you are using a classifier, you need to specify a target that has descrete values. FreqAI includes a variety of classifiers, such as the `CatboostClassifier` via the flag `--freqaimodel CatboostClassifier`. If you elects to use a classifier, the classes need to be set using strings. For example, if you want to predict if the price 100 candles into the future goes up or down you would set +If you are using a classifier, you need to specify a target that has discrete values. FreqAI includes a variety of classifiers, such as the `CatboostClassifier` via the flag `--freqaimodel CatboostClassifier`. If you elects to use a classifier, the classes need to be set using strings. For example, if you want to predict if the price 100 candles into the future goes up or down you would set ```python df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') @@ -241,7 +241,6 @@ df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'do If you want to predict multiple targets you must specify all labels in the same label column. You could, for example, add the label `same` to define where the price was unchanged by setting - ```python df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') df['&s-up_or_down'] = np.where( df["close"].shift(-100) == df["close"], 'same', df['&s-up_or_down']) diff --git a/docs/freqai-running.md b/docs/freqai-running.md index 9e2b13c44..7972a6c92 100644 --- a/docs/freqai-running.md +++ b/docs/freqai-running.md @@ -155,7 +155,6 @@ where `unique-id` is the `identifier` set in the `freqai` configuration file. Th ![tensorboard](assets/tensorboard.jpg) - ## Setting up a follower You can indicate to the bot that it should not train models, but instead should look for models trained by a leader with a specific `identifier` by defining: From 7672586de9ff92f20993977802374156d533e64a Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 19:43:37 +0200 Subject: [PATCH 56/60] Fix unreliable hyperopt test --- tests/optimize/test_hyperopt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 5666ebabc..c52bc9799 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -910,8 +910,9 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir, }) hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.exchange.get_max_leverage = lambda *x, **xx: 1.0 - hyperopt.backtesting.exchange.get_min_pair_stake_amount = lambda *x, **xx: 1.0 + hyperopt.backtesting.exchange.get_min_pair_stake_amount = lambda *x, **xx: 0.00001 hyperopt.backtesting.exchange.get_max_pair_stake_amount = lambda *x, **xx: 100.0 + hyperopt.backtesting.exchange._markets = get_markets() assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter) From f0194710513de86e59a086be28518180dbf52cd5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Oct 2022 19:30:59 +0200 Subject: [PATCH 57/60] Don't round prices if no custom prices have been used closes #7573 --- freqtrade/optimize/backtesting.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 83159dfe4..720069f84 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -617,13 +617,16 @@ class Backtesting: exit_reason = row[EXIT_TAG_IDX] # Custom exit pricing only for exit-signals if order_type == 'limit': - close_rate = strategy_safe_wrapper(self.strategy.custom_exit_price, - default_retval=close_rate)( + rate = strategy_safe_wrapper(self.strategy.custom_exit_price, + default_retval=close_rate)( pair=trade.pair, trade=trade, # type: ignore[arg-type] current_time=exit_candle_time, proposed_rate=close_rate, current_profit=current_profit, exit_tag=exit_reason) + if rate != close_rate: + close_rate = price_to_precision(rate, trade.price_precision, + self.precision_mode) # We can't place orders lower than current low. # freqtrade does not support this in live, and the order would fill immediately if trade.is_short: @@ -660,7 +663,6 @@ class Backtesting: # amount = amount or trade.amount amount = amount_to_contract_precision(amount or trade.amount, trade.amount_precision, self.precision_mode, trade.contract_size) - rate = price_to_precision(close_rate, trade.price_precision, self.precision_mode) order = Order( id=self.order_id_counter, ft_trade_id=trade.id, @@ -674,12 +676,12 @@ class Backtesting: side=trade.exit_side, order_type=order_type, status="open", - price=rate, - average=rate, + price=close_rate, + average=close_rate, amount=amount, filled=0, remaining=amount, - cost=amount * rate, + cost=amount * close_rate, ) trade.orders.append(order) return trade @@ -726,18 +728,21 @@ class Backtesting: def get_valid_price_and_stake( self, pair: str, row: Tuple, propose_rate: float, stake_amount: float, direction: LongShort, current_time: datetime, entry_tag: Optional[str], - trade: Optional[LocalTrade], order_type: str + trade: Optional[LocalTrade], order_type: str, price_precision: Optional[float] ) -> Tuple[float, float, float, float]: if order_type == 'limit': - propose_rate = strategy_safe_wrapper(self.strategy.custom_entry_price, - default_retval=propose_rate)( + new_rate = strategy_safe_wrapper(self.strategy.custom_entry_price, + default_retval=propose_rate)( pair=pair, current_time=current_time, proposed_rate=propose_rate, entry_tag=entry_tag, side=direction, ) # default value is the open rate # We can't place orders higher than current high (otherwise it'd be a stop limit entry) # which freqtrade does not support in live. + if new_rate != propose_rate: + propose_rate = price_to_precision(new_rate, price_precision, + self.precision_mode) if direction == "short": propose_rate = max(propose_rate, row[LOW_IDX]) else: @@ -799,9 +804,11 @@ class Backtesting: pos_adjust = trade is not None and requested_rate is None stake_amount_ = stake_amount or (trade.stake_amount if trade else 0.0) + precision_price = self.exchange.get_precision_price(pair) + propose_rate, stake_amount, leverage, min_stake_amount = self.get_valid_price_and_stake( pair, row, row[OPEN_IDX], stake_amount_, direction, current_time, entry_tag, trade, - order_type + order_type, precision_price, ) # replace proposed rate if another rate was requested @@ -817,8 +824,6 @@ class Backtesting: if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount): self.order_id_counter += 1 base_currency = self.exchange.get_pair_base_currency(pair) - precision_price = self.exchange.get_precision_price(pair) - propose_rate = price_to_precision(propose_rate, precision_price, self.precision_mode) amount_p = (stake_amount / propose_rate) * leverage contract_size = self.exchange.get_contract_size(pair) From 1d8d360a128830f5940b2fb9c145b766d7a94438 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Oct 2022 14:32:30 +0000 Subject: [PATCH 58/60] update _search_all_objects functioning --- freqtrade/commands/list_commands.py | 11 ++++------ freqtrade/resolvers/iresolver.py | 31 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index eb761eeec..7ab9202aa 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -1,7 +1,6 @@ import csv import logging import sys -from pathlib import Path from typing import Any, Dict, List import rapidjson @@ -10,7 +9,6 @@ from colorama import init as colorama_init from tabulate import tabulate from freqtrade.configuration import setup_utils_configuration -from freqtrade.constants import USERPATH_STRATEGIES from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException from freqtrade.exchange import market_is_active, validate_exchanges @@ -41,7 +39,7 @@ def start_list_exchanges(args: Dict[str, Any]) -> None: print(tabulate(exchanges, headers=['Exchange name', 'Valid', 'reason'])) -def _print_objs_tabular(objs: List, print_colorized: bool, base_dir: Path) -> None: +def _print_objs_tabular(objs: List, print_colorized: bool) -> None: if print_colorized: colorama_init(autoreset=True) red = Fore.RED @@ -55,7 +53,7 @@ def _print_objs_tabular(objs: List, print_colorized: bool, base_dir: Path) -> No names = [s['name'] for s in objs] objs_to_print = [{ 'name': s['name'] if s['name'] else "--", - 'location': s['location'].relative_to(base_dir), + 'location': s['location_rel'], 'status': (red + "LOAD FAILED" + reset if s['class'] is None else "OK" if names.count(s['name']) == 1 else yellow + "DUPLICATE NAME" + reset) @@ -76,9 +74,8 @@ def start_list_strategies(args: Dict[str, Any]) -> None: """ config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) - directory = Path(config.get('strategy_path', config['user_data_dir'] / USERPATH_STRATEGIES)) strategy_objs = StrategyResolver.search_all_objects( - directory, not args['print_one_column'], config.get('recursive_strategy_search', False)) + config, not args['print_one_column'], config.get('recursive_strategy_search', False)) # Sort alphabetically strategy_objs = sorted(strategy_objs, key=lambda x: x['name']) for obj in strategy_objs: @@ -90,7 +87,7 @@ def start_list_strategies(args: Dict[str, Any]) -> None: if args['print_one_column']: print('\n'.join([s['name'] for s in strategy_objs])) else: - _print_objs_tabular(strategy_objs, config.get('print_colorized', False), directory) + _print_objs_tabular(strategy_objs, config.get('print_colorized', False)) def start_list_timeframes(args: Dict[str, Any]) -> None: diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index 9682e1c2b..df21f5a2d 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -183,9 +183,35 @@ class IResolver: ) @classmethod - def search_all_objects(cls, directory: Path, enum_failed: bool, + def search_all_objects(cls, config: Config, enum_failed: bool, recursive: bool = False) -> List[Dict[str, Any]]: """ + Searches for valid objects + :param config: Config object + :param enum_failed: If True, will return None for modules which fail. + Otherwise, failing modules are skipped. + :param recursive: Recursively walk directory tree searching for strategies + :return: List of dicts containing 'name', 'class' and 'location' entries + """ + result = [] + + abs_paths = cls.build_search_paths(config, user_subdir=cls.user_subdir) + print(abs_paths) + for path in abs_paths: + result.extend(cls._search_all_objects(path, enum_failed, recursive)) + return result + + @classmethod + def _build_rel_location(cls, directory: Path, entry: Path) -> str: + + builtin = cls.initial_search_path == directory + return f"/{entry.relative_to(directory)}" if builtin else entry.relative_to( + directory) + + @classmethod + def _search_all_objects(cls, directory: Path, enum_failed: bool, + recursive: bool = False) -> List[Dict[str, Any]]: + """ Searches a directory for valid objects :param directory: Path to search :param enum_failed: If True, will return None for modules which fail. @@ -204,7 +230,7 @@ class IResolver: and not entry.name.startswith('__') and not entry.name.startswith('.') ): - objects.extend(cls.search_all_objects(entry, enum_failed, recursive=recursive)) + objects.extend(cls._search_all_objects(entry, enum_failed, recursive=recursive)) # Only consider python files if entry.suffix != '.py': logger.debug('Ignoring %s', entry) @@ -217,5 +243,6 @@ class IResolver: {'name': obj[0].__name__ if obj is not None else '', 'class': obj[0] if obj is not None else None, 'location': entry, + 'location_rel': cls._build_rel_location(directory, entry), }) return objects From 9d4ba767c4d7514001a52a780fa348a85f6260c8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Oct 2022 14:41:25 +0000 Subject: [PATCH 59/60] Update usages of search_all_objects --- freqtrade/optimize/hyperopt_tools.py | 5 ++--- freqtrade/resolvers/iresolver.py | 11 ++++++----- freqtrade/resolvers/strategy_resolver.py | 8 ++++++++ freqtrade/rpc/api_server/api_v1.py | 4 +--- tests/strategy/test_strategy_loading.py | 6 +++--- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 65bdc4db5..393c055c4 100755 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -12,7 +12,7 @@ import tabulate from colorama import Fore, Style from pandas import isna, json_normalize -from freqtrade.constants import FTHYPT_FILEVERSION, USERPATH_STRATEGIES, Config +from freqtrade.constants import FTHYPT_FILEVERSION, Config from freqtrade.enums import HyperoptState from freqtrade.exceptions import OperationalException from freqtrade.misc import deep_merge_dicts, round_coin_value, round_dict, safe_value_fallback2 @@ -50,9 +50,8 @@ class HyperoptTools(): Get Strategy-location (filename) from strategy_name """ from freqtrade.resolvers.strategy_resolver import StrategyResolver - directory = Path(config.get('strategy_path', config['user_data_dir'] / USERPATH_STRATEGIES)) strategy_objs = StrategyResolver.search_all_objects( - directory, False, config.get('recursive_strategy_search', False)) + config, False, config.get('recursive_strategy_search', False)) strategies = [s for s in strategy_objs if s['name'] == strategy_name] if strategies: strategy = strategies[0] diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index df21f5a2d..56376baa4 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -196,7 +196,6 @@ class IResolver: result = [] abs_paths = cls.build_search_paths(config, user_subdir=cls.user_subdir) - print(abs_paths) for path in abs_paths: result.extend(cls._search_all_objects(path, enum_failed, recursive)) return result @@ -209,8 +208,9 @@ class IResolver: directory) @classmethod - def _search_all_objects(cls, directory: Path, enum_failed: bool, - recursive: bool = False) -> List[Dict[str, Any]]: + def _search_all_objects( + cls, directory: Path, enum_failed: bool, recursive: bool = False, + basedir: Optional[Path] = None) -> List[Dict[str, Any]]: """ Searches a directory for valid objects :param directory: Path to search @@ -230,7 +230,8 @@ class IResolver: and not entry.name.startswith('__') and not entry.name.startswith('.') ): - objects.extend(cls._search_all_objects(entry, enum_failed, recursive=recursive)) + objects.extend(cls._search_all_objects( + entry, enum_failed, recursive, basedir or directory)) # Only consider python files if entry.suffix != '.py': logger.debug('Ignoring %s', entry) @@ -243,6 +244,6 @@ class IResolver: {'name': obj[0].__name__ if obj is not None else '', 'class': obj[0] if obj is not None else None, 'location': entry, - 'location_rel': cls._build_rel_location(directory, entry), + 'location_rel': cls._build_rel_location(basedir or directory, entry), }) return objects diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index c574246ac..a1eb3d190 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -268,6 +268,14 @@ class StrategyResolver(IResolver): "or contains Python code errors." ) + @classmethod + def build_search_paths(cls, config: Config, user_subdir: Optional[str] = None, + extra_dirs: List[str] = []) -> List[Path]: + + if 'strategy_path' in config: + extra_dirs = [config['strategy_path']] + extra_dirs + return super().build_search_paths(config, user_subdir, extra_dirs) + def warn_deprecated_setting(strategy: IStrategy, old: str, new: str, error=False): if hasattr(strategy, old): diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 135892dc6..0e6f9500a 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -253,11 +253,9 @@ def plot_config(rpc: RPC = Depends(get_rpc)): @router.get('/strategies', response_model=StrategyListResponse, tags=['strategy']) def list_strategies(config=Depends(get_config)): - directory = Path(config.get( - 'strategy_path', config['user_data_dir'] / USERPATH_STRATEGIES)) from freqtrade.resolvers.strategy_resolver import StrategyResolver strategies = StrategyResolver.search_all_objects( - directory, False, config.get('recursive_strategy_search', False)) + config, False, config.get('recursive_strategy_search', False)) strategies = sorted(strategies, key=lambda x: x['name']) return {'strategies': [x['name'] for x in strategies]} diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index adffd0875..8b9ae658b 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -32,7 +32,7 @@ def test_search_strategy(): def test_search_all_strategies_no_failed(): directory = Path(__file__).parent / "strats" - strategies = StrategyResolver.search_all_objects(directory, enum_failed=False) + strategies = StrategyResolver._search_all_objects(directory, enum_failed=False) assert isinstance(strategies, list) assert len(strategies) == 9 assert isinstance(strategies[0], dict) @@ -40,7 +40,7 @@ def test_search_all_strategies_no_failed(): def test_search_all_strategies_with_failed(): directory = Path(__file__).parent / "strats" - strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) + strategies = StrategyResolver._search_all_objects(directory, enum_failed=True) assert isinstance(strategies, list) assert len(strategies) == 10 # with enum_failed=True search_all_objects() shall find 2 good strategies @@ -49,7 +49,7 @@ def test_search_all_strategies_with_failed(): assert len([x for x in strategies if x['class'] is None]) == 1 directory = Path(__file__).parent / "strats_nonexistingdir" - strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) + strategies = StrategyResolver._search_all_objects(directory, enum_failed=True) assert len(strategies) == 0 From 4a8cb3359b7a8dd6676817f91efbdb51562918e4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Oct 2022 14:59:55 +0000 Subject: [PATCH 60/60] Fix broken tests --- freqtrade/resolvers/iresolver.py | 4 ++-- freqtrade/resolvers/strategy_resolver.py | 2 +- freqtrade/rpc/api_server/api_v1.py | 2 -- tests/rpc/test_rpc_apiserver.py | 3 ++- tests/strategy/test_strategy_loading.py | 11 +++++------ 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index 56376baa4..5c4ba1568 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -204,8 +204,8 @@ class IResolver: def _build_rel_location(cls, directory: Path, entry: Path) -> str: builtin = cls.initial_search_path == directory - return f"/{entry.relative_to(directory)}" if builtin else entry.relative_to( - directory) + return f"/{entry.relative_to(directory)}" if builtin else str( + entry.relative_to(directory)) @classmethod def _search_all_objects( diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index a1eb3d190..ae27df3c5 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -272,7 +272,7 @@ class StrategyResolver(IResolver): def build_search_paths(cls, config: Config, user_subdir: Optional[str] = None, extra_dirs: List[str] = []) -> List[Path]: - if 'strategy_path' in config: + if 'strategy_path' in config and config['strategy_path'] not in extra_dirs: extra_dirs = [config['strategy_path']] + extra_dirs return super().build_search_paths(config, user_subdir, extra_dirs) diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 0e6f9500a..c0c9b8f57 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -1,13 +1,11 @@ import logging from copy import deepcopy -from pathlib import Path from typing import List, Optional from fastapi import APIRouter, Depends, Query from fastapi.exceptions import HTTPException from freqtrade import __version__ -from freqtrade.constants import USERPATH_STRATEGIES from freqtrade.data.history import get_datahandler from freqtrade.enums import CandleType, TradingMode from freqtrade.exceptions import OperationalException diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 684f68819..f0d74698e 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1443,8 +1443,9 @@ def test_api_plot_config(botclient): assert isinstance(rc.json()['subplots'], dict) -def test_api_strategies(botclient): +def test_api_strategies(botclient, tmpdir): ftbot, client = botclient + ftbot.config['user_data_dir'] = Path(tmpdir) rc = client_get(client, f"{BASE_URI}/strategies") diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index 8b9ae658b..ae5a4024c 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -77,10 +77,9 @@ def test_load_strategy_base64(dataframe_1m, caplog, default_conf): def test_load_strategy_invalid_directory(caplog, default_conf): - default_conf['strategy'] = 'StrategyTestV3' extra_dir = Path.cwd() / 'some/path' - with pytest.raises(OperationalException): - StrategyResolver._load_strategy(CURRENT_TEST_STRATEGY, config=default_conf, + with pytest.raises(OperationalException, match=r"Impossible to load Strategy.*"): + StrategyResolver._load_strategy('StrategyTestV333', config=default_conf, extra_dir=extra_dir) assert log_has_re(r'Path .*' + r'some.*path.*' + r'.* does not exist', caplog) @@ -102,8 +101,8 @@ def test_load_strategy_noname(default_conf): StrategyResolver.load_strategy(default_conf) -@pytest.mark.filterwarnings("ignore:deprecated") -@pytest.mark.parametrize('strategy_name', ['StrategyTestV2']) +@ pytest.mark.filterwarnings("ignore:deprecated") +@ pytest.mark.parametrize('strategy_name', ['StrategyTestV2']) def test_strategy_pre_v3(dataframe_1m, default_conf, strategy_name): default_conf.update({'strategy': strategy_name}) @@ -349,7 +348,7 @@ def test_strategy_override_use_exit_profit_only(caplog, default_conf): assert log_has("Override strategy 'exit_profit_only' with value in config file: True.", caplog) -@pytest.mark.filterwarnings("ignore:deprecated") +@ pytest.mark.filterwarnings("ignore:deprecated") def test_missing_implements(default_conf, caplog): default_location = Path(__file__).parent / "strats"