import asyncio import logging.config from aiogram import F, Router from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery import app.telegram.keyboards.inline as kbi import database.request as rq from app.bybit.get_functions.get_positions import get_active_positions_by_symbol, get_active_orders_by_symbol from app.bybit.open_positions import start_trading_cycle from app.helper_functions import safe_float from app.telegram.tasks.tasks import ( add_start_task_merged, cancel_start_task_merged ) from logger_helper.logger_helper import LOGGING_CONFIG logging.config.dictConfig(LOGGING_CONFIG) logger = logging.getLogger("start_trading") router_start_trading = Router(name="start_trading") @router_start_trading.callback_query(F.data == "start_trading") async def start_trading(callback_query: CallbackQuery, state: FSMContext) -> None: """ Handles the "start_trading" callback query. Clears the FSM state and sends a message to the user to select the trading mode. :param callback_query: Message :param state: FSMContext :return: None """ try: await state.clear() tg_id = callback_query.from_user.id symbol = await rq.get_user_symbol(tg_id=callback_query.from_user.id) deals = await get_active_positions_by_symbol( tg_id=callback_query.from_user.id, symbol=symbol ) position = next((d for d in deals if d.get("symbol") == symbol), None) if position: size = position.get("size", 0) else: size = 0 if safe_float(size) > 0: await callback_query.answer( text="У вас есть активная позиция по текущей паре", ) return orders = await get_active_orders_by_symbol( tg_id=callback_query.from_user.id, symbol=symbol) if orders is not None: await callback_query.answer( text="У вас есть активный ордер по текущей паре", ) return conditional_data = await rq.get_user_conditional_settings( tg_id=callback_query.from_user.id ) timer_start = conditional_data.timer_start cancel_start_task_merged(user_id=callback_query.from_user.id) async def delay_start(): if timer_start > 0: await callback_query.message.edit_text( text=f"Торговля будет запущена с задержкой {timer_start} мин.", reply_markup=kbi.cancel_timer_merged, ) await rq.set_start_timer( tg_id=callback_query.from_user.id, timer_start=0 ) await asyncio.sleep(timer_start * 60) await rq.set_auto_trading( tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True, ) 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 ) res = await start_trading_cycle( tg_id=callback_query.from_user.id, ) error_messages = { "Limit price is out min price": "Цена лимитного ордера меньше допустимого", "Limit price is out max price": "Цена лимитного ордера больше допустимого", "Risk is too high for this trade": "Риск сделки превышает допустимый убыток", "estimated will trigger liq": "Лимитный ордер может вызвать мгновенную ликвидацию. Проверьте параметры ордера.", "ab not enough for new order": "Недостаточно средств для создания нового ордера", "InvalidRequestError": "Произошла ошибка при запуске торговли.", "Order does not meet minimum order value": "Сумма ставки меньше допустимого для запуска торговли. " "Увеличьте ставку, чтобы запустить торговлю", "position idx not match position mode": "Измените режим позиции, чтобы запустить торговлю", "Qty invalid": "Некорректное значение ставки для данного инструмента", "The number of contracts exceeds maximum limit allowed": "️️Превышен максимальный лимит ставки", "The number of contracts exceeds minimum limit allowed": "️️Лимит ставки меньше минимально допустимого", } if res == "OK": await callback_query.message.edit_text(text="Торговля запущена") await state.clear() else: await rq.set_auto_trading( tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, ) text = error_messages.get(res, "Произошла ошибка при запуске торговли") await callback_query.message.edit_text( text=text, reply_markup=kbi.profile_bybit ) await callback_query.message.edit_text("Запуск торговли...") task = asyncio.create_task(delay_start()) await add_start_task_merged(user_id=callback_query.from_user.id, task=task) except Exception as e: await callback_query.answer(text="Произошла ошибка при запуске торговли") logger.error( "Error processing command start_trading for user %s: %s", callback_query.from_user.id, e, ) except asyncio.CancelledError: logger.error("Cancelled timer for user %s", callback_query.from_user.id) @router_start_trading.callback_query( lambda c: c.data == "cancel_timer_merged" ) async def cancel_start_trading( callback_query: CallbackQuery, state: FSMContext ) -> None: """ Handles the "cancel_timer" callback query. Clears the FSM state and sends a message to the user to cancel the start trading process. :param callback_query: Message :param state: FSMContext :return: None """ try: await state.clear() if callback_query.data == "cancel_timer_merged": cancel_start_task_merged(user_id=callback_query.from_user.id) await callback_query.message.edit_text( text="Запуск торговли отменен", reply_markup=kbi.profile_bybit ) except Exception as e: await callback_query.answer("Произошла ошибка при отмене запуска торговли") logger.error( "Error processing command cancel_timer for user %s: %s", callback_query.from_user.id, e, )