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 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
Beispiel #3
0
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
Beispiel #5
0
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 `{round(order_size, 2)}` *{bridge}* is currently placed on coin *{current_coin}*.\n\n"
                        f"_Waiting for buy order to complete_.".replace(".", "\.")
                    ]
            except Exception:
                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:
                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: `{round(balance, 6)}` *{current_coin}*\n"
                    f"\t\- Current coin exchange ratio: `{round(usd_price, 6)}` *USD*/*{current_coin}*\n"
                    f"\t\- Value in *USD*: `{round((balance * usd_price), 2)}` *USD*\n"
                    f"\t\- Value in *BTC*: `{round((balance * btc_price), 6)}` *BTC*\n\n"
                    f"_Initially bought for_ {round(buy_price, 2)} *{bridge}*\n"
                    f"_Exchange ratio when purchased:_ `{round((buy_price / alt_amount), 6)}` *{bridge}*/*{current_coin}*".replace(
                        ".", "\."
                    )
                ]
                message = telegram_text_truncator(m_list)
                con.close()
            except Exception:
                con.close()
                return [
                    "❌ Something went wrong, unable to generate value at this time\."
                ]
        except Exception:
            message = ["❌ Unable to perform actions on the database\."]
    return message
Beispiel #6
0
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")

            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:
                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 * 5 * ( 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 WHERE 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}:*\n".replace(".", "\.")
                ]
                for coin in query:
                    m_list.append(
                        f"*{coin[1]}*:\n"
                        f"\t\- Price: `{coin[2]}` {bridge}\n"
                        f"\t\- Ratio: `{round(coin[3], 6)}`\n\n".replace(".", "\.")
                    )

                message = telegram_text_truncator(m_list)
                con.close()
            except Exception:
                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:
            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