Update buy/sell fill telegram notifications
This commit is contained in:
parent
4d1ce51207
commit
a237667bc9
@ -28,7 +28,6 @@ from freqtrade.misc import chunks, plural, round_coin_value
|
|||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc import RPC, RPCException, RPCHandler
|
from freqtrade.rpc import RPC, RPCException, RPCHandler
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
logger.debug('Included module rpc.telegram ...')
|
logger.debug('Included module rpc.telegram ...')
|
||||||
@ -227,7 +226,7 @@ class Telegram(RPCHandler):
|
|||||||
)
|
)
|
||||||
if msg.get('buy_tag', None):
|
if msg.get('buy_tag', None):
|
||||||
content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n")
|
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"*Open Rate:* `{msg['limit']:.8f}`\n")
|
||||||
content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n")
|
content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n")
|
||||||
content.append(
|
content.append(
|
||||||
@ -242,7 +241,66 @@ class Telegram(RPCHandler):
|
|||||||
message += ")`"
|
message += ")`"
|
||||||
return 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:
|
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['amount'] = round(msg['amount'], 8)
|
||||||
msg['profit_percent'] = round(msg['profit_ratio'] * 100, 2)
|
msg['profit_percent'] = round(msg['profit_ratio'] * 100, 2)
|
||||||
msg['duration'] = msg['close_date'].replace(
|
msg['duration'] = msg['close_date'].replace(
|
||||||
@ -263,15 +321,17 @@ class Telegram(RPCHandler):
|
|||||||
else:
|
else:
|
||||||
msg['profit_extra'] = ''
|
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"
|
"*Profit:* `{profit_ratio:.2%}{profit_extra}`\n"
|
||||||
"*Buy Tag:* `{buy_tag}`\n"
|
"*Buy Tag:* `{buy_tag}`\n"
|
||||||
"*Sell Reason:* `{sell_reason}`\n"
|
"*Sell Reason:* `{sell_reason}`\n"
|
||||||
"*Duration:* `{duration} ({duration_min:.1f} min)`\n"
|
"*Duration:* `{duration} ({duration_min:.1f} min)`\n"
|
||||||
"*Amount:* `{amount:.8f}`\n"
|
"*Amount:* `{amount:.8f}` {currency}\n"
|
||||||
"*Open Rate:* `{open_rate:.8f}`\n"
|
"*Close Rate:* `{close_rate:.8f}`").format(
|
||||||
"*Current Rate:* `{current_rate:.8f}`\n"
|
**msg) # TODO: Updated from `limit`, confirm this is correct variable to use? Limit not in dict for _fill
|
||||||
"*Close Rate:* `{limit:.8f}`").format(**msg)
|
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
@ -287,15 +347,14 @@ class Telegram(RPCHandler):
|
|||||||
"Reason: {reason}.".format(**msg))
|
"Reason: {reason}.".format(**msg))
|
||||||
|
|
||||||
elif msg_type == RPCMessageType.BUY_FILL:
|
elif msg_type == RPCMessageType.BUY_FILL:
|
||||||
message = ("\N{LARGE CIRCLE} *{exchange}:* "
|
message = self._format_buy_msg_fill(msg)
|
||||||
"Buy order for {pair} (#{trade_id}) filled "
|
|
||||||
"for {open_rate}.".format(**msg))
|
|
||||||
elif msg_type == RPCMessageType.SELL_FILL:
|
elif msg_type == RPCMessageType.SELL_FILL:
|
||||||
message = ("\N{LARGE CIRCLE} *{exchange}:* "
|
message = self._format_sell_msg_fill(msg)
|
||||||
"Sell order for {pair} (#{trade_id}) filled "
|
|
||||||
"for {close_rate}.".format(**msg))
|
|
||||||
elif msg_type == RPCMessageType.SELL:
|
elif msg_type == RPCMessageType.SELL:
|
||||||
message = self._format_sell_msg(msg)
|
message = self._format_sell_msg(msg)
|
||||||
|
|
||||||
elif msg_type == RPCMessageType.PROTECTION_TRIGGER:
|
elif msg_type == RPCMessageType.PROTECTION_TRIGGER:
|
||||||
message = (
|
message = (
|
||||||
"*Protection* triggered due to {reason}. "
|
"*Protection* triggered due to {reason}. "
|
||||||
@ -357,7 +416,7 @@ class Telegram(RPCHandler):
|
|||||||
elif float(msg['profit_percent']) >= 0.0:
|
elif float(msg['profit_percent']) >= 0.0:
|
||||||
return "\N{EIGHT SPOKED ASTERISK}"
|
return "\N{EIGHT SPOKED ASTERISK}"
|
||||||
elif msg['sell_reason'] == "stop_loss":
|
elif msg['sell_reason'] == "stop_loss":
|
||||||
return"\N{WARNING SIGN}"
|
return "\N{WARNING SIGN}"
|
||||||
else:
|
else:
|
||||||
return "\N{CROSS MARK}"
|
return "\N{CROSS MARK}"
|
||||||
|
|
||||||
@ -689,9 +748,9 @@ class Telegram(RPCHandler):
|
|||||||
duration_msg = tabulate(
|
duration_msg = tabulate(
|
||||||
[
|
[
|
||||||
['Wins', str(timedelta(seconds=durations['wins']))
|
['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']))
|
['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']
|
headers=['', 'Avg. Duration']
|
||||||
)
|
)
|
||||||
@ -922,9 +981,9 @@ class Telegram(RPCHandler):
|
|||||||
trade_id = int(context.args[0])
|
trade_id = int(context.args[0])
|
||||||
msg = self._rpc._rpc_delete(trade_id)
|
msg = self._rpc._rpc_delete(trade_id)
|
||||||
self._send_msg((
|
self._send_msg((
|
||||||
'`{result_msg}`\n'
|
'`{result_msg}`\n'
|
||||||
'Please make sure to take care of this asset on the exchange manually.'
|
'Please make sure to take care of this asset on the exchange manually.'
|
||||||
).format(**msg))
|
).format(**msg))
|
||||||
|
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
@ -943,7 +1002,7 @@ class Telegram(RPCHandler):
|
|||||||
output = "<b>Performance:</b>\n"
|
output = "<b>Performance:</b>\n"
|
||||||
for i, trade in enumerate(trades):
|
for i, trade in enumerate(trades):
|
||||||
stat_line = (
|
stat_line = (
|
||||||
f"{i+1}.\t <code>{trade['pair']}\t"
|
f"{i + 1}.\t <code>{trade['pair']}\t"
|
||||||
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
||||||
f"({trade['profit_ratio']:.2%}) "
|
f"({trade['profit_ratio']:.2%}) "
|
||||||
f"({trade['count']})</code>\n")
|
f"({trade['count']})</code>\n")
|
||||||
@ -978,7 +1037,7 @@ class Telegram(RPCHandler):
|
|||||||
output = "<b>Buy Tag Performance:</b>\n"
|
output = "<b>Buy Tag Performance:</b>\n"
|
||||||
for i, trade in enumerate(trades):
|
for i, trade in enumerate(trades):
|
||||||
stat_line = (
|
stat_line = (
|
||||||
f"{i+1}.\t <code>{trade['buy_tag']}\t"
|
f"{i + 1}.\t <code>{trade['buy_tag']}\t"
|
||||||
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
||||||
f"({trade['profit_ratio']:.2%}) "
|
f"({trade['profit_ratio']:.2%}) "
|
||||||
f"({trade['count']})</code>\n")
|
f"({trade['count']})</code>\n")
|
||||||
@ -1013,7 +1072,7 @@ class Telegram(RPCHandler):
|
|||||||
output = "<b>Sell Reason Performance:</b>\n"
|
output = "<b>Sell Reason Performance:</b>\n"
|
||||||
for i, trade in enumerate(trades):
|
for i, trade in enumerate(trades):
|
||||||
stat_line = (
|
stat_line = (
|
||||||
f"{i+1}.\t <code>{trade['sell_reason']}\t"
|
f"{i + 1}.\t <code>{trade['sell_reason']}\t"
|
||||||
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
||||||
f"({trade['profit_ratio']:.2%}) "
|
f"({trade['profit_ratio']:.2%}) "
|
||||||
f"({trade['count']})</code>\n")
|
f"({trade['count']})</code>\n")
|
||||||
@ -1048,7 +1107,7 @@ class Telegram(RPCHandler):
|
|||||||
output = "<b>Mix Tag Performance:</b>\n"
|
output = "<b>Mix Tag Performance:</b>\n"
|
||||||
for i, trade in enumerate(trades):
|
for i, trade in enumerate(trades):
|
||||||
stat_line = (
|
stat_line = (
|
||||||
f"{i+1}.\t <code>{trade['mix_tag']}\t"
|
f"{i + 1}.\t <code>{trade['mix_tag']}\t"
|
||||||
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
|
||||||
f"({trade['profit']:.2%}) "
|
f"({trade['profit']:.2%}) "
|
||||||
f"({trade['count']})</code>\n")
|
f"({trade['count']})</code>\n")
|
||||||
|
Loading…
Reference in New Issue
Block a user