develop #3
| @@ -1,12 +1,9 @@ | |||||||
| import asyncio | import asyncio | ||||||
| import nest_asyncio |  | ||||||
|  |  | ||||||
| import time | import time | ||||||
|  | import json | ||||||
| import logging.config | import logging.config | ||||||
| from pybit import exceptions | from pybit import exceptions | ||||||
| from pybit.unified_trading import HTTP, WebSocket | from pybit.unified_trading import HTTP | ||||||
| from websocket import WebSocketConnectionClosedException |  | ||||||
|  |  | ||||||
| from logger_helper.logger_helper import LOGGING_CONFIG | from logger_helper.logger_helper import LOGGING_CONFIG | ||||||
| import app.services.Bybit.functions.price_symbol as price_symbol | import app.services.Bybit.functions.price_symbol as price_symbol | ||||||
| import app.services.Bybit.functions.balance as balance_g | import app.services.Bybit.functions.balance as balance_g | ||||||
| @@ -16,8 +13,6 @@ import app.telegram.Keyboards.inline_keyboards as inline_markup | |||||||
| logging.config.dictConfig(LOGGING_CONFIG) | logging.config.dictConfig(LOGGING_CONFIG) | ||||||
| logger = logging.getLogger("futures") | logger = logging.getLogger("futures") | ||||||
|  |  | ||||||
| nest_asyncio.apply() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def safe_float(val) -> float: | def safe_float(val) -> float: | ||||||
|     """ |     """ | ||||||
| @@ -33,6 +28,53 @@ def safe_float(val) -> float: | |||||||
|         return 0.0 |         return 0.0 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def format_trade_details_position(data): | ||||||
|  |     """ | ||||||
|  |     Форматирует информацию о сделке в виде строки. | ||||||
|  |     """ | ||||||
|  |     msg = data.get('data', [{}])[0] | ||||||
|  |  | ||||||
|  |     closed_size = float(msg.get('closedSize', 0)) | ||||||
|  |     symbol = msg.get('symbol', 'N/A') | ||||||
|  |     entry_price = float(msg.get('execPrice', 0)) | ||||||
|  |     qty = float(msg.get('execQty', 0)) | ||||||
|  |     order_type = msg.get('orderType', 'N/A') | ||||||
|  |     side = msg.get('side', '') | ||||||
|  |     commission_fee = float(msg.get('execFee', 0)) | ||||||
|  |     pnl = float(msg.get('execPnl', 0)) | ||||||
|  |  | ||||||
|  |     movement = '' | ||||||
|  |     if side.lower() == 'buy': | ||||||
|  |         movement = 'Покупка' | ||||||
|  |     elif side.lower() == 'sell': | ||||||
|  |         movement = 'Продажа' | ||||||
|  |     else: | ||||||
|  |         movement = side | ||||||
|  |  | ||||||
|  |     if closed_size > 0: | ||||||
|  |         return ( | ||||||
|  |             f"Сделка закрыта:\n" | ||||||
|  |             f"Торговая пара: {symbol}\n" | ||||||
|  |             f"Цена исполнения: {entry_price:.6f}\n" | ||||||
|  |             f"Количество: {qty}\n" | ||||||
|  |             f"Закрыто позиций: {closed_size}\n" | ||||||
|  |             f"Тип ордера: {order_type}\n" | ||||||
|  |             f"Движение: {movement}\n" | ||||||
|  |             f"Комиссия за сделку: {commission_fee:.6f}\n" | ||||||
|  |             f"Реализованная прибыль: {pnl:.6f} USDT" | ||||||
|  |         ) | ||||||
|  |     else: | ||||||
|  |         return ( | ||||||
|  |             f"Сделка открыта:\n" | ||||||
|  |             f"Торговая пара: {symbol}\n" | ||||||
|  |             f"Цена исполнения: {entry_price:.6f}\n" | ||||||
|  |             f"Количество: {qty}\n" | ||||||
|  |             f"Тип ордера: {order_type}\n" | ||||||
|  |             f"Движение: {movement}\n" | ||||||
|  |             f"Комиссия за сделку: {commission_fee:.6f}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def parse_pnl_from_msg(msg) -> float: | def parse_pnl_from_msg(msg) -> float: | ||||||
|     """ |     """ | ||||||
|     Извлекает реализованную прибыль/убыток из сообщения. |     Извлекает реализованную прибыль/убыток из сообщения. | ||||||
| @@ -49,8 +91,6 @@ async def handle_execution_message(message, msg: dict) -> None: | |||||||
|     Обработчик сообщений об исполнении сделки. |     Обработчик сообщений об исполнении сделки. | ||||||
|     Логирует событие и проверяет условия для мартингейла и TP. |     Логирует событие и проверяет условия для мартингейла и TP. | ||||||
|     """ |     """ | ||||||
|     logger.info(f"Исполнена сделка: {msg}") |  | ||||||
|     await message.answer(f"Исполнена сделка: {msg}") |  | ||||||
|  |  | ||||||
|     pnl = parse_pnl_from_msg(msg) |     pnl = parse_pnl_from_msg(msg) | ||||||
|     tg_id = message.from_user.id |     tg_id = message.from_user.id | ||||||
| @@ -66,6 +106,9 @@ async def handle_execution_message(message, msg: dict) -> None: | |||||||
|     positions_list = positions_resp.get('result', {}).get('list', []) |     positions_list = positions_resp.get('result', {}).get('list', []) | ||||||
|     position = positions_list[0] if positions_list else None |     position = positions_list[0] if positions_list else None | ||||||
|  |  | ||||||
|  |     trade_info = format_trade_details_position(msg) | ||||||
|  |     await message.answer(f"{trade_info}", reply_markup=inline_markup.back_to_main) | ||||||
|  |  | ||||||
|     liquidation_threshold = -100 |     liquidation_threshold = -100 | ||||||
|  |  | ||||||
|     if pnl <= liquidation_threshold: |     if pnl <= liquidation_threshold: | ||||||
| @@ -94,64 +137,6 @@ async def handle_execution_message(message, msg: dict) -> None: | |||||||
|                 await rq.update_martingale_step(tg_id, 0) |                 await rq.update_martingale_step(tg_id, 0) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def start_execution_ws(tg_id, message) -> None: |  | ||||||
|     """ |  | ||||||
|     Запускает WebSocket для отслеживания исполнения сделок в режиме реального времени. |  | ||||||
|     Переподключается при ошибках. |  | ||||||
|     """ |  | ||||||
|     api_key = await rq.get_bybit_api_key(tg_id) |  | ||||||
|     api_secret = await rq.get_bybit_secret_key(tg_id) |  | ||||||
|  |  | ||||||
|     reconnect_delay = 5 |  | ||||||
|  |  | ||||||
|     while True: |  | ||||||
|         try: |  | ||||||
|             ws = WebSocket(api_key=api_key, |  | ||||||
|                            api_secret=api_secret, |  | ||||||
|                            testnet=False, |  | ||||||
|                            channel_type="private") |  | ||||||
|  |  | ||||||
|             async def on_execution(msg): |  | ||||||
|                 await handle_execution_message(message, msg) |  | ||||||
|  |  | ||||||
|             def on_execution_sync(msg): |  | ||||||
|                 asyncio.create_task(on_execution(msg)) |  | ||||||
|  |  | ||||||
|             ws.execution_stream(on_execution_sync) |  | ||||||
|  |  | ||||||
|             while True: |  | ||||||
|                 await asyncio.sleep(1) |  | ||||||
|  |  | ||||||
|         except WebSocketConnectionClosedException: |  | ||||||
|             logging.warning("WebSocket закрыт, переподключение через 5 секунд...") |  | ||||||
|             await asyncio.sleep(reconnect_delay) |  | ||||||
|  |  | ||||||
|         except Exception as e: |  | ||||||
|             logging.error(f"Ошибка WebSocket: {e}") |  | ||||||
|             await asyncio.sleep(reconnect_delay) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def info_access_open_deal(message, symbol, trade_mode, margin_mode, leverage, qty, tp, sl, entry_price, |  | ||||||
|                                 limit_price, order_type) -> None: |  | ||||||
|     """ |  | ||||||
|     Отправляет сообщение об успешном открытии позиции или выставлении лимитного ордера. |  | ||||||
|     """ |  | ||||||
|     human_margin_mode = 'Isolated' if margin_mode == 'ISOLATED_MARGIN' else 'Cross' |  | ||||||
|     text = ( |  | ||||||
|         f"{'Позиция была успешна открыта' if order_type == 'Market' else 'Лимитный ордер установлен'}!\n" |  | ||||||
|         f"Торговая пара: {symbol}\n" |  | ||||||
|         f"Цена входа: {entry_price if order_type == 'Market' else round(limit_price, 5)}\n" |  | ||||||
|         f"Движение: {trade_mode}\n" |  | ||||||
|         f"Тип-маржи: {human_margin_mode}\n" |  | ||||||
|         f"Кредитное плечо: {leverage}x\n" |  | ||||||
|         f"Количество: {qty}\n" |  | ||||||
|         f"Тейк-профит: {round(tp, 5)}\n" |  | ||||||
|         f"Стоп-лосс: {round(sl, 5)}\n" |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.create_close_deal_markup(symbol)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def error_max_step(message) -> None: | async def error_max_step(message) -> None: | ||||||
|     """ |     """ | ||||||
|     Сообщение об ошибке превышения максимального количества шагов мартингейла. |     Сообщение об ошибке превышения максимального количества шагов мартингейла. | ||||||
| @@ -340,10 +325,6 @@ async def open_position(tg_id, message, side: str, margin_mode: str, tpsl_mode=' | |||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         if response.get('retCode', -1) == 0: |         if response.get('retCode', -1) == 0: | ||||||
|             await info_access_open_deal(message, symbol, data_main_stgs.get('trading_mode', ''), |  | ||||||
|                                         bybit_margin_mode, |  | ||||||
|                                         data_main_stgs.get('size_leverage', 1), next_quantity, take_profit_price, |  | ||||||
|                                         stop_loss_price, entry_price, limit_price, order_type=order_type) |  | ||||||
|             await rq.update_martingale_step(tg_id, current_martingale_step) |             await rq.update_martingale_step(tg_id, current_martingale_step) | ||||||
|             return True |             return True | ||||||
|         else: |         else: | ||||||
| @@ -417,7 +398,7 @@ async def set_take_profit_stop_loss(tg_id: int, message, take_profit_price: floa | |||||||
|         return |         return | ||||||
|  |  | ||||||
|     client = HTTP(api_key=api_key, api_secret=secret_key) |     client = HTTP(api_key=api_key, api_secret=secret_key) | ||||||
|     await cancel_all_tp_sl_orders(client, symbol) |     await cancel_all_tp_sl_orders(tg_id, symbol) | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         try: |         try: | ||||||
| @@ -648,15 +629,6 @@ async def close_user_trade(tg_id: int, symbol: str, message): | |||||||
|                 if include_fee: |                 if include_fee: | ||||||
|                     pnl -= trade_fee |                     pnl -= trade_fee | ||||||
|                 pnl_percent = (pnl / (entry_price * qty)) * 100 if entry_price * qty > 0 else 0 |                 pnl_percent = (pnl / (entry_price * qty)) * 100 if entry_price * qty > 0 else 0 | ||||||
|  |  | ||||||
|                 text = ( |  | ||||||
|                     f"Сделка {symbol} успешно закрыта.\n" |  | ||||||
|                     f"Цена входа: {entry_price if entry_price else limit_price}\n" |  | ||||||
|                     f"Цена закрытия: {current_price}\n" |  | ||||||
|                     f"Прибыль: {pnl:.4f} USDT ({pnl_percent:.2f}%)\n" |  | ||||||
|                     f"{'Включая комиссию биржи' if include_fee else 'Без учета комиссии'}" |  | ||||||
|                 ) |  | ||||||
|                 await message.answer(text) |  | ||||||
|                 return True |                 return True | ||||||
|             else: |             else: | ||||||
|                 if message: |                 if message: | ||||||
|   | |||||||
| @@ -1,14 +1,12 @@ | |||||||
| import asyncio | import logging.config | ||||||
| import logging.config |  | ||||||
| from aiogram import F, Router | from aiogram import F, Router | ||||||
|  |  | ||||||
| from app.tasks.tasks import active_close_tasks, active_start_tasks | from app.tasks.tasks import handle_stop_close_trade, handle_start_close_trade, handle_stop_trading, handle_start_trading | ||||||
| from logger_helper.logger_helper import LOGGING_CONFIG | from logger_helper.logger_helper import LOGGING_CONFIG | ||||||
|  |  | ||||||
| from app.services.Bybit.functions.Futures import (close_user_trade, close_trade_after_delay, | from app.services.Bybit.functions.Futures import (close_user_trade, open_position, set_take_profit_stop_loss, \ | ||||||
|                                                   trading_cycle, open_position, set_take_profit_stop_loss, \ |  | ||||||
|                                                   get_active_positions_by_symbol, get_active_orders_by_symbol, |                                                   get_active_positions_by_symbol, get_active_orders_by_symbol, | ||||||
|                                                   start_execution_ws) |                                                   ) | ||||||
| from app.services.Bybit.functions.balance import get_balance | from app.services.Bybit.functions.balance import get_balance | ||||||
| import app.telegram.Keyboards.inline_keyboards as inline_markup | import app.telegram.Keyboards.inline_keyboards as inline_markup | ||||||
|  |  | ||||||
| @@ -35,15 +33,16 @@ async def clb_start_bybit_trade_message(callback: CallbackQuery) -> None: | |||||||
|     Обработка нажатия кнопок запуска торговли или возврата в главное меню. |     Обработка нажатия кнопок запуска торговли или возврата в главное меню. | ||||||
|     Отправляет информацию о балансе, символе, цене и инструкциях по торговле. |     Отправляет информацию о балансе, символе, цене и инструкциях по торговле. | ||||||
|     """ |     """ | ||||||
|     balance = await get_balance(callback.from_user.id, callback.message) |     user_id = callback.from_user.id | ||||||
|     price = await get_price(callback.from_user.id) |     balance = await get_balance(user_id, callback.message) | ||||||
|  |     price = await get_price(user_id) | ||||||
|  |  | ||||||
|     if balance: |     if balance: | ||||||
|         symbol = await rq.get_symbol(callback.from_user.id) |         symbol = await rq.get_symbol(user_id) | ||||||
|  |  | ||||||
|         text = ( |         text = ( | ||||||
|             f"💎 Торговля на Bybit\n\n" |             f"💎 Торговля на Bybit\n\n" | ||||||
|             f"⚖️ Ваш баланс (USDT): {balance}\n" |             f"⚖️ Ваш баланс (USDT): {float(balance):.2f}\n" | ||||||
|             f"📊 Текущая торговая пара: {symbol}\n" |             f"📊 Текущая торговая пара: {symbol}\n" | ||||||
|             f"$$$ Цена: {price}\n\n" |             f"$$$ Цена: {price}\n\n" | ||||||
|             "Как начать торговлю?\n\n" |             "Как начать торговлю?\n\n" | ||||||
| @@ -52,7 +51,6 @@ async def clb_start_bybit_trade_message(callback: CallbackQuery) -> None: | |||||||
|             "3️⃣ Нажмите кнопку 'Выбрать тип входа' и после нажмите начать торговлю.\n" |             "3️⃣ Нажмите кнопку 'Выбрать тип входа' и после нажмите начать торговлю.\n" | ||||||
|         ) |         ) | ||||||
|         await callback.message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.trading_markup) |         await callback.message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.trading_markup) | ||||||
|         asyncio.create_task(start_execution_ws(callback.from_user.id, callback.message)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def start_bybit_trade_message(message: Message) -> None: | async def start_bybit_trade_message(message: Message) -> None: | ||||||
| @@ -240,6 +238,7 @@ async def start_trading_process(callback: CallbackQuery) -> None: | |||||||
|  |  | ||||||
|     await message.answer("Начинаю торговлю с использованием текущих настроек...") |     await message.answer("Начинаю торговлю с использованием текущих настроек...") | ||||||
|  |  | ||||||
|  |  | ||||||
|     timer_data = await rq.get_user_timer(tg_id) |     timer_data = await rq.get_user_timer(tg_id) | ||||||
|     if isinstance(timer_data, dict): |     if isinstance(timer_data, dict): | ||||||
|         timer_minute = timer_data.get('timer_minutes', 0) |         timer_minute = timer_data.get('timer_minutes', 0) | ||||||
| @@ -247,15 +246,7 @@ async def start_trading_process(callback: CallbackQuery) -> None: | |||||||
|         timer_minute = timer_data or 0 |         timer_minute = timer_data or 0 | ||||||
|  |  | ||||||
|     if timer_minute > 0: |     if timer_minute > 0: | ||||||
|         old_task = active_start_tasks.get(tg_id) |         await handle_start_trading(tg_id, message) | ||||||
|         if old_task and not old_task.done(): |  | ||||||
|             old_task.cancel() |  | ||||||
|             try: |  | ||||||
|                 await old_task |  | ||||||
|             except asyncio.CancelledError: |  | ||||||
|                 logger.info(f"Старая задача торговли для пользователя {tg_id} отменена") |  | ||||||
|         task = asyncio.create_task(trading_cycle(tg_id, message)) |  | ||||||
|         active_start_tasks[tg_id] = task |  | ||||||
|         await message.answer(f"Торговля начнётся через {timer_minute} мин. Для отмены нажмите кнопку ниже.", |         await message.answer(f"Торговля начнётся через {timer_minute} мин. Для отмены нажмите кнопку ниже.", | ||||||
|                              reply_markup=inline_markup.cancel_start_markup) |                              reply_markup=inline_markup.cancel_start_markup) | ||||||
|         await rq.update_user_timer(tg_id, minutes=0) |         await rq.update_user_timer(tg_id, minutes=0) | ||||||
| @@ -281,6 +272,9 @@ async def show_my_trades(callback: CallbackQuery) -> None: | |||||||
|  |  | ||||||
| @router_functions_bybit_trade.callback_query(F.data == "clb_open_deals") | @router_functions_bybit_trade.callback_query(F.data == "clb_open_deals") | ||||||
| async def show_my_trades_callback(callback: CallbackQuery): | async def show_my_trades_callback(callback: CallbackQuery): | ||||||
|  |     """ | ||||||
|  |     Показывает открытые позиции пользователя по символу. | ||||||
|  |     """ | ||||||
|     await callback.answer() |     await callback.answer() | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
| @@ -373,13 +367,9 @@ async def cancel_start_callback(callback: CallbackQuery) -> None: | |||||||
|     Отменяет задачу старта торговли по таймеру, если она активна. |     Отменяет задачу старта торговли по таймеру, если она активна. | ||||||
|     """ |     """ | ||||||
|     tg_id = callback.from_user.id |     tg_id = callback.from_user.id | ||||||
|     task = active_start_tasks.get(tg_id) |     await handle_stop_close_trade(tg_id) | ||||||
|     if task: |  | ||||||
|         task.cancel() |     await callback.message.answer("Торговля по таймеру отменена.", reply_markup=inline_markup.back_to_main) | ||||||
|         del active_start_tasks[tg_id] |  | ||||||
|         await callback.message.answer("Торговля по таймеру отменена.", reply_markup=inline_markup.back_to_main) |  | ||||||
|     else: |  | ||||||
|         await callback.message.answer("Нет активности для отмены.", reply_markup=inline_markup.back_to_main) |  | ||||||
|     await callback.answer() |     await callback.answer() | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -394,7 +384,7 @@ async def close_trade_callback(callback: CallbackQuery) -> None: | |||||||
|     result = await close_user_trade(tg_id, symbol, message=callback.message) |     result = await close_user_trade(tg_id, symbol, message=callback.message) | ||||||
|  |  | ||||||
|     if result: |     if result: | ||||||
|         await callback.message.answer("Сделка успешно закрыта.", reply_markup=inline_markup.back_to_main) |         await handle_stop_trading(tg_id) | ||||||
|         logger.info(f"Сделка {symbol} успешно закрыта.") |         logger.info(f"Сделка {symbol} успешно закрыта.") | ||||||
|     else: |     else: | ||||||
|         logger.error(f"Не удалось закрыть сделку {symbol}.") |         logger.error(f"Не удалось закрыть сделку {symbol}.") | ||||||
| @@ -436,17 +426,7 @@ async def process_close_delay(message: Message, state: FSMContext) -> None: | |||||||
|  |  | ||||||
|     delay = delay_minutes * 60 |     delay = delay_minutes * 60 | ||||||
|  |  | ||||||
|     if tg_id in active_close_tasks: |     await handle_start_close_trade(tg_id, message, symbol, delay) | ||||||
|         old_task = active_close_tasks[tg_id] |  | ||||||
|         if not old_task.done(): |  | ||||||
|             old_task.cancel() |  | ||||||
|             try: |  | ||||||
|                 await old_task |  | ||||||
|             except asyncio.CancelledError: |  | ||||||
|                 logger.info(f"Предыдущая задача закрытия сделки пользователя {tg_id} отменена") |  | ||||||
|  |  | ||||||
|     task = asyncio.create_task(close_trade_after_delay(tg_id, message, symbol, delay)) |  | ||||||
|     active_close_tasks[tg_id] = task |  | ||||||
|  |  | ||||||
|     await message.answer(f"Закрытие сделки {symbol} запланировано через {delay} секунд.", |     await message.answer(f"Закрытие сделки {symbol} запланировано через {delay} секунд.", | ||||||
|                          reply_markup=inline_markup.cancel_start_markup) |                          reply_markup=inline_markup.cancel_start_markup) | ||||||
| @@ -458,11 +438,9 @@ async def reset_martingale(callback: CallbackQuery) -> None: | |||||||
|     """ |     """ | ||||||
|     Сбрасывает шаги мартингейла пользователя. |     Сбрасывает шаги мартингейла пользователя. | ||||||
|     """ |     """ | ||||||
|     await callback.answer() |  | ||||||
|     tg_id = callback.from_user.id |     tg_id = callback.from_user.id | ||||||
|     await rq.update_martingale_step(tg_id, 0) |     await rq.update_martingale_step(tg_id, 0) | ||||||
|     await callback.message.answer("Сброс шагов выполнен.", |     await callback.answer("Сброс шагов выполнен.") | ||||||
|                                   reply_markup=inline_markup.back_to_main) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @router_functions_bybit_trade.callback_query(F.data == "clb_cancel") | @router_functions_bybit_trade.callback_query(F.data == "clb_cancel") | ||||||
|   | |||||||
| @@ -3,29 +3,37 @@ from logger_helper.logger_helper import LOGGING_CONFIG | |||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
| from typing import Any | from typing import Any | ||||||
|  |  | ||||||
|  | from app.telegram.database.models import ( | ||||||
|  |     async_session, | ||||||
|  |     User_Telegram_Id as UTi, | ||||||
|  |     User_Main_Settings as UMS, | ||||||
|  |     User_Bybit_API as UBA, | ||||||
|  |     User_Symbol, | ||||||
|  |     User_Risk_Management_Settings as URMS, | ||||||
|  |     User_Condition_Settings as UCS, | ||||||
|  |     User_Additional_Settings as UAS, | ||||||
|  |     Trading_Mode, | ||||||
|  |     Margin_type, | ||||||
|  |     Trigger, | ||||||
|  |     USER_DEALS, | ||||||
|  |     UserTimer, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from sqlalchemy import select, update | ||||||
|  |  | ||||||
| logging.config.dictConfig(LOGGING_CONFIG) | logging.config.dictConfig(LOGGING_CONFIG) | ||||||
| logger = logging.getLogger("requests") | logger = logging.getLogger("requests") | ||||||
|  |  | ||||||
| from app.telegram.database.models import async_session |  | ||||||
| from app.telegram.database.models import User_Telegram_Id as UTi |  | ||||||
| from app.telegram.database.models import User_Main_Settings as UMS |  | ||||||
| from app.telegram.database.models import User_Bybit_API as UBA |  | ||||||
| from app.telegram.database.models import User_Symbol |  | ||||||
| from app.telegram.database.models import User_Risk_Management_Settings as URMS |  | ||||||
| from app.telegram.database.models import User_Condition_Settings as UCS |  | ||||||
| from app.telegram.database.models import User_Additional_Settings as UAS |  | ||||||
| from app.telegram.database.models import Trading_Mode |  | ||||||
| from app.telegram.database.models import Margin_type |  | ||||||
| from app.telegram.database.models import Trigger |  | ||||||
| from app.telegram.database.models import USER_DEALS, UserTimer |  | ||||||
|  |  | ||||||
| import app.telegram.functions.functions as func  # functions | # --- Функции сохранения в БД --- | ||||||
|  |  | ||||||
| from sqlalchemy import select, delete, update | async def save_tg_id_new_user(tg_id) -> None: | ||||||
|  |     """ | ||||||
|  |     Сохраняет Telegram ID нового пользователя в базу, если такого ещё нет. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
| # SET_DB |         tg_id (int): Telegram ID пользователя. | ||||||
| async def save_tg_id_new_user(tg_id): |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(UTi).where(UTi.tg_id == tg_id)) |         user = await session.scalar(select(UTi).where(UTi.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -37,26 +45,33 @@ async def save_tg_id_new_user(tg_id): | |||||||
|         await session.commit() |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
| async def set_new_user_bybit_api(tg_id): | async def set_new_user_bybit_api(tg_id) -> None: | ||||||
|  |     """ | ||||||
|  |     Создаёт запись API пользователя Bybit, если её ещё нет. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(UBA).where(UBA.tg_id == tg_id)) |         user = await session.scalar(select(UBA).where(UBA.tg_id == tg_id)) | ||||||
|  |  | ||||||
|         if not user: |         if not user: | ||||||
|             session.add(UBA( |             session.add(UBA(tg_id=tg_id)) | ||||||
|                 tg_id=tg_id, |  | ||||||
|             )) |  | ||||||
|  |  | ||||||
|         await session.commit() |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
| async def set_new_user_symbol(tg_id): | async def set_new_user_symbol(tg_id) -> None: | ||||||
|  |     """ | ||||||
|  |     Создаёт запись торгового символа пользователя, если её нет. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(User_Symbol).where(User_Symbol.tg_id == tg_id)) |         user = await session.scalar(select(User_Symbol).where(User_Symbol.tg_id == tg_id)) | ||||||
|  |  | ||||||
|         if not user: |         if not user: | ||||||
|             session.add(User_Symbol( |             session.add(User_Symbol(tg_id=tg_id)) | ||||||
|                 tg_id=tg_id |  | ||||||
|             )) |  | ||||||
|  |  | ||||||
|             logger.info(f"Symbol был успешно добавлен %s", tg_id) |             logger.info(f"Symbol был успешно добавлен %s", tg_id) | ||||||
|  |  | ||||||
| @@ -64,6 +79,14 @@ async def set_new_user_symbol(tg_id): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def set_new_user_default_main_settings(tg_id, trading_mode, margin_type) -> None: | async def set_new_user_default_main_settings(tg_id, trading_mode, margin_type) -> None: | ||||||
|  |     """ | ||||||
|  |     Создаёт основные настройки пользователя по умолчанию. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |         trading_mode (str): Режим торговли. | ||||||
|  |         margin_type (str): Тип маржи. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         settings = await session.scalar(select(UMS).where(UMS.tg_id == tg_id)) |         settings = await session.scalar(select(UMS).where(UMS.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -80,6 +103,12 @@ async def set_new_user_default_main_settings(tg_id, trading_mode, margin_type) - | |||||||
|  |  | ||||||
|  |  | ||||||
| async def set_new_user_default_risk_management_settings(tg_id) -> None: | async def set_new_user_default_risk_management_settings(tg_id) -> None: | ||||||
|  |     """ | ||||||
|  |     Создаёт настройки риск-менеджмента по умолчанию. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         settings = await session.scalar(select(URMS).where(URMS.tg_id == tg_id)) |         settings = await session.scalar(select(URMS).where(URMS.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -94,6 +123,13 @@ async def set_new_user_default_risk_management_settings(tg_id) -> None: | |||||||
|  |  | ||||||
|  |  | ||||||
| async def set_new_user_default_condition_settings(tg_id, trigger) -> None: | async def set_new_user_default_condition_settings(tg_id, trigger) -> None: | ||||||
|  |     """ | ||||||
|  |     Создаёт условные настройки по умолчанию. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |         trigger (Any): Значение триггера по умолчанию. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         settings = await session.scalar(select(UCS).where(UCS.tg_id == tg_id)) |         settings = await session.scalar(select(UCS).where(UCS.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -109,6 +145,12 @@ async def set_new_user_default_condition_settings(tg_id, trigger) -> None: | |||||||
|  |  | ||||||
|  |  | ||||||
| async def set_new_user_default_additional_settings(tg_id) -> None: | async def set_new_user_default_additional_settings(tg_id) -> None: | ||||||
|  |     """ | ||||||
|  |     Создаёт дополнительные настройки по умолчанию. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         settings = await session.scalar(select(UAS).where(UAS.tg_id == tg_id)) |         settings = await session.scalar(select(UAS).where(UAS.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -122,32 +164,46 @@ async def set_new_user_default_additional_settings(tg_id) -> None: | |||||||
|         await session.commit() |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
| # GET_DB | # --- Функции получения данных из БД --- | ||||||
|  |  | ||||||
| async def check_user(tg_id): | async def check_user(tg_id): | ||||||
|  |     """ | ||||||
|  |     Проверяет наличие пользователя в базе. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         tg_id (int): Telegram ID пользователя. | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         Optional[UTi]: Пользователь или None. | ||||||
|  |     """ | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(UTi).where(UTi.tg_id == tg_id)) |         user = await session.scalar(select(UTi).where(UTi.tg_id == tg_id)) | ||||||
|         return user |         return user | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_bybit_api_key(tg_id): | async def get_bybit_api_key(tg_id): | ||||||
|  |     """Получить API ключ Bybit пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         api_key = await session.scalar(select(UBA.api_key).where(UBA.tg_id == tg_id)) |         api_key = await session.scalar(select(UBA.api_key).where(UBA.tg_id == tg_id)) | ||||||
|         return api_key |         return api_key | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_bybit_secret_key(tg_id): | async def get_bybit_secret_key(tg_id): | ||||||
|  |     """Получить секретный ключ Bybit пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         secret_key = await session.scalar(select(UBA.secret_key).where(UBA.tg_id == tg_id)) |         secret_key = await session.scalar(select(UBA.secret_key).where(UBA.tg_id == tg_id)) | ||||||
|         return secret_key |         return secret_key | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_symbol(tg_id): | async def get_symbol(tg_id): | ||||||
|  |     """Получить символ пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         symbol = await session.scalar(select(User_Symbol.symbol).where(User_Symbol.tg_id == tg_id)) |         symbol = await session.scalar(select(User_Symbol.symbol).where(User_Symbol.tg_id == tg_id)) | ||||||
|         return symbol |         return symbol | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_user_trades(tg_id): | async def get_user_trades(tg_id): | ||||||
|  |     """Получить сделки пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         query = select(USER_DEALS.symbol, USER_DEALS.side).where(USER_DEALS.tg_id == tg_id) |         query = select(USER_DEALS.symbol, USER_DEALS.side).where(USER_DEALS.tg_id == tg_id) | ||||||
|         result = await session.execute(query) |         result = await session.execute(query) | ||||||
| @@ -155,14 +211,63 @@ async def get_user_trades(tg_id): | |||||||
|         return trades |         return trades | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def get_entry_order_type(tg_id: object) -> str | None | Any: | ||||||
|  |     """Получить тип входного ордера пользователя.""" | ||||||
|  |     async with async_session() as session: | ||||||
|  |         order_type = await session.scalar( | ||||||
|  |             select(UMS.entry_order_type).where(UMS.tg_id == tg_id) | ||||||
|  |         ) | ||||||
|  |         # Если в базе не установлен тип — возвращаем значение по умолчанию | ||||||
|  |         return order_type or 'Market' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # --- Функции обновления данных --- | ||||||
|  |  | ||||||
| async def update_user_trades(tg_id, **kwargs): | async def update_user_trades(tg_id, **kwargs): | ||||||
|  |     """Обновить сделки пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         query = update(USER_DEALS).where(USER_DEALS.tg_id == tg_id).values(**kwargs) |         query = update(USER_DEALS).where(USER_DEALS.tg_id == tg_id).values(**kwargs) | ||||||
|         await session.execute(query) |         await session.execute(query) | ||||||
|         await session.commit() |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def update_symbol(tg_id: int, symbol: str) -> None: | ||||||
|  |     """Обновить торговый символ пользователя.""" | ||||||
|  |     async with async_session() as session: | ||||||
|  |         await session.execute(update(User_Symbol).where(User_Symbol.tg_id == tg_id).values(symbol=symbol)) | ||||||
|  |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def update_api_key(tg_id: int, api: str) -> None: | ||||||
|  |     """Обновить API ключ пользователя.""" | ||||||
|  |     async with async_session() as session: | ||||||
|  |         await session.execute(update(UBA).where(UBA.tg_id == tg_id).values(api_key=api)) | ||||||
|  |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def update_secret_key(tg_id: int, api: str) -> None: | ||||||
|  |     """Обновить секретный ключ пользователя.""" | ||||||
|  |     async with async_session() as session: | ||||||
|  |         await session.execute(update(UBA).where(UBA.tg_id == tg_id).values(secret_key=api)) | ||||||
|  |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # --- Более мелкие обновления и запросы по настройкам --- | ||||||
|  |  | ||||||
|  | async def update_trade_mode_user(tg_id, trading_mode) -> None: | ||||||
|  |     """Обновить режим торговли пользователя.""" | ||||||
|  |     async with async_session() as session: | ||||||
|  |         mode = await session.scalar(select(Trading_Mode.mode).where(Trading_Mode.mode == trading_mode)) | ||||||
|  |  | ||||||
|  |         if mode: | ||||||
|  |             logger.info("Изменён торговый режим для пользователя %s", tg_id) | ||||||
|  |             await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(trading_mode=mode)) | ||||||
|  |  | ||||||
|  |             await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
| async def delete_user_trade(tg_id: int, symbol: str): | async def delete_user_trade(tg_id: int, symbol: str): | ||||||
|  |     """Удалить сделку пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute( |         await session.execute( | ||||||
|             USER_DEALS.__table__.delete().where( |             USER_DEALS.__table__.delete().where( | ||||||
| @@ -173,24 +278,28 @@ async def delete_user_trade(tg_id: int, symbol: str): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def get_for_registration_trading_mode(): | async def get_for_registration_trading_mode(): | ||||||
|  |     """Получить режим торговли по умолчанию.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         mode = await session.scalar(select(Trading_Mode.mode).where(Trading_Mode.id == 1)) |         mode = await session.scalar(select(Trading_Mode.mode).where(Trading_Mode.id == 1)) | ||||||
|         return mode |         return mode | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_for_registration_margin_type(): | async def get_for_registration_margin_type(): | ||||||
|  |     """Получить тип маржи по умолчанию.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         type = await session.scalar(select(Margin_type.type).where(Margin_type.id == 1)) |         type = await session.scalar(select(Margin_type.type).where(Margin_type.id == 1)) | ||||||
|         return type |         return type | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_for_registration_trigger(): | async def get_for_registration_trigger(): | ||||||
|  |     """Получить триггер по умолчанию.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         trigger = await session.scalar(select(Trigger.trigger).where(Trigger.id == 1)) |         trigger = await session.scalar(select(Trigger.trigger).where(Trigger.id == 1)) | ||||||
|         return trigger |         return trigger | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_user_main_settings(tg_id): | async def get_user_main_settings(tg_id): | ||||||
|  |     """Получить основные настройки пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(UMS).where(UMS.tg_id == tg_id)) |         user = await session.scalar(select(UMS).where(UMS.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -223,6 +332,7 @@ async def get_user_main_settings(tg_id): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def get_user_risk_management_settings(tg_id): | async def get_user_risk_management_settings(tg_id): | ||||||
|  |     """Получить риск-менеджмента настройки пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(URMS).where(URMS.tg_id == tg_id)) |         user = await session.scalar(select(URMS).where(URMS.tg_id == tg_id)) | ||||||
|  |  | ||||||
| @@ -244,41 +354,8 @@ async def get_user_risk_management_settings(tg_id): | |||||||
|             return data |             return data | ||||||
|  |  | ||||||
|  |  | ||||||
| # UPDATE_SYMBOL |  | ||||||
| async def update_symbol(tg_id, symbol) -> None: |  | ||||||
|     async with async_session() as session: |  | ||||||
|         await session.execute(update(User_Symbol).where(User_Symbol.tg_id == tg_id).values(symbol=symbol)) |  | ||||||
|  |  | ||||||
|         await session.commit() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def update_api_key(tg_id, api): |  | ||||||
|     async with async_session() as session: |  | ||||||
|         api_key = await session.execute(update(UBA).where(UBA.tg_id == tg_id).values(api_key=api)) |  | ||||||
|  |  | ||||||
|         await session.commit() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def update_secret_key(tg_id, api): |  | ||||||
|     async with async_session() as session: |  | ||||||
|         secret_key = await session.execute(update(UBA).where(UBA.tg_id == tg_id).values(secret_key=api)) |  | ||||||
|  |  | ||||||
|         await session.commit() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # UPDATE_MAIN_SETTINGS_DB |  | ||||||
| async def update_trade_mode_user(tg_id, trading_mode) -> None: |  | ||||||
|     async with async_session() as session: |  | ||||||
|         mode = await session.scalar(select(Trading_Mode.mode).where(Trading_Mode.mode == trading_mode)) |  | ||||||
|  |  | ||||||
|         if mode: |  | ||||||
|             logger.info("Изменен трейд мод %s", tg_id) |  | ||||||
|             await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(trading_mode=mode)) |  | ||||||
|  |  | ||||||
|             await session.commit() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def update_margin_type(tg_id, margin_type) -> None: | async def update_margin_type(tg_id, margin_type) -> None: | ||||||
|  |     """Обновить тип маржи пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         type = await session.scalar(select(Margin_type.type).where(Margin_type.type == margin_type)) |         type = await session.scalar(select(Margin_type.type).where(Margin_type.type == margin_type)) | ||||||
|  |  | ||||||
| @@ -290,6 +367,7 @@ async def update_margin_type(tg_id, margin_type) -> None: | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_size_leverange(tg_id, num): | async def update_size_leverange(tg_id, num): | ||||||
|  |     """Обновить размер левеража пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(size_leverage=num)) |         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(size_leverage=num)) | ||||||
|  |  | ||||||
| @@ -297,6 +375,7 @@ async def update_size_leverange(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_starting_quantity(tg_id, num): | async def update_starting_quantity(tg_id, num): | ||||||
|  |     """Обновить размер левеража пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(starting_quantity=num)) |         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(starting_quantity=num)) | ||||||
|  |  | ||||||
| @@ -304,6 +383,7 @@ async def update_starting_quantity(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_martingale_factor(tg_id, num): | async def update_martingale_factor(tg_id, num): | ||||||
|  |     """Обновить размер левеража пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(martingale_factor=num)) |         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(martingale_factor=num)) | ||||||
|  |  | ||||||
| @@ -311,15 +391,17 @@ async def update_martingale_factor(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_maximal_quantity(tg_id, num): | async def update_maximal_quantity(tg_id, num): | ||||||
|  |     """Обновить размер левеража пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(maximal_quantity=num)) |         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(maximal_quantity=num)) | ||||||
|  |  | ||||||
|         await session.commit() |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
| # UPDATE_RISK_MANAGEMENT_SETTINGS_DB | # ОБНОВЛЕНИЕ НАСТРОЕК РИСК-МЕНЕДЖМЕНТА | ||||||
|  |  | ||||||
| async def update_price_profit(tg_id, num): | async def update_price_profit(tg_id, num): | ||||||
|  |     """Обновить цену тейк-профита (прибыль) пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(price_profit=num)) |         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(price_profit=num)) | ||||||
|  |  | ||||||
| @@ -327,6 +409,7 @@ async def update_price_profit(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_price_loss(tg_id, num): | async def update_price_loss(tg_id, num): | ||||||
|  |     """Обновить цену тейк-лосса (убыток) пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(price_loss=num)) |         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(price_loss=num)) | ||||||
|  |  | ||||||
| @@ -334,6 +417,7 @@ async def update_price_loss(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_max_risk_deal(tg_id, num): | async def update_max_risk_deal(tg_id, num): | ||||||
|  |     """Обновить максимальную сумму риска пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(max_risk_deal=num)) |         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(max_risk_deal=num)) | ||||||
|  |  | ||||||
| @@ -341,6 +425,7 @@ async def update_max_risk_deal(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_entry_order_type(tg_id, order_type): | async def update_entry_order_type(tg_id, order_type): | ||||||
|  |     """Обновить тип входного ордера пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute( |         await session.execute( | ||||||
|             update(UMS) |             update(UMS) | ||||||
| @@ -350,16 +435,8 @@ async def update_entry_order_type(tg_id, order_type): | |||||||
|         await session.commit() |         await session.commit() | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_entry_order_type(tg_id: object) -> str | None | Any: |  | ||||||
|     async with async_session() as session: |  | ||||||
|         order_type = await session.scalar( |  | ||||||
|             select(UMS.entry_order_type).where(UMS.tg_id == tg_id) |  | ||||||
|         ) |  | ||||||
|         # Если в базе не установлен тип — возвращаем значение по умолчанию |  | ||||||
|         return order_type or 'Market' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_limit_price(tg_id): | async def get_limit_price(tg_id): | ||||||
|  |     """Получить лимитную цену пользователя как float, либо None.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         result = await session.execute( |         result = await session.execute( | ||||||
|             select(UMS.limit_order_price) |             select(UMS.limit_order_price) | ||||||
| @@ -375,6 +452,7 @@ async def get_limit_price(tg_id): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_limit_price(tg_id, price): | async def update_limit_price(tg_id, price): | ||||||
|  |     """Обновить лимитную цену пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute( |         await session.execute( | ||||||
|             update(UMS) |             update(UMS) | ||||||
| @@ -385,6 +463,7 @@ async def update_limit_price(tg_id, price): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_commission_fee(tg_id, num): | async def update_commission_fee(tg_id, num): | ||||||
|  |     """Обновить комиссию пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(commission_fee=num)) |         await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(commission_fee=num)) | ||||||
|  |  | ||||||
| @@ -392,6 +471,7 @@ async def update_commission_fee(tg_id, num): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def get_user_timer(tg_id): | async def get_user_timer(tg_id): | ||||||
|  |     """Получить данные о таймере пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         result = await session.execute(select(UserTimer).where(UserTimer.tg_id == tg_id)) |         result = await session.execute(select(UserTimer).where(UserTimer.tg_id == tg_id)) | ||||||
|         user_timer = result.scalars().first() |         user_timer = result.scalars().first() | ||||||
| @@ -422,38 +502,39 @@ async def get_user_timer(tg_id): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_user_timer(tg_id, minutes: int): | async def update_user_timer(tg_id, minutes: int): | ||||||
|  |     """Обновить данные о таймере пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         try: |         try: | ||||||
|             async with async_session() as session: |             timer_start = None | ||||||
|                 timer_start = None |             timer_end = None | ||||||
|                 timer_end = None |  | ||||||
|  |  | ||||||
|                 if minutes > 0: |             if minutes > 0: | ||||||
|                     timer_start = datetime.utcnow() |                 timer_start = datetime.utcnow() | ||||||
|                     timer_end = timer_start + timedelta(minutes=minutes) |                 timer_end = timer_start + timedelta(minutes=minutes) | ||||||
|  |  | ||||||
|                 result = await session.execute(select(UserTimer).where(UserTimer.tg_id == tg_id)) |             result = await session.execute(select(UserTimer).where(UserTimer.tg_id == tg_id)) | ||||||
|                 user_timer = result.scalars().first() |             user_timer = result.scalars().first() | ||||||
|  |  | ||||||
|                 if user_timer: |             if user_timer: | ||||||
|                     user_timer.timer_minutes = minutes |                 user_timer.timer_minutes = minutes | ||||||
|                     user_timer.timer_start = timer_start |                 user_timer.timer_start = timer_start | ||||||
|                     user_timer.timer_end = timer_end |                 user_timer.timer_end = timer_end | ||||||
|                 else: |             else: | ||||||
|                     user_timer = UserTimer( |                 user_timer = UserTimer( | ||||||
|                         tg_id=tg_id, |                     tg_id=tg_id, | ||||||
|                         timer_minutes=minutes, |                     timer_minutes=minutes, | ||||||
|                         timer_start=timer_start, |                     timer_start=timer_start, | ||||||
|                         timer_end=timer_end |                     timer_end=timer_end | ||||||
|                     ) |                 ) | ||||||
|                     session.add(user_timer) |                 session.add(user_timer) | ||||||
|  |  | ||||||
|                 await session.commit() |             await session.commit() | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             logging.error(f"Ошибка обновления таймера пользователя {tg_id}: {e}") |             logging.error(f"Ошибка обновления таймера пользователя {tg_id}: {e}") | ||||||
|  |  | ||||||
|  |  | ||||||
| async def get_martingale_step(tg_id): | async def get_martingale_step(tg_id): | ||||||
|  |     """Получить шаг мартингейла пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         result = await session.execute(select(UMS).where(UMS.tg_id == tg_id)) |         result = await session.execute(select(UMS).where(UMS.tg_id == tg_id)) | ||||||
|         user_settings = result.scalars().first() |         user_settings = result.scalars().first() | ||||||
| @@ -461,6 +542,7 @@ async def get_martingale_step(tg_id): | |||||||
|  |  | ||||||
|  |  | ||||||
| async def update_martingale_step(tg_id, step): | async def update_martingale_step(tg_id, step): | ||||||
|  |     """Обновить шаг мартингейла пользователя.""" | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(martingale_step=step)) |         await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(martingale_step=step)) | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user