def update_btb(update: Update, _: CallbackContext) -> int: logger.info(f"Updating Binance Trade Bot. ({update.message.text})") keyboard = [["OK 👌"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) if update.message.text != "Cancel update": message = ("The bot has been stopped and is now updating\.\n" "Wait a few seconds, then restart manually\.") update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") try: find_and_kill_binance_trade_bot_process() subprocess.call( f"cd {settings.ROOT_PATH} && " f"git pull && " f"$(which python3) -m pip install -r requirements.txt --upgrade", shell=True, ) except Exception as e: logger.error(f"Unable to update Binance Trade Bot: {e}") message = "Unable to update Binance Trade Bot" update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") else: message = "👌 Exited without changes\.\n" "Binance Trade Bot was *not* updated\." update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") return MENU
def delete_db(update: Update, _: CallbackContext) -> int: logger.info( f"Asking if the user really wants to delete the db. ({update.message.text})" ) if update.message.text != "Go back": message = "✔ Successfully deleted database file\." db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") log_file_path = os.path.join(settings.ROOT_PATH, "logs/crypto_trading.log") try: copyfile(db_file_path, f"{db_file_path}.backup") os.remove(db_file_path) except Exception as e: logger.error(f"❌ Unable to delete database file: {e}") message = "❌ Unable to delete database file\." try: with open(log_file_path, "w") as f: f.truncate() except Exception as e: logger.error(f"❌ Unable to clear log file: {e}") message = "❌ Unable to clear log file\." else: message = "👌 Exited without changes\.\n" "Your database was *not* deleted\." keyboard = [["OK"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") return MENU
def update_tg_bot(update: Update, _: CallbackContext) -> int: logger.info(f"Updating BTB Manager Telegram. ({update.message.text})") if update.message.text != "Cancel update": message = ("The bot is updating\.\n" "Wait a few seconds then start the bot again with /start") keyboard = [["/start"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") try: subprocess.call( f"git pull && $(which python3) -m pip install -r requirements.txt --upgrade && " f'$(which python3) -m btb_manager_telegram -p "{settings.ROOT_PATH}" &', shell=True, ) kill_btb_manager_telegram_process() except Exception as e: logger.error(f"❌ Unable to update BTB Manager Telegram: {e}") message = "Unable to update BTB Manager Telegram" update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") else: message = ("👌 Exited without changes\.\n" "BTB Manager Telegram was *not* updated\.") keyboard = [["OK 👌"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") return MENU
def edit_coin(update: Update, _: CallbackContext) -> int: logger.info(f"Editing coin list. ({update.message.text})") if update.message.text != "/stop": message = (f"✔ Successfully edited coin list file to:\n\n" f"```\n" f"{update.message.text}\n" f"```".replace(".", "\.")) coin_file_path = os.path.join(settings.ROOT_PATH, "supported_coin_list") try: copyfile(coin_file_path, f"{coin_file_path}.backup") with open(coin_file_path, "w") as f: f.write(update.message.text + "\n") except Exception as e: logger.error(f"❌ Unable to edit coin list file: {e}", exc_info=True) message = "❌ Unable to edit coin list file\." else: message = "👌 Exited without changes\.\nYour `supported_coin_list` file was *not* modified\." keyboard = [["Go back"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") return MENU
def edit_user_config(update: Update, _: CallbackContext) -> int: logger.info(f"Editing user configuration. ({update.message.text})") if update.message.text != "/stop": message = (f"✔ Successfully edited user configuration file to:\n\n" f"```\n" f"{update.message.text}\n" f"```".replace(".", "\.")) user_cfg_file_path = os.path.join(settings.ROOT_PATH, "user.cfg") try: copyfile(user_cfg_file_path, f"{user_cfg_file_path}.backup") with open(user_cfg_file_path, "w") as f: f.write(update.message.text + "\n\n\n") except Exception as e: logger.error(f"❌ Unable to edit user configuration file: {e}") message = "❌ Unable to edit user configuration file\." else: message = ("👌 Exited without changes\.\n" "Your `user.cfg` file was *not* modified\.") keyboard = [["Go back"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") return MENU
def check_progress(): logger.info("Progress button pressed.") db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") message = [f"⚠ Unable to find database file at `{db_file_path}`\."] if os.path.exists(db_file_path): try: con = sqlite3.connect(db_file_path) cur = con.cursor() # Get progress information try: cur.execute( """SELECT th1.alt_coin_id AS coin, th1.alt_trade_amount AS amount, th1.crypto_trade_amount AS priceInUSD,(th1.alt_trade_amount - ( SELECT th2.alt_trade_amount FROM trade_history th2 WHERE th2.state = 'COMPLETE' AND th2.alt_coin_id = th1.alt_coin_id AND th1.datetime > th2.datetime AND th2.selling = 0 ORDER BY th2.datetime DESC LIMIT 1)) AS change, (SELECT th2.datetime FROM trade_history th2 WHERE th2.state = 'COMPLETE' AND th2.alt_coin_id = th1.alt_coin_id AND th1.datetime > th2.datetime AND th2.selling = 0 ORDER BY th2.datetime DESC LIMIT 1) AS pre_last_trade_date, datetime FROM trade_history th1 WHERE th1.state = 'COMPLETE' AND th1.selling = 0 ORDER BY th1.datetime DESC LIMIT 15""" ) query = cur.fetchall() # Generate message m_list = ["Current coin amount progress:\n\n"] for coin in query: last_trade_date = datetime.strptime( coin[5], "%Y-%m-%d %H:%M:%S.%f") if coin[4] is None: pre_last_trade_date = datetime.strptime( coin[5], "%Y-%m-%d %H:%M:%S.%f") else: pre_last_trade_date = datetime.strptime( coin[4], "%Y-%m-%d %H:%M:%S.%f") time_passed = last_trade_date - pre_last_trade_date last_trade_date = last_trade_date.strftime( "%H:%M:%S %d/%m/%Y") m_list.append( f"*{coin[0]}*\n" f"\t\- Amount: `{format_float(coin[1])}` *{coin[0]}*\n" f"\t\- Price: `{round(coin[2]*0.71, 2)}` *GBP*\n" f"\t\- Price: `{round(coin[2], 2)}` *USD*\n" f"\t\- Change: {f'`{format_float(coin[3])}` *{coin[0]}* `{round(coin[3] / (coin[1] - coin[3]) * 100, 2)}` *%* in {time_passed.days} days, {time_passed.seconds // 3600} hours' if coin[3] is not None else f'`{coin[3]}`'}\n" f"\t\- Trade datetime: `{last_trade_date}`\n\n". replace(".", "\.")) message = telegram_text_truncator(m_list) con.close() except Exception as e: logger.error( f"❌ Unable to fetch progress information from database: {e}", exc_info=True, ) con.close() return [ "❌ Unable to fetch progress information from database\." ] except Exception as e: logger.error(f"❌ Unable to perform actions on the database: {e}", exc_info=True) message = ["❌ Unable to perform actions on the database\."] return message
def is_tg_bot_update_available(): try: proc = subprocess.Popen( ["bash", "-c", "git remote update && git status -uno"], stdout=subprocess.PIPE, ) output, _ = proc.communicate() re = "Your branch is behind" in str(output) except Exception as e: logger.error(e, exc_info=True) re = None return re
def next_coin(): logger.info("Next coin button pressed.") db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") user_cfg_file_path = os.path.join(settings.ROOT_PATH, "user.cfg") message = [f"⚠ Unable to find database file at `{db_file_path}`\."] if os.path.exists(db_file_path): try: # Get bridge currency symbol with open(user_cfg_file_path) as cfg: config = ConfigParser() config.read_file(cfg) bridge = config.get("binance_user_config", "bridge") scout_multiplier = config.get("binance_user_config", "scout_multiplier") con = sqlite3.connect(db_file_path) cur = con.cursor() # Get prices and percentages for a jump to the next coin try: cur.execute( f"""SELECT p.to_coin_id as other_coin, sh.other_coin_price, (current_coin_price - 0.001 * '{scout_multiplier}' * current_coin_price) / sh.target_ratio AS 'price_needs_to_drop_to', ((current_coin_price - 0.001 * '{scout_multiplier}' * current_coin_price) / sh.target_ratio) / sh.other_coin_price as 'percentage' FROM scout_history sh JOIN pairs p ON p.id = sh.pair_id WHERE p.from_coin_id = (SELECT alt_coin_id FROM trade_history ORDER BY datetime DESC LIMIT 1) ORDER BY sh.datetime DESC, percentage DESC LIMIT (SELECT count(DISTINCT pairs.to_coin_id) FROM pairs JOIN coins ON coins.symbol = pairs.to_coin_id WHERE coins.enabled = 1 AND pairs.from_coin_id=(SELECT alt_coin_id FROM trade_history ORDER BY datetime DESC LIMIT 1));""" ) query = cur.fetchall() m_list = [] for coin in query: percentage = round(coin[3] * 100, 2) m_list.append( f"*{coin[0]} \(`{format_float(percentage)}`%\)*\n" f"\t\- Current Price: `{format_float(round(coin[1], 8))}` {bridge}\n" f"\t\- Target Price: `{format_float(round(coin[2], 8))}` {bridge}\n\n" .replace(".", "\.")) message = telegram_text_truncator(m_list) con.close() except Exception as e: logger.error( f"❌ Something went wrong, unable to generate next coin at this time: {e}", exc_info=True, ) con.close() return [ "❌ Something went wrong, unable to generate next coin at this time\.", "⚠ Please make sure logging for _Binance Trade Bot_ is enabled\.", ] except Exception as e: logger.error(f"❌ Unable to perform actions on the database: {e}", exc_info=True) message = ["❌ Unable to perform actions on the database\."] return message
def is_btb_bot_update_available(): try: proc = subprocess.Popen( [ "bash", "-c", f"cd {settings.ROOT_PATH} && git remote update && git status -uno", ], stdout=subprocess.PIPE, ) output, _ = proc.communicate() re = "Your branch is behind" in str(output) except Exception as e: logger.error(e) re = None return re
def trade_history(): logger.info("Trade history button pressed.") db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") message = [f"⚠ Unable to find database file at `{db_file_path}`\."] if os.path.exists(db_file_path): try: con = sqlite3.connect(db_file_path) cur = con.cursor() # Get last 10 trades try: cur.execute( """SELECT alt_coin_id, crypto_coin_id, selling, state, alt_trade_amount, crypto_trade_amount, datetime FROM trade_history ORDER BY datetime DESC LIMIT 10;""" ) query = cur.fetchall() m_list = [ f"Last **{10 if len(query) > 10 else len(query)}** trades:\n\n" ] for trade in query: if trade[4] is None: continue date = datetime.strptime(trade[6], "%Y-%m-%d %H:%M:%S.%f") m_list.append( f"`{date.strftime('%H:%M:%S %d/%m/%Y')}`\n" f"*{'Sold' if trade[2] else 'Bought'}* `{format_float(trade[4])}` *{trade[0]}*{f' for `{format_float(trade[5])}` *{trade[1]}*' if trade[5] is not None else ''}\n" f"Status: _*{trade[3]}*_\n\n".replace(".", "\.") ) message = telegram_text_truncator(m_list) con.close() except Exception as e: logger.error( f"❌ Something went wrong, unable to generate trade history at this time: {e}", exc_info=True, ) con.close() return [ "❌ Something went wrong, unable to generate trade history at this time\." ] except Exception as e: logger.error( f"❌ Unable to perform actions on the database: {e}", exc_info=True ) message = ["❌ Unable to perform actions on the database\."] return message
def execute_custom_script(update: Update, _: CallbackContext) -> int: logger.info(f"Going to 🤖 execute custom script. ({update.message.text})") keyboard = [["OK 👌"]] reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) custom_scripts_path = "./config/custom_scripts.json" if update.message.text != "Cancel": with open(custom_scripts_path) as f: scripts = json.load(f) try: command = ["bash", "-c", str(scripts[update.message.text])] except Exception as e: logger.error( f"Unable to find script named {update.message.text} in custom_scripts.json file: {e}", exc_info=True, ) message = f"Unable to find script named `{escape_markdown(update.message.text, version=2)}` in `custom_scripts.json` file\." update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") try: proc = subprocess.Popen( command, stdout=subprocess.PIPE, ) output, _ = proc.communicate() message_list = telegram_text_truncator( escape_markdown(output.decode("utf-8"), version=2), padding_chars_head="```\n", padding_chars_tail="```", ) for message in message_list: update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") except Exception as e: logger.error(f"Error during script execution: {e}", exc_info=True) message = "Error during script execution\." update.message.reply_text(message, reply_markup=reply_markup, parse_mode="MarkdownV2") return MENU
def setup_telegram_constants(): logger.info("Retrieving Telegram token and chat_id from apprise.yml file.") telegram_url = None yaml_file_path = os.path.join(settings.ROOT_PATH, "config/apprise.yml") if os.path.exists(yaml_file_path): with open(yaml_file_path) as f: try: parsed_urls = yaml.load(f, Loader=yaml.FullLoader)["urls"] except Exception: logger.error( "Unable to correctly read apprise.yml file. Make sure it is correctly set up. Aborting." ) exit(-1) for url in parsed_urls: if url.startswith("tgram"): telegram_url = url.split("//")[1] if not telegram_url: logger.error( "No telegram configuration was found in your apprise.yml file. Aborting." ) exit(-1) else: logger.error( f'Unable to find apprise.yml file at "{yaml_file_path}". Aborting.' ) exit(-1) try: settings.TOKEN = telegram_url.split("/")[0] settings.CHAT_ID = telegram_url.split("/")[1] logger.info( f"Successfully retrieved Telegram configuration. " f"The bot will only respond to user in the chat with chat_id {settings.CHAT_ID}" ) except Exception: logger.error( "No chat_id has been set in the yaml configuration, anyone would be able to control your bot. Aborting." ) exit(-1)
def panic_btn(): logger.info("🚨 Panic Button button pressed.") # Check if open orders / not in usd db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") if not os.path.exists(db_file_path): return ["ERROR: Database file not found\.", -1] user_cfg_file_path = os.path.join(settings.ROOT_PATH, "user.cfg") if not os.path.exists(user_cfg_file_path): return ["ERROR: `user.cfg` file not found\.", -1] try: con = sqlite3.connect(db_file_path) cur = con.cursor() # Get last trade try: cur.execute( """SELECT alt_coin_id, crypto_coin_id, selling, state, alt_trade_amount, crypto_trade_amount FROM trade_history ORDER BY datetime DESC LIMIT 1;""" ) ( alt_coin_id, crypto_coin_id, selling, state, alt_trade_amount, crypto_trade_amount, ) = cur.fetchone() if not selling: price_old = crypto_trade_amount / alt_trade_amount price_now = get_current_price(alt_coin_id, crypto_coin_id) if state == "COMPLETE": return [ f"You are currently holding `{round(alt_trade_amount, 6)}` *{alt_coin_id}* bought for `{round(crypto_trade_amount, 2)}` *{crypto_coin_id}*.\n\n" f"Exchange rate when bought:\n" f"`{round(price_old, 4)}` *{crypto_coin_id}*/*{alt_coin_id}*\n\n" f"Current exchange rate:\n" f"`{round(price_now, 4)}` *{crypto_coin_id}*/*{alt_coin_id}*\n\n" f"Current value:\n" f"`{round(price_now * alt_trade_amount, 4)}` *{crypto_coin_id}*\n\n" f"Change:\n" f"`{round((price_now - price_old) / price_old * 100, 2)}` *%*\n\n" f"Would you like to stop _Binance Trade Bot_ and sell at market price?" .replace(".", "\."), BOUGHT, ] else: return [ f"You have an open buy order of `{alt_trade_amount}` *{alt_coin_id}* for `{crypto_trade_amount}` *{crypto_coin_id}*.\n\n" f"Limit buy at price:\n" f"`{round(price_old, 4)}` *{crypto_coin_id}*/*{alt_coin_id}*\n\n" f"Current exchange rate:\n" f"`{round(price_now, 4)}` *{crypto_coin_id}*/*{alt_coin_id}*\n\n" f"Change:\n" f"`{round((price_now - price_old) / price_old * 100, 2)}` *%*\n\n" f"Would you like to stop _Binance Trade Bot_ and cancel the open order?" .replace(".", "\."), BUYING, ] else: if state == "COMPLETE": return [ f"Your balance is already in *{crypto_coin_id}*.\n\n" f"Would you like to stop _Binance Trade Bot_?".replace( ".", "\."), SOLD, ] else: price_old = crypto_trade_amount / alt_trade_amount price_now = get_current_price(alt_coin_id, crypto_coin_id) return [ f"You have an open sell order of `{alt_trade_amount}` *{alt_coin_id}* for `{crypto_trade_amount}` *{crypto_coin_id}*.\n\n" f"Limit sell at price:\n" f"`{round(price_old, 4)}` *{crypto_coin_id}*/*{alt_coin_id}*\n\n" f"Current exchange rate:\n" f"`{round(price_now, 4)}` *{crypto_coin_id}*/*{alt_coin_id}*\n\n" f"Change:\n" f"`{round((price_now - price_old) / price_old * 100, 2)}` *%*\n\n" f"Would you like to stop _Binance Trade Bot_ and cancel the open order?" .replace(".", "\."), SELLING, ] con.close() except Exception as e: con.close() logger.error( f"❌ Something went wrong, the panic button is not working at this time: {e}", exc_info=True, ) return [ "❌ Something went wrong, the panic button is not working at this time\.", -1, ] except Exception as e: logger.error(f"❌ Unable to perform actions on the database: {e}", exc_info=True) return ["❌ Unable to perform actions on the database\.", -1]
def current_ratios(): logger.info("Current ratios button pressed.") db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") user_cfg_file_path = os.path.join(settings.ROOT_PATH, "user.cfg") message = [f"⚠ Unable to find database file at `{db_file_path}`\."] if os.path.exists(db_file_path): try: # Get bridge currency symbol with open(user_cfg_file_path) as cfg: config = ConfigParser() config.read_file(cfg) bridge = config.get("binance_user_config", "bridge") scout_multiplier = config.get("binance_user_config", "scout_multiplier") con = sqlite3.connect(db_file_path) cur = con.cursor() # Get current coin symbol try: cur.execute( """SELECT alt_coin_id FROM trade_history ORDER BY datetime DESC LIMIT 1;""" ) current_coin = cur.fetchone()[0] if current_coin is None: raise Exception() except Exception as e: logger.error( f"❌ Unable to fetch current coin from database: {e}", exc_info=True) con.close() return ["❌ Unable to fetch current coin from database\."] # Get prices and ratios of all alt coins try: cur.execute( f"""SELECT sh.datetime, p.to_coin_id, sh.other_coin_price, ( ( ( current_coin_price / other_coin_price ) - 0.001 * '{scout_multiplier}' * ( current_coin_price / other_coin_price ) ) - sh.target_ratio ) AS 'ratio_dict' FROM scout_history sh JOIN pairs p ON p.id = sh.pair_id WHERE p.from_coin_id='{current_coin}' AND p.from_coin_id = ( SELECT alt_coin_id FROM trade_history ORDER BY datetime DESC LIMIT 1) ORDER BY sh.datetime DESC LIMIT ( SELECT count(DISTINCT pairs.to_coin_id) FROM pairs JOIN coins ON coins.symbol = pairs.to_coin_id WHERE coins.enabled = 1 AND pairs.from_coin_id='{current_coin}');""" ) query = cur.fetchall() # Generate message last_update = datetime.strptime(query[0][0], "%Y-%m-%d %H:%M:%S.%f") query = sorted(query, key=lambda k: k[-1], reverse=True) m_list = [ f"\nLast update: `{last_update.strftime('%H:%M:%S %d/%m/%Y')}`\n\n" f"*Coin ratios compared to {current_coin} in decreasing order:*\n" .replace(".", "\.") ] for coin in query: m_list.append( f"*{coin[1]}*:\n" f"\t\- Price: `{coin[2]}` {bridge}\n" f"\t\- Ratio: `{format_float(coin[3])}`\n\n".replace( ".", "\.")) message = telegram_text_truncator(m_list) con.close() except Exception as e: logger.error( f"❌ Something went wrong, unable to generate ratios at this time: {e}", exc_info=True, ) con.close() return [ "❌ Something went wrong, unable to generate ratios at this time\.", "⚠ Please make sure logging for _Binance Trade Bot_ is enabled\.", ] except Exception as e: logger.error(f"❌ Unable to perform actions on the database: {e}", exc_info=True) message = ["❌ Unable to perform actions on the database\."] return message
def current_value(): logger.info("Current value button pressed.") db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") message = [f"⚠ Unable to find database file at `{db_file_path}`\."] if os.path.exists(db_file_path): try: con = sqlite3.connect(db_file_path) cur = con.cursor() # Get current coin symbol, bridge symbol, order state, order size, initial buying price try: cur.execute( """SELECT alt_coin_id, crypto_coin_id, state, alt_trade_amount, crypto_starting_balance, crypto_trade_amount FROM trade_history ORDER BY datetime DESC LIMIT 1;""" ) ( current_coin, bridge, state, alt_amount, order_size, buy_price, ) = cur.fetchone() if current_coin is None: raise Exception() if state == "ORDERED": return [ f"A buy order of `{format_float(order_size)}` *{bridge}* is currently placed on coin *{current_coin}*.\n\n" f"_Waiting for buy order to complete_.".replace( ".", "\.") ] except Exception as e: logger.error( f"❌ Unable to fetch current coin from database: {e}", exc_info=True) con.close() return ["❌ Unable to fetch current coin from database\."] # Get balance, current coin price in USD, current coin price in BTC try: cur.execute(f"""SELECT balance, usd_price, btc_price, datetime FROM 'coin_value' WHERE coin_id = '{current_coin}' ORDER BY datetime DESC LIMIT 1;""") query = cur.fetchone() cur.execute("""SELECT cv.balance, cv.usd_price FROM coin_value as cv WHERE cv.coin_id = (SELECT th.alt_coin_id FROM trade_history as th WHERE th.datetime > DATETIME ('now', '-1 day') AND th.selling = 0 ORDER BY th.datetime ASC LIMIT 1) AND cv.datetime > (SELECT th.datetime FROM trade_history as th WHERE th.datetime > DATETIME ('now', '-1 day') AND th.selling = 0 ORDER BY th.datetime ASC LIMIT 1) ORDER BY cv.datetime ASC LIMIT 1;""") query_1_day = cur.fetchone() cur.execute("""SELECT cv.balance, cv.usd_price FROM coin_value as cv WHERE cv.coin_id = (SELECT th.alt_coin_id FROM trade_history as th WHERE th.datetime > DATETIME ('now', '-7 day') AND th.selling = 0 ORDER BY th.datetime ASC LIMIT 1) AND cv.datetime > (SELECT th.datetime FROM trade_history as th WHERE th.datetime > DATETIME ('now', '-7 day') AND th.selling = 0 ORDER BY th.datetime ASC LIMIT 1) ORDER BY cv.datetime ASC LIMIT 1;""") query_7_day = cur.fetchone() if query is None: return [ f"❌ No information about *{current_coin}* available in the database\.", "⚠ If you tried using the `Current value` button during a trade please try again after the trade has been completed\.", ] balance, usd_price, btc_price, last_update = query if balance is None: balance = 0 if usd_price is None: usd_price = 0 if btc_price is None: btc_price = 0 last_update = datetime.strptime(last_update, "%Y-%m-%d %H:%M:%S.%f") return_rate_1_day, return_rate_7_day = 0, 0 balance_1_day, usd_price_1_day, balance_7_day, usd_price_7_day = ( 0, 0, 0, 0, ) if (query_1_day is not None and all(elem is not None for elem in query_1_day) and usd_price != 0): balance_1_day, usd_price_1_day = query_1_day return_rate_1_day = round( (balance * usd_price - balance_1_day * usd_price_1_day) / (balance_1_day * usd_price_1_day) * 100, 2, ) if (query_7_day is not None and all(elem is not None for elem in query_7_day) and usd_price != 0): balance_7_day, usd_price_7_day = query_7_day return_rate_7_day = round( (balance * usd_price - balance_7_day * usd_price_7_day) / (balance_7_day * usd_price_7_day) * 100, 2, ) except Exception as e: logger.error( f"❌ Unable to fetch current coin information from database: {e}", exc_info=True, ) con.close() return [ "❌ Unable to fetch current coin information from database\.", "⚠ If you tried using the `Current value` button during a trade please try again after the trade has been completed\.", ] # Generate message try: m_list = [ f"\nLast update: `{last_update.strftime('%H:%M:%S %d/%m/%Y')}`\n\n" f"*Current coin {current_coin}:*\n" f"\t\- Balance: `{format_float(balance)}` *{current_coin}*\n" f"\t\- Exchange rate purchased: `{format_float(buy_price / alt_amount)}` *{bridge}*/*{current_coin}* \n" f"\t\- Exchange rate now: `{format_float(usd_price)}` *USD*/*{current_coin}*\n" f"\t\- Change in value: `{round((balance * usd_price - buy_price) / buy_price * 100, 2)}` *%*\n" f"\t\- Value in *GBP*: `{round((balance * usd_price)*0.71, 2)}` *GBP*\n" f"\t\- Value in *USD*: `{round(balance * usd_price, 2)}` *USD*\n" f"\t\- Value in *BTC*: `{format_float(balance * btc_price)}` *BTC*\n\n" f"_Bought for_ `{round(buy_price, 2)}` *{bridge}* / `{round(buy_price*0.71, 2)}` *GBP*\n" f"_*1 day* value change USD_: `{return_rate_1_day}` *%*\n" f"_*7 days* value change USD_: `{return_rate_7_day}` *%*\n" ] message = telegram_text_truncator(m_list) con.close() except Exception as e: logger.error( f"❌ Something went wrong, unable to generate value at this time: {e}", exc_info=True, ) con.close() return [ "❌ Something went wrong, unable to generate value at this time\." ] except Exception as e: logger.error(f"❌ Unable to perform actions on the database: {e}", exc_info=True) message = ["❌ Unable to perform actions on the database\."] return message
def current_value(): logger.info("Current value button pressed.") db_file_path = os.path.join(settings.ROOT_PATH, "data/crypto_trading.db") message = [f"⚠ Unable to find database file at `{db_file_path}`\."] if os.path.exists(db_file_path): try: con = sqlite3.connect(db_file_path) cur = con.cursor() # Get current coin symbol, bridge symbol, order state, order size, initial buying price try: cur.execute( """SELECT alt_coin_id, crypto_coin_id, state, alt_trade_amount, crypto_starting_balance, crypto_trade_amount FROM trade_history ORDER BY datetime DESC LIMIT 1;""" ) ( current_coin, bridge, state, alt_amount, order_size, buy_price, ) = cur.fetchone() if current_coin is None: raise Exception() if state == "ORDERED": return [ f"A buy order of `{format_float(order_size)}` *{bridge}* is currently placed on coin *{current_coin}*.\n\n" f"_Waiting for buy order to complete_.".replace(".", "\.") ] except Exception as e: logger.error( f"❌ Unable to fetch current coin from database: {e}", exc_info=True ) con.close() return ["❌ Unable to fetch current coin from database\."] # Get balance, current coin price in USD, current coin price in BTC try: cur.execute( f"""SELECT balance, usd_price, btc_price, datetime FROM 'coin_value' WHERE coin_id = '{current_coin}' ORDER BY datetime DESC LIMIT 1;""" ) query = cur.fetchone() if query is None: return [ f"❌ No information about *{current_coin}* available in the database\.", "⚠ If you tried using the `Current value` button during a trade please try again after the trade has been completed\.", ] balance, usd_price, btc_price, last_update = query if balance is None: balance = 0 if usd_price is None: usd_price = 0 if btc_price is None: btc_price = 0 last_update = datetime.strptime(last_update, "%Y-%m-%d %H:%M:%S.%f") except Exception as e: logger.error( f"❌ Unable to fetch current coin information from database: {e}", exc_info=True, ) con.close() return [ "❌ Unable to fetch current coin information from database\.", "⚠ If you tried using the `Current value` button during a trade please try again after the trade has been completed\.", ] # Generate message try: m_list = [ f"\nLast update: `{last_update.strftime('%H:%M:%S %d/%m/%Y')}`\n\n" f"*Current coin {current_coin}:*\n" f"\t\- Balance: `{format_float(balance)}` *{current_coin}*\n" f"\t\- Current coin exchange rate: `{format_float(usd_price)}` *USD*/*{current_coin}*\n" f"\t\- Value in *USD*: `{round(balance * usd_price, 2)}` *USD*\n" f"\t\- Value in *BTC*: `{format_float(balance * btc_price)}` *BTC*\n\n" f"_Initially bought for_ `{round(buy_price, 2)}` *{bridge}*\n" f"_Exchange rate when purchased:_ `{format_float(buy_price / alt_amount)}` *{bridge}*/*{current_coin}*\n" f"{f'*Change in value*: `{round((balance * usd_price - buy_price) / buy_price * 100, 2)}` *%*' if bridge in ['USDT', 'BUSD'] else ''}".replace( ".", "\." ) ] message = telegram_text_truncator(m_list) con.close() except Exception as e: logger.error( f"❌ Something went wrong, unable to generate value at this time: {e}", exc_info=True, ) con.close() return [ "❌ Something went wrong, unable to generate value at this time\." ] except Exception as e: logger.error( f"❌ Unable to perform actions on the database: {e}", exc_info=True ) message = ["❌ Unable to perform actions on the database\."] return message