forked from kodorvan/stcs
		
	
		
			
				
	
	
		
			423 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import logging.config
 | 
						|
 | 
						|
from aiogram import F, Router
 | 
						|
from aiogram.fsm.context import FSMContext
 | 
						|
from aiogram.types import CallbackQuery, Message
 | 
						|
 | 
						|
import app.telegram.keyboards.inline as kbi
 | 
						|
import database.request as rq
 | 
						|
from app.helper_functions import is_number, safe_float
 | 
						|
from app.telegram.states.states import RiskManagementState
 | 
						|
from logger_helper.logger_helper import LOGGING_CONFIG
 | 
						|
 | 
						|
logging.config.dictConfig(LOGGING_CONFIG)
 | 
						|
logger = logging.getLogger("risk_management")
 | 
						|
 | 
						|
router_risk_management = Router(name="risk_management")
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.callback_query(F.data == "take_profit_percent")
 | 
						|
async def take_profit_percent(callback_query: CallbackQuery, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles the 'profit_price_change' callback query.
 | 
						|
 | 
						|
    Clears the current FSM state, edits the message text to display the take profit percent options,
 | 
						|
    and shows an inline keyboard for selection.
 | 
						|
 | 
						|
    Args:
 | 
						|
        callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        await state.clear()
 | 
						|
        await state.set_state(RiskManagementState.take_profit_percent_state)
 | 
						|
        msg = await callback_query.message.edit_text(
 | 
						|
            text="Введите процент изменения цены для фиксации прибыли: ",
 | 
						|
            reply_markup=kbi.back_to_risk_management,
 | 
						|
        )
 | 
						|
        await state.update_data(prompt_message_id=msg.message_id)
 | 
						|
        logger.debug(
 | 
						|
            "Command profit_price_change processed successfully for user: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
        )
 | 
						|
    except Exception as e:
 | 
						|
        await callback_query.answer(
 | 
						|
            text="Произошла ошибка. Пожалуйста, попробуйте позже."
 | 
						|
        )
 | 
						|
        logger.error(
 | 
						|
            "Error processing command profit_price_change for user %s: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.message(RiskManagementState.take_profit_percent_state)
 | 
						|
async def set_take_profit_percent(message: Message, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles user input for setting the take profit percentage.
 | 
						|
 | 
						|
    Updates FSM context with the selected percentage and persists the choice in database.
 | 
						|
    Sends an acknowledgement to user and clears FSM state afterward.
 | 
						|
 | 
						|
    Args:
 | 
						|
        message (Message): Incoming message from user containing the take profit percentage.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        try:
 | 
						|
            data = await state.get_data()
 | 
						|
            if "prompt_message_id" in data:
 | 
						|
                prompt_message_id = data["prompt_message_id"]
 | 
						|
                await message.bot.delete_message(
 | 
						|
                    chat_id=message.chat.id, message_id=prompt_message_id
 | 
						|
                )
 | 
						|
            await message.delete()
 | 
						|
        except Exception as e:
 | 
						|
            if "message to delete not found" in str(e).lower():
 | 
						|
                pass  # Ignore this error
 | 
						|
            else:
 | 
						|
                raise e
 | 
						|
 | 
						|
        take_profit_percent_value = message.text
 | 
						|
 | 
						|
        if not is_number(take_profit_percent_value):
 | 
						|
            await message.answer(
 | 
						|
                text="Ошибка: введите валидное число.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
            logger.debug(
 | 
						|
                "User %s input invalid (not an valid number): %s",
 | 
						|
                message.from_user.id,
 | 
						|
                take_profit_percent_value,
 | 
						|
            )
 | 
						|
            return
 | 
						|
 | 
						|
        if safe_float(take_profit_percent_value) < 0.1 or safe_float(take_profit_percent_value) > 100:
 | 
						|
            await message.answer(
 | 
						|
                text="Ошибка: введите число от 1 до 100.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
            logger.debug(
 | 
						|
                "User %s input invalid (not an valid number): %s",
 | 
						|
                message.from_user.id,
 | 
						|
                take_profit_percent_value,
 | 
						|
            )
 | 
						|
            return
 | 
						|
 | 
						|
        req = await rq.set_take_profit_percent(
 | 
						|
            tg_id=message.from_user.id,
 | 
						|
            take_profit_percent=safe_float(take_profit_percent_value),
 | 
						|
        )
 | 
						|
 | 
						|
        if req:
 | 
						|
            await message.answer(
 | 
						|
                text=f"Процент изменения цены для фиксации прибыли "
 | 
						|
                f"установлен на {take_profit_percent_value}%.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            await message.answer(
 | 
						|
                text="Произошла ошибка при установке процента изменения цены для фиксации прибыли. "
 | 
						|
                "Пожалуйста, попробуйте позже.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
 | 
						|
        await state.clear()
 | 
						|
    except Exception as e:
 | 
						|
        logger.error(
 | 
						|
            "Error processing command profit_price_change for user %s: %s",
 | 
						|
            message.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.callback_query(F.data == "stop_loss_percent")
 | 
						|
async def stop_loss_percent(callback_query: CallbackQuery, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles the 'stop_loss_percent' callback query.
 | 
						|
 | 
						|
    Clears the current FSM state, edits the message text to display the stop loss percentage options,
 | 
						|
    and shows an inline keyboard for selection.
 | 
						|
 | 
						|
    Args:
 | 
						|
        callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        await state.clear()
 | 
						|
        await state.set_state(RiskManagementState.stop_loss_percent_state)
 | 
						|
        msg = await callback_query.message.edit_text(
 | 
						|
            text="Введите процент изменения цены для фиксации убытка: ",
 | 
						|
            reply_markup=kbi.back_to_risk_management,
 | 
						|
        )
 | 
						|
        await state.update_data(prompt_message_id=msg.message_id)
 | 
						|
        logger.debug(
 | 
						|
            "Command stop_loss_percent processed successfully for user: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
        )
 | 
						|
    except Exception as e:
 | 
						|
        await callback_query.answer(
 | 
						|
            text="Произошла ошибка. Пожалуйста, попробуйте позже."
 | 
						|
        )
 | 
						|
        logger.error(
 | 
						|
            "Error processing command stop_loss_percent for user %s: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.message(RiskManagementState.stop_loss_percent_state)
 | 
						|
async def set_stop_loss_percent(message: Message, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles user input for setting the stop loss percentage.
 | 
						|
 | 
						|
    Updates FSM context with the selected percentage and persists the choice in database.
 | 
						|
    Sends an acknowledgement to user and clears FSM state afterward.
 | 
						|
 | 
						|
    Args:
 | 
						|
        message (Message): Incoming message from user containing the stop loss percentage.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        try:
 | 
						|
            data = await state.get_data()
 | 
						|
            if "prompt_message_id" in data:
 | 
						|
                prompt_message_id = data["prompt_message_id"]
 | 
						|
                await message.bot.delete_message(
 | 
						|
                    chat_id=message.chat.id, message_id=prompt_message_id
 | 
						|
                )
 | 
						|
            await message.delete()
 | 
						|
        except Exception as e:
 | 
						|
            if "message to delete not found" in str(e).lower():
 | 
						|
                pass  # Ignore this error
 | 
						|
            else:
 | 
						|
                raise e
 | 
						|
 | 
						|
        stop_loss_percent_value = message.text
 | 
						|
 | 
						|
        if not is_number(stop_loss_percent_value):
 | 
						|
            await message.answer(
 | 
						|
                text="Ошибка: введите валидное число.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
            logger.debug(
 | 
						|
                "User %s input invalid (not an valid number): %s",
 | 
						|
                message.from_user.id,
 | 
						|
                stop_loss_percent_value,
 | 
						|
            )
 | 
						|
            return
 | 
						|
 | 
						|
        if safe_float(stop_loss_percent_value) < 0.1 or safe_float(stop_loss_percent_value) > 100:
 | 
						|
            await message.answer(
 | 
						|
                text="Ошибка: введите число от 1 до 100.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
            logger.debug(
 | 
						|
                "User %s input invalid (not an valid number): %s",
 | 
						|
                message.from_user.id,
 | 
						|
                stop_loss_percent_value,
 | 
						|
            )
 | 
						|
            return
 | 
						|
 | 
						|
        req = await rq.set_stop_loss_percent(
 | 
						|
            tg_id=message.from_user.id, stop_loss_percent=safe_float(stop_loss_percent_value)
 | 
						|
        )
 | 
						|
 | 
						|
        if req:
 | 
						|
            await message.answer(
 | 
						|
                text=f"Процент изменения цены для фиксации убытка "
 | 
						|
                f"установлен на {stop_loss_percent_value}%.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            await message.answer(
 | 
						|
                text="Произошла ошибка при установке процента изменения цены для фиксации убытка. "
 | 
						|
                "Пожалуйста, попробуйте позже.",
 | 
						|
                reply_markup=kbi.back_to_risk_management,
 | 
						|
            )
 | 
						|
 | 
						|
        await state.clear()
 | 
						|
    except Exception as e:
 | 
						|
        await message.answer(
 | 
						|
            text="Произошла ошибка при установке процента изменения цены для фиксации убытка. "
 | 
						|
            "Пожалуйста, попробуйте позже.",
 | 
						|
            reply_markup=kbi.back_to_risk_management,
 | 
						|
        )
 | 
						|
        logger.error(
 | 
						|
            "Error processing command stop_loss_percent for user %s: %s",
 | 
						|
            message.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.callback_query(F.data == "commission_fee")
 | 
						|
async def commission_fee(callback_query: CallbackQuery, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles the 'commission_fee' callback query.
 | 
						|
 | 
						|
    Clears the current FSM state, edits the message text to display the commission fee options,
 | 
						|
    and shows an inline keyboard for selection.
 | 
						|
 | 
						|
    Args:
 | 
						|
        callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        await state.clear()
 | 
						|
        await state.set_state(RiskManagementState.commission_fee_state)
 | 
						|
        msg = await callback_query.message.edit_text(
 | 
						|
            text="Учитывать комиссию биржи для расчета прибыли?: ",
 | 
						|
            reply_markup=kbi.commission_fee,
 | 
						|
        )
 | 
						|
        await state.update_data(prompt_message_id=msg.message_id)
 | 
						|
        logger.debug(
 | 
						|
            "Command commission_fee processed successfully for user: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
        )
 | 
						|
    except Exception as e:
 | 
						|
        await callback_query.answer(
 | 
						|
            text="Произошла ошибка. Пожалуйста, попробуйте позже."
 | 
						|
        )
 | 
						|
        logger.error(
 | 
						|
            "Error processing command commission_fee for user %s: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.callback_query(
 | 
						|
    lambda c: c.data in ["Yes_commission_fee", "No_commission_fee"]
 | 
						|
)
 | 
						|
async def set_commission_fee(callback_query: CallbackQuery, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles user input for setting the commission fee.
 | 
						|
 | 
						|
    Updates FSM context with the selected option and persists the choice in database.
 | 
						|
    Sends an acknowledgement to user and clears FSM state afterward.
 | 
						|
 | 
						|
    Args:
 | 
						|
        callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        req = await rq.set_commission_fee(
 | 
						|
            tg_id=callback_query.from_user.id, commission_fee=callback_query.data
 | 
						|
        )
 | 
						|
 | 
						|
        if not req:
 | 
						|
            await callback_query.answer(
 | 
						|
                text="Произошла ошибка при установке комиссии биржи. Пожалуйста, попробуйте позже."
 | 
						|
            )
 | 
						|
            return
 | 
						|
 | 
						|
        if callback_query.data == "Yes_commission_fee":
 | 
						|
            await callback_query.answer(text="Комиссия биржи учитывается.")
 | 
						|
        else:
 | 
						|
            await callback_query.answer(text="Комиссия биржи не учитывается.")
 | 
						|
 | 
						|
    except Exception as e:
 | 
						|
        logger.error(
 | 
						|
            "Error processing command commission_fee for user %s: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
    finally:
 | 
						|
        await state.clear()
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.callback_query(F.data == "compensation_commission")
 | 
						|
async def compensation_commission(callback_query: CallbackQuery, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles the 'compensation_commission' callback query.
 | 
						|
 | 
						|
    Clears the current FSM state, edits the message text to display the compensation commission options,
 | 
						|
    and shows an inline keyboard for selection.
 | 
						|
 | 
						|
    Args:
 | 
						|
        callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        await state.clear()
 | 
						|
        msg = await callback_query.message.edit_text(
 | 
						|
            text="Выберите за счет чего будет происходить компенсация комиссии: ",
 | 
						|
            reply_markup=kbi.commission_place,
 | 
						|
        )
 | 
						|
        await state.update_data(prompt_message_id=msg.message_id)
 | 
						|
        logger.debug(
 | 
						|
            "Command compensation_commission processed successfully for user: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
        )
 | 
						|
    except Exception as e:
 | 
						|
        await callback_query.answer(
 | 
						|
            text="Произошла ошибка. Пожалуйста, попробуйте позже."
 | 
						|
        )
 | 
						|
        logger.error(
 | 
						|
            "Error processing command compensation_commission for user %s: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
@router_risk_management.callback_query(
 | 
						|
    lambda c: c.data in ["Commission_for_qty", "Commission_for_tp"]
 | 
						|
)
 | 
						|
async def set_compensation_commission(callback_query: CallbackQuery, state: FSMContext) -> None:
 | 
						|
    """
 | 
						|
    Handles user input for setting the compensation commission.
 | 
						|
 | 
						|
    Updates FSM context with the selected option and persists the choice in database.
 | 
						|
    Sends an acknowledgement to user and clears FSM state afterward.
 | 
						|
 | 
						|
    Args:
 | 
						|
        callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
 | 
						|
        state (FSMContext): Finite State Machine context for the current user session.
 | 
						|
 | 
						|
    Logs:
 | 
						|
        Success or error messages with user identification.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
 | 
						|
        req = await rq.set_commission_place(
 | 
						|
            tg_id=callback_query.from_user.id, commission_place=callback_query.data
 | 
						|
        )
 | 
						|
 | 
						|
        if not req:
 | 
						|
            await callback_query.answer(
 | 
						|
                text="Произошла ошибка при установке компенсации комиссии. Пожалуйста, попробуйте позже."
 | 
						|
            )
 | 
						|
            return
 | 
						|
 | 
						|
        if callback_query.data == "Commission_for_qty":
 | 
						|
            await callback_query.answer(text="Комиссия компенсируется по ставке.")
 | 
						|
        else:
 | 
						|
            await callback_query.answer(text="Комиссия компенсируется по тейк-профиту.")
 | 
						|
    except Exception as e:
 | 
						|
        logger.error(
 | 
						|
            "Error processing command compensation_commission for user %s: %s",
 | 
						|
            callback_query.from_user.id,
 | 
						|
            e,
 | 
						|
        )
 | 
						|
    finally:
 | 
						|
        await state.clear() |