Convert endpoints to async
This commit is contained in:
+121
-120
@@ -23,7 +23,7 @@ from telegram import (CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup,
|
|||||||
ReplyKeyboardMarkup, Update)
|
ReplyKeyboardMarkup, Update)
|
||||||
from telegram.constants import MessageLimit, ParseMode
|
from telegram.constants import MessageLimit, ParseMode
|
||||||
from telegram.error import BadRequest, NetworkError, TelegramError
|
from telegram.error import BadRequest, NetworkError, TelegramError
|
||||||
from telegram.ext import Application, CallbackContext, CallbackQueryHandler, CommandHandler, Updater
|
from telegram.ext import Application, CallbackContext, CallbackQueryHandler, CommandHandler
|
||||||
from telegram.helpers import escape_markdown
|
from telegram.helpers import escape_markdown
|
||||||
|
|
||||||
from freqtrade.__init__ import __version__
|
from freqtrade.__init__ import __version__
|
||||||
@@ -489,7 +489,9 @@ class Telegram(RPCHandler):
|
|||||||
|
|
||||||
message = self.compose_message(deepcopy(msg), msg_type) # type: ignore
|
message = self.compose_message(deepcopy(msg), msg_type) # type: ignore
|
||||||
if message:
|
if message:
|
||||||
self._send_msg(message, disable_notification=(noti == 'silent'))
|
asyncio.run_coroutine_threadsafe(
|
||||||
|
self._send_msg(message, disable_notification=(noti == 'silent')),
|
||||||
|
self._loop)
|
||||||
|
|
||||||
def _get_sell_emoji(self, msg):
|
def _get_sell_emoji(self, msg):
|
||||||
"""
|
"""
|
||||||
@@ -572,7 +574,7 @@ class Telegram(RPCHandler):
|
|||||||
return lines_detail
|
return lines_detail
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _status(self, update: Update, context: CallbackContext) -> None:
|
async def _status(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /status.
|
Handler for /status.
|
||||||
Returns the current TradeThread status
|
Returns the current TradeThread status
|
||||||
@@ -582,12 +584,12 @@ class Telegram(RPCHandler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if context.args and 'table' in context.args:
|
if context.args and 'table' in context.args:
|
||||||
self._status_table(update, context)
|
await self._status_table(update, context)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self._status_msg(update, context)
|
await self._status_msg(update, context)
|
||||||
|
|
||||||
def _status_msg(self, update: Update, context: CallbackContext) -> None:
|
async def _status_msg(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
handler for `/status` and `/status <id>`.
|
handler for `/status` and `/status <id>`.
|
||||||
|
|
||||||
@@ -671,9 +673,9 @@ class Telegram(RPCHandler):
|
|||||||
lines_detail = self._prepare_order_details(
|
lines_detail = self._prepare_order_details(
|
||||||
r['orders'], r['quote_currency'], r['is_open'])
|
r['orders'], r['quote_currency'], r['is_open'])
|
||||||
lines.extend(lines_detail if lines_detail else "")
|
lines.extend(lines_detail if lines_detail else "")
|
||||||
self.__send_status_msg(lines, r)
|
await self.__send_status_msg(lines, r)
|
||||||
|
|
||||||
def __send_status_msg(self, lines: List[str], r: Dict[str, Any]) -> None:
|
async def __send_status_msg(self, lines: List[str], r: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Send status message.
|
Send status message.
|
||||||
"""
|
"""
|
||||||
@@ -684,13 +686,13 @@ class Telegram(RPCHandler):
|
|||||||
if (len(msg) + len(line) + 1) < MAX_MESSAGE_LENGTH:
|
if (len(msg) + len(line) + 1) < MAX_MESSAGE_LENGTH:
|
||||||
msg += line + '\n'
|
msg += line + '\n'
|
||||||
else:
|
else:
|
||||||
self._send_msg(msg.format(**r))
|
await self._send_msg(msg.format(**r))
|
||||||
msg = "*Trade ID:* `{trade_id}` - continued\n" + line + '\n'
|
msg = "*Trade ID:* `{trade_id}` - continued\n" + line + '\n'
|
||||||
|
|
||||||
self._send_msg(msg.format(**r))
|
await self._send_msg(msg.format(**r))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _status_table(self, update: Update, context: CallbackContext) -> None:
|
async def _status_table(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /status table.
|
Handler for /status table.
|
||||||
Returns the current TradeThread status in table format
|
Returns the current TradeThread status in table format
|
||||||
@@ -723,12 +725,11 @@ class Telegram(RPCHandler):
|
|||||||
# insert separators line between Total
|
# insert separators line between Total
|
||||||
lines = message.split("\n")
|
lines = message.split("\n")
|
||||||
message = "\n".join(lines[:-1] + [lines[1]] + [lines[-1]])
|
message = "\n".join(lines[:-1] + [lines[1]] + [lines[-1]])
|
||||||
self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML,
|
await self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML,
|
||||||
reload_able=True, callback_path="update_status_table",
|
reload_able=True, callback_path="update_status_table",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
async def _timeunit_stats(self, update: Update, context: CallbackContext, unit: str) -> None:
|
||||||
def _timeunit_stats(self, update: Update, context: CallbackContext, unit: str) -> None:
|
|
||||||
"""
|
"""
|
||||||
Handler for /daily <n>
|
Handler for /daily <n>
|
||||||
Returns a daily profit (in BTC) over the last n days.
|
Returns a daily profit (in BTC) over the last n days.
|
||||||
@@ -775,11 +776,11 @@ class Telegram(RPCHandler):
|
|||||||
f'<b>{val.message} Profit over the last {timescale} {val.message2}</b>:\n'
|
f'<b>{val.message} Profit over the last {timescale} {val.message2}</b>:\n'
|
||||||
f'<pre>{stats_tab}</pre>'
|
f'<pre>{stats_tab}</pre>'
|
||||||
)
|
)
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True,
|
await self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True,
|
||||||
callback_path=val.callback, query=update.callback_query)
|
callback_path=val.callback, query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _daily(self, update: Update, context: CallbackContext) -> None:
|
async def _daily(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /daily <n>
|
Handler for /daily <n>
|
||||||
Returns a daily profit (in BTC) over the last n days.
|
Returns a daily profit (in BTC) over the last n days.
|
||||||
@@ -787,10 +788,10 @@ class Telegram(RPCHandler):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self._timeunit_stats(update, context, 'days')
|
await self._timeunit_stats(update, context, 'days')
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _weekly(self, update: Update, context: CallbackContext) -> None:
|
async def _weekly(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /weekly <n>
|
Handler for /weekly <n>
|
||||||
Returns a weekly profit (in BTC) over the last n weeks.
|
Returns a weekly profit (in BTC) over the last n weeks.
|
||||||
@@ -798,10 +799,10 @@ class Telegram(RPCHandler):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self._timeunit_stats(update, context, 'weeks')
|
await self._timeunit_stats(update, context, 'weeks')
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _monthly(self, update: Update, context: CallbackContext) -> None:
|
async def _monthly(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /monthly <n>
|
Handler for /monthly <n>
|
||||||
Returns a monthly profit (in BTC) over the last n months.
|
Returns a monthly profit (in BTC) over the last n months.
|
||||||
@@ -809,10 +810,10 @@ class Telegram(RPCHandler):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self._timeunit_stats(update, context, 'months')
|
await self._timeunit_stats(update, context, 'months')
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _profit(self, update: Update, context: CallbackContext) -> None:
|
async def _profit(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /profit.
|
Handler for /profit.
|
||||||
Returns a cumulative profit statistics.
|
Returns a cumulative profit statistics.
|
||||||
@@ -886,11 +887,11 @@ class Telegram(RPCHandler):
|
|||||||
f"*Max Drawdown:* `{stats['max_drawdown']:.2%} "
|
f"*Max Drawdown:* `{stats['max_drawdown']:.2%} "
|
||||||
f"({round_coin_value(stats['max_drawdown_abs'], stake_cur)})`"
|
f"({round_coin_value(stats['max_drawdown_abs'], stake_cur)})`"
|
||||||
)
|
)
|
||||||
self._send_msg(markdown_msg, reload_able=True, callback_path="update_profit",
|
await self._send_msg(markdown_msg, reload_able=True, callback_path="update_profit",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _stats(self, update: Update, context: CallbackContext) -> None:
|
async def _stats(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /stats
|
Handler for /stats
|
||||||
Show stats of recent trades
|
Show stats of recent trades
|
||||||
@@ -921,7 +922,7 @@ class Telegram(RPCHandler):
|
|||||||
headers=['Exit Reason', 'Exits', 'Wins', 'Losses']
|
headers=['Exit Reason', 'Exits', 'Wins', 'Losses']
|
||||||
)
|
)
|
||||||
if len(exit_reasons_tabulate) > 25:
|
if len(exit_reasons_tabulate) > 25:
|
||||||
self._send_msg(f"```\n{exit_reasons_msg}```", ParseMode.MARKDOWN)
|
await self._send_msg(f"```\n{exit_reasons_msg}```", ParseMode.MARKDOWN)
|
||||||
exit_reasons_msg = ''
|
exit_reasons_msg = ''
|
||||||
|
|
||||||
durations = stats['durations']
|
durations = stats['durations']
|
||||||
@@ -936,10 +937,10 @@ class Telegram(RPCHandler):
|
|||||||
)
|
)
|
||||||
msg = (f"""```\n{exit_reasons_msg}```\n```\n{duration_msg}```""")
|
msg = (f"""```\n{exit_reasons_msg}```\n```\n{duration_msg}```""")
|
||||||
|
|
||||||
self._send_msg(msg, ParseMode.MARKDOWN)
|
await self._send_msg(msg, ParseMode.MARKDOWN)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _balance(self, update: Update, context: CallbackContext) -> None:
|
async def _balance(self, update: Update, context: CallbackContext) -> None:
|
||||||
""" Handler for /balance """
|
""" Handler for /balance """
|
||||||
full_result = context.args and 'full' in context.args
|
full_result = context.args and 'full' in context.args
|
||||||
result = self._rpc._rpc_balance(self._config['stake_currency'],
|
result = self._rpc._rpc_balance(self._config['stake_currency'],
|
||||||
@@ -1017,11 +1018,11 @@ class Telegram(RPCHandler):
|
|||||||
f"\t`{result['stake']}: {total_stake}`{stake_improve}\n"
|
f"\t`{result['stake']}: {total_stake}`{stake_improve}\n"
|
||||||
f"\t`{result['symbol']}: {value}`{fiat_val}\n"
|
f"\t`{result['symbol']}: {value}`{fiat_val}\n"
|
||||||
)
|
)
|
||||||
self._send_msg(output, reload_able=True, callback_path="update_balance",
|
await self._send_msg(output, reload_able=True, callback_path="update_balance",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _start(self, update: Update, context: CallbackContext) -> None:
|
async def _start(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /start.
|
Handler for /start.
|
||||||
Starts TradeThread
|
Starts TradeThread
|
||||||
@@ -1030,10 +1031,10 @@ class Telegram(RPCHandler):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc._rpc_start()
|
msg = self._rpc._rpc_start()
|
||||||
self._send_msg(f"Status: `{msg['status']}`")
|
await self._send_msg(f"Status: `{msg['status']}`")
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _stop(self, update: Update, context: CallbackContext) -> None:
|
async def _stop(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /stop.
|
Handler for /stop.
|
||||||
Stops TradeThread
|
Stops TradeThread
|
||||||
@@ -1042,10 +1043,10 @@ class Telegram(RPCHandler):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc._rpc_stop()
|
msg = self._rpc._rpc_stop()
|
||||||
self._send_msg(f"Status: `{msg['status']}`")
|
await self._send_msg(f"Status: `{msg['status']}`")
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _reload_config(self, update: Update, context: CallbackContext) -> None:
|
async def _reload_config(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /reload_config.
|
Handler for /reload_config.
|
||||||
Triggers a config file reload
|
Triggers a config file reload
|
||||||
@@ -1054,10 +1055,10 @@ class Telegram(RPCHandler):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc._rpc_reload_config()
|
msg = self._rpc._rpc_reload_config()
|
||||||
self._send_msg(f"Status: `{msg['status']}`")
|
await self._send_msg(f"Status: `{msg['status']}`")
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _stopentry(self, update: Update, context: CallbackContext) -> None:
|
async def _stopentry(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /stop_buy.
|
Handler for /stop_buy.
|
||||||
Sets max_open_trades to 0 and gracefully sells all open trades
|
Sets max_open_trades to 0 and gracefully sells all open trades
|
||||||
@@ -1066,10 +1067,10 @@ class Telegram(RPCHandler):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc._rpc_stopentry()
|
msg = self._rpc._rpc_stopentry()
|
||||||
self._send_msg(f"Status: `{msg['status']}`")
|
await self._send_msg(f"Status: `{msg['status']}`")
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _force_exit(self, update: Update, context: CallbackContext) -> None:
|
async def _force_exit(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /forceexit <id>.
|
Handler for /forceexit <id>.
|
||||||
Sells the given trade at current price
|
Sells the given trade at current price
|
||||||
@@ -1100,51 +1101,51 @@ class Telegram(RPCHandler):
|
|||||||
|
|
||||||
buttons_aligned.append([InlineKeyboardButton(
|
buttons_aligned.append([InlineKeyboardButton(
|
||||||
text='Cancel', callback_data='force_exit__cancel')])
|
text='Cancel', callback_data='force_exit__cancel')])
|
||||||
self._send_msg(msg="Which trade?", keyboard=buttons_aligned)
|
await self._send_msg(msg="Which trade?", keyboard=buttons_aligned)
|
||||||
|
|
||||||
def _force_exit_action(self, trade_id):
|
async def _force_exit_action(self, trade_id):
|
||||||
if trade_id != 'cancel':
|
if trade_id != 'cancel':
|
||||||
try:
|
try:
|
||||||
self._rpc._rpc_force_exit(trade_id)
|
self._rpc._rpc_force_exit(trade_id)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
await self._send_msg(str(e))
|
||||||
|
|
||||||
def _force_exit_inline(self, update: Update, _: CallbackContext) -> None:
|
async def _force_exit_inline(self, update: Update, _: CallbackContext) -> None:
|
||||||
if update.callback_query:
|
if update.callback_query:
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
if query.data and '__' in query.data:
|
if query.data and '__' in query.data:
|
||||||
# Input data is "force_exit__<tradid|cancel>"
|
# Input data is "force_exit__<tradid|cancel>"
|
||||||
trade_id = query.data.split("__")[1].split(' ')[0]
|
trade_id = query.data.split("__")[1].split(' ')[0]
|
||||||
if trade_id == 'cancel':
|
if trade_id == 'cancel':
|
||||||
query.answer()
|
await query.answer()
|
||||||
query.edit_message_text(text="Force exit canceled.")
|
await query.edit_message_text(text="Force exit canceled.")
|
||||||
return
|
return
|
||||||
trade: Optional[Trade] = Trade.get_trades(trade_filter=Trade.id == trade_id).first()
|
trade: Optional[Trade] = Trade.get_trades(trade_filter=Trade.id == trade_id).first()
|
||||||
query.answer()
|
query.answer()
|
||||||
if trade:
|
if trade:
|
||||||
query.edit_message_text(
|
await query.edit_message_text(
|
||||||
text=f"Manually exiting Trade #{trade_id}, {trade.pair}")
|
text=f"Manually exiting Trade #{trade_id}, {trade.pair}")
|
||||||
self._force_exit_action(trade_id)
|
await self._force_exit_action(trade_id)
|
||||||
else:
|
else:
|
||||||
query.edit_message_text(text=f"Trade {trade_id} not found.")
|
await query.edit_message_text(text=f"Trade {trade_id} not found.")
|
||||||
|
|
||||||
def _force_enter_action(self, pair, price: Optional[float], order_side: SignalDirection):
|
async def _force_enter_action(self, pair, price: Optional[float], order_side: SignalDirection):
|
||||||
if pair != 'cancel':
|
if pair != 'cancel':
|
||||||
try:
|
try:
|
||||||
self._rpc._rpc_force_entry(pair, price, order_side=order_side)
|
await self._rpc._rpc_force_entry(pair, price, order_side=order_side)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
logger.exception("Forcebuy error!")
|
logger.exception("Forcebuy error!")
|
||||||
self._send_msg(str(e), ParseMode.HTML)
|
await self._send_msg(str(e), ParseMode.HTML)
|
||||||
|
|
||||||
def _force_enter_inline(self, update: Update, _: CallbackContext) -> None:
|
async def _force_enter_inline(self, update: Update, _: CallbackContext) -> None:
|
||||||
if update.callback_query:
|
if update.callback_query:
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
if query.data and '_||_' in query.data:
|
if query.data and '_||_' in query.data:
|
||||||
pair, side = query.data.split('_||_')
|
pair, side = query.data.split('_||_')
|
||||||
order_side = SignalDirection(side)
|
order_side = SignalDirection(side)
|
||||||
query.answer()
|
await query.answer()
|
||||||
query.edit_message_text(text=f"Manually entering {order_side} for {pair}")
|
await query.edit_message_text(text=f"Manually entering {order_side} for {pair}")
|
||||||
self._force_enter_action(pair, None, order_side)
|
await self._force_enter_action(pair, None, order_side)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _layout_inline_keyboard(
|
def _layout_inline_keyboard(
|
||||||
@@ -1157,7 +1158,7 @@ class Telegram(RPCHandler):
|
|||||||
return [buttons[i:i + cols] for i in range(0, len(buttons), cols)]
|
return [buttons[i:i + cols] for i in range(0, len(buttons), cols)]
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _force_enter(
|
async def _force_enter(
|
||||||
self, update: Update, context: CallbackContext, order_side: SignalDirection) -> None:
|
self, update: Update, context: CallbackContext, order_side: SignalDirection) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /forcelong <asset> <price> and `/forceshort <asset> <price>
|
Handler for /forcelong <asset> <price> and `/forceshort <asset> <price>
|
||||||
@@ -1169,7 +1170,7 @@ class Telegram(RPCHandler):
|
|||||||
if context.args:
|
if context.args:
|
||||||
pair = context.args[0]
|
pair = context.args[0]
|
||||||
price = float(context.args[1]) if len(context.args) > 1 else None
|
price = float(context.args[1]) if len(context.args) > 1 else None
|
||||||
self._force_enter_action(pair, price, order_side)
|
await self._force_enter_action(pair, price, order_side)
|
||||||
else:
|
else:
|
||||||
whitelist = self._rpc._rpc_whitelist()['whitelist']
|
whitelist = self._rpc._rpc_whitelist()['whitelist']
|
||||||
pair_buttons = [
|
pair_buttons = [
|
||||||
@@ -1179,12 +1180,12 @@ class Telegram(RPCHandler):
|
|||||||
buttons_aligned = self._layout_inline_keyboard(pair_buttons)
|
buttons_aligned = self._layout_inline_keyboard(pair_buttons)
|
||||||
|
|
||||||
buttons_aligned.append([InlineKeyboardButton(text='Cancel', callback_data='cancel')])
|
buttons_aligned.append([InlineKeyboardButton(text='Cancel', callback_data='cancel')])
|
||||||
self._send_msg(msg="Which pair?",
|
await self._send_msg(msg="Which pair?",
|
||||||
keyboard=buttons_aligned,
|
keyboard=buttons_aligned,
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _trades(self, update: Update, context: CallbackContext) -> None:
|
async def _trades(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /trades <n>
|
Handler for /trades <n>
|
||||||
Returns last n recent trades.
|
Returns last n recent trades.
|
||||||
@@ -1213,10 +1214,10 @@ class Telegram(RPCHandler):
|
|||||||
tablefmt='simple')
|
tablefmt='simple')
|
||||||
message = (f"<b>{min(trades['trades_count'], nrecent)} recent trades</b>:\n"
|
message = (f"<b>{min(trades['trades_count'], nrecent)} recent trades</b>:\n"
|
||||||
+ (f"<pre>{trades_tab}</pre>" if trades['trades_count'] > 0 else ''))
|
+ (f"<pre>{trades_tab}</pre>" if trades['trades_count'] > 0 else ''))
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
await self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _delete_trade(self, update: Update, context: CallbackContext) -> None:
|
async def _delete_trade(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /delete <id>.
|
Handler for /delete <id>.
|
||||||
Delete the given trade
|
Delete the given trade
|
||||||
@@ -1228,13 +1229,13 @@ class Telegram(RPCHandler):
|
|||||||
raise RPCException("Trade-id not set.")
|
raise RPCException("Trade-id not set.")
|
||||||
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(
|
await self._send_msg(
|
||||||
f"`{msg['result_msg']}`\n"
|
f"`{msg['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.'
|
||||||
)
|
)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _cancel_open_order(self, update: Update, context: CallbackContext) -> None:
|
async def _cancel_open_order(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /cancel_open_order <id>.
|
Handler for /cancel_open_order <id>.
|
||||||
Cancel open order for tradeid
|
Cancel open order for tradeid
|
||||||
@@ -1246,10 +1247,10 @@ class Telegram(RPCHandler):
|
|||||||
raise RPCException("Trade-id not set.")
|
raise RPCException("Trade-id not set.")
|
||||||
trade_id = int(context.args[0])
|
trade_id = int(context.args[0])
|
||||||
self._rpc._rpc_cancel_open_order(trade_id)
|
self._rpc._rpc_cancel_open_order(trade_id)
|
||||||
self._send_msg('Open order canceled.')
|
await self._send_msg('Open order canceled.')
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _performance(self, update: Update, context: CallbackContext) -> None:
|
async def _performance(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /performance.
|
Handler for /performance.
|
||||||
Shows a performance statistic from finished trades
|
Shows a performance statistic from finished trades
|
||||||
@@ -1272,12 +1273,12 @@ class Telegram(RPCHandler):
|
|||||||
else:
|
else:
|
||||||
output += stat_line
|
output += stat_line
|
||||||
|
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML,
|
await self._send_msg(output, parse_mode=ParseMode.HTML,
|
||||||
reload_able=True, callback_path="update_performance",
|
reload_able=True, callback_path="update_performance",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _enter_tag_performance(self, update: Update, context: CallbackContext) -> None:
|
async def _enter_tag_performance(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /buys PAIR .
|
Handler for /buys PAIR .
|
||||||
Shows a performance statistic from finished trades
|
Shows a performance statistic from finished trades
|
||||||
@@ -1304,12 +1305,12 @@ class Telegram(RPCHandler):
|
|||||||
else:
|
else:
|
||||||
output += stat_line
|
output += stat_line
|
||||||
|
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML,
|
await self._send_msg(output, parse_mode=ParseMode.HTML,
|
||||||
reload_able=True, callback_path="update_enter_tag_performance",
|
reload_able=True, callback_path="update_enter_tag_performance",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _exit_reason_performance(self, update: Update, context: CallbackContext) -> None:
|
async def _exit_reason_performance(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /sells.
|
Handler for /sells.
|
||||||
Shows a performance statistic from finished trades
|
Shows a performance statistic from finished trades
|
||||||
@@ -1331,17 +1332,17 @@ class Telegram(RPCHandler):
|
|||||||
f"({trade['count']})</code>\n")
|
f"({trade['count']})</code>\n")
|
||||||
|
|
||||||
if len(output + stat_line) >= MAX_MESSAGE_LENGTH:
|
if len(output + stat_line) >= MAX_MESSAGE_LENGTH:
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML)
|
await self._send_msg(output, parse_mode=ParseMode.HTML)
|
||||||
output = stat_line
|
output = stat_line
|
||||||
else:
|
else:
|
||||||
output += stat_line
|
output += stat_line
|
||||||
|
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML,
|
await self._send_msg(output, parse_mode=ParseMode.HTML,
|
||||||
reload_able=True, callback_path="update_exit_reason_performance",
|
reload_able=True, callback_path="update_exit_reason_performance",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _mix_tag_performance(self, update: Update, context: CallbackContext) -> None:
|
async def _mix_tag_performance(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /mix_tags.
|
Handler for /mix_tags.
|
||||||
Shows a performance statistic from finished trades
|
Shows a performance statistic from finished trades
|
||||||
@@ -1363,17 +1364,17 @@ class Telegram(RPCHandler):
|
|||||||
f"({trade['count']})</code>\n")
|
f"({trade['count']})</code>\n")
|
||||||
|
|
||||||
if len(output + stat_line) >= MAX_MESSAGE_LENGTH:
|
if len(output + stat_line) >= MAX_MESSAGE_LENGTH:
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML)
|
await self._send_msg(output, parse_mode=ParseMode.HTML)
|
||||||
output = stat_line
|
output = stat_line
|
||||||
else:
|
else:
|
||||||
output += stat_line
|
output += stat_line
|
||||||
|
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML,
|
await self._send_msg(output, parse_mode=ParseMode.HTML,
|
||||||
reload_able=True, callback_path="update_mix_tag_performance",
|
reload_able=True, callback_path="update_mix_tag_performance",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _count(self, update: Update, context: CallbackContext) -> None:
|
async def _count(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /count.
|
Handler for /count.
|
||||||
Returns the number of trades running
|
Returns the number of trades running
|
||||||
@@ -1387,19 +1388,19 @@ class Telegram(RPCHandler):
|
|||||||
tablefmt='simple')
|
tablefmt='simple')
|
||||||
message = f"<pre>{message}</pre>"
|
message = f"<pre>{message}</pre>"
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML,
|
await self._send_msg(message, parse_mode=ParseMode.HTML,
|
||||||
reload_able=True, callback_path="update_count",
|
reload_able=True, callback_path="update_count",
|
||||||
query=update.callback_query)
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _locks(self, update: Update, context: CallbackContext) -> None:
|
async def _locks(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /locks.
|
Handler for /locks.
|
||||||
Returns the currently active locks
|
Returns the currently active locks
|
||||||
"""
|
"""
|
||||||
rpc_locks = self._rpc._rpc_locks()
|
rpc_locks = self._rpc._rpc_locks()
|
||||||
if not rpc_locks['locks']:
|
if not rpc_locks['locks']:
|
||||||
self._send_msg('No active locks.', parse_mode=ParseMode.HTML)
|
await self._send_msg('No active locks.', parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
for locks in chunks(rpc_locks['locks'], 25):
|
for locks in chunks(rpc_locks['locks'], 25):
|
||||||
message = tabulate([[
|
message = tabulate([[
|
||||||
@@ -1411,10 +1412,10 @@ class Telegram(RPCHandler):
|
|||||||
tablefmt='simple')
|
tablefmt='simple')
|
||||||
message = f"<pre>{escape(message)}</pre>"
|
message = f"<pre>{escape(message)}</pre>"
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
await self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _delete_locks(self, update: Update, context: CallbackContext) -> None:
|
async def _delete_locks(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /delete_locks.
|
Handler for /delete_locks.
|
||||||
Returns the currently active locks
|
Returns the currently active locks
|
||||||
@@ -1429,10 +1430,10 @@ class Telegram(RPCHandler):
|
|||||||
pair = arg
|
pair = arg
|
||||||
|
|
||||||
self._rpc._rpc_delete_lock(lockid=lockid, pair=pair)
|
self._rpc._rpc_delete_lock(lockid=lockid, pair=pair)
|
||||||
self._locks(update, context)
|
await self._locks(update, context)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _whitelist(self, update: Update, context: CallbackContext) -> None:
|
async def _whitelist(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /whitelist
|
Handler for /whitelist
|
||||||
Shows the currently active whitelist
|
Shows the currently active whitelist
|
||||||
@@ -1449,39 +1450,39 @@ class Telegram(RPCHandler):
|
|||||||
message += f"`{', '.join(whitelist['whitelist'])}`"
|
message += f"`{', '.join(whitelist['whitelist'])}`"
|
||||||
|
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
self._send_msg(message)
|
await self._send_msg(message)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _blacklist(self, update: Update, context: CallbackContext) -> None:
|
async def _blacklist(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /blacklist
|
Handler for /blacklist
|
||||||
Shows the currently active blacklist
|
Shows the currently active blacklist
|
||||||
"""
|
"""
|
||||||
self.send_blacklist_msg(self._rpc._rpc_blacklist(context.args))
|
await self.send_blacklist_msg(self._rpc._rpc_blacklist(context.args))
|
||||||
|
|
||||||
def send_blacklist_msg(self, blacklist: Dict):
|
async def send_blacklist_msg(self, blacklist: Dict):
|
||||||
errmsgs = []
|
errmsgs = []
|
||||||
for pair, error in blacklist['errors'].items():
|
for pair, error in blacklist['errors'].items():
|
||||||
errmsgs.append(f"Error: {error['error_msg']}")
|
errmsgs.append(f"Error: {error['error_msg']}")
|
||||||
if errmsgs:
|
if errmsgs:
|
||||||
self._send_msg('\n'.join(errmsgs))
|
await self._send_msg('\n'.join(errmsgs))
|
||||||
|
|
||||||
message = f"Blacklist contains {blacklist['length']} pairs\n"
|
message = f"Blacklist contains {blacklist['length']} pairs\n"
|
||||||
message += f"`{', '.join(blacklist['blacklist'])}`"
|
message += f"`{', '.join(blacklist['blacklist'])}`"
|
||||||
|
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
self._send_msg(message)
|
await self._send_msg(message)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _blacklist_delete(self, update: Update, context: CallbackContext) -> None:
|
async def _blacklist_delete(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /bl_delete
|
Handler for /bl_delete
|
||||||
Deletes pair(s) from current blacklist
|
Deletes pair(s) from current blacklist
|
||||||
"""
|
"""
|
||||||
self.send_blacklist_msg(self._rpc._rpc_blacklist_delete(context.args or []))
|
await self.send_blacklist_msg(self._rpc._rpc_blacklist_delete(context.args or []))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _logs(self, update: Update, context: CallbackContext) -> None:
|
async def _logs(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /logs
|
Handler for /logs
|
||||||
Shows the latest logs
|
Shows the latest logs
|
||||||
@@ -1500,17 +1501,17 @@ class Telegram(RPCHandler):
|
|||||||
escape_markdown(logrec[4], version=2))
|
escape_markdown(logrec[4], version=2))
|
||||||
if len(msgs + msg) + 10 >= MAX_MESSAGE_LENGTH:
|
if len(msgs + msg) + 10 >= MAX_MESSAGE_LENGTH:
|
||||||
# Send message immediately if it would become too long
|
# Send message immediately if it would become too long
|
||||||
self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN_V2)
|
await self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN_V2)
|
||||||
msgs = msg + '\n'
|
msgs = msg + '\n'
|
||||||
else:
|
else:
|
||||||
# Append message to messages to send
|
# Append message to messages to send
|
||||||
msgs += msg + '\n'
|
msgs += msg + '\n'
|
||||||
|
|
||||||
if msgs:
|
if msgs:
|
||||||
self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN_V2)
|
await self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN_V2)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _edge(self, update: Update, context: CallbackContext) -> None:
|
async def _edge(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /edge
|
Handler for /edge
|
||||||
Shows information related to Edge
|
Shows information related to Edge
|
||||||
@@ -1518,17 +1519,17 @@ class Telegram(RPCHandler):
|
|||||||
edge_pairs = self._rpc._rpc_edge()
|
edge_pairs = self._rpc._rpc_edge()
|
||||||
if not edge_pairs:
|
if not edge_pairs:
|
||||||
message = '<b>Edge only validated following pairs:</b>'
|
message = '<b>Edge only validated following pairs:</b>'
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
await self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
for chunk in chunks(edge_pairs, 25):
|
for chunk in chunks(edge_pairs, 25):
|
||||||
edge_pairs_tab = tabulate(chunk, headers='keys', tablefmt='simple')
|
edge_pairs_tab = tabulate(chunk, headers='keys', tablefmt='simple')
|
||||||
message = (f'<b>Edge only validated following pairs:</b>\n'
|
message = (f'<b>Edge only validated following pairs:</b>\n'
|
||||||
f'<pre>{edge_pairs_tab}</pre>')
|
f'<pre>{edge_pairs_tab}</pre>')
|
||||||
|
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
await self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _help(self, update: Update, context: CallbackContext) -> None:
|
async def _help(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /help.
|
Handler for /help.
|
||||||
Show commands of the bot
|
Show commands of the bot
|
||||||
@@ -1606,17 +1607,17 @@ class Telegram(RPCHandler):
|
|||||||
"*/version:* `Show version`"
|
"*/version:* `Show version`"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._send_msg(message, parse_mode=ParseMode.MARKDOWN)
|
await self._send_msg(message, parse_mode=ParseMode.MARKDOWN)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _health(self, update: Update, context: CallbackContext) -> None:
|
async def _health(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /health
|
Handler for /health
|
||||||
Shows the last process timestamp
|
Shows the last process timestamp
|
||||||
"""
|
"""
|
||||||
health = self._rpc.health()
|
health = self._rpc.health()
|
||||||
message = f"Last process: `{health['last_process_loc']}`"
|
message = f"Last process: `{health['last_process_loc']}`"
|
||||||
self._send_msg(message)
|
await self._send_msg(message)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
async def _version(self, update: Update, context: CallbackContext) -> None:
|
async def _version(self, update: Update, context: CallbackContext) -> None:
|
||||||
@@ -1635,7 +1636,7 @@ class Telegram(RPCHandler):
|
|||||||
await self._send_msg(version_string)
|
await self._send_msg(version_string)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _show_config(self, update: Update, context: CallbackContext) -> None:
|
async def _show_config(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /show_config.
|
Handler for /show_config.
|
||||||
Show config information information
|
Show config information information
|
||||||
@@ -1664,7 +1665,7 @@ class Telegram(RPCHandler):
|
|||||||
else:
|
else:
|
||||||
pa_info = "*Position adjustment:* Off\n"
|
pa_info = "*Position adjustment:* Off\n"
|
||||||
|
|
||||||
self._send_msg(
|
await self._send_msg(
|
||||||
f"*Mode:* `{'Dry-run' if val['dry_run'] else 'Live'}`\n"
|
f"*Mode:* `{'Dry-run' if val['dry_run'] else 'Live'}`\n"
|
||||||
f"*Exchange:* `{val['exchange']}`\n"
|
f"*Exchange:* `{val['exchange']}`\n"
|
||||||
f"*Market: * `{val['trading_mode']}`\n"
|
f"*Market: * `{val['trading_mode']}`\n"
|
||||||
@@ -1766,7 +1767,7 @@ class Telegram(RPCHandler):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _changemarketdir(self, update: Update, context: CallbackContext) -> None:
|
async def _changemarketdir(self, update: Update, context: CallbackContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler for /marketdir.
|
Handler for /marketdir.
|
||||||
Updates the bot's market_direction
|
Updates the bot's market_direction
|
||||||
@@ -1789,14 +1790,14 @@ class Telegram(RPCHandler):
|
|||||||
|
|
||||||
if new_market_dir is not None:
|
if new_market_dir is not None:
|
||||||
self._rpc._update_market_direction(new_market_dir)
|
self._rpc._update_market_direction(new_market_dir)
|
||||||
self._send_msg("Successfully updated market direction"
|
await self._send_msg("Successfully updated market direction"
|
||||||
f" from *{old_market_dir}* to *{new_market_dir}*.")
|
f" from *{old_market_dir}* to *{new_market_dir}*.")
|
||||||
else:
|
else:
|
||||||
raise RPCException("Invalid market direction provided. \n"
|
raise RPCException("Invalid market direction provided. \n"
|
||||||
"Valid market directions: *long, short, even, none*")
|
"Valid market directions: *long, short, even, none*")
|
||||||
elif context.args is not None and len(context.args) == 0:
|
elif context.args is not None and len(context.args) == 0:
|
||||||
old_market_dir = self._rpc._get_market_direction()
|
old_market_dir = self._rpc._get_market_direction()
|
||||||
self._send_msg(f"Currently set market direction: *{old_market_dir}*")
|
await self._send_msg(f"Currently set market direction: *{old_market_dir}*")
|
||||||
else:
|
else:
|
||||||
raise RPCException("Invalid usage of command /marketdir. \n"
|
raise RPCException("Invalid usage of command /marketdir. \n"
|
||||||
"Usage: */marketdir [short | long | even | none]*")
|
"Usage: */marketdir [short | long | even | none]*")
|
||||||
|
|||||||
Reference in New Issue
Block a user