def switch_on(bot, update, job_queue, chat_data): """Add the job to the queue""" msg = update.message if mq.get_user_settings(msg.chat_id)[base_config.NOTIFICATIONS]: msg.reply_text(messages.ALREADY_ON_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.update_setting(msg.chat_id, setting=base_config.NOTIFICATIONS, value=True) if 'job' in chat_data: chat_data['job'].schedule_removal() job = job_queue.run_repeating(notify, int(mq.get_user_settings(msg.chat_id)[base_config.INTERVAL]), context={'chat_id': msg.chat_id}) chat_data['job'] = job msg.reply_text(messages.NOTIFICATIONS_ON_TEXT, parse_mode=messages.MARKDOWN)
def show_your_coins(bot, update): """Show the user's coins list""" msg = update.message msg.reply_text('`' + '`, `'.join(mq.get_user_settings(msg.chat_id)[base_config.COINS]) + '`', reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def show_your_exchanges(bot, update): """Show user's exchanges list""" user_exchanges = mq.get_user_settings(update.message.chat_id)[base_config.EXCHANGES] update.message.reply_text('`' + '`, `'.join(user_exchanges) + '`', reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def set_interval_dialog(bot, update, chat_data, job_queue): """ Begin the dialog with for setting an interval value Args: :param bot: <object> bot instance :param update: <dict> update object that contains updates from user chat :param chat_data: <dict> stores the data for the chat. In this case a job object stores in it :param job_queue: <object> queue of jobs. The notify job automatically adds to queue after start Returns: :return: settings menu identifier """ msg = update.message interval = int(msg.text) if interval <= 0: msg.reply_text(messages.SET_INTERVAL_BAD_VALUE_TEXT, parse_mode=messages.MARKDOWN) else: mq.update_setting(msg.chat_id, setting=base_config.INTERVAL, value=interval) if mq.get_user_settings(msg.chat_id)[base_config.NOTIFICATIONS]: chat_data['job'].schedule_removal() job = job_queue.run_repeating(notify, interval, context={"chat_id": msg.chat_id}) chat_data['job'] = job msg.reply_text(messages.SET_INTERVAL_SUCC_TEXT.format(interval), reply_markup=kb_settings, parse_mode=messages.MARKDOWN) return SETTINGS_MENU return SET_INTERVAL
def remove_exchange(bot, update, args): """Remove exchange to exchanges list by which the bot will notify the user""" msg = update.message try: exchange = args[0].replace('-', '_').lower() user_exchanges = mq.get_user_settings( msg.chat_id)[base_config.EXCHANGES] if exchange not in user_exchanges: user_exchanges = exchange_convert(user_exchanges) msg.reply_text(messages.ALREADY_DISABLED_EXCHANGE_TEXT.format( '`' + '`, `'.join(user_exchanges) + '`'), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.remove_from_list(msg.chat_id, list=base_config.EXCHANGES, value=exchange) new_user_exchanges = '`' + '`, `'.join( exchange_convert(set(user_exchanges) - {exchange})) + '`' msg.reply_text( messages.REMOVE_EXCHANGE_SUCC_TEXT.format(new_user_exchanges), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU except (IndexError, ValueError): msg.reply_text(messages.REMOVE_EXCHANGE_HELP_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def add_exchange(bot, update, args): """Add exchange to exchanges list by which the bot will notify the user""" msg = update.message try: exchange = args[0].replace('-', '_').lower() if exchange not in mq.exchanges: exchanges = exchange_convert(mq.exchanges) msg.reply_text(messages.UNSUPPORTED_EXCHANGE_TEXT.format( '`' + '`, `'.join(exchanges) + '`'), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU user_exchanges = mq.get_user_settings( msg.chat_id)[base_config.EXCHANGES] if exchange in user_exchanges: msg.reply_text(messages.ALREADY_ENABLED_EXCHANGE_TEXT.format( '`' + exchange_convert(exchange) + '`'), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.add_to_list(msg.chat_id, list=base_config.EXCHANGES, value=exchange) new_user_exchanges = '`' + '`, `'.join( exchange_convert(set(user_exchanges + [exchange]))) + '`' msg.reply_text( messages.ADD_EXCHANGE_SUCC_TEXT.format(new_user_exchanges), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU except (IndexError, ValueError): msg.reply_text(messages.ADD_EXCHANGE_HELP_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def remove_coin(bot, update, args): """Remove coin from coins list by which the bot will notify the user""" msg = update.message try: coin = args[0].upper() user_coins = mq.get_user_settings(msg.chat_id)[base_config.COINS] if coin not in user_coins: msg.reply_text( messages.ALREADY_DISABLED_COIN.format('`' + '`, `'.join(user_coins) + '`'), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.remove_from_list(msg.chat_id, list=base_config.COINS, value=coin) new_user_coins = '`' + '`, `'.join(set(user_coins) - {coin}) + '`' msg.reply_text(messages.REMOVE_COIN_SUCC_TEXT.format(new_user_coins), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU except (IndexError, ValueError): msg.reply_text(messages.REMOVE_COIN_HELP_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def add_coin(bot, update, args): """Add coin to coins list by which the bot will notify the user""" msg = update.message try: coin = args[0].upper() if coin not in mq.coins: msg.reply_text( messages.UNSUPPORTED_COIN_TEXT.format('`' + '`, `'.join(mq.coins) + '`'), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU user_coins = mq.get_user_settings(msg.chat_id)[base_config.COINS] if coin in user_coins: msg.reply_text(messages.ALREADY_ENABLED_COIN.format('`' + coin + '`'), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.add_to_list(msg.chat_id, list=base_config.COINS, value=coin) new_user_coins = '`' + '`, `'.join(set(user_coins + [coin])) + '`' msg.reply_text(messages.ADD_COIN_SUCC_TEXT.format(new_user_coins), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU except (IndexError, ValueError): msg.reply_text(messages.ADD_COIN_HELP_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def set_interval(bot, update, args, chat_data, job_queue): """Set interval between notifications in seconds""" msg = update.message try: interval = int(args[0]) if interval <= 0: msg.reply_text(messages.SET_INTERVAL_BAD_VALUE_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.update_setting(msg.chat_id, setting=base_config.INTERVAL, value=interval) if mq.get_user_settings(msg.chat_id)[base_config.NOTIFICATIONS]: chat_data['job'].schedule_removal() job = job_queue.run_repeating(notify, interval, context={'chat_id': msg.chat_id}) chat_data['job'] = job msg.reply_text(messages.SET_INTERVAL_SUCC_TEXT.format(interval), reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU except (IndexError, ValueError, IndexError): msg.reply_text(messages.SET_INTERVAL_HELP_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU except OverflowError: msg.reply_text(messages.SET_INTERVAL_BIG_VALUE_EXCEPTION, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU
def switch(bot, update, job_queue, chat_data): """Switch notifications on/off""" if mq.get_user_settings(update.message.chat_id)[base_config.NOTIFICATIONS]: switch_off(bot, update, job_queue, chat_data) else: switch_on(bot, update, job_queue, chat_data) return SETTINGS_MENU
def switch_off(bot, update, job_queue, chat_data): """Remove the job if the user changed their mind""" msg = update.message if not mq.get_user_settings(msg.chat_id)[base_config.NOTIFICATIONS]: msg.reply_text(messages.ALREADY_OFF_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) return MAIN_MENU mq.update_setting(msg.chat_id, setting=base_config.NOTIFICATIONS, value=False) chat_data['job'].schedule_removal() msg.reply_text(messages.NOTIFICATIONS_OFF_TEXT, parse_mode=messages.MARKDOWN)
def start(bot, update, args, job_queue, chat_data): """ Main entry point of the bot. This command starts the bot interface and checks user authorization. Args: :param bot: <object> bot instance :param update: <dict> update object that contains updates from user chat :param args: arguments that user enters after command. In this case command /start receives the unique hash key for user authentication :param job_queue: <object> queue of jobs. The notify job automatically adds to queue after start :param chat_data: <dict> stores the data for the chat. In this case a job object stores in it. Returns: :return: Main menu identifier """ msg = update.message user = mq.get_user(msg.chat_id) if not user: if len(args) == 0: msg.reply_text(messages.ABOUT_TEXT, parse_mode=messages.MARKDOWN) msg.reply_text(messages.GET_REGISTRATION_TEXT, parse_mode=messages.MARKDOWN) return BLACK_HOLE else: key = args[0] email = mq.get_user_email(key) if not email or mq.get_user_by_email(email): msg.reply_text(messages.AUTHORIZATION_FAIL_TEXT, parse_mode=messages.MARKDOWN) return BLACK_HOLE else: mq.add_user(msg, email) msg.reply_text(messages.AUTHORIZATION_SUCC_TEXT, parse_mode=messages.MARKDOWN) msg.reply_text(messages.HELLO_TEXT, reply_markup=kb_main, parse_mode=messages.MARKDOWN) # Add job to queue if 'job' not in chat_data: user_settings = mq.get_user_settings(msg.chat_id) if user_settings[base_config.NOTIFICATIONS]: job = job_queue.run_repeating( notify, int(user_settings[base_config.INTERVAL]), context={'chat_id': msg.chat_id}) chat_data['job'] = job return MAIN_MENU
def threshold(bot, update): """ Send static message for threshold setting Returns: :return: threshold menu identifier """ msg = update.message threshold = mq.get_user_settings(msg.chat_id)[base_config.THRESHOLD] msg.reply_text(messages.SET_THRESHOLD_TEXT.format(threshold), reply_markup=kb_back, parse_mode=messages.MARKDOWN) return SET_THRESHOLD
def interval(bot, update): """ Send static message for interval setting Returns: :return: interval menu identifier """ msg = update.message interval = mq.get_user_settings(msg.chat_id)[base_config.INTERVAL] msg.reply_text(messages.SET_INTERVAL_TEXT.format(interval), reply_markup=kb_back, parse_mode=messages.MARKDOWN) return SET_INTERVAL
def add_remove_exchange(bot, update): """ Begin dialog for change exchange's list Returns: :return: change exchange's list dialog identifier """ msg = update.message user_ex = '`' + '`, `'.join( exchange_convert( mq.get_user_settings(msg.chat_id)[base_config.EXCHANGES])) + '`' msg.reply_text(messages.ADD_RM_EX_TEXT.format(user_ex), reply_markup=kb_back, parse_mode=messages.MARKDOWN) return ADD_RM_EX
def remove_coin_dialog(bot, update): """Remove coin from user's list and send message to user about operation's result""" msg = update.message coin = msg.text[3:].strip(' \t\n\r').upper() user_coins = mq.get_user_settings(msg.chat_id)[base_config.COINS] if coin not in user_coins: msg.reply_text( messages.ALREADY_DISABLED_COIN.format('`' + '`, `'.join(user_coins) + '`'), parse_mode=messages.MARKDOWN) return ADD_RM_COINS mq.remove_from_list(msg.chat_id, list=base_config.COINS, value=coin) new_user_coins = '`' + '`, `'.join(set(user_coins) - {coin}) + '`' msg.reply_text(messages.REMOVE_COIN_SUCC_TEXT.format(new_user_coins), parse_mode=messages.MARKDOWN) return ADD_RM_COINS
def show_settings(bot, update): """ Send message to user with his current settings """ msg = update.message user_settings = mq.get_user_settings(msg.chat_id) coins = '`' + '`, `'.join(user_settings[base_config.COINS]) + '`' exchanges = '`' + '`, `'.join( exchange_convert(user_settings[base_config.EXCHANGES])) + '`' threshold = str(user_settings[base_config.THRESHOLD]) interval = str(user_settings[base_config.INTERVAL]) notifications = 'enabled 🔊' if user_settings[ base_config.NOTIFICATIONS] else 'disabled 🔇' settings_message = messages.SETTINGS_TEXT.format(notifications, interval, threshold, coins, exchanges) msg.reply_text(settings_message, parse_mode=messages.MARKDOWN) return ALERTS_MENU
def add_coin_dialog(bot, update): """Add coin to user's list and send message to user about operation's result""" msg = update.message coin = msg.text[4:].strip(' \t\n\r').upper() if coin not in mq.coins: msg.reply_text(messages.UNSUPPORTED_COIN_CONV_TEXT.format(coin), parse_mode=messages.MARKDOWN) return ADD_RM_COINS user_coins = mq.get_user_settings(msg.chat_id)[base_config.COINS] if coin in user_coins: msg.reply_text(messages.ALREADY_ENABLED_COIN.format(coin), parse_mode=messages.MARKDOWN) return ADD_RM_COINS mq.add_to_list(msg.chat_id, list=base_config.COINS, value=coin) new_user_coins = '`' + '`, `'.join(set(user_coins + [coin])) + '`' msg.reply_text(messages.ADD_COIN_SUCC_TEXT.format(new_user_coins), parse_mode=messages.MARKDOWN) return ADD_RM_COINS
def add_remove_coin(bot, update): """ Begin dialog for change coin's list Args: :param bot: <telegram.Bot> bot instance :param update: <telegram.update.Update> update instance Returns: :return: change coin's list dialog identifier """ msg = update.message user_coins = '`' + '`, `'.join( mq.get_user_settings(msg.chat_id)[base_config.COINS]) + '`' msg.reply_text(messages.ADD_RM_COINS_TEXT.format(user_coins), reply_markup=kb_back, parse_mode=messages.MARKDOWN) return ADD_RM_COINS
def remove_exchange_dialog(bot, update): """Remove exchange from user's list and send message to user about operation's result""" msg = update.message exchange = msg.text[3:].strip(' \t\n\r').replace('-', '_').lower() user_exchanges = mq.get_user_settings(msg.chat_id)[base_config.EXCHANGES] if exchange not in user_exchanges: user_exchanges = exchange_convert(user_exchanges) msg.reply_text(messages.ALREADY_DISABLED_EXCHANGE_TEXT.format( '`' + '`, `'.join(user_exchanges) + '`'), parse_mode=messages.MARKDOWN) return ADD_RM_EX mq.remove_from_list(msg.chat_id, list=base_config.EXCHANGES, value=exchange) new_user_exchanges = '`' + '`, `'.join( exchange_convert(set(user_exchanges) - {exchange})) + '`' msg.reply_text( messages.REMOVE_EXCHANGE_SUCC_TEXT.format(new_user_exchanges), parse_mode=messages.MARKDOWN) return ADD_RM_EX
def add_exchange_dialog(bot, update): """Add exchange to user's list and send message to user about operation's result """ msg = update.message exchange = msg.text[4:].strip(' \t\n\r').replace('-', '_').lower() if exchange not in mq.exchanges: msg.reply_text( messages.UNSUPPORTED_EXCHANGE_CONV_TEXTS.format(exchange), parse_mode=messages.MARKDOWN) return ADD_RM_EX user_exchanges = mq.get_user_settings(msg.chat_id)[base_config.EXCHANGES] if exchange in user_exchanges: msg.reply_text(messages.ALREADY_ENABLED_EXCHANGE_TEXT.format( exchange_convert(exchange)), parse_mode=messages.MARKDOWN) return ADD_RM_EX mq.add_to_list(msg.chat_id, list=base_config.EXCHANGES, value=exchange) new_user_exchanges = '`' + '`, `'.join( set(exchange_convert(user_exchanges + [exchange]))) + '`' msg.reply_text(messages.ADD_EXCHANGE_SUCC_TEXT.format(new_user_exchanges), parse_mode=messages.MARKDOWN) return ADD_RM_EX
def crawl(chat_id): """ Return list of lists that contains coin name, two exchanges names, and diff in percent between bid and ask on coin on this exchanges (diff always positive, bid bigger than ask) Args: :param chat_id: <int> or <string> user's chat id Returns: :return: <list> of lists that contains 4 items: [coin name, first exchange name, second exchange name, diff in percent between bid and ask coin's price on exchanges], bid price is higher than ask price """ user_settings = mq.get_user_settings(chat_id) threshold = user_settings[base_config.THRESHOLD] user_coins = user_settings[base_config.COINS] user_exchanges = user_settings[base_config.EXCHANGES] res = [] for user_coin in user_coins: try: coin_doc = mq.get_coin(user_coin) exchanges_list = [] for user_exch in user_exchanges: try: exch_doc_list = list( filter( lambda coin_exch: coin_exch['name'] == user_exch, coin_doc['exchanges'])) if len(exch_doc_list) > 0: exch_doc = exch_doc_list[0] name = exch_doc['name'] ask = exch_doc['ask'] bid = exch_doc['bid'] if ask and bid: exchanges_list.append({ 'name': name, 'ask': ask, 'bid': bid }) except Exception as e: logger.warning('chat_id: {}; error: {}\n' '{}'.format(chat_id, str(e), format_exc())) if len(exchanges_list) > 1: combined_exchanges = combinations(exchanges_list, 2) for exchanges_pair in combined_exchanges: try: check_res = _price_checker( exchanges_pair=exchanges_pair, threshold=threshold, coin_name=coin_doc['name'].replace('/', '\_')) if check_res: res.append(check_res) except Exception as e: logger.warning('chat_id: {}; error: {}\n' '{}'.format(chat_id, str(e), format_exc())) except Exception as e: logger.warning('chat_id: {}; error: {}\n' '{}'.format(chat_id, str(e), format_exc())) return res