diff --git a/app/bybit/open_positions.py b/app/bybit/open_positions.py index f3bd6d4..90ca3ac 100644 --- a/app/bybit/open_positions.py +++ b/app/bybit/open_positions.py @@ -123,6 +123,7 @@ async def start_trading_cycle( "Order does not meet minimum order value", "position idx not match position mode", "Qty invalid", + "The number of contracts exceeds maximum limit allowed" } else None ) @@ -132,7 +133,9 @@ async def start_trading_cycle( return None -async def trading_cycle(tg_id: int, symbol: str, reverse_side: str, size: str) -> str | None: +async def trading_cycle( + tg_id: int, symbol: str, reverse_side: str, size: str +) -> str | None: try: user_deals_data = await rq.get_user_deal_by_symbol(tg_id=tg_id, symbol=symbol) trade_mode = user_deals_data.trade_mode @@ -169,7 +172,6 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str, size: str) - leverage=leverage, ) - if reverse_side == "Buy": real_side = "Sell" else: @@ -239,6 +241,7 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str, size: str) - "Risk is too high for this trade", "ab not enough for new order", "InvalidRequestError", + "The number of contracts exceeds maximum limit allowed" } else None ) @@ -320,8 +323,8 @@ async def open_positions( po_position_idx = 1 if side == "Buy" else 2 if margin_type == "ISOLATED_MARGIN": get_leverage = safe_float( - leverage_to_buy if side == "Buy" else leverage_to_sell - ) + leverage_to_buy if side == "Buy" else leverage_to_sell + ) else: get_leverage = safe_float(leverage) else: @@ -359,7 +362,6 @@ async def open_positions( tg_id=tg_id, entry_price=price_for_calc, symbol=symbol, - order_quantity=order_quantity, leverage=get_leverage, ) @@ -388,7 +390,6 @@ async def open_positions( take_profit_price = max(take_profit_price, 0) stop_loss_price = max(stop_loss_price, 0) - # Place order order_params = { "category": "linear", diff --git a/app/telegram/handlers/get_positions_handlers.py b/app/telegram/handlers/get_positions_handlers.py index c0f1c9d..59263b6 100644 --- a/app/telegram/handlers/get_positions_handlers.py +++ b/app/telegram/handlers/get_positions_handlers.py @@ -5,7 +5,6 @@ from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery import app.telegram.keyboards.inline as kbi - from app.bybit.get_functions.get_positions import ( get_active_orders, get_active_orders_by_symbol, @@ -22,7 +21,7 @@ router_get_positions_handlers = Router(name="get_positions_handlers") @router_get_positions_handlers.callback_query(F.data == "my_deals") async def get_positions_handlers( - callback_query: CallbackQuery, state: FSMContext + callback_query: CallbackQuery, state: FSMContext ) -> None: """ Gets the user's active positions. @@ -43,7 +42,7 @@ async def get_positions_handlers( @router_get_positions_handlers.callback_query(F.data == "change_position") async def get_positions_handler( - callback_query: CallbackQuery, state: FSMContext + callback_query: CallbackQuery, state: FSMContext ) -> None: """ Gets the user's active positions. @@ -70,11 +69,15 @@ async def get_positions_handler( await callback_query.answer(text="Нет активных позиций.") return - active_symbols_sides = [(pos.get("symbol"), pos.get("side")) for pos in active_positions] + active_symbols_sides = [ + (pos.get("symbol"), pos.get("side")) for pos in active_positions + ] await callback_query.message.edit_text( text="Ваши активные позиции:", - reply_markup=kbi.create_active_positions_keyboard(symbols=active_symbols_sides), + reply_markup=kbi.create_active_positions_keyboard( + symbols=active_symbols_sides + ), ) except Exception as e: logger.error("Error in get_positions_handler: %s", e) @@ -113,7 +116,8 @@ async def get_position_handler(callback_query: CallbackQuery, state: FSMContext) size = position.get("size") or "Нет данных" take_profit = position.get("takeProfit") or "Нет данных" stop_loss = position.get("stopLoss") or "Нет данных" - position_idx = position.get("positionIdx") + position_idx = position.get("positionIdx") or "Нет данных" + liq_price = position.get("liqPrice") or "Нет данных" else: side = "Нет данных" symbol = "Нет данных" @@ -122,6 +126,7 @@ async def get_position_handler(callback_query: CallbackQuery, state: FSMContext) take_profit = "Нет данных" stop_loss = "Нет данных" position_idx = "Нет данных" + liq_price = "Нет данных" side_rus = ( "Покупка" @@ -129,23 +134,42 @@ async def get_position_handler(callback_query: CallbackQuery, state: FSMContext) else "Продажа" if side == "Sell" else "Нет данных" ) - position_idx_rus = ("Односторонний" if position_idx == 0 - else "Покупка в режиме хеджирования" if position_idx == 1 - else "Продажа в режиме хеджирования" if position_idx == 2 - else "Нет данных") + position_idx_rus = ( + "Односторонний" + if position_idx == 0 + else ( + "Покупка в режиме хеджирования" + if position_idx == 1 + else ( + "Продажа в режиме хеджирования" + if position_idx == 2 + else "Нет данных" + ) + ) + ) + + text_lines = [ + f"Торговая пара: {symbol}", + f"Режим позиции: {position_idx_rus}", + f"Цена входа: {avg_price}", + f"Количество: {size}", + f"Движение: {side_rus}", + ] + + if take_profit and take_profit != "Нет данных": + text_lines.append(f"Тейк-профит: {take_profit}") + if stop_loss and stop_loss != "Нет данных": + text_lines.append(f"Стоп-лосс: {stop_loss}") + if liq_price and liq_price != "Нет данных": + text_lines.append(f"Цена ликвидации: {liq_price}") + + text = "\n".join(text_lines) await callback_query.message.edit_text( - text=f"Торговая пара: {symbol}\n" - f"Режим позиции: {position_idx_rus}\n" - f"Цена входа: {avg_price}\n" - f"Количество: {size}\n" - f"Движение: {side_rus}\n" - f"Тейк-профит: {take_profit}\n" - f"Стоп-лосс: {stop_loss}\n", - reply_markup=kbi.make_close_position_keyboard(symbol_pos=symbol, - side=side, - position_idx=position_idx, - qty=size), + text=text, + reply_markup=kbi.make_close_position_keyboard( + symbol_pos=symbol, side=side, position_idx=position_idx, qty=size + ), ) except Exception as e: @@ -159,7 +183,7 @@ async def get_position_handler(callback_query: CallbackQuery, state: FSMContext) @router_get_positions_handlers.callback_query(F.data == "open_orders") async def get_open_orders_handler( - callback_query: CallbackQuery, state: FSMContext + callback_query: CallbackQuery, state: FSMContext ) -> None: """ Gets the user's open orders. @@ -186,7 +210,9 @@ async def get_open_orders_handler( await callback_query.answer(text="Нет активных ордеров.") return - active_orders_sides = [(pos.get("symbol"), pos.get("side")) for pos in active_positions] + active_orders_sides = [ + (pos.get("symbol"), pos.get("side")) for pos in active_positions + ] await callback_query.message.edit_text( text="Ваши активные ордера:", @@ -222,13 +248,13 @@ async def get_order_handler(callback_query: CallbackQuery, state: FSMContext): if orders: side = orders.get("side") - symbol = orders.get("symbol") or "Нет данных" - price = orders.get("price") or "Нет данных" - qty = orders.get("qty") or "Нет данных" - order_type = orders.get("orderType") or "" - trigger_price = orders.get("triggerPrice") or "Нет данных" - take_profit = orders.get("takeProfit") or "Нет данных" - stop_loss = orders.get("stopLoss") or "Нет данных" + symbol = orders.get("symbol") + price = orders.get("price") + qty = orders.get("qty") + order_type = orders.get("orderType") + trigger_price = orders.get("triggerPrice") + take_profit = orders.get("takeProfit") + stop_loss = orders.get("stopLoss") order_id = orders.get("orderId") else: side = "Нет данных" @@ -253,16 +279,31 @@ async def get_order_handler(callback_query: CallbackQuery, state: FSMContext): else "Лимитный" if order_type == "Limit" else "Нет данных" ) + text_lines = [ + f"Торговая пара: {symbol}", + f"Количество: {qty}", + f"Движение: {side_rus}", + f"Тип ордера: {order_type_rus}", + ] + if price: + text_lines.append(f"Цена: {price}") + + if trigger_price and trigger_price != "Нет данных": + text_lines.append(f"Триггер цена: {trigger_price}") + + if take_profit and take_profit != "Нет данных": + text_lines.append(f"Тейк-профит: {take_profit}") + + if stop_loss and stop_loss != "Нет данных": + text_lines.append(f"Стоп-лосс: {stop_loss}") + + text = "\n".join(text_lines) + await callback_query.message.edit_text( - text=f"Торговая пара: {symbol}\n" - f"Цена: {price}\n" - f"Количество: {qty}\n" - f"Движение: {side_rus}\n" - f"Тип ордера: {order_type_rus}\n" - f"Триггер цена: {trigger_price}\n" - f"Тейк-профит: {take_profit}\n" - f"Стоп-лосс: {stop_loss}\n", - reply_markup=kbi.make_close_orders_keyboard(symbol_order=symbol, order_id=order_id), + text=text, + reply_markup=kbi.make_close_orders_keyboard( + symbol_order=symbol, order_id=order_id + ), ) except Exception as e: logger.error("Error in get_order_handler: %s", e) diff --git a/app/telegram/handlers/start_trading.py b/app/telegram/handlers/start_trading.py index cc05813..85683f6 100644 --- a/app/telegram/handlers/start_trading.py +++ b/app/telegram/handlers/start_trading.py @@ -162,17 +162,18 @@ async def start_trading_long(callback_query: CallbackQuery, state: FSMContext) - "Order does not meet minimum order value": "Сумма ордера не достаточна для запуска торговли", "position idx not match position mode": "Торговля уже запущена в режиме хеджирования на продажу для данного инструмента", "Qty invalid": "Некорректное значение ордера для данного инструмента", + "The number of contracts exceeds maximum limit allowed": "️️Количество контрактов превышает допустимое максимальное количество контрактов", } if res == "OK": - await callback_query.answer(text="Торговля запущена") + await callback_query.message.edit_text(text="Торговля запущена") await state.clear() else: await rq.set_auto_trading( tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, side=side ) text = error_messages.get(res, "Произошла ошибка при запуске торговли") - await callback_query.answer(text=text) + await callback_query.message.edit_text(text=text, reply_markup=kbi.profile_bybit) await callback_query.message.edit_text("Запуск торговли...") task = asyncio.create_task(delay_start()) @@ -299,6 +300,11 @@ async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None await rq.set_auto_trading( tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True, side=side ) + if side == "Buy": + r_side = "Sell" + else: + r_side = "Buy" + await rq.set_auto_trading(tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True, side=r_side) res = await start_trading_cycle( tg_id=callback_query.from_user.id, side=side, @@ -315,17 +321,24 @@ async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None "Order does not meet minimum order value": "Сумма ордера не достаточна для запуска торговли", "position idx not match position mode": "Торговля уже запущена в режиме хеджирования на продажу для данного инструмента", "Qty invalid": "Некорректное значение ордера для данного инструмента", + "The number of contracts exceeds maximum limit allowed": "️ ️️Количество контрактов превышает допустимое максимальное количество контрактов", } if res == "OK": - await callback_query.answer(text="Торговля запущена") + await callback_query.message.edit_text(text="Торговля запущена") await state.clear() else: await rq.set_auto_trading( tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, side=side ) + if side == "Buy": + r_side = "Sell" + else: + r_side = "Buy" + await rq.set_auto_trading(tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, + side=r_side) text = error_messages.get(res, "Произошла ошибка при запуске торговли") - await callback_query.answer(text=text) + await callback_query.message.edit_text(text=text, reply_markup=kbi.profile_bybit) await callback_query.message.edit_text("Запуск торговли...") task = asyncio.create_task(delay_start()) diff --git a/app/telegram/handlers/stop_trading.py b/app/telegram/handlers/stop_trading.py index 6d83cb0..e9fc6c4 100644 --- a/app/telegram/handlers/stop_trading.py +++ b/app/telegram/handlers/stop_trading.py @@ -37,21 +37,32 @@ async def stop_all_trading(callback_query: CallbackQuery, state: FSMContext): await rq.set_stop_timer(tg_id=callback_query.from_user.id, timer_end=0) await asyncio.sleep(timer_end * 60) - user_auto_trading_list = await rq.get_all_user_auto_trading(tg_id=callback_query.from_user.id) + user_auto_trading_list = await rq.get_all_user_auto_trading( + tg_id=callback_query.from_user.id + ) - for active_auto_trading in user_auto_trading_list: - if active_auto_trading.auto_trading: - symbol = active_auto_trading.symbol - get_side = active_auto_trading.side - req = await rq.set_auto_trading( - tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, side=get_side - ) - if not req: - await callback_query.edit_text(text="Произошла ошибка при остановке торговли", - reply_markup=kbi.profile_bybit) - return - - await callback_query.message.edit_text(text="Торговля остановлена", reply_markup=kbi.profile_bybit) + if any(item.auto_trading for item in user_auto_trading_list): + for active_auto_trading in user_auto_trading_list: + if active_auto_trading.auto_trading: + symbol = active_auto_trading.symbol + get_side = active_auto_trading.side + req = await rq.set_auto_trading( + tg_id=callback_query.from_user.id, + symbol=symbol, + auto_trading=False, + side=get_side, + ) + if not req: + await callback_query.message.edit_text( + text="Произошла ошибка при остановке торговли", + reply_markup=kbi.profile_bybit, + ) + return + await callback_query.message.edit_text( + text="Торговля остановлена", reply_markup=kbi.profile_bybit + ) + else: + await callback_query.message.edit_text(text="Нет активной торговли") task = asyncio.create_task(delay_start()) await add_stop_task(user_id=callback_query.from_user.id, task=task) @@ -74,11 +85,15 @@ async def cancel_stop_trading(callback_query: CallbackQuery, state: FSMContext): try: await state.clear() cancel_stop_task(callback_query.from_user.id) - await callback_query.message.edit_text(text="Таймер отменён.", reply_markup=kbi.profile_bybit) + await callback_query.message.edit_text( + text="Таймер отменён.", reply_markup=kbi.profile_bybit + ) except Exception as e: - await callback_query.answer(text="Произошла ошибка при отмене остановки торговли") + await callback_query.answer( + text="Произошла ошибка при отмене остановки торговли" + ) logger.error( "Error processing command cancel_timer_stop for user %s: %s", callback_query.from_user.id, e, - ) \ No newline at end of file + )