Files
stcs/app/telegram/handlers/main_settings/risk_management.py

344 lines
13 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) < 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) < 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()