From a237667bc98b309dcd5d2f52d65beff2f3198949 Mon Sep 17 00:00:00 2001 From: ethan Date: Fri, 12 Nov 2021 16:18:04 -0500 Subject: [PATCH 1/7] Update buy/sell fill telegram notifications --- freqtrade/rpc/telegram.py | 105 +++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index f53154dff..2a700348f 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -28,7 +28,6 @@ from freqtrade.misc import chunks, plural, round_coin_value from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException, RPCHandler - logger = logging.getLogger(__name__) logger.debug('Included module rpc.telegram ...') @@ -227,7 +226,7 @@ class Telegram(RPCHandler): ) if msg.get('buy_tag', None): content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}`\n") + content.append(f"*Amount:* `{msg['amount']:.8f} {msg['pair'].split('/')[0]}`\n") content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n") content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n") content.append( @@ -242,7 +241,66 @@ class Telegram(RPCHandler): message += ")`" return message + def _format_buy_msg_fill(self, msg: Dict[str, Any]) -> str: + if self._rpc._fiat_converter: + msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( + msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + else: + msg['stake_amount_fiat'] = 0 + + content = [] + content.append( + f"\N{CHECK MARK} *{msg['exchange']}:* Bought {msg['pair']}" + f" (#{msg['trade_id']})\n" + ) + if msg.get('buy_tag', None): + content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") + content.append(f"*Amount:* `{msg['amount']:.8f} {msg['pair'].split('/')[0]}`\n") + content.append( + f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + ) + if msg.get('fiat_currency', None): + content.append( + f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + ) + + message = ''.join(content) + message += ")`" + return message + def _format_sell_msg(self, msg: Dict[str, Any]) -> str: + msg['amount'] = round(msg['amount'], 8) + msg['duration'] = msg['close_date'].replace( + microsecond=0) - msg['open_date'].replace(microsecond=0) + msg['duration_min'] = msg['duration'].total_seconds() / 60 + msg['buy_tag'] = msg['buy_tag'] if "buy_tag" in msg.keys() else None + + # Check if all sell properties are available. + # This might not be the case if the message origin is triggered by /forcesell + if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency']) + and self._rpc._fiat_converter): + msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount( + msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) + msg['profit_extra'] = (' ({gain}: {profit_amount:.8f} {stake_currency}' + ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) + else: + msg['profit_extra'] = '' + + msg['currency'] = msg['pair'].split('/')[0] + message = ("\N{LARGE RED CIRCLE} *{exchange}:* Selling {pair} (#{trade_id})\n" + "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" + "*Buy Tag:* `{buy_tag}`\n" + "*Sell Reason:* `{sell_reason}`\n" + "*Duration:* `{duration} ({duration_min:.1f} min)`\n" + "*Amount:* `{amount:.8f}` {currency}\n" + "*Open Rate:* `{open_rate:.8f}`\n" + "*Current Rate:* `{current_rate:.8f}`\n" + "*Close Rate:* `{close_rate:.8f}`").format( + **msg) # TODO: Updated from `limit`, confirm this is correct variable? + + return message + + def _format_sell_msg_fill(self, msg: Dict[str, Any]) -> str: msg['amount'] = round(msg['amount'], 8) msg['profit_percent'] = round(msg['profit_ratio'] * 100, 2) msg['duration'] = msg['close_date'].replace( @@ -263,15 +321,17 @@ class Telegram(RPCHandler): else: msg['profit_extra'] = '' - message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n" + msg['currency'] = msg['pair'].split('/')[0] + import pprint + pprint.pprint(msg) + message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" "*Buy Tag:* `{buy_tag}`\n" "*Sell Reason:* `{sell_reason}`\n" "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}`\n" - "*Open Rate:* `{open_rate:.8f}`\n" - "*Current Rate:* `{current_rate:.8f}`\n" - "*Close Rate:* `{limit:.8f}`").format(**msg) + "*Amount:* `{amount:.8f}` {currency}\n" + "*Close Rate:* `{close_rate:.8f}`").format( + **msg) # TODO: Updated from `limit`, confirm this is correct variable to use? Limit not in dict for _fill return message @@ -287,15 +347,14 @@ class Telegram(RPCHandler): "Reason: {reason}.".format(**msg)) elif msg_type == RPCMessageType.BUY_FILL: - message = ("\N{LARGE CIRCLE} *{exchange}:* " - "Buy order for {pair} (#{trade_id}) filled " - "for {open_rate}.".format(**msg)) + message = self._format_buy_msg_fill(msg) + elif msg_type == RPCMessageType.SELL_FILL: - message = ("\N{LARGE CIRCLE} *{exchange}:* " - "Sell order for {pair} (#{trade_id}) filled " - "for {close_rate}.".format(**msg)) + message = self._format_sell_msg_fill(msg) + elif msg_type == RPCMessageType.SELL: message = self._format_sell_msg(msg) + elif msg_type == RPCMessageType.PROTECTION_TRIGGER: message = ( "*Protection* triggered due to {reason}. " @@ -357,7 +416,7 @@ class Telegram(RPCHandler): elif float(msg['profit_percent']) >= 0.0: return "\N{EIGHT SPOKED ASTERISK}" elif msg['sell_reason'] == "stop_loss": - return"\N{WARNING SIGN}" + return "\N{WARNING SIGN}" else: return "\N{CROSS MARK}" @@ -689,9 +748,9 @@ class Telegram(RPCHandler): duration_msg = tabulate( [ ['Wins', str(timedelta(seconds=durations['wins'])) - if durations['wins'] != 'N/A' else 'N/A'], + if durations['wins'] != 'N/A' else 'N/A'], ['Losses', str(timedelta(seconds=durations['losses'])) - if durations['losses'] != 'N/A' else 'N/A'] + if durations['losses'] != 'N/A' else 'N/A'] ], headers=['', 'Avg. Duration'] ) @@ -922,9 +981,9 @@ class Telegram(RPCHandler): trade_id = int(context.args[0]) msg = self._rpc._rpc_delete(trade_id) self._send_msg(( - '`{result_msg}`\n' - 'Please make sure to take care of this asset on the exchange manually.' - ).format(**msg)) + '`{result_msg}`\n' + 'Please make sure to take care of this asset on the exchange manually.' + ).format(**msg)) except RPCException as e: self._send_msg(str(e)) @@ -943,7 +1002,7 @@ class Telegram(RPCHandler): output = "Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i+1}.\t {trade['pair']}\t" + f"{i + 1}.\t {trade['pair']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit_ratio']:.2%}) " f"({trade['count']})\n") @@ -978,7 +1037,7 @@ class Telegram(RPCHandler): output = "Buy Tag Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i+1}.\t {trade['buy_tag']}\t" + f"{i + 1}.\t {trade['buy_tag']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit_ratio']:.2%}) " f"({trade['count']})\n") @@ -1013,7 +1072,7 @@ class Telegram(RPCHandler): output = "Sell Reason Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i+1}.\t {trade['sell_reason']}\t" + f"{i + 1}.\t {trade['sell_reason']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit_ratio']:.2%}) " f"({trade['count']})\n") @@ -1048,7 +1107,7 @@ class Telegram(RPCHandler): output = "Mix Tag Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i+1}.\t {trade['mix_tag']}\t" + f"{i + 1}.\t {trade['mix_tag']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit']:.2%}) " f"({trade['count']})\n") From 32e33762963c23dd170729da3bf160b743e5fd55 Mon Sep 17 00:00:00 2001 From: ethan Date: Fri, 12 Nov 2021 21:49:07 -0500 Subject: [PATCH 2/7] Update buy/sell fill telegram notifications --- freqtrade/rpc/telegram.py | 102 +++++++++++++++++---------------- tests/rpc/test_rpc_telegram.py | 61 ++++++++++++-------- 2 files changed, 90 insertions(+), 73 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 2a700348f..11574c1f7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -219,6 +219,7 @@ class Telegram(RPCHandler): else: msg['stake_amount_fiat'] = 0 + msg['currency'] = msg['pair'].split('/')[0] content = [] content.append( f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}" @@ -226,7 +227,7 @@ class Telegram(RPCHandler): ) if msg.get('buy_tag', None): content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f} {msg['pair'].split('/')[0]}`\n") + content.append(f"*Amount:* `{msg['amount']:.8f}` {msg['currency']}\n") content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n") content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n") content.append( @@ -241,13 +242,14 @@ class Telegram(RPCHandler): message += ")`" return message - def _format_buy_msg_fill(self, msg: Dict[str, Any]) -> str: + def _format_buy_fill_msg(self, msg: Dict[str, Any]) -> str: if self._rpc._fiat_converter: msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) else: msg['stake_amount_fiat'] = 0 + msg['currency'] = msg['pair'].split('/')[0] content = [] content.append( f"\N{CHECK MARK} *{msg['exchange']}:* Bought {msg['pair']}" @@ -255,7 +257,8 @@ class Telegram(RPCHandler): ) if msg.get('buy_tag', None): content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f} {msg['pair'].split('/')[0]}`\n") + content.append(f"*Amount:* `{msg['amount']:.8f}` {msg['currency']}\n") + content.append(f"*Open Rate:* `{msg['open_rate']:.8f}`\n") content.append( f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" ) @@ -269,38 +272,6 @@ class Telegram(RPCHandler): return message def _format_sell_msg(self, msg: Dict[str, Any]) -> str: - msg['amount'] = round(msg['amount'], 8) - msg['duration'] = msg['close_date'].replace( - microsecond=0) - msg['open_date'].replace(microsecond=0) - msg['duration_min'] = msg['duration'].total_seconds() / 60 - msg['buy_tag'] = msg['buy_tag'] if "buy_tag" in msg.keys() else None - - # Check if all sell properties are available. - # This might not be the case if the message origin is triggered by /forcesell - if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency']) - and self._rpc._fiat_converter): - msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount( - msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) - msg['profit_extra'] = (' ({gain}: {profit_amount:.8f} {stake_currency}' - ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) - else: - msg['profit_extra'] = '' - - msg['currency'] = msg['pair'].split('/')[0] - message = ("\N{LARGE RED CIRCLE} *{exchange}:* Selling {pair} (#{trade_id})\n" - "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" - "*Buy Tag:* `{buy_tag}`\n" - "*Sell Reason:* `{sell_reason}`\n" - "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}` {currency}\n" - "*Open Rate:* `{open_rate:.8f}`\n" - "*Current Rate:* `{current_rate:.8f}`\n" - "*Close Rate:* `{close_rate:.8f}`").format( - **msg) # TODO: Updated from `limit`, confirm this is correct variable? - - return message - - def _format_sell_msg_fill(self, msg: Dict[str, Any]) -> str: msg['amount'] = round(msg['amount'], 8) msg['profit_percent'] = round(msg['profit_ratio'] * 100, 2) msg['duration'] = msg['close_date'].replace( @@ -320,18 +291,49 @@ class Telegram(RPCHandler): ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) else: msg['profit_extra'] = '' - msg['currency'] = msg['pair'].split('/')[0] + message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n" + "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" + "*Buy Tag:* `{buy_tag}`\n" + "*Sell Reason:* `{sell_reason}`\n" + "*Duration:* `{duration} ({duration_min:.1f} min)`\n" + "*Amount:* `{amount:.8f}` {currency}\n" + "*Open Rate:* `{open_rate:.8f}`\n" + "*Current Rate:* `{current_rate:.8f}`\n" + "*Close Rate:* `{limit:.8f}`").format(**msg) + + return message + + def _format_sell_fill_msg(self, msg: Dict[str, Any]) -> str: import pprint pprint.pprint(msg) + msg['amount'] = round(msg['amount'], 8) + msg['profit_percent'] = round(msg['profit_ratio'] * 100, 2) + msg['duration'] = msg['close_date'].replace( + microsecond=0) - msg['open_date'].replace(microsecond=0) + msg['duration_min'] = msg['duration'].total_seconds() / 60 + + msg['buy_tag'] = msg['buy_tag'] if "buy_tag" in msg.keys() else None + msg['emoji'] = self._get_sell_emoji(msg) + + # Check if all sell properties are available. + # This might not be the case if the message origin is triggered by /forcesell + if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency']) + and self._rpc._fiat_converter): + msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount( + msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) + msg['profit_extra'] = (' ({gain}: {profit_amount:.8f} {stake_currency}' + ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) + else: + msg['profit_extra'] = '' + msg['currency'] = msg['pair'].split('/')[0] message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" "*Buy Tag:* `{buy_tag}`\n" "*Sell Reason:* `{sell_reason}`\n" "*Duration:* `{duration} ({duration_min:.1f} min)`\n" "*Amount:* `{amount:.8f}` {currency}\n" - "*Close Rate:* `{close_rate:.8f}`").format( - **msg) # TODO: Updated from `limit`, confirm this is correct variable to use? Limit not in dict for _fill + "*Close Rate:* `{close_rate:.8f}`").format(**msg) return message @@ -347,10 +349,10 @@ class Telegram(RPCHandler): "Reason: {reason}.".format(**msg)) elif msg_type == RPCMessageType.BUY_FILL: - message = self._format_buy_msg_fill(msg) + message = self._format_buy_fill_msg(msg) elif msg_type == RPCMessageType.SELL_FILL: - message = self._format_sell_msg_fill(msg) + message = self._format_sell_fill_msg(msg) elif msg_type == RPCMessageType.SELL: message = self._format_sell_msg(msg) @@ -360,11 +362,13 @@ class Telegram(RPCHandler): "*Protection* triggered due to {reason}. " "`{pair}` will be locked until `{lock_end_time}`." ).format(**msg) + elif msg_type == RPCMessageType.PROTECTION_TRIGGER_GLOBAL: message = ( "*Protection* triggered due to {reason}. " "*All pairs* will be locked until `{lock_end_time}`." ).format(**msg) + elif msg_type == RPCMessageType.STATUS: message = '*Status:* `{status}`'.format(**msg) @@ -748,9 +752,9 @@ class Telegram(RPCHandler): duration_msg = tabulate( [ ['Wins', str(timedelta(seconds=durations['wins'])) - if durations['wins'] != 'N/A' else 'N/A'], + if durations['wins'] != 'N/A' else 'N/A'], ['Losses', str(timedelta(seconds=durations['losses'])) - if durations['losses'] != 'N/A' else 'N/A'] + if durations['losses'] != 'N/A' else 'N/A'] ], headers=['', 'Avg. Duration'] ) @@ -981,9 +985,9 @@ class Telegram(RPCHandler): trade_id = int(context.args[0]) msg = self._rpc._rpc_delete(trade_id) self._send_msg(( - '`{result_msg}`\n' - 'Please make sure to take care of this asset on the exchange manually.' - ).format(**msg)) + '`{result_msg}`\n' + 'Please make sure to take care of this asset on the exchange manually.' + ).format(**msg)) except RPCException as e: self._send_msg(str(e)) @@ -1002,7 +1006,7 @@ class Telegram(RPCHandler): output = "Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i + 1}.\t {trade['pair']}\t" + f"{i+1}.\t {trade['pair']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit_ratio']:.2%}) " f"({trade['count']})\n") @@ -1037,7 +1041,7 @@ class Telegram(RPCHandler): output = "Buy Tag Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i + 1}.\t {trade['buy_tag']}\t" + f"{i+1}.\t {trade['buy_tag']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit_ratio']:.2%}) " f"({trade['count']})\n") @@ -1072,7 +1076,7 @@ class Telegram(RPCHandler): output = "Sell Reason Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i + 1}.\t {trade['sell_reason']}\t" + f"{i+1}.\t {trade['sell_reason']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit_ratio']:.2%}) " f"({trade['count']})\n") @@ -1107,7 +1111,7 @@ class Telegram(RPCHandler): output = "Mix Tag Performance:\n" for i, trade in enumerate(trades): stat_line = ( - f"{i + 1}.\t {trade['mix_tag']}\t" + f"{i+1}.\t {trade['mix_tag']}\t" f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} " f"({trade['profit']:.2%}) " f"({trade['count']})\n") diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 68f7457d5..0b4ff968b 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1613,7 +1613,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None: assert msg_mock.call_args[0][0] \ == '\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n' \ '*Buy Tag:* `buy_signal_01`\n' \ - '*Amount:* `1333.33333333`\n' \ + '*Amount:* `1333.33333333` ETH\n' \ '*Open Rate:* `0.00001099`\n' \ '*Current Rate:* `0.00001099`\n' \ '*Total:* `(0.00100000 BTC, 12.345 USD)`' @@ -1686,17 +1686,25 @@ def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: telegram.send_msg({ 'type': RPCMessageType.BUY_FILL, - 'buy_tag': 'buy_signal_01', 'trade_id': 1, + 'buy_tag': 'buy_signal_01', 'exchange': 'Binance', - 'pair': 'ETH/USDT', - 'open_rate': 200, - 'stake_amount': 100, - 'amount': 0.5, - 'open_date': arrow.utcnow().datetime + 'pair': 'ETH/BTC', + 'stake_amount': 0.001, + # 'stake_amount_fiat': 0.0, + 'stake_currency': 'BTC', + 'fiat_currency': 'USD', + 'open_rate': 1.099e-05, + 'amount': 1333.3333333333335, + 'open_date': arrow.utcnow().shift(hours=-1) }) - assert (msg_mock.call_args[0][0] == '\N{LARGE CIRCLE} *Binance:* ' - 'Buy order for ETH/USDT (#1) filled for 200.') + + assert msg_mock.call_args[0][0] \ + == '\N{CHECK MARK} *Binance:* Bought ETH/BTC (#1)\n' \ + '*Buy Tag:* `buy_signal_01`\n' \ + '*Amount:* `1333.33333333` ETH\n' \ + '*Open Rate:* `0.00001099`\n' \ + '*Total:* `(0.00100000 BTC, 12.345 USD)`' def test_send_msg_sell_notification(default_conf, mocker) -> None: @@ -1727,11 +1735,11 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n' - '*Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n' + '*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n' '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `1:00:00 (60.0 min)`\n' - '*Amount:* `1333.33333333`\n' + '*Amount:* `1333.33333333` KEY\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' '*Close Rate:* `0.00003201`' @@ -1759,11 +1767,11 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n' - '*Profit:* `-57.41%`\n' + '*Unrealized Profit:* `-57.41%`\n' '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `1 day, 2:30:00 (1590.0 min)`\n' - '*Amount:* `1333.33333333`\n' + '*Amount:* `1333.33333333` KEY\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' '*Close Rate:* `0.00003201`' @@ -1813,25 +1821,30 @@ def test_send_msg_sell_fill_notification(default_conf, mocker) -> None: 'type': RPCMessageType.SELL_FILL, 'trade_id': 1, 'exchange': 'Binance', - 'pair': 'ETH/USDT', + 'pair': 'KEY/ETH', 'gain': 'loss', 'limit': 3.201e-05, - 'amount': 0.1, + 'amount': 1333.3333333333335, 'order_type': 'market', - 'open_rate': 500, - 'close_rate': 550, - 'current_rate': 3.201e-05, + 'open_rate': 7.5e-05, + 'close_rate': 3.201e-05, 'profit_amount': -0.05746268, 'profit_ratio': -0.57405275, 'stake_currency': 'ETH', - 'fiat_currency': 'USD', 'buy_tag': 'buy_signal1', 'sell_reason': SellType.STOP_LOSS.value, - 'open_date': arrow.utcnow().shift(hours=-1), + 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'close_date': arrow.utcnow(), }) assert msg_mock.call_args[0][0] \ - == ('\N{LARGE CIRCLE} *Binance:* Sell order for ETH/USDT (#1) filled for 550.') + == ('\N{WARNING SIGN} *Binance:* Sold KEY/ETH (#1)\n' + '*Profit:* `-57.41%`\n' + '*Buy Tag:* `buy_signal1`\n' + '*Sell Reason:* `stop_loss`\n' + '*Duration:* `1 day, 2:30:00 (1590.0 min)`\n' + '*Amount:* `1333.33333333` KEY\n' + '*Close Rate:* `0.00003201`' + ) def test_send_msg_status_notification(default_conf, mocker) -> None: @@ -1892,7 +1905,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] == ('\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n' '*Buy Tag:* `buy_signal_01`\n' - '*Amount:* `1333.33333333`\n' + '*Amount:* `1333.33333333` ETH\n' '*Open Rate:* `0.00001099`\n' '*Current Rate:* `0.00001099`\n' '*Total:* `(0.00100000 BTC)`') @@ -1923,11 +1936,11 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: 'close_date': arrow.utcnow(), }) assert msg_mock.call_args[0][0] == ('\N{WARNING SIGN} *Binance:* Selling KEY/ETH (#1)\n' - '*Profit:* `-57.41%`\n' + '*Unrealized Profit:* `-57.41%`\n' '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `2:35:03 (155.1 min)`\n' - '*Amount:* `1333.33333333`\n' + '*Amount:* `1333.33333333` KEY\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' '*Close Rate:* `0.00003201`' From a177e58dc4d7b64d082136ae27233fb778318646 Mon Sep 17 00:00:00 2001 From: ethan Date: Sat, 13 Nov 2021 08:49:02 -0500 Subject: [PATCH 3/7] Remove "currency" generating from splitting pair str --- freqtrade/rpc/telegram.py | 14 ++++++-------- tests/rpc/test_rpc_telegram.py | 14 +++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 11574c1f7..7bb5b71f9 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -219,7 +219,6 @@ class Telegram(RPCHandler): else: msg['stake_amount_fiat'] = 0 - msg['currency'] = msg['pair'].split('/')[0] content = [] content.append( f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}" @@ -227,7 +226,7 @@ class Telegram(RPCHandler): ) if msg.get('buy_tag', None): content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}` {msg['currency']}\n") + content.append(f"*Amount:* `{msg['amount']:.8f}`\n") content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n") content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n") content.append( @@ -249,7 +248,6 @@ class Telegram(RPCHandler): else: msg['stake_amount_fiat'] = 0 - msg['currency'] = msg['pair'].split('/')[0] content = [] content.append( f"\N{CHECK MARK} *{msg['exchange']}:* Bought {msg['pair']}" @@ -257,7 +255,7 @@ class Telegram(RPCHandler): ) if msg.get('buy_tag', None): content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}` {msg['currency']}\n") + content.append(f"*Amount:* `{msg['amount']:.8f}`\n") content.append(f"*Open Rate:* `{msg['open_rate']:.8f}`\n") content.append( f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" @@ -291,13 +289,13 @@ class Telegram(RPCHandler): ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) else: msg['profit_extra'] = '' - msg['currency'] = msg['pair'].split('/')[0] + message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n" "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" "*Buy Tag:* `{buy_tag}`\n" "*Sell Reason:* `{sell_reason}`\n" "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}` {currency}\n" + "*Amount:* `{amount:.8f}`\n" "*Open Rate:* `{open_rate:.8f}`\n" "*Current Rate:* `{current_rate:.8f}`\n" "*Close Rate:* `{limit:.8f}`").format(**msg) @@ -326,13 +324,13 @@ class Telegram(RPCHandler): ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) else: msg['profit_extra'] = '' - msg['currency'] = msg['pair'].split('/')[0] + message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" "*Buy Tag:* `{buy_tag}`\n" "*Sell Reason:* `{sell_reason}`\n" "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}` {currency}\n" + "*Amount:* `{amount:.8f}`\n" "*Close Rate:* `{close_rate:.8f}`").format(**msg) return message diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 0b4ff968b..95a2f4549 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1613,7 +1613,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None: assert msg_mock.call_args[0][0] \ == '\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n' \ '*Buy Tag:* `buy_signal_01`\n' \ - '*Amount:* `1333.33333333` ETH\n' \ + '*Amount:* `1333.33333333`\n' \ '*Open Rate:* `0.00001099`\n' \ '*Current Rate:* `0.00001099`\n' \ '*Total:* `(0.00100000 BTC, 12.345 USD)`' @@ -1702,7 +1702,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: assert msg_mock.call_args[0][0] \ == '\N{CHECK MARK} *Binance:* Bought ETH/BTC (#1)\n' \ '*Buy Tag:* `buy_signal_01`\n' \ - '*Amount:* `1333.33333333` ETH\n' \ + '*Amount:* `1333.33333333`\n' \ '*Open Rate:* `0.00001099`\n' \ '*Total:* `(0.00100000 BTC, 12.345 USD)`' @@ -1739,7 +1739,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `1:00:00 (60.0 min)`\n' - '*Amount:* `1333.33333333` KEY\n' + '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' '*Close Rate:* `0.00003201`' @@ -1771,7 +1771,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `1 day, 2:30:00 (1590.0 min)`\n' - '*Amount:* `1333.33333333` KEY\n' + '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' '*Close Rate:* `0.00003201`' @@ -1842,7 +1842,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker) -> None: '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `1 day, 2:30:00 (1590.0 min)`\n' - '*Amount:* `1333.33333333` KEY\n' + '*Amount:* `1333.33333333`\n' '*Close Rate:* `0.00003201`' ) @@ -1905,7 +1905,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] == ('\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n' '*Buy Tag:* `buy_signal_01`\n' - '*Amount:* `1333.33333333` ETH\n' + '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00001099`\n' '*Current Rate:* `0.00001099`\n' '*Total:* `(0.00100000 BTC)`') @@ -1940,7 +1940,7 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: '*Buy Tag:* `buy_signal1`\n' '*Sell Reason:* `stop_loss`\n' '*Duration:* `2:35:03 (155.1 min)`\n' - '*Amount:* `1333.33333333` KEY\n' + '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' '*Close Rate:* `0.00003201`' From 7412b7ba5185b9a65963140209f142462e6ed6ca Mon Sep 17 00:00:00 2001 From: ethan Date: Sat, 13 Nov 2021 10:23:47 -0500 Subject: [PATCH 4/7] buy/sell fill notification code consolidation --- freqtrade/rpc/telegram.py | 150 +++++++++++++++----------------------- 1 file changed, 58 insertions(+), 92 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 7bb5b71f9..63174024e 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -220,53 +220,48 @@ class Telegram(RPCHandler): msg['stake_amount_fiat'] = 0 content = [] - content.append( - f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}" - f" (#{msg['trade_id']})\n" - ) - if msg.get('buy_tag', None): - content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}`\n") - content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n") - content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n") - content.append( - f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" - ) - if msg.get('fiat_currency', None): + # Buy Order Fill + if msg['type'] == RPCMessageType.BUY_FILL: content.append( - f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + f"\N{CHECK MARK} *{msg['exchange']}:* Bought {msg['pair']}" + f" (#{msg['trade_id']})\n" ) + if msg.get('buy_tag', None): + content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") + content.append(f"*Amount:* `{msg['amount']:.8f}`\n") + content.append(f"*Open Rate:* `{msg['open_rate']:.8f}`\n") + content.append( + f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + ) + if msg.get('fiat_currency', None): + content.append( + f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + ) - message = ''.join(content) - message += ")`" - return message - - def _format_buy_fill_msg(self, msg: Dict[str, Any]) -> str: - if self._rpc._fiat_converter: - msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( - msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + message = ''.join(content) + message += ")`" + # Buy Order Ask else: - msg['stake_amount_fiat'] = 0 - - content = [] - content.append( - f"\N{CHECK MARK} *{msg['exchange']}:* Bought {msg['pair']}" - f" (#{msg['trade_id']})\n" - ) - if msg.get('buy_tag', None): - content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}`\n") - content.append(f"*Open Rate:* `{msg['open_rate']:.8f}`\n") - content.append( - f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" - ) - if msg.get('fiat_currency', None): content.append( - f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}" + f" (#{msg['trade_id']})\n" ) + if msg.get('buy_tag', None): + content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") + content.append(f"*Amount:* `{msg['amount']:.8f}`\n") + content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n") + content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n") + content.append( + f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + ) + if msg.get('fiat_currency', None): + content.append( + f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + ) + + message = ''.join(content) + message += ")`" - message = ''.join(content) - message += ")`" return message def _format_sell_msg(self, msg: Dict[str, Any]) -> str: @@ -290,71 +285,42 @@ class Telegram(RPCHandler): else: msg['profit_extra'] = '' - message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n" - "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" - "*Buy Tag:* `{buy_tag}`\n" - "*Sell Reason:* `{sell_reason}`\n" - "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}`\n" - "*Open Rate:* `{open_rate:.8f}`\n" - "*Current Rate:* `{current_rate:.8f}`\n" - "*Close Rate:* `{limit:.8f}`").format(**msg) + # Sell Order Fill + if msg['type'] == RPCMessageType.SELL_FILL: + message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" + "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" + "*Buy Tag:* `{buy_tag}`\n" + "*Sell Reason:* `{sell_reason}`\n" + "*Duration:* `{duration} ({duration_min:.1f} min)`\n" + "*Amount:* `{amount:.8f}`\n" + "*Close Rate:* `{close_rate:.8f}`").format(**msg) - return message - - def _format_sell_fill_msg(self, msg: Dict[str, Any]) -> str: - import pprint - pprint.pprint(msg) - msg['amount'] = round(msg['amount'], 8) - msg['profit_percent'] = round(msg['profit_ratio'] * 100, 2) - msg['duration'] = msg['close_date'].replace( - microsecond=0) - msg['open_date'].replace(microsecond=0) - msg['duration_min'] = msg['duration'].total_seconds() / 60 - - msg['buy_tag'] = msg['buy_tag'] if "buy_tag" in msg.keys() else None - msg['emoji'] = self._get_sell_emoji(msg) - - # Check if all sell properties are available. - # This might not be the case if the message origin is triggered by /forcesell - if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency']) - and self._rpc._fiat_converter): - msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount( - msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) - msg['profit_extra'] = (' ({gain}: {profit_amount:.8f} {stake_currency}' - ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) + # Sell Order Ask else: - msg['profit_extra'] = '' - - message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" - "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" - "*Buy Tag:* `{buy_tag}`\n" - "*Sell Reason:* `{sell_reason}`\n" - "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}`\n" - "*Close Rate:* `{close_rate:.8f}`").format(**msg) - + message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n" + "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" + "*Buy Tag:* `{buy_tag}`\n" + "*Sell Reason:* `{sell_reason}`\n" + "*Duration:* `{duration} ({duration_min:.1f} min)`\n" + "*Amount:* `{amount:.8f}`\n" + "*Open Rate:* `{open_rate:.8f}`\n" + "*Current Rate:* `{current_rate:.8f}`\n" + "*Close Rate:* `{limit:.8f}`").format(**msg) return message def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: - - if msg_type == RPCMessageType.BUY: + if msg_type in [RPCMessageType.BUY, RPCMessageType.BUY_FILL]: message = self._format_buy_msg(msg) + elif msg_type in [RPCMessageType.SELL, RPCMessageType.SELL_FILL]: + message = self._format_sell_msg(msg) + elif msg_type in (RPCMessageType.BUY_CANCEL, RPCMessageType.SELL_CANCEL): msg['message_side'] = 'buy' if msg_type == RPCMessageType.BUY_CANCEL else 'sell' message = ("\N{WARNING SIGN} *{exchange}:* " "Cancelling open {message_side} Order for {pair} (#{trade_id}). " "Reason: {reason}.".format(**msg)) - elif msg_type == RPCMessageType.BUY_FILL: - message = self._format_buy_fill_msg(msg) - - elif msg_type == RPCMessageType.SELL_FILL: - message = self._format_sell_fill_msg(msg) - - elif msg_type == RPCMessageType.SELL: - message = self._format_sell_msg(msg) - elif msg_type == RPCMessageType.PROTECTION_TRIGGER: message = ( "*Protection* triggered due to {reason}. " From 0bc9384451c22c70f3ad805b3701dec1d217838b Mon Sep 17 00:00:00 2001 From: ethan Date: Sat, 13 Nov 2021 14:52:59 -0500 Subject: [PATCH 5/7] more notification code consolidation --- freqtrade/rpc/telegram.py | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 63174024e..36bbf1a64 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -285,27 +285,22 @@ class Telegram(RPCHandler): else: msg['profit_extra'] = '' - # Sell Order Fill - if msg['type'] == RPCMessageType.SELL_FILL: - message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" - "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" - "*Buy Tag:* `{buy_tag}`\n" - "*Sell Reason:* `{sell_reason}`\n" - "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}`\n" - "*Close Rate:* `{close_rate:.8f}`").format(**msg) + message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" + "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" + "*Buy Tag:* `{buy_tag}`\n" + "*Sell Reason:* `{sell_reason}`\n" + "*Duration:* `{duration} ({duration_min:.1f} min)`\n" + "*Amount:* `{amount:.8f}`\n").format(**msg) + + if msg['type'] == RPCMessageType.SELL: + message = message.replace('Sold', 'Selling').replace('Profit', 'Unrealized Profit') + message += ("*Open Rate:* `{open_rate:.8f}`\n" + "*Current Rate:* `{current_rate:.8f}`\n" + "*Close Rate:* `{limit:.8f}`").format(**msg) + + elif msg['type'] == RPCMessageType.SELL_FILL: + message += ("*Close Rate:* `{close_rate:.8f}`").format(**msg) - # Sell Order Ask - else: - message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n" - "*Unrealized Profit:* `{profit_ratio:.2%}{profit_extra}`\n" - "*Buy Tag:* `{buy_tag}`\n" - "*Sell Reason:* `{sell_reason}`\n" - "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}`\n" - "*Open Rate:* `{open_rate:.8f}`\n" - "*Current Rate:* `{current_rate:.8f}`\n" - "*Close Rate:* `{limit:.8f}`").format(**msg) return message def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: From c4c1b301cde2418026b4b69aa2be54b58ddc9ba5 Mon Sep 17 00:00:00 2001 From: ethan Date: Sat, 13 Nov 2021 15:46:00 -0500 Subject: [PATCH 6/7] buy notification code consolidation --- freqtrade/rpc/telegram.py | 54 +++++++++++---------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 36bbf1a64..c678309aa 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -219,49 +219,25 @@ class Telegram(RPCHandler): else: msg['stake_amount_fiat'] = 0 - content = [] - # Buy Order Fill + message = "\N{CHECK MARK} *{exchange}:* Bought {pair} (#{trade_id})\n".format(**msg) + message += "*Buy Tag:* `{buy_tag}`\n".format(**msg) if msg.get('buy_tag', None) else "" + message += "*Amount:* `{amount:.8f}`\n".format(**msg) + if msg['type'] == RPCMessageType.BUY_FILL: - content.append( - f"\N{CHECK MARK} *{msg['exchange']}:* Bought {msg['pair']}" - f" (#{msg['trade_id']})\n" - ) - if msg.get('buy_tag', None): - content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}`\n") - content.append(f"*Open Rate:* `{msg['open_rate']:.8f}`\n") - content.append( - f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" - ) - if msg.get('fiat_currency', None): - content.append( - f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" - ) + message += f"*Open Rate:* `{msg['open_rate']:.8f}`\n" - message = ''.join(content) - message += ")`" - # Buy Order Ask - else: - content.append( - f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}" - f" (#{msg['trade_id']})\n" - ) - if msg.get('buy_tag', None): - content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n") - content.append(f"*Amount:* `{msg['amount']:.8f}`\n") - content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n") - content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n") - content.append( - f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" - ) - if msg.get('fiat_currency', None): - content.append( - f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" - ) + elif msg['type'] == RPCMessageType.BUY: + message = message.replace('Bought', 'Buying')\ + .replace("\N{CHECK MARK}", "\N{LARGE BLUE CIRCLE}") + message += f"*Open Rate:* `{msg['limit']:.8f}`\n"\ + f"*Current Rate:* `{msg['current_rate']:.8f}`\n" - message = ''.join(content) - message += ")`" + message += f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" + if msg.get('fiat_currency', None): + message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" + + message += ")`" return message def _format_sell_msg(self, msg: Dict[str, Any]) -> str: From 7c1161992467cf319543cbc6095b7e2decc970fd Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Nov 2021 09:19:21 +0100 Subject: [PATCH 7/7] avoid using replace in messages --- freqtrade/rpc/telegram.py | 45 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index c678309aa..e9c2c23a1 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -28,6 +28,7 @@ from freqtrade.misc import chunks, plural, round_coin_value from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException, RPCHandler + logger = logging.getLogger(__name__) logger.debug('Included module rpc.telegram ...') @@ -218,17 +219,20 @@ class Telegram(RPCHandler): msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) else: msg['stake_amount_fiat'] = 0 + is_fill = msg['type'] == RPCMessageType.BUY_FILL + emoji = '\N{CHECK MARK}' if is_fill else '\N{LARGE BLUE CIRCLE}' - message = "\N{CHECK MARK} *{exchange}:* Bought {pair} (#{trade_id})\n".format(**msg) - message += "*Buy Tag:* `{buy_tag}`\n".format(**msg) if msg.get('buy_tag', None) else "" - message += "*Amount:* `{amount:.8f}`\n".format(**msg) + message = ( + f"{emoji} *{msg['exchange']}:* {'Bought' if is_fill else 'Buying'} {msg['pair']}" + f" (#{msg['trade_id']})\n" + ) + message += f"*Buy Tag:* `{msg['buy_tag']}`\n" if msg.get('buy_tag', None) else "" + message += f"*Amount:* `{msg['amount']:.8f}`\n" if msg['type'] == RPCMessageType.BUY_FILL: message += f"*Open Rate:* `{msg['open_rate']:.8f}`\n" elif msg['type'] == RPCMessageType.BUY: - message = message.replace('Bought', 'Buying')\ - .replace("\N{CHECK MARK}", "\N{LARGE BLUE CIRCLE}") message += f"*Open Rate:* `{msg['limit']:.8f}`\n"\ f"*Current Rate:* `{msg['current_rate']:.8f}`\n" @@ -256,26 +260,29 @@ class Telegram(RPCHandler): and self._rpc._fiat_converter): msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount( msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) - msg['profit_extra'] = (' ({gain}: {profit_amount:.8f} {stake_currency}' - ' / {profit_fiat:.3f} {fiat_currency})').format(**msg) + msg['profit_extra'] = ( + f" ({msg['gain']}: {msg['profit_amount']:.8f} {msg['stake_currency']}" + f" / {msg['profit_fiat']:.3f} {msg['fiat_currency']})") else: msg['profit_extra'] = '' - - message = ("{emoji} *{exchange}:* Sold {pair} (#{trade_id})\n" - "*Profit:* `{profit_ratio:.2%}{profit_extra}`\n" - "*Buy Tag:* `{buy_tag}`\n" - "*Sell Reason:* `{sell_reason}`\n" - "*Duration:* `{duration} ({duration_min:.1f} min)`\n" - "*Amount:* `{amount:.8f}`\n").format(**msg) + is_fill = msg['type'] == RPCMessageType.SELL_FILL + message = ( + f"{msg['emoji']} *{msg['exchange']}:* " + f"{'Sold' if is_fill else 'Selling'} {msg['pair']} (#{msg['trade_id']})\n" + f"*{'Profit' if is_fill else 'Unrealized Profit'}:* " + f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" + f"*Buy Tag:* `{msg['buy_tag']}`\n" + f"*Sell Reason:* `{msg['sell_reason']}`\n" + f"*Duration:* `{msg['duration']} ({msg['duration_min']:.1f} min)`\n" + f"*Amount:* `{msg['amount']:.8f}`\n") if msg['type'] == RPCMessageType.SELL: - message = message.replace('Sold', 'Selling').replace('Profit', 'Unrealized Profit') - message += ("*Open Rate:* `{open_rate:.8f}`\n" - "*Current Rate:* `{current_rate:.8f}`\n" - "*Close Rate:* `{limit:.8f}`").format(**msg) + message += (f"*Open Rate:* `{msg['open_rate']:.8f}`\n" + f"*Current Rate:* `{msg['current_rate']:.8f}`\n" + f"*Close Rate:* `{msg['limit']:.8f}`") elif msg['type'] == RPCMessageType.SELL_FILL: - message += ("*Close Rate:* `{close_rate:.8f}`").format(**msg) + message += f"*Close Rate:* `{msg['close_rate']:.8f}`" return message