Merge pull request #7549 from froggleston/discord_sendmsg
Add support for dp.send_msg() to webhooks
This commit is contained in:
@@ -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'},
|
||||
|
@@ -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': [],
|
||||
|
||||
@@ -51,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
|
||||
|
@@ -88,10 +88,13 @@ class RPCManager:
|
||||
"""
|
||||
while queue:
|
||||
msg = queue.popleft()
|
||||
self.send_msg({
|
||||
'type': RPCMessageType.STRATEGY_MSG,
|
||||
'msg': msg,
|
||||
})
|
||||
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({
|
||||
'type': RPCMessageType.STRATEGY_MSG,
|
||||
'msg': msg,
|
||||
})
|
||||
|
||||
def startup_messages(self, config: Config, pairlist, protections) -> None:
|
||||
if config['dry_run']:
|
||||
|
@@ -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,36 +41,44 @@ 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']
|
||||
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'] in (
|
||||
RPCMessageType.PROTECTION_TRIGGER,
|
||||
RPCMessageType.PROTECTION_TRIGGER_GLOBAL,
|
||||
RPCMessageType.WHITELIST,
|
||||
RPCMessageType.ANALYZED_DF,
|
||||
RPCMessageType.STRATEGY_MSG):
|
||||
# Don't fail for non-implemented types
|
||||
return
|
||||
else:
|
||||
raise NotImplementedError('Unknown message type: {}'.format(msg['type']))
|
||||
|
||||
valuedict = self._get_value_dict(msg)
|
||||
|
||||
if not valuedict:
|
||||
logger.info("Message type '%s' not configured for webhooks", msg['type'])
|
||||
return
|
||||
|
Reference in New Issue
Block a user