forked from kodorvan/stcs
1557 lines
62 KiB
Python
1557 lines
62 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.bybit.get_functions.get_instruments_info import get_instruments_info
|
||
from app.bybit.get_functions.get_tickers import get_tickers
|
||
from app.bybit.set_functions.set_leverage import (
|
||
set_leverage,
|
||
set_leverage_to_buy_and_sell,
|
||
)
|
||
from app.bybit.set_functions.set_margin_mode import set_margin_mode
|
||
from app.bybit.set_functions.set_switch_position_mode import set_switch_position_mode
|
||
from app.helper_functions import get_base_currency, is_int, is_number, safe_float
|
||
from app.telegram.states.states import AdditionalSettingsState
|
||
from logger_helper.logger_helper import LOGGING_CONFIG
|
||
|
||
logging.config.dictConfig(LOGGING_CONFIG)
|
||
logger = logging.getLogger("additional_settings")
|
||
|
||
router_additional_settings = Router(name="additional_settings")
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "trade_mode")
|
||
async def settings_for_trade_mode(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handles the 'trade_mode' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display trade mode options
|
||
with explanation for 'Long' and 'Short' modes, 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 callback_query.message.edit_text(
|
||
text="Выберите режим позиции:\n\n"
|
||
"Односторонний режим — возможно удержание Лонг или же Шорт позиции в контракте.\n\n"
|
||
"Хеджирование — возможно удержание обеих Лонг и Шорт позиций в контракте одновременно.",
|
||
reply_markup=kbi.trade_mode,
|
||
)
|
||
logger.debug(
|
||
"Command trade_mode processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command trade_mode for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(
|
||
lambda c: c.data == "Merged_Single" or c.data == "Both_Sides"
|
||
)
|
||
async def trade_mode(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles callback queries related to trade mode selection.
|
||
|
||
Updates FSM context with selected trade mode and persists the choice in database.
|
||
Sends an acknowledgement to user and clears FSM state afterward.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Incoming callback query indicating selected trade mode.
|
||
state (FSMContext): Finite State Machine context for the current user session.
|
||
|
||
Logs:
|
||
Success or error messages with user identification.
|
||
"""
|
||
try:
|
||
symbol = await rq.get_user_symbol(tg_id=callback_query.from_user.id)
|
||
additional_settings = await rq.get_user_additional_settings(
|
||
tg_id=callback_query.from_user.id
|
||
)
|
||
get_leverage = additional_settings.leverage or "10"
|
||
get_leverage_to_buy = additional_settings.leverage_to_buy or "10"
|
||
get_leverage_to_sell = additional_settings.leverage_to_sell or "10"
|
||
leverage_to_float = safe_float(get_leverage)
|
||
leverage_to_buy_float = safe_float(get_leverage_to_buy)
|
||
leverage_to_sell_float = safe_float(get_leverage_to_sell)
|
||
margin_type = additional_settings.margin_type or "ISOLATED_MARGIN"
|
||
mode = 0 if callback_query.data.startswith("Merged_Single") else 3
|
||
response = await set_switch_position_mode(
|
||
tg_id=callback_query.from_user.id, symbol=symbol, mode=mode
|
||
)
|
||
|
||
if not response:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при обновлении режима позиции."
|
||
)
|
||
return
|
||
|
||
req = await rq.set_trade_mode(
|
||
tg_id=callback_query.from_user.id, trade_mode=callback_query.data
|
||
)
|
||
if not req:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при обновлении режима позиции."
|
||
)
|
||
return
|
||
|
||
if (
|
||
response
|
||
== "You have an existing position, so position mode cannot be switched"
|
||
):
|
||
await callback_query.answer(
|
||
text="У вас уже есть позиция по паре, "
|
||
"поэтому режим позиции не может быть изменен."
|
||
)
|
||
return
|
||
|
||
if response == "Open orders exist, so you cannot change position mode":
|
||
await callback_query.answer(
|
||
text="У вас есть открытые ордера, "
|
||
"поэтому режим позиции не может быть изменен."
|
||
)
|
||
return
|
||
|
||
if callback_query.data.startswith("Merged_Single"):
|
||
await callback_query.answer(text="Выбран режим позиции: Односторонний")
|
||
await set_leverage(
|
||
tg_id=callback_query.from_user.id,
|
||
symbol=symbol,
|
||
leverage=str(leverage_to_float),
|
||
)
|
||
|
||
elif callback_query.data.startswith("Both_Sides"):
|
||
await callback_query.answer(text="Выбран режим позиции: Хеджирование")
|
||
if margin_type == "ISOLATED_MARGIN":
|
||
await set_leverage_to_buy_and_sell(
|
||
tg_id=callback_query.from_user.id,
|
||
symbol=symbol,
|
||
leverage_to_buy=str(leverage_to_buy_float),
|
||
leverage_to_sell=str(leverage_to_sell_float),
|
||
)
|
||
else:
|
||
await set_leverage(
|
||
tg_id=callback_query.from_user.id,
|
||
symbol=symbol,
|
||
leverage=str(leverage_to_float),
|
||
)
|
||
|
||
except Exception as e:
|
||
await callback_query.answer(text="Произошла ошибка при смене режима позиции.")
|
||
logger.error(
|
||
"Error processing set trade_mode for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "margin_type")
|
||
async def settings_for_margin_type(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handles the 'margin_type' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display margin type 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 callback_query.message.edit_text(
|
||
text="Выберите тип маржи:\n\n"
|
||
"Примечание: Если у вас есть открытые позиции, то маржа примениться ко всем позициям",
|
||
reply_markup=kbi.margin_type
|
||
)
|
||
logger.debug(
|
||
"Command margin_type processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command margin_type for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(
|
||
lambda c: c.data == "ISOLATED_MARGIN" or c.data == "REGULAR_MARGIN"
|
||
)
|
||
async def set_margin_type(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles callback queries starting with 'Isolated' or 'Cross'.
|
||
|
||
Updates FSM context with selected margin type and persists the choice in database.
|
||
Sends an acknowledgement to user and clears FSM state afterward.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Incoming callback query indicating selected margin type.
|
||
state (FSMContext): Finite State Machine context for the current user session.
|
||
|
||
Logs:
|
||
Success or error messages with user identification.
|
||
"""
|
||
try:
|
||
symbol = await rq.get_user_symbol(tg_id=callback_query.from_user.id)
|
||
additional_settings = await rq.get_user_additional_settings(
|
||
tg_id=callback_query.from_user.id
|
||
)
|
||
get_leverage = additional_settings.leverage or "10"
|
||
get_leverage_to_buy = additional_settings.leverage_to_buy or "10"
|
||
get_leverage_to_sell = additional_settings.leverage_to_sell or "10"
|
||
leverage_to_float = safe_float(get_leverage)
|
||
leverage_to_buy_float = safe_float(get_leverage_to_buy)
|
||
leverage_to_sell_float = safe_float(get_leverage_to_sell)
|
||
bybit_margin_mode = callback_query.data
|
||
response = await set_margin_mode(
|
||
tg_id=callback_query.from_user.id, margin_mode=bybit_margin_mode
|
||
)
|
||
|
||
if not response:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке типа маржи"
|
||
)
|
||
return
|
||
|
||
req = await rq.set_margin_type(
|
||
tg_id=callback_query.from_user.id, margin_type=callback_query.data
|
||
)
|
||
|
||
if not req:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке типа маржи"
|
||
)
|
||
return
|
||
|
||
if callback_query.data.startswith("ISOLATED_MARGIN"):
|
||
await callback_query.answer(text="Выбран тип маржи: Изолированная")
|
||
await set_leverage_to_buy_and_sell(
|
||
tg_id=callback_query.from_user.id,
|
||
symbol=symbol,
|
||
leverage_to_buy=str(leverage_to_buy_float),
|
||
leverage_to_sell=str(leverage_to_sell_float),
|
||
)
|
||
elif callback_query.data.startswith("REGULAR_MARGIN"):
|
||
await callback_query.answer(text="Выбран тип маржи: Кросс")
|
||
await set_leverage(
|
||
tg_id=callback_query.from_user.id,
|
||
symbol=symbol,
|
||
leverage=str(leverage_to_float),
|
||
)
|
||
else:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке типа маржи"
|
||
)
|
||
|
||
except Exception as e:
|
||
await callback_query.answer(text="Произошла ошибка при установке типа маржи")
|
||
logger.error(
|
||
"Error processing command margin_type for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "order_type")
|
||
async def settings_for_order_type(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handles the 'order_type' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display order type 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 callback_query.message.edit_text(
|
||
text="Выберите тип ордера:\n\n"
|
||
"Рыночный ордер - исполняется немедленно по лучшей доступной цене.\n\n"
|
||
"Лимитный ордер - это ордер на покупку или продажу по указанной цене или лучше.\n\n"
|
||
"Условный ордер - активируются при достижении триггерной цены.",
|
||
reply_markup=kbi.order_type,
|
||
)
|
||
logger.debug(
|
||
"Command order_type processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command order_type for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(
|
||
lambda c: c.data == "Market" or c.data == "Limit" or c.data == "Conditional"
|
||
)
|
||
async def set_order_type(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles callback queries starting with 'Market', 'Limit', or 'Conditional'.
|
||
|
||
Updates FSM context with selected order type and persists the choice in database.
|
||
Sends an acknowledgement to user and clears FSM state afterward.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Incoming callback query indicating selected order type.
|
||
state (FSMContext): Finite State Machine context for the current user session.
|
||
|
||
Logs:
|
||
Success or error messages with user identification.
|
||
"""
|
||
try:
|
||
await state.update_data(order_type=callback_query.data)
|
||
req = await rq.set_order_type(
|
||
tg_id=callback_query.from_user.id, order_type=callback_query.data
|
||
)
|
||
|
||
if not req:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке типа ордера"
|
||
)
|
||
return
|
||
|
||
if callback_query.data.startswith("Market"):
|
||
await callback_query.answer(text="Выбран тип ордера: Рыночный")
|
||
elif callback_query.data.startswith("Limit"):
|
||
await callback_query.answer(text="Выбран тип ордера: Лимитный")
|
||
elif callback_query.data.startswith("Conditional"):
|
||
await callback_query.answer(text="Выбран тип ордера: Условный")
|
||
else:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке типа ордера"
|
||
)
|
||
|
||
except Exception as e:
|
||
await callback_query.answer(text="Произошла ошибка при установке типа ордера")
|
||
logger.error(
|
||
"Error processing command order_type for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "conditional_order_type")
|
||
async def settings_for_conditional_order_type(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handles the 'conditional_order_type' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display conditional order type 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 callback_query.message.edit_text(
|
||
text="Выберите тип условного ордера:\n\n"
|
||
"Рыночный ордер - исполняется немедленно по лучшей доступной цене при достижении триггерной цены.\n\n"
|
||
"Лимитный ордер - это ордер на покупку или продажу по указанной цене или лучше.\n\n",
|
||
reply_markup=kbi.conditional_order_type,
|
||
)
|
||
logger.debug(
|
||
"Command conditional_order_type processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command conditional_order_type for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(
|
||
lambda c: c.data == "set_market" or c.data == "set_limit"
|
||
)
|
||
async def conditional_order_type(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handles callback queries starting with 'set_market' or 'set_limit'.
|
||
|
||
Updates FSM context with selected conditional order type and persists the choice in database.
|
||
Sends an acknowledgement to user and clears FSM state afterward.
|
||
|
||
Args:
|
||
callback_query (CallbackQuery): Incoming callback query indicating selected conditional order type.
|
||
state (FSMContext): Finite State Machine context for the current user session.
|
||
|
||
Logs:
|
||
Success or error messages with user identification.
|
||
"""
|
||
try:
|
||
await state.update_data(conditional_order_type=callback_query.data)
|
||
|
||
if callback_query.data.startswith("set_market"):
|
||
await callback_query.answer(text="Выбран тип условного ордера: Рыночный")
|
||
order_type = "Market"
|
||
elif callback_query.data.startswith("set_limit"):
|
||
await callback_query.answer(text="Выбран тип условного ордера: Лимитный")
|
||
order_type = "Limit"
|
||
else:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при обновлении типа условного ордера"
|
||
)
|
||
return
|
||
|
||
req = await rq.set_conditional_order_type(
|
||
tg_id=callback_query.from_user.id, conditional_order_type=order_type
|
||
)
|
||
|
||
if not req:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при обновлении типа условного ордера"
|
||
)
|
||
return
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при обновлении типа условного ордера."
|
||
)
|
||
logger.error(
|
||
"Error processing conditional_order_type for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "limit_price")
|
||
async def limit_price(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'limit_price' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display the limit price 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 callback_query.message.edit_text(
|
||
text="Выберите цену лимита:\n\n"
|
||
"1. Установить цену - указать цену\n"
|
||
"2. Последняя цена - использовать последнюю цену\n",
|
||
reply_markup=kbi.change_limit_price,
|
||
)
|
||
logger.debug(
|
||
"Command limit_price processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command limit_price for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(lambda c: c.data == "last_price")
|
||
async def last_price(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'last_price' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display the last price option,
|
||
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:
|
||
symbol = await rq.get_user_symbol(tg_id=callback_query.from_user.id)
|
||
get_tickers_info = await get_tickers(
|
||
tg_id=callback_query.from_user.id, symbol=symbol
|
||
)
|
||
if get_tickers_info is None:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке цены лимита."
|
||
)
|
||
return
|
||
|
||
mark_price = get_tickers_info.get("lastPrice") or 0
|
||
req = await rq.set_limit_price(
|
||
tg_id=callback_query.from_user.id, limit_price=safe_float(mark_price)
|
||
)
|
||
if req:
|
||
await callback_query.answer(
|
||
text=f"Цена лимита установлена на последнюю цену: {mark_price}"
|
||
)
|
||
else:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка при установке цены лимита."
|
||
)
|
||
|
||
except Exception as e:
|
||
await callback_query.answer(text="Произошла ошибка при установке цены лимита.")
|
||
logger.error(
|
||
"Error processing last_price for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
finally:
|
||
await state.clear()
|
||
|
||
|
||
@router_additional_settings.callback_query(lambda c: c.data == "set_limit_price")
|
||
async def set_limit_price_handler(
|
||
callback_query: CallbackQuery, state: FSMContext
|
||
) -> None:
|
||
"""
|
||
Handles the 'set_limit_price_handler' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to prompt for the limit price,
|
||
and shows an inline keyboard for input.
|
||
|
||
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(AdditionalSettingsState.limit_price_state)
|
||
await callback_query.answer()
|
||
await state.update_data(prompt_message_id=callback_query.message.message_id)
|
||
msg = await callback_query.message.edit_text(
|
||
text="Введите цену:", reply_markup=kbi.back_to_change_limit_price
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command set_limit_price processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command set_limit_price for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.limit_price_state)
|
||
async def set_limit_price(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the limit price.
|
||
|
||
Updates FSM context with the selected limit price 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 selected limit price.
|
||
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
|
||
|
||
limit_price_value = message.text
|
||
|
||
if not is_number(limit_price_value):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
limit_price_value,
|
||
)
|
||
return
|
||
|
||
req = await rq.set_limit_price(
|
||
tg_id=message.from_user.id, limit_price=safe_float(limit_price_value)
|
||
)
|
||
if req:
|
||
await message.answer(
|
||
text=f"Цена лимита установлена на: {limit_price_value}",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке цены лимита.",
|
||
reply_markup=kbi.back_to_change_limit_price,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке цены лимита.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing set_limit_price for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(lambda c: c.data == "trigger_price")
|
||
async def trigger_price(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'trigger_price' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to prompt for the trigger price,
|
||
and shows an inline keyboard for input.
|
||
|
||
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(AdditionalSettingsState.trigger_price_state)
|
||
await callback_query.answer()
|
||
await state.update_data(prompt_message_id=callback_query.message.message_id)
|
||
msg = await callback_query.message.edit_text(
|
||
text="Введите цену:", reply_markup=kbi.back_to_additional_settings
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command trigger_price processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command trigger_price for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.trigger_price_state)
|
||
async def set_trigger_price(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the trigger price.
|
||
|
||
Updates FSM context with the selected trigger price 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 selected trigger price.
|
||
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
|
||
|
||
trigger_price_value = message.text
|
||
|
||
if not is_number(trigger_price_value):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
trigger_price_value,
|
||
)
|
||
return
|
||
|
||
req = await rq.set_trigger_price(
|
||
tg_id=message.from_user.id, trigger_price=safe_float(trigger_price_value)
|
||
)
|
||
if req:
|
||
await message.answer(
|
||
text=f"Цена триггера установлена на: {trigger_price_value}",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке цены триггера.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке цены триггера.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing set_trigger_price for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "leverage")
|
||
async def leverage_to_buy(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'leverage' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display the leverage 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 callback_query.answer()
|
||
additional_settings = await rq.get_user_additional_settings(
|
||
callback_query.from_user.id
|
||
)
|
||
get_trade_mode = additional_settings.trade_mode or "Both_Sides"
|
||
get_margin_type = additional_settings.margin_type or "ISOLATED_MARGIN"
|
||
if get_trade_mode == "Both_Sides" and get_margin_type == "ISOLATED_MARGIN":
|
||
await state.set_state(AdditionalSettingsState.leverage_to_buy_state)
|
||
msg = await callback_query.message.edit_text(
|
||
text="Введите размер кредитного плеча для Лонг:",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
else:
|
||
await state.set_state(AdditionalSettingsState.leverage_state)
|
||
msg = await callback_query.message.edit_text(
|
||
text="Введите размер кредитного плеча:",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command leverage processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command leverage for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.leverage_state)
|
||
async def leverage(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the leverage.
|
||
|
||
Updates FSM context with the selected leverage 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 selected leverage.
|
||
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
|
||
|
||
get_leverage = message.text
|
||
tg_id = message.from_user.id
|
||
if not is_number(get_leverage):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
get_leverage,
|
||
)
|
||
return
|
||
|
||
leverage_float = safe_float(get_leverage)
|
||
if leverage_float < 1 or leverage_float > 100:
|
||
await message.answer(
|
||
text="Ошибка: число должно быть от 1 до 100.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (out of range): %s",
|
||
message.from_user.id,
|
||
leverage_float,
|
||
)
|
||
return
|
||
|
||
symbol = await rq.get_user_symbol(tg_id=tg_id)
|
||
instruments_info = await get_instruments_info(tg_id=tg_id, symbol=symbol)
|
||
|
||
if instruments_info is not None:
|
||
min_leverage = (
|
||
safe_float(instruments_info.get("leverageFilter").get("minLeverage"))
|
||
or 1
|
||
)
|
||
max_leverage = (
|
||
safe_float(instruments_info.get("leverageFilter").get("maxLeverage"))
|
||
or 100
|
||
)
|
||
|
||
if leverage_float > max_leverage or leverage_float < min_leverage:
|
||
await message.answer(
|
||
text=f"Кредитное плечо должно быть от {min_leverage} до {max_leverage}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.info(
|
||
"User %s input invalid (out of range): %s, %s, %s: %s",
|
||
message.from_user.id,
|
||
symbol,
|
||
min_leverage,
|
||
max_leverage,
|
||
leverage_float,
|
||
)
|
||
return
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
response = await set_leverage(
|
||
tg_id=message.from_user.id, symbol=symbol, leverage=str(leverage_float)
|
||
)
|
||
|
||
if not response:
|
||
await message.answer(
|
||
text="Невозможно установить кредитное плечо для текущего режима торговли.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
return
|
||
|
||
req_leverage = await rq.set_leverage(
|
||
tg_id=message.from_user.id, leverage=str(leverage_float)
|
||
)
|
||
req_leverage_to_buy_and_sell = await rq.set_leverage_to_buy_and_sell(
|
||
tg_id=message.from_user.id,
|
||
leverage_to_buy=str(leverage_float),
|
||
leverage_to_sell=str(leverage_float),
|
||
)
|
||
if req_leverage and req_leverage_to_buy_and_sell:
|
||
await message.answer(
|
||
text=f"Кредитное плечо успешно установлено на {leverage_float}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.info(
|
||
"User %s set leverage: %s", message.from_user.id, leverage_float
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing command leverage for user %s: %s", message.from_user.id, e
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.leverage_to_buy_state)
|
||
async def set_leverage_to_buy(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the leverage to buy.
|
||
|
||
Updates FSM context with the selected leverage to buy 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 selected leverage to buy.
|
||
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
|
||
|
||
get_leverage_to_buy = message.text
|
||
tg_id = message.from_user.id
|
||
|
||
if not is_number(get_leverage_to_buy):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
get_leverage_to_buy,
|
||
)
|
||
return
|
||
|
||
leverage_to_buy_float = safe_float(get_leverage_to_buy)
|
||
if leverage_to_buy_float < 1 or leverage_to_buy_float > 100:
|
||
await message.answer(
|
||
text="Ошибка: число должно быть от 1 до 100.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (out of range): %s",
|
||
message.from_user.id,
|
||
get_leverage_to_buy,
|
||
)
|
||
return
|
||
|
||
symbol = await rq.get_user_symbol(tg_id=tg_id)
|
||
instruments_info = await get_instruments_info(tg_id=tg_id, symbol=symbol)
|
||
|
||
if instruments_info is not None:
|
||
max_leverage = safe_float(
|
||
instruments_info.get("leverageFilter").get("maxLeverage")
|
||
)
|
||
if leverage_to_buy_float > max_leverage:
|
||
await message.answer(
|
||
text=f"Кредитное плечо {leverage_to_buy_float} превышает максимальное {max_leverage} для {symbol}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.info(
|
||
"The requested leverage %s exceeds the maximum %s for %s for user: %s: %s",
|
||
leverage_to_buy_float,
|
||
max_leverage,
|
||
symbol,
|
||
message.from_user.id,
|
||
)
|
||
return
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing command leverage_to_buy for user %s",
|
||
message.from_user.id,
|
||
)
|
||
|
||
await state.update_data(leverage_to_buy=leverage_to_buy_float)
|
||
await state.set_state(AdditionalSettingsState.leverage_to_sell_state)
|
||
msg = await message.answer(
|
||
text="Введите размер кредитного плеча для Шорт:",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command leverage_to_buy processed successfully for user: %s",
|
||
message.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча.. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing command leverage_to_buy for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.leverage_to_sell_state)
|
||
async def set_leverage_to_sell(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the leverage to sell.
|
||
|
||
Updates FSM context with the selected leverage 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 selected leverage.
|
||
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
|
||
|
||
get_leverage_to_sell = message.text
|
||
get_leverage_to_buy = (await state.get_data()).get("leverage_to_buy")
|
||
tg_id = message.from_user.id
|
||
|
||
if not is_number(get_leverage_to_sell):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
leverage_to_buy or get_leverage_to_sell,
|
||
)
|
||
return
|
||
|
||
leverage_to_buy_float = safe_float(get_leverage_to_buy)
|
||
leverage_to_sell_float = safe_float(get_leverage_to_sell)
|
||
if leverage_to_sell_float < 1 or leverage_to_sell_float > 100:
|
||
await message.answer(
|
||
text="Ошибка: число должно быть от 1 до 100.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (out of range): %s",
|
||
message.from_user.id,
|
||
get_leverage_to_sell,
|
||
)
|
||
return
|
||
|
||
symbol = await rq.get_user_symbol(tg_id=tg_id)
|
||
instruments_info = await get_instruments_info(tg_id=tg_id, symbol=symbol)
|
||
|
||
if instruments_info is not None:
|
||
min_leverage = safe_float(
|
||
instruments_info.get("leverageFilter").get("minLeverage")
|
||
)
|
||
if leverage_to_sell_float < min_leverage:
|
||
await message.answer(
|
||
text=f"Кредитное плечо {leverage_to_sell_float} ниже минимального {min_leverage} для {symbol}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.info(
|
||
"The requested leverage %s is below the minimum %s for %s for user: %s",
|
||
leverage_to_sell_float,
|
||
min_leverage,
|
||
symbol,
|
||
message.from_user.id,
|
||
)
|
||
return
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
response = await set_leverage_to_buy_and_sell(
|
||
tg_id=message.from_user.id,
|
||
symbol=symbol,
|
||
leverage_to_buy=str(leverage_to_buy_float),
|
||
leverage_to_sell=str(leverage_to_sell_float),
|
||
)
|
||
if not response:
|
||
await message.answer(
|
||
text="Невозможно установить кредитное плечо для текущего режима торговли.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
return
|
||
|
||
req = await rq.set_leverage_to_buy_and_sell(
|
||
tg_id=message.from_user.id,
|
||
leverage_to_buy=str(leverage_to_buy_float),
|
||
leverage_to_sell=str(leverage_to_sell_float),
|
||
)
|
||
|
||
if req:
|
||
await message.answer(
|
||
text=f"Размер кредитного плеча установлен на {leverage_to_buy_float} для Лонга "
|
||
f"и {leverage_to_sell_float} для Шорта .",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кредитного плеча. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing command set_leverage for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "order_quantity")
|
||
async def order_quantity(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'order_quantity' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display the order quantity 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(AdditionalSettingsState.quantity_state)
|
||
symbol = await rq.get_user_symbol(tg_id=callback_query.from_user.id)
|
||
name_symbol = get_base_currency(symbol)
|
||
msg = await callback_query.message.edit_text(
|
||
text=f"Укажите размер для ордера в следующей валюте: {name_symbol}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command order_quantity processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command order_quantity for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.quantity_state)
|
||
async def set_order_quantity(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the order quantity.
|
||
|
||
Updates FSM context with the selected order quantity 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 selected order quantity.
|
||
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
|
||
|
||
order_quantity_value = message.text
|
||
|
||
if not is_number(order_quantity_value):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
order_quantity_value,
|
||
)
|
||
return
|
||
|
||
quantity = safe_float(order_quantity_value)
|
||
symbol = await rq.get_user_symbol(tg_id=message.from_user.id)
|
||
instruments_info = await get_instruments_info(
|
||
tg_id=message.from_user.id, symbol=symbol
|
||
)
|
||
|
||
if instruments_info is not None:
|
||
max_order_qty = safe_float(
|
||
instruments_info.get("lotSizeFilter").get("maxOrderQty")
|
||
)
|
||
min_order_qty = safe_float(
|
||
instruments_info.get("lotSizeFilter").get("minOrderQty")
|
||
)
|
||
|
||
if quantity < min_order_qty or quantity > max_order_qty:
|
||
await message.answer(
|
||
text=f"Количество ордера должно быть от {min_order_qty} до {max_order_qty}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
return
|
||
|
||
req = await rq.set_order_quantity(
|
||
tg_id=message.from_user.id, order_quantity=quantity
|
||
)
|
||
|
||
if req:
|
||
await message.answer(
|
||
text=f"Количество ордера установлено на {message.text}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кол-ва ордера. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке кол-ва ордера. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error("Error processing command set_order_quantity: %s", e)
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "martingale_factor")
|
||
async def martingale_factor(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'martingale_factor' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display the martingale factor 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(AdditionalSettingsState.martingale_factor_state)
|
||
msg = await callback_query.message.edit_text(
|
||
text="Введите коэффициент мартингейла:",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command martingale_factor processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command martingale_factor for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.martingale_factor_state)
|
||
async def set_martingale_factor(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the martingale factor.
|
||
|
||
Updates FSM context with the selected martingale factor 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 selected martingale factor.
|
||
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
|
||
|
||
martingale_factor_value = message.text
|
||
|
||
if not is_number(martingale_factor_value):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
martingale_factor_value,
|
||
)
|
||
return
|
||
|
||
martingale_factor_value_float = safe_float(martingale_factor_value)
|
||
req = await rq.set_martingale_factor(
|
||
tg_id=message.from_user.id, martingale_factor=martingale_factor_value_float
|
||
)
|
||
|
||
if req:
|
||
await message.answer(
|
||
text=f"Коэффициент мартингейла установлен на {message.text}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке коэффициента мартингейла. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке коэффициента мартингейла. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error("Error processing command set_martingale_factor: %s", e)
|
||
|
||
|
||
@router_additional_settings.callback_query(F.data == "max_bets_in_series")
|
||
async def max_bets_in_series(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handles the 'max_bets_in_series' callback query.
|
||
|
||
Clears the current FSM state, edits the message text to display the max bets in series 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(AdditionalSettingsState.max_bets_in_series_state)
|
||
msg = await callback_query.message.edit_text(
|
||
text="Введите максимальное количество ставок в серии:",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
await state.update_data(prompt_message_id=msg.message_id)
|
||
logger.debug(
|
||
"Command max_bets_in_series processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
except Exception as e:
|
||
await callback_query.answer(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||
)
|
||
logger.error(
|
||
"Error processing command max_bets_in_series for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_additional_settings.message(AdditionalSettingsState.max_bets_in_series_state)
|
||
async def set_max_bets_in_series(message: Message, state: FSMContext) -> None:
|
||
"""
|
||
Handles user input for setting the max bets in series.
|
||
|
||
Updates FSM context with the selected max steps 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 selected max bets in series.
|
||
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
|
||
|
||
max_bets_in_series_value = message.text
|
||
|
||
if not is_int(max_bets_in_series_value):
|
||
await message.answer(
|
||
"Ошибка: введите валидное число.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.debug(
|
||
"User %s input invalid (not an valid number): %s",
|
||
message.from_user.id,
|
||
max_bets_in_series_value,
|
||
)
|
||
return
|
||
|
||
req = await rq.set_max_bets_in_series(
|
||
tg_id=message.from_user.id, max_bets_in_series=int(max_bets_in_series_value)
|
||
)
|
||
|
||
if req:
|
||
await message.answer(
|
||
text=f"Максимальное количество шагов установлено на {message.text}.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
else:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке максимального количества шагов. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
|
||
await state.clear()
|
||
except Exception as e:
|
||
await message.answer(
|
||
text="Произошла ошибка при установке максимального количества шагов. Пожалуйста, попробуйте позже.",
|
||
reply_markup=kbi.back_to_additional_settings,
|
||
)
|
||
logger.error(
|
||
"Error processing command set_max_bets_in_series for user %s: %s",
|
||
message.from_user.id,
|
||
e,
|
||
)
|