forked from kodorvan/stcs
		
	
		
			
				
	
	
		
			171 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
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": "️️Лимит ставки меньше минимально допустимого",
 | 
						||
                "Order placement failed as your position may exceed the max":
 | 
						||
                    "Не удалось разместить ордер, так как ваша позиция может превышать максимальный лимит."
 | 
						||
                    "Пожалуйста, уменьшите кредитное плечо, чтобы увеличить максимальное значение"
 | 
						||
            }
 | 
						||
 | 
						||
            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,
 | 
						||
        )
 |