From cfaf13c90ff1a7baf7fc0dbaab97ea8c67815a0d Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sun, 6 Feb 2022 02:21:16 +0000 Subject: [PATCH 1/7] update --- freqtrade/rpc/telegram.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 8b33e8dfa..9079e1361 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -435,6 +435,7 @@ class Telegram(RPCHandler): results = self._rpc._rpc_trade_status(trade_ids=trade_ids) position_adjust = self._config.get('position_adjustment_enable', False) + max_entries = self._config.get('max_entry_position_adjustment', -1) messages = [] for r in results: r['open_date_hum'] = arrow.get(r['open_date']).humanize() From c4a54cc9cd01803b3fde8120711657a4e42fcecb Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sun, 6 Feb 2022 02:31:14 +0000 Subject: [PATCH 2/7] refinement of status --- freqtrade/rpc/telegram.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 9079e1361..7500c0568 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -450,7 +450,10 @@ class Telegram(RPCHandler): ] if position_adjust: - lines.append("*Number of Buy(s):* `{num_entries}`") + max_buy_str = '' + if max_entries > 0: + max_buy_str = f"/{max_entries + 1}" + lines.append("*Number of Buy(s):* `{num_entries}`" + max_buy_str) lines.extend([ "*Open Rate:* `{open_rate:.8f}`", From 0477070faa3de8ba0aff9a2a86cc2c65a7118fbc Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sun, 6 Feb 2022 02:49:02 +0000 Subject: [PATCH 3/7] hide some lines if trade is closed --- freqtrade/rpc/telegram.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 7500c0568..06da7862e 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -442,7 +442,7 @@ class Telegram(RPCHandler): r['num_entries'] = len(r['filled_entry_orders']) r['sell_reason'] = r.get('sell_reason', "") lines = [ - "*Trade ID:* `{trade_id}` `(since {open_date_hum})`", + "*Trade ID:* `{trade_id}`" + ("` (since {open_date_hum})`" if r['is_open'] else ""), "*Current Pair:* {pair}", "*Amount:* `{amount} ({stake_amount} {base_currency})`", "*Buy Tag:* `{buy_tag}`" if r['buy_tag'] else "", @@ -460,27 +460,28 @@ class Telegram(RPCHandler): "*Close Rate:* `{close_rate:.8f}`" if r['close_rate'] else "", "*Open Date:* `{open_date}`", "*Close Date:* `{close_date}`" if r['close_date'] else "", - "*Current Rate:* `{current_rate:.8f}`", + "*Current Rate:* `{current_rate:.8f}`" if r['is_open'] else "", ("*Current Profit:* " if r['is_open'] else "*Close Profit: *") + "`{profit_ratio:.2%}`", ]) - if (r['stop_loss_abs'] != r['initial_stop_loss_abs'] - and r['initial_stop_loss_ratio'] is not None): - # Adding initial stoploss only if it is different from stoploss - lines.append("*Initial Stoploss:* `{initial_stop_loss_abs:.8f}` " - "`({initial_stop_loss_ratio:.2%})`") + if r['is_open']: + if (r['stop_loss_abs'] != r['initial_stop_loss_abs'] + and r['initial_stop_loss_ratio'] is not None): + # Adding initial stoploss only if it is different from stoploss + lines.append("*Initial Stoploss:* `{initial_stop_loss_abs:.8f}` " + "`({initial_stop_loss_ratio:.2%})`") - # Adding stoploss and stoploss percentage only if it is not None - lines.append("*Stoploss:* `{stop_loss_abs:.8f}` " + - ("`({stop_loss_ratio:.2%})`" if r['stop_loss_ratio'] else "")) - lines.append("*Stoploss distance:* `{stoploss_current_dist:.8f}` " - "`({stoploss_current_dist_ratio:.2%})`") - if r['open_order']: - if r['sell_order_status']: - lines.append("*Open Order:* `{open_order}` - `{sell_order_status}`") - else: - lines.append("*Open Order:* `{open_order}`") + # Adding stoploss and stoploss percentage only if it is not None + lines.append("*Stoploss:* `{stop_loss_abs:.8f}` " + + ("`({stop_loss_ratio:.2%})`" if r['stop_loss_ratio'] else "")) + lines.append("*Stoploss distance:* `{stoploss_current_dist:.8f}` " + "`({stoploss_current_dist_ratio:.2%})`") + if r['open_order']: + if r['sell_order_status']: + lines.append("*Open Order:* `{open_order}` - `{sell_order_status}`") + else: + lines.append("*Open Order:* `{open_order}`") if len(r['filled_entry_orders']) > 1: lines_detail = self._prepare_buy_details( From 131b2d68d8f6b071dd3ab412627c6199cbc110a0 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sun, 6 Feb 2022 03:04:23 +0000 Subject: [PATCH 4/7] reduce complexity (flake8) --- freqtrade/rpc/telegram.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 06da7862e..5da98f21b 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -450,9 +450,7 @@ class Telegram(RPCHandler): ] if position_adjust: - max_buy_str = '' - if max_entries > 0: - max_buy_str = f"/{max_entries + 1}" + max_buy_str = (f"/{max_entries + 1}" if (max_entries > 0) else "") lines.append("*Number of Buy(s):* `{num_entries}`" + max_buy_str) lines.extend([ From 4cf514e293984b0a6596352d9c84f1ceca0dd6d0 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sun, 6 Feb 2022 03:16:56 +0000 Subject: [PATCH 5/7] fix flake8 --- freqtrade/rpc/telegram.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 5da98f21b..e3916a7c7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -442,7 +442,8 @@ class Telegram(RPCHandler): r['num_entries'] = len(r['filled_entry_orders']) r['sell_reason'] = r.get('sell_reason', "") lines = [ - "*Trade ID:* `{trade_id}`" + ("` (since {open_date_hum})`" if r['is_open'] else ""), + "*Trade ID:* `{trade_id}`" + + ("` (since {open_date_hum})`" if r['is_open'] else ""), "*Current Pair:* {pair}", "*Amount:* `{amount} ({stake_amount} {base_currency})`", "*Buy Tag:* `{buy_tag}`" if r['buy_tag'] else "", @@ -468,23 +469,22 @@ class Telegram(RPCHandler): and r['initial_stop_loss_ratio'] is not None): # Adding initial stoploss only if it is different from stoploss lines.append("*Initial Stoploss:* `{initial_stop_loss_abs:.8f}` " - "`({initial_stop_loss_ratio:.2%})`") + "`({initial_stop_loss_ratio:.2%})`") # Adding stoploss and stoploss percentage only if it is not None lines.append("*Stoploss:* `{stop_loss_abs:.8f}` " + - ("`({stop_loss_ratio:.2%})`" if r['stop_loss_ratio'] else "")) + ("`({stop_loss_ratio:.2%})`" if r['stop_loss_ratio'] else "")) lines.append("*Stoploss distance:* `{stoploss_current_dist:.8f}` " - "`({stoploss_current_dist_ratio:.2%})`") + "`({stoploss_current_dist_ratio:.2%})`") if r['open_order']: if r['sell_order_status']: lines.append("*Open Order:* `{open_order}` - `{sell_order_status}`") else: lines.append("*Open Order:* `{open_order}`") - if len(r['filled_entry_orders']) > 1: - lines_detail = self._prepare_buy_details( - r['filled_entry_orders'], r['base_currency']) - lines.extend(lines_detail) + lines_detail = self._prepare_buy_details( + r['filled_entry_orders'], r['base_currency']) + lines.extend((lines_detail if (len(r['filled_entry_orders']) > 1) else "")) # Filter empty lines using list-comprehension messages.append("\n".join([line for line in lines if line]).format(**r)) From 2a3ab1ef6147a0dd649f27ecc3df273372c23f75 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sun, 6 Feb 2022 07:08:27 +0000 Subject: [PATCH 6/7] 1 more line to be hidden --- freqtrade/rpc/telegram.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index e3916a7c7..eca519e77 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -370,7 +370,7 @@ class Telegram(RPCHandler): else: return "\N{CROSS MARK}" - def _prepare_buy_details(self, filled_orders, base_currency): + def _prepare_buy_details(self, filled_orders, base_currency, is_open): """ Prepare details of trade with buy adjustment enabled """ @@ -400,8 +400,9 @@ class Telegram(RPCHandler): hours, remainder = divmod(dur_buys.seconds, 3600) minutes, seconds = divmod(remainder, 60) lines.append("*Buy #{}:* at {:.2%} avg profit".format(x+1, minus_on_buy)) - lines.append("({})".format(current_buy_datetime - .humanize(granularity=["day", "hour", "minute"]))) + if is_open: + lines.append("({})".format(current_buy_datetime + .humanize(granularity=["day", "hour", "minute"]))) lines.append("*Buy Amount:* {} ({:.8f} {})" .format(cur_buy_amount, order["cost"], base_currency)) lines.append("*Average Buy Price:* {} ({:.2%} from 1st buy rate)" @@ -483,7 +484,7 @@ class Telegram(RPCHandler): lines.append("*Open Order:* `{open_order}`") lines_detail = self._prepare_buy_details( - r['filled_entry_orders'], r['base_currency']) + r['filled_entry_orders'], r['base_currency'], r['is_open']) lines.extend((lines_detail if (len(r['filled_entry_orders']) > 1) else "")) # Filter empty lines using list-comprehension From ee2a7a968bfbf0082be6c4c19492da085ef3edeb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 6 Feb 2022 16:26:00 +0100 Subject: [PATCH 7/7] Add tests for /status on closed trades --- tests/rpc/test_rpc_telegram.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index da0bff4d8..6227bc4ad 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -263,6 +263,34 @@ def test_telegram_status_multi_entry(default_conf, update, mocker, fee) -> None: assert re.search(r'Number of Buy.*2', msg) assert re.search(r'Average Buy Price', msg) assert re.search(r'Order filled at', msg) + assert re.search(r'Close Date:', msg) is None + assert re.search(r'Close Profit:', msg) is None + + +@pytest.mark.usefixtures("init_persistence") +def test_telegram_status_closed_trade(default_conf, update, mocker, fee) -> None: + update.message.chat.id = "123" + default_conf['telegram']['enabled'] = False + default_conf['telegram']['chat_id'] = "123" + default_conf['position_adjustment_enable'] = True + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + fetch_order=MagicMock(return_value=None), + get_rate=MagicMock(return_value=0.22), + ) + + telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) + + create_mock_trades(fee) + trades = Trade.get_trades([Trade.is_open.is_(False)]) + trade = trades[0] + context = MagicMock() + context.args = [str(trade.id)] + telegram._status(update=update, context=context) + assert msg_mock.call_count == 1 + msg = msg_mock.call_args_list[0][0][0] + assert re.search(r'Close Date:', msg) + assert re.search(r'Close Profit:', msg) def test_status_handle(default_conf, update, ticker, fee, mocker) -> None: