From 81145334756e5d4706eaa5503a891f9367f5d4b8 Mon Sep 17 00:00:00 2001 From: algizn97 Date: Fri, 10 Oct 2025 13:24:32 +0500 Subject: [PATCH] When adjusting the leverage, the SL changes according to the criteria. In place of the position mode, there is now a trading mode. All unnecessary functions are also removed. --- .../main_settings/additional_settings.py | 934 +++--------------- 1 file changed, 148 insertions(+), 786 deletions(-) diff --git a/app/telegram/handlers/main_settings/additional_settings.py b/app/telegram/handlers/main_settings/additional_settings.py index 1d1dd4e..df2d1d9 100644 --- a/app/telegram/handlers/main_settings/additional_settings.py +++ b/app/telegram/handlers/main_settings/additional_settings.py @@ -7,14 +7,9 @@ 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_leverage import set_leverage 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.helper_functions import is_int, is_number, safe_float from app.telegram.states.states import AdditionalSettingsState from logger_helper.logger_helper import LOGGING_CONFIG @@ -26,7 +21,7 @@ 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 + callback_query: CallbackQuery, state: FSMContext ) -> None: """ Handles the 'trade_mode' callback query. @@ -44,9 +39,10 @@ async def settings_for_trade_mode( try: await state.clear() await callback_query.message.edit_text( - text="Выберите режим позиции:\n\n" - "Односторонний режим — возможно удержание Лонг или же Шорт позиции в контракте.\n\n" - "Хеджирование — возможно удержание обеих Лонг и Шорт позиций в контракте одновременно.", + text="Выберите режим торговли:\n\n" + "Лонг - все сделки серии открываются на покупку.\n" + "Шорт - все сделки серии открываются на продажу.\n" + "Свитч - направление каждой сделки серии меняется по переменно.\n", reply_markup=kbi.trade_mode, ) logger.debug( @@ -66,7 +62,7 @@ async def settings_for_trade_mode( @router_additional_settings.callback_query( - lambda c: c.data == "Merged_Single" or c.data == "Both_Sides" + lambda c: c.data == "Long" or c.data == "Short" or c.data == "Switch" ) async def trade_mode(callback_query: CallbackQuery, state: FSMContext) -> None: """ @@ -83,78 +79,20 @@ async def trade_mode(callback_query: CallbackQuery, state: FSMContext) -> None: 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="Произошла ошибка при обновлении режима позиции." + 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), - ) - + await callback_query.answer(text="Режим торговли успешно изменен") + logger.debug( + "Trade mode changed successfully for user: %s", callback_query.from_user.id + ) except Exception as e: await callback_query.answer(text="Произошла ошибка при смене режима позиции.") logger.error( @@ -166,9 +104,97 @@ async def trade_mode(callback_query: CallbackQuery, state: FSMContext) -> None: await state.clear() +@router_additional_settings.callback_query(F.data == "switch_side_start") +async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) -> None: + """ + Handles the 'switch_side_start' callback query. + + Clears the current FSM state, edits the message text to display the switch side start message, + 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.switch_side, + ) + logger.debug( + "Command switch_side_start processed successfully for user: %s", + callback_query.from_user.id, + ) + except Exception as e: + await callback_query.answer( + text="Произошла ошибка. Пожалуйста, попробуйте позже." + ) + logger.error( + "Error processing command switch_side_start for user %s: %s", + callback_query.from_user.id, + e, + ) + + +@router_additional_settings.callback_query(lambda c: c.data == "switch_direction" or c.data == "switch_opposite") +async def switch_side_handler(callback_query: CallbackQuery, state: FSMContext) -> None: + """ + Handles callback queries related to switch side selection. + + Updates FSM context with selected switch side 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 switch side. + state (FSMContext): Finite State Machine context for the current user session. + + Logs: + Success or error messages with user identification. + """ + try: + if callback_query.data == "switch_direction": + switch_side = "По направлению" + elif callback_query.data == "switch_opposite": + switch_side = "Противоположно" + else: + switch_side = None + + req = await rq.set_switch_side( + tg_id=callback_query.from_user.id, switch_side=switch_side + ) + + if not req: + await callback_query.answer( + text="Произошла ошибка при установке направления переключения" + ) + return + + await callback_query.answer(text=f"Выбрано: {switch_side}") + logger.debug( + "Switch side changed successfully for user: %s", callback_query.from_user.id + ) + except Exception as e: + await callback_query.answer( + text="Произошла ошибка при смене направления переключения" + ) + logger.error( + "Error processing set switch_side 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 + callback_query: CallbackQuery, state: FSMContext ) -> None: """ Handles the 'margin_type' callback query. @@ -228,11 +254,8 @@ async def set_margin_type(callback_query: CallbackQuery, state: FSMContext) -> N 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 @@ -254,21 +277,16 @@ async def set_margin_type(callback_query: CallbackQuery, state: FSMContext) -> N ) return + await set_leverage( + tg_id=callback_query.from_user.id, + symbol=symbol, + leverage=str(leverage_to_float), + ) + 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="Произошла ошибка при установке типа маржи" @@ -285,394 +303,6 @@ async def set_margin_type(callback_query: CallbackQuery, state: FSMContext) -> N 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: """ @@ -784,7 +414,7 @@ async def set_trigger_price(message: Message, state: FSMContext) -> None: @router_additional_settings.callback_query(F.data == "leverage") -async def leverage_to_buy(callback_query: CallbackQuery, state: FSMContext) -> None: +async def leverage_handler(callback_query: CallbackQuery, state: FSMContext) -> None: """ Handles the 'leverage' callback query. @@ -801,25 +431,12 @@ async def leverage_to_buy(callback_query: CallbackQuery, state: FSMContext) -> N try: await state.clear() await callback_query.answer() - additional_settings = await rq.get_user_additional_settings( - callback_query.from_user.id + await state.set_state(AdditionalSettingsState.leverage_state) + msg = await callback_query.message.edit_text( + text="Введите размер кредитного плеча:", + reply_markup=kbi.back_to_additional_settings, ) - 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) + await state.update_data(prompt_message_id=msg.message_id) logger.debug( "Command leverage processed successfully for user: %s", callback_query.from_user.id, @@ -836,7 +453,7 @@ async def leverage_to_buy(callback_query: CallbackQuery, state: FSMContext) -> N @router_additional_settings.message(AdditionalSettingsState.leverage_state) -async def leverage(message: Message, state: FSMContext) -> None: +async def set_leverage_handler(message: Message, state: FSMContext) -> None: """ Handles user input for setting the leverage. @@ -880,29 +497,18 @@ async def leverage(message: Message, state: FSMContext) -> None: 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 + safe_float(instruments_info.get("leverageFilter").get("minLeverage")) + or 1 ) max_leverage = ( - safe_float(instruments_info.get("leverageFilter").get("maxLeverage")) - or 100 + safe_float(instruments_info.get("leverageFilter").get("maxLeverage")) + or 100 ) if leverage_float > max_leverage or leverage_float < min_leverage: @@ -939,16 +545,15 @@ async def leverage(message: Message, state: FSMContext) -> None: 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: + + if req_leverage: await message.answer( text=f"Кредитное плечо успешно установлено на {leverage_float}", reply_markup=kbi.back_to_additional_settings, ) + risk_percent = 100 / safe_float(leverage_float) + await rq.set_stop_loss_percent( + tg_id=message.from_user.id, stop_loss_percent=risk_percent) logger.info( "User %s set leverage: %s", message.from_user.id, leverage_float ) @@ -969,247 +574,6 @@ async def leverage(message: Message, state: FSMContext) -> None: ) -@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: """ @@ -1228,10 +592,8 @@ async def order_quantity(callback_query: CallbackQuery, state: FSMContext) -> No 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}.", + text=f"Введите базовую ставку в USDT:", reply_markup=kbi.back_to_additional_settings, ) await state.update_data(prompt_message_id=msg.message_id) @@ -1295,25 +657,6 @@ async def set_order_quantity(message: Message, state: FSMContext) -> None: 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 @@ -1321,7 +664,7 @@ async def set_order_quantity(message: Message, state: FSMContext) -> None: if req: await message.answer( - text=f"Количество ордера установлено на {message.text}", + text=f"Базовая ставка установлена на {message.text} USDT", reply_markup=kbi.back_to_additional_settings, ) else: @@ -1333,7 +676,7 @@ async def set_order_quantity(message: Message, state: FSMContext) -> None: await state.clear() except Exception as e: await message.answer( - text="Произошла ошибка при установке кол-ва ордера. Пожалуйста, попробуйте позже.", + text="Произошла ошибка при установке базовой ставки. Пожалуйста, попробуйте позже.", reply_markup=kbi.back_to_additional_settings, ) logger.error("Error processing command set_order_quantity: %s", e) @@ -1422,6 +765,13 @@ async def set_martingale_factor(message: Message, state: FSMContext) -> None: return martingale_factor_value_float = safe_float(martingale_factor_value) + + if martingale_factor_value_float < 0.1 or martingale_factor_value_float > 10: + await message.answer(text="Ошибка: коэффициент мартингейла должен быть в диапазоне от 0.1 до 10") + logger.debug("User %s input invalid (not in range 0.1 to 10): %s", message.from_user.id, + martingale_factor_value_float) + return + req = await rq.set_martingale_factor( tg_id=message.from_user.id, martingale_factor=martingale_factor_value_float ) @@ -1528,6 +878,18 @@ async def set_max_bets_in_series(message: Message, state: FSMContext) -> None: ) return + if safe_float(max_bets_in_series_value) < 1 or safe_float(max_bets_in_series_value) > 100: + await message.answer( + "Ошибка: число должно быть в диапазоне от 1 до 100.", + reply_markup=kbi.back_to_additional_settings, + ) + logger.debug( + "User %s input invalid (not in range 1 to 100): %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) )