import logging.config import math import app.telegram.keyboards.inline as kbi import database.request as rq from app.bybit.get_functions.get_instruments_info import get_instruments_info from app.bybit.logger_bybit.logger_bybit import LOGGING_CONFIG from app.bybit.open_positions import trading_cycle, trading_cycle_profit from app.bybit.set_functions.set_tp_sl import set_tp_sl_for_position from app.helper_functions import format_value, safe_float, truncate_float logging.config.dictConfig(LOGGING_CONFIG) logger = logging.getLogger("telegram_message_handler") class TelegramMessageHandler: def __init__(self, telegram_bot): self.telegram_bot = telegram_bot async def format_order_update(self, message, tg_id): try: user_additional_data = await rq.get_user_additional_settings(tg_id=tg_id) trigger_price = safe_float(user_additional_data.trigger_price) if trigger_price > 0: order_data = message.get("data", [{}])[0] symbol = format_value(order_data.get("symbol")) side = format_value(order_data.get("side")) side_rus = ( "Покупка" if side == "Buy" else "Продажа" if side == "Sell" else "Нет данных" ) order_status = format_value(order_data.get("orderStatus")) tr_price = format_value(order_data.get("triggerPrice")) status_map = { "Untriggered": "Условный ордер выставлен", } if order_status == "Filled" or order_status not in status_map: return None text = ( f"Торговая пара: {symbol}\n" f"Движение: {side_rus}\n" ) if tr_price and tr_price != "Нет данных": text += f"Триггер цена: {tr_price}\n" await self.telegram_bot.send_message( chat_id=tg_id, text=text, reply_markup=kbi.profile_bybit ) await rq.set_trigger_price(tg_id=tg_id, trigger_price=0) except Exception as e: logger.error("Error in format_order_update: %s", e) async def format_execution_update(self, message, tg_id): try: execution = message.get("data", [{}])[0] closed_size = format_value(execution.get("closedSize")) symbol = format_value(execution.get("symbol")) exec_price = format_value(execution.get("execPrice")) exec_qty = format_value(execution.get("execQty")) exec_fees = format_value(execution.get("execFee")) fee_rate = format_value(execution.get("feeRate")) side = format_value(execution.get("side")) side_rus = ( "Покупка" if side == "Buy" else "Продажа" if side == "Sell" else "Нет данных" ) if safe_float(exec_fees) == 0: exec_fee = safe_float(exec_price) * safe_float(exec_qty) * safe_float( fee_rate ) else: exec_fee = safe_float(exec_fees) if safe_float(closed_size) == 0: await rq.set_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, fee=safe_float(exec_fee) ) user_auto_trading = await rq.get_user_auto_trading( tg_id=tg_id, symbol=symbol ) get_total_fee = user_auto_trading.total_fee total_fee = safe_float(exec_fee) + safe_float(get_total_fee) exec_pnl = format_value(execution.get("execPnl")) ex_pnl = safe_float(exec_pnl) pnl = safe_float(exec_pnl) header = ( "Сделка закрыта:" if safe_float(closed_size) > 0 else "Сделка открыта:" ) text = f"{header}\n" f"Торговая пара: {symbol}\n" auto_trading = ( user_auto_trading.auto_trading if user_auto_trading else False ) user_deals_data = await rq.get_user_deal_by_symbol( tg_id=tg_id, symbol=symbol ) commission_fee = user_deals_data.commission_fee commission_place = user_deals_data.commission_place current_series = user_deals_data.current_series current_step = user_deals_data.current_step order_quantity = user_deals_data.order_quantity pnl_series = user_deals_data.pnl_series margin_type = user_deals_data.margin_type take_profit_percent = user_deals_data.take_profit_percent stop_loss_percent = user_deals_data.stop_loss_percent fee = safe_float(user_auto_trading.fee) total_pnl = safe_float(exec_pnl) - safe_float(exec_fee) - fee leverage = safe_float(user_deals_data.leverage) if commission_fee == "Yes_commission_fee": if commission_place == "Commission_for_qty": total_quantity = safe_float(order_quantity) + safe_float( total_fee ) * 2 else: total_quantity = safe_float(order_quantity) else: total_quantity = safe_float(order_quantity) if user_deals_data is not None and auto_trading and safe_float(closed_size) == 0: await rq.set_total_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, total_fee=total_fee ) text += f"Текущая ставка: {total_quantity:.2f} USDT\n" text += f"Серия №: {current_series}\n" text += f"Сделка №: {current_step}\n" text += ( f"Цена исполнения: {exec_price}\n" f"Комиссия: {exec_fee:.8f}\n" ) if safe_float(closed_size) == 0: instruments_info = await get_instruments_info(tg_id=tg_id, symbol=symbol) qty_step_str = instruments_info.get("lotSizeFilter").get("qtyStep") qty_step = safe_float(qty_step_str) qty = (safe_float(order_quantity) * safe_float(leverage)) / safe_float(exec_price) decimals = abs(int(round(math.log10(qty_step)))) qty_format = math.floor(qty / qty_step) * qty_step qty_formatted = round(qty_format, decimals) total_commission = 0 if commission_fee == "Yes_commission_fee": if commission_place == "Commission_for_tp": total_commission = safe_float(total_fee) / qty_formatted if margin_type == "ISOLATED_MARGIN": if side == "Buy": take_profit_price = safe_float(exec_price) * ( 1 + take_profit_percent / 100) + total_commission stop_loss_price = None else: take_profit_price = safe_float(exec_price) * ( 1 - take_profit_percent / 100) - total_commission stop_loss_price = None else: if side == "Buy": take_profit_price = safe_float(exec_price) * ( 1 + take_profit_percent / 100) + total_commission stop_loss_price = safe_float(exec_price) * (1 - stop_loss_percent / 100) else: take_profit_price = safe_float(exec_price) * ( 1 - take_profit_percent / 100) - total_commission stop_loss_price = safe_float(exec_price) * (1 + stop_loss_percent / 100) take_profit_price = max(take_profit_price, 0) stop_loss_price = max(stop_loss_price, 0) await set_tp_sl_for_position(tg_id=tg_id, symbol=symbol, take_profit_price=take_profit_price, stop_loss_price=stop_loss_price, position_idx=0) take_profit_truncated = await truncate_float(take_profit_price, 4) stop_loss_truncated = await truncate_float(stop_loss_price, 4) text += (f"Движение: {side_rus}\n" f"Тейк-профит: {take_profit_truncated}\n" f"Стоп-лосс: {stop_loss_truncated}\n" ) else: new_pnl = safe_float(pnl_series) + total_pnl await rq.set_pnl_series_by_symbol( tg_id=tg_id, symbol=symbol, pnl_series=new_pnl) text += f"\nДоход: {ex_pnl:.4f}\n" text += f"Реализованный PNL: {total_pnl:.4f}\n" text += f"Прибыль серии: {safe_float(new_pnl):.4f}\n" await self.telegram_bot.send_message( chat_id=tg_id, text=text, reply_markup=kbi.profile_bybit ) user_symbols = user_auto_trading.symbol if user_auto_trading else None if ( auto_trading and safe_float(closed_size) > 0 and user_symbols is not None ): if safe_float(pnl) > 0: profit_text = "📈 Начинаю новую серию с базовой ставки\n" await self.telegram_bot.send_message( chat_id=tg_id, text=profit_text, reply_markup=kbi.profile_bybit ) if side == "Buy": r_side = "Sell" else: r_side = "Buy" await rq.set_last_side_by_symbol( tg_id=tg_id, symbol=symbol, last_side=r_side) await rq.set_total_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, total_fee=0 ) await rq.set_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, fee=0 ) await rq.set_pnl_series_by_symbol(tg_id=tg_id, symbol=symbol, pnl_series=0) res = await trading_cycle_profit( tg_id=tg_id, symbol=symbol, side=r_side ) if res == "OK": pass else: errors = { "Max bets in series": "❗️ Максимальное количество сделок в серии достигнуто", "Risk is too high for this trade": "❗️ Риск сделки слишком высок для продолжения", "ab not enough for new order": "❗️ Недостаточно средств для продолжения торговли", "InvalidRequestError": "❗️ Недостаточно средств для размещения нового ордера с заданным количеством и плечом.", "The number of contracts exceeds maximum limit allowed": "❗️ Превышен максимальный лимит ставки", } error_text = errors.get( res, "❗️ Не удалось открыть новую сделку" ) await rq.set_auto_trading( tg_id=tg_id, symbol=symbol, auto_trading=False ) await rq.set_total_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, total_fee=0 ) await rq.set_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, fee=0 ) await self.telegram_bot.send_message( chat_id=tg_id, text=error_text, reply_markup=kbi.profile_bybit, ) else: open_order_text = "\n❗️ Открываю новую сделку с увеличенной ставкой.\n" await self.telegram_bot.send_message( chat_id=tg_id, text=open_order_text ) if side == "Buy": r_side = "Sell" else: r_side = "Buy" res = await trading_cycle( tg_id=tg_id, symbol=symbol, side=r_side ) if res == "OK": pass else: errors = { "Max bets in series": "❗️ Максимальное количество сделок в серии достигнуто", "Risk is too high for this trade": "❗️ Риск сделки слишком высок для продолжения", "ab not enough for new order": "❗️ Недостаточно средств для продолжения торговли", "InvalidRequestError": "❗️ Недостаточно средств для размещения нового ордера с заданным количеством и плечом.", "The number of contracts exceeds maximum limit allowed": "❗️ Превышен максимальный лимит ставки", } error_text = errors.get( res, "❗️ Не удалось открыть новую сделку" ) await rq.set_auto_trading( tg_id=tg_id, symbol=symbol, auto_trading=False ) await rq.set_total_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, total_fee=0 ) await rq.set_fee_user_auto_trading( tg_id=tg_id, symbol=symbol, fee=0 ) await self.telegram_bot.send_message( chat_id=tg_id, text=error_text, reply_markup=kbi.profile_bybit, ) except Exception as e: logger.error("Error in telegram_message_handler: %s", e, exc_info=True)