From 8fcb80df69f0e898529674be4cf570b189f77a23 Mon Sep 17 00:00:00 2001 From: froggleston Date: Fri, 7 Oct 2022 16:06:30 +0100 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 8e3a4eca4198e157e794d2d2b1ef936764c9d615 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 9 Oct 2022 09:15:11 +0200 Subject: [PATCH 7/7] 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