diff --git a/BibytBot_API.py b/BibytBot_API.py index 3cb2ffd..e8a3b81 100644 --- a/BibytBot_API.py +++ b/BibytBot_API.py @@ -6,8 +6,11 @@ from aiogram.types import Message from app.telegram.database.models import async_main -from app.telegram.handlers.handlers import router # Для вызова событий -from app.telegram.functions.main_settings.settings import router_main_settings # Для вызова событий +from app.telegram.handlers.handlers import router +from app.telegram.functions.main_settings.settings import router_main_settings +from app.telegram.functions.risk_management_settings.settings import router_risk_management_settings +from app.services.Bybit.functions.Add_Bybit_API import router_register_bybit_api +from app.services.Bybit.functions.functions import router_functions_bybit_trade from config import TOKEN_TG_BOT @@ -21,6 +24,9 @@ async def main(): dp.include_router(router) dp.include_router(router_main_settings) + dp.include_router(router_risk_management_settings) + dp.include_router(router_register_bybit_api) + dp.include_router(router_functions_bybit_trade) await dp.start_polling(bot) diff --git a/BibytBot_API.pyproj b/BibytBot_API.pyproj index d6c1cc1..595308b 100644 --- a/BibytBot_API.pyproj +++ b/BibytBot_API.pyproj @@ -21,6 +21,12 @@ false + + + + + + @@ -37,6 +43,9 @@ + + + diff --git a/README.md b/README.md index dc5b023..713dc9c 100644 --- a/README.md +++ b/README.md @@ -1 +1,20 @@ -abobus \ No newline at end of file +# Чат-робот STCS +__ + +**Функционал:** ++ **Настройки** + + Основные параметры *(Настроен, работает)* + + Режим торговли Лонг/Шорт *(настроены)*, Switch/Smart *(не настроены)* + + Тип маржи: Изолированная / Кросс *(настроено)* + + Размер кредитного плеча: от x1 до x100 *(настроено)* + + Начальная ставка: числовое значение *(настроено)* + + Коэффициент мартингейла: число *(настроено)* + + Максимальное количество ставок в серии: число *(настроено)* + + Риск-менеджмент (Настроен, работает) + + Процент изменения цены для фиксации прибыли (TP%): число *(настроено)* + + Процент изменения цены для фиксации убытков (SL%): число (пример: 1%) *(настроено)* + + Максимальный риск на сделку (в % от баланса): число (опционально) *(настроено)* + + Условия запуска *(Не настроен)* + + Дополнительные параметры *(Не настроен)* + + Подключение Bybit *(настроено)* + + Информация о правильном получении и сохранении Bybit-API keys *(настроено)* diff --git a/app/services/Bybit/functions/Add_Bybit_API.py b/app/services/Bybit/functions/Add_Bybit_API.py new file mode 100644 index 0000000..291da46 --- /dev/null +++ b/app/services/Bybit/functions/Add_Bybit_API.py @@ -0,0 +1,73 @@ +from aiogram import F, Router + +import app.telegram.Keyboards.inline_keyboards as inline_markup + +import app.telegram.database.requests as rq +from aiogram.types import Message, CallbackQuery + +# FSM - Механизм состояния +from aiogram.fsm.state import State, StatesGroup +from aiogram.fsm.context import FSMContext + +router_register_bybit_api = Router() + +class state_reg_bybit_api(StatesGroup): + api_key = State() + secret_key = State() + +@router_register_bybit_api.callback_query(F.data == 'clb_new_user_connect_bybit_api_message') +async def info_for_bybit_api_message(callback: CallbackQuery): + text = '''Подключение Bybit аккаунта + +1. Зарегистрируйтесь или войдите в свой аккаунт на Bybit (https://www.bybit.com/). +2. В личном кабинете выберите раздел API. +3. Создание нового API ключа + - Нажмите кнопку Create New Key (Создать новый ключ). + - Выберите системно-сгенерированный ключ. + - Укажите название API ключа (любое). + - Выберите права доступа для торговли (Trade). + - Можно ограничить доступ по IP для безопасности. +4. Подтверждение создания + - Подтвердите создание ключа. + - Отправьте чат-роботу. + +Важно: сохраните отдельно API Key и Secret Key в надежном месте. Secret ключ отображается только один раз. + ''' + + await callback.message.answer(text=text, parse_mode='html', reply_markup=inline_markup.connect_bybit_api_markup) + + await callback.answer() + +@router_register_bybit_api.callback_query(F.data == 'clb_new_user_connect_bybit_api') +async def add_api_key_message(callback: CallbackQuery, state: FSMContext): + await state.set_state(state_reg_bybit_api.api_key) + + text = 'Отправьте KEY_API ниже: ' + + await callback.message.answer(text=text) + +@router_register_bybit_api.message(state_reg_bybit_api.api_key) +async def add_api_key_and_message_for_secret_key(message: Message, state: FSMContext): + await state.update_data(api_key = message.text) + + text = 'Отправьте SECRET_KEY ниже' + + await message.answer(text=text) + + await state.set_state(state_reg_bybit_api.secret_key) + +@router_register_bybit_api.message(state_reg_bybit_api.secret_key) +async def add_secret_key(message: Message, state: FSMContext): + await state.update_data(secret_key = message.text) + + data = await state.get_data() + + await rq.update_api_key(message.from_user.id, data['api_key']) + await rq.update_secret_key(message.from_user.id, data['secret_key']) + await rq.set_new_user_symbol(message.from_user.id) + + await state.clear() + + await message.answer('Данные добавлены, нажмите на профиль и начните торговлю!') + + \ No newline at end of file diff --git a/app/services/Bybit/functions/Futures.py b/app/services/Bybit/functions/Futures.py new file mode 100644 index 0000000..1f68dc0 --- /dev/null +++ b/app/services/Bybit/functions/Futures.py @@ -0,0 +1,254 @@ +import time + +from typing import Optional +from asyncio import Handle + +from annotated_types import T +from pybit import exceptions +from pybit.unified_trading import HTTP +from pybit.unified_trading import WebSocket + +from app.services.Bybit.functions import price_symbol +import app.services.Bybit.functions.balance as balance_g +import app.telegram.database.requests as rq + +import logging +logging.basicConfig(level=logging.DEBUG) + +def handle_message(message): + print(message) + +async def info_access_open_deal(message, symbol, trade_mode, margin_mode, leverage, qty): + match margin_mode: + case 'ISOLATED_MARGIN': + margin_mode = 'Isolated' + case 'REGULAR_MARGIN': + margin_mode = 'Cross' + + text = f'''Позиция была успешна открыта! + Торговая пара: {symbol} + Движение: {trade_mode} + Тип-маржи: {margin_mode} + Кредитное плечо: {leverage} + Количество: {qty} + ''' + + await message.answer(text=text, parse_mode='html') + +async def error_max_step(message): + await message.answer('Сделка не была совершена, превышен лимит максимального количества ставок') + +async def error_max_risk(message): + await message.answer('Сделка не была совершена, слишком высокий риск') + +async def contract_long(tg_id, message, margin_mode): + api_key = await rq.get_bybit_api_key(tg_id) + secret_key = await rq.get_bybit_secret_key(tg_id) + SYMBOL = await rq.get_symbol(tg_id) + + data_main_stgs = await rq.get_user_main_settings(tg_id) + data_risk_management_stgs = await rq.get_user_risk_management_settings(tg_id) + + match margin_mode: + case 'Isolated': + margin_mode = 'ISOLATED_MARGIN' + case 'Cross': + margin_mode = 'REGULAR_MARGIN' + + client = HTTP( + api_key=api_key, + api_secret=secret_key + ) + + try: + balance = 0 + price = 0 + + balance = await balance_g.get_balance(tg_id) + price = await price_symbol.get_price(tg_id, message) + + client.set_margin_mode( + setMarginMode=margin_mode # margin_type + ) + + martingale_factor = float(data_main_stgs['martingale_factor']) # Исправлено: было maximal_quantity + max_martingale_steps = int(data_main_stgs['maximal_quantity']) + starting_quantity = float(data_main_stgs['starting_quantity']) + max_risk_percent = float(data_risk_management_stgs['max_risk_deal']) + loss_profit = float(data_risk_management_stgs['price_loss']) + takeProfit= float(data_risk_management_stgs['price_profit']) + + # Инициализация переменных + next_quantity = starting_quantity + last_quantity = starting_quantity + realised_pnl = 0.0 + + current_martingale_step = 0 # Текущая ставка в серии + + next_quantity = 0 + realised_pnl = 0 + + last_quantity = starting_quantity + + # Пример расчёта следующего размера позиции + try: + position_info = client.get_positions(category='linear', symbol=SYMBOL) + position = position_info['result']['list'][0] # или другой нужный индекс + + realised_pnl = float(position['unrealisedPnl']) + + if realised_pnl > 0: + starting_quantity = next_quantity + current_martingale_step = 0 + elif not realised_pnl: + next_quantity = starting_quantity + current_martingale_step += 1 + else: + current_martingale_step += 1 + next_quantity = last_quantity * martingale_factor + starting_quantity = next_quantity + except Exception as e: + print("Не получены позиции") + next_quantity = starting_quantity + + potential_loss = (next_quantity * float(price)) * (loss_profit / 100) + allowed_loss = float(balance) * (max_risk_percent / 100) + + if current_martingale_step >= max_martingale_steps: + print("Достигнут максимум ставок в серии (8)!") + print("Торговля не продолжится") + + await error_max_step(message) + else: + if potential_loss > allowed_loss: + print(f"ОШИБКА: Риск превышен!") + print(f"Ручной qty = {next_quantity} → Убыток = {potential_loss} USDT") + print(f"Разрешено = {allowed_loss} USDT (1% от баланса)") + + await error_max_risk(message) + else: + print(f"Риск в допустимых пределах. Qty = {next_quantity}") + + r = client.place_order( + category='linear', + symbol=SYMBOL, + side='Buy', + orderType="Market", + leverage=int(data_main_stgs['size_leverage']), + qty=next_quantity, + takeProfit=takeProfit, # TP - закрывает позицию, когда цена достигает нужного уровня + stopProfit=float(data_risk_management_stgs['price_loss']), # SL - закрывает позицию, когда убыток достигает нужного уровня + orderLinkId=f"deal_{SYMBOL}_{time.time()}" + ) + + await info_access_open_deal(message, SYMBOL, data_main_stgs['trading_mode'], margin_mode, data_main_stgs['size_leverage'], next_quantity) + + except exceptions.InvalidRequestError as e: + await message.answer('Недостаточно баланса') + except Exception as e: + await message.answer('Непредвиденная оишбка') + +async def contract_short(tg_id, message, margin_mode): + api_key = await rq.get_bybit_api_key(tg_id) + secret_key = await rq.get_bybit_secret_key(tg_id) + SYMBOL = await rq.get_symbol(tg_id) + + data_main_stgs = await rq.get_user_main_settings(tg_id) + data_risk_management_stgs = await rq.get_user_risk_management_settings(tg_id) + + match margin_mode: + case 'Isolated': + margin_mode = 'ISOLATED_MARGIN' + case 'Cross': + margin_mode = 'REGULAR_MARGIN' + + client = HTTP( + api_key=api_key, + api_secret=secret_key + ) + + try: + balance = 0 + price = 0 + + balance = await balance_g.get_balance(tg_id) + price = await price_symbol.get_price(tg_id, message) + + client.set_margin_mode( + setMarginMode=margin_mode # margin_type + ) + + martingale_factor = float(data_main_stgs['martingale_factor']) # Исправлено: было maximal_quantity + max_martingale_steps = int(data_main_stgs['maximal_quantity']) + starting_quantity = float(data_main_stgs['starting_quantity']) + max_risk_percent = float(data_risk_management_stgs['max_risk_deal']) + loss_profit = float(data_risk_management_stgs['price_loss']) + takeProfit = float(data_risk_management_stgs['price_profit']) + + # Инициализация переменных + next_quantity = starting_quantity + last_quantity = starting_quantity + realised_pnl = 0.0 + + current_martingale_step = 0 # Текущая ставка в серии + + next_quantity = 0 + realised_pnl = 0 + + last_quantity = starting_quantity + + # Пример расчёта следующего размера позиции + try: + position_info = client.get_positions(category='linear', symbol=SYMBOL) + position = position_info['result']['list'][0] # или другой нужный индекс + + realised_pnl = float(position['unrealisedPnl']) + + if realised_pnl > 0: + starting_quantity = next_quantity + current_martingale_step = 0 + elif not realised_pnl: + next_quantity = starting_quantity + current_martingale_step += 1 + else: + current_martingale_step += 1 + next_quantity = last_quantity * martingale_factor + starting_quantity = next_quantity + except Exception as e: + print("Не получены позиции") + next_quantity = starting_quantity + + potential_loss = (next_quantity * float(price)) * (loss_profit / 100) + allowed_loss = float(balance) * (max_risk_percent / 100) + + if current_martingale_step >= max_martingale_steps: + print("Достигнут максимум ставок в серии (8)!") + print("Торговля не продолжится") + + await error_max_step(message) + else: + if potential_loss > allowed_loss: + print(f"ОШИБКА: Риск превышен!") + print(f"Ручной qty = {next_quantity} → Убыток = {potential_loss} USDT") + print(f"Разрешено = {allowed_loss} USDT (1% от баланса)") + + await error_max_risk(message) + else: + print(f"Риск в допустимых пределах. Qty = {next_quantity}") + + r = client.place_order( + category='linear', + symbol=SYMBOL, + side='Sell', + orderType="Market", + leverage=int(data_main_stgs['size_leverage']), + qty=next_quantity, + orderLinkId=f"deal_{SYMBOL}_{time.time()}" + ) + + await info_access_open_deal(message, SYMBOL, data_main_stgs['trading_mode'], margin_mode, data_main_stgs['size_leverage'], next_quantity) + + except exceptions.InvalidRequestError as e: + await message.answer('Недостаточно баланса') + except Exception as e: + await message.answer('Непредвиденная оишбка') \ No newline at end of file diff --git a/app/services/Bybit/functions/balance.py b/app/services/Bybit/functions/balance.py new file mode 100644 index 0000000..db3d74d --- /dev/null +++ b/app/services/Bybit/functions/balance.py @@ -0,0 +1,33 @@ +import app.telegram.database.requests as rq + +from pybit.unified_trading import HTTP + +client = HTTP() + +async def get_balance(tg_id, message): + api_key = await rq.get_bybit_api_key(tg_id) + secret_key = await rq.get_bybit_secret_key(tg_id) + + client = HTTP( + api_key=api_key, + api_secret=secret_key + ) + + if api_key == 'None' or secret_key == 'None': + await message.answer('⚠️ Подключите платформу для торговли') + return 0 + + try: + check_user = client.get_wallet_balance() + + if check_user: + try: + balance = client.get_wallet_balance(accountType='UNIFIED', coin='USDT')['result']['list'][0]['coin'][0]['walletBalance'] + + return balance + except Exception as e: + await message.answer('⚠️ Ошибка при получении баланса пользователя') + return 0 + except Exception as e: + await message.answer('⚠️ Неверные данные API, перепроверьте их') + return 0 \ No newline at end of file diff --git a/app/services/Bybit/functions/func_min_qty.py b/app/services/Bybit/functions/func_min_qty.py new file mode 100644 index 0000000..0544b64 --- /dev/null +++ b/app/services/Bybit/functions/func_min_qty.py @@ -0,0 +1,21 @@ +import app.telegram.database.requests as rq +import app.services.Bybit.functions.price_symbol as price_s + +from pybit.unified_trading import HTTP + +client = HTTP() + +async def get_min_qty(tg_id, message): + api_key = await rq.get_bybit_api_key(tg_id) + secret_key = await rq.get_bybit_secret_key(tg_id) + SYMBOL = await rq.get_symbol(tg_id) + + client = HTTP( + api_key=api_key, + api_secret=secret_key + ) + + price = await price_s.get_price(tg_id, message) + min_qty = int(5 / price * 1.1) + + return min_qty \ No newline at end of file diff --git a/app/services/Bybit/functions/functions.py b/app/services/Bybit/functions/functions.py new file mode 100644 index 0000000..86ff692 --- /dev/null +++ b/app/services/Bybit/functions/functions.py @@ -0,0 +1,99 @@ +from aiogram import F, Router + +from app.services.Bybit.functions import Futures, func_min_qty +from app.services.Bybit.functions.balance import get_balance +import app.telegram.Keyboards.inline_keyboards as inline_markup + +import app.telegram.database.requests as rq +from aiogram.types import Message, CallbackQuery + +# FSM - Механизм состояния +from aiogram.fsm.state import State, StatesGroup +from aiogram.fsm.context import FSMContext + +router_functions_bybit_trade = Router() + +class state_update_symbol(StatesGroup): + symbol = State() + +@router_functions_bybit_trade.callback_query(F.data == 'clb_start_trading') +async def clb_start_bybit_trade_message(callback: CallbackQuery, state: FSMContext): + api = await rq.get_bybit_api_key(callback.from_user.id) + secret = await rq.get_bybit_secret_key(callback.from_user.id) + balance = await get_balance(callback.from_user.id, callback.message) + + if balance: + symbol = await rq.get_symbol(callback.from_user.id) + + text = f'''💎 Торговля на Bybit + +⚖️ Ваш баланс (USDT): {balance} +📊 Текущая торговая пара: {symbol} + +Как начать торговлю? + +1️⃣ Проверьте и тщательно настройте все параметры в вашем профиле. +2️⃣ Нажмите ниже кнопку 'Указать торговую пару' и введите торговую пару заглавными буквами, без лишних символов (например: BTCUSDT). +''' + await callback.message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.trading_markup) + +async def start_bybit_trade_message(message, state): + api = await rq.get_bybit_api_key(message.from_user.id) + secret = await rq.get_bybit_secret_key(message.from_user.id) + balance = await get_balance(message.from_user.id, message) + + if balance: + symbol = await rq.get_symbol(message.from_user.id) + + text = f'''💎 Торговля на Bybit + +⚖️ Ваш баланс (USDT): {balance} +📊 Текущая торговая пара: {symbol} + +Как начать торговлю? + +1️⃣ Проверьте и тщательно настройте все параметры в вашем профиле. +2️⃣ Нажмите ниже кнопку 'Указать торговую пару' и введите торговую пару заглавными буквами, без лишних символов (например: BTCUSDT). +''' + + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.trading_markup) + +@router_functions_bybit_trade.callback_query(F.data == 'clb_update_trading_pair') +async def update_symbol_for_trade_message(callback: CallbackQuery, state: FSMContext): + await state.set_state(state_update_symbol.symbol) + + await callback.message.answer(text='Укажите торговую пару заглавными буквами без пробелов и лишних символов (пример: BTCUSDT): ') + +@router_functions_bybit_trade.message(state_update_symbol.symbol) +async def update_symbol_for_trade(message: Message, state: FSMContext): + await state.update_data(symbol = message.text) + + data = await state.get_data() + + await message.answer('Пара была успешно обновлена') + await rq.update_symbol(message.from_user.id, data['symbol']) + await start_bybit_trade_message(message, state) + + await state.clear() + +@router_functions_bybit_trade.callback_query(F.data == 'clb_open_deal') +async def make_deal_bybit (callback: CallbackQuery): + data_main_stgs = await rq.get_user_main_settings(callback.from_user.id) + + trade_mode = data_main_stgs['trading_mode'] + qty = data_main_stgs['starting_quantity'] + margin_mode = data_main_stgs['margin_type'] + qty_min = await func_min_qty.get_min_qty(callback.from_user.id, callback.message) + + if qty < qty_min: + await callback.message.edit_text(f"Количество вашей ставки ({qty}) меньше минимального количества ({qty_min}) для данной торговой пары") + else: + match trade_mode: + case 'Long': + await Futures.contract_long(callback.from_user.id, callback.message, margin_mode) + case 'Short': + await Futures.contract_short(callback.from_user.id, callback.message, margin_mode) + case 'Switch': + await callback.message.edit_text('Режим Switch пока недоступен') + case 'Smart': + await callback.message.edit_text('Режим Smart пока недоступен') \ No newline at end of file diff --git a/app/services/Bybit/functions/min_qty.py b/app/services/Bybit/functions/min_qty.py new file mode 100644 index 0000000..07c1485 --- /dev/null +++ b/app/services/Bybit/functions/min_qty.py @@ -0,0 +1,23 @@ +from app.services.Bybit.functions import price_symbol +import app.telegram.database.requests as rq + +from pybit.unified_trading import HTTP + +client = HTTP() + +async def get_min_qty(tg_id): + api_key = await rq.get_bybit_api_key(tg_id) + secret_key = await rq.get_bybit_secret_key(tg_id) + SYMBOL = await rq.get_symbol(tg_id) + + client = HTTP( + api_key=api_key, + api_secret=secret_key + ) + + price = await price_symbol(tg_id) + json_data = client.get_instruments_info(symbol=SYMBOL, category='linear') + + min_qty = int(5 / price * 1.1) # 1% 5 USDT + + return min_qty \ No newline at end of file diff --git a/app/services/Bybit/functions/price_symbol.py b/app/services/Bybit/functions/price_symbol.py new file mode 100644 index 0000000..8971a66 --- /dev/null +++ b/app/services/Bybit/functions/price_symbol.py @@ -0,0 +1,24 @@ +import app.telegram.database.requests as rq + +from pybit import exceptions +from pybit.unified_trading import HTTP + +client = HTTP() + +async def get_price(tg_id, message): + api_key = await rq.get_bybit_api_key(tg_id) + secret_key = await rq.get_bybit_secret_key(tg_id) + SYMBOL = await rq.get_symbol(tg_id) + + client = HTTP( + api_key=api_key, + api_secret=secret_key + ) + + try: + price = float(client.get_tickers(category='linear', symbol=SYMBOL).get('result').get('list')[0].get('ask1Price')) + + return price + except exceptions.InvalidRequestError as e: + await message.answer('Неверно указана торговая пара') + return 1.0 \ No newline at end of file diff --git a/app/telegram/Keyboards/inline_keyboards.py b/app/telegram/Keyboards/inline_keyboards.py index 4748f3d..e9c034d 100644 --- a/app/telegram/Keyboards/inline_keyboards.py +++ b/app/telegram/Keyboards/inline_keyboards.py @@ -1,15 +1,15 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup -start_markup = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Зарегистрироваться", callback_data="callback_registration")], - [InlineKeyboardButton(text="Авторизоваться", callback_data="callback_autorisation")] +start_markup = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="🔥 Начать торговлю", callback_data="clb_start_chatbot_message")] ]) settings_markup = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Настройки", callback_data='clb_settings_message')] + [InlineKeyboardButton(text="Настройки", callback_data='clb_settings_message')], + [InlineKeyboardButton(text="Запуск", callback_data='clb_start_trading')] ]) -back_btn_profile = [InlineKeyboardButton(text="Назад", callback_data='callback_autorisation')] +back_btn_profile = [InlineKeyboardButton(text="Назад", callback_data='clb_start_chatbot_message')] special_settings_markup = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Основные настройки", callback_data='clb_change_main_settings'), @@ -18,9 +18,20 @@ special_settings_markup = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Условия запуска", callback_data='clb_change_condition_settings'), InlineKeyboardButton(text="Дополнительные параметры", callback_data='clb_change_additional_settings')], + [InlineKeyboardButton(text="Подключить Bybit", callback_data='clb_new_user_connect_bybit_api_message')], + back_btn_profile ]) +connect_bybit_api_markup = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Подключить Bybit", callback_data='clb_new_user_connect_bybit_api')] +]) + +trading_markup = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Указать торговую пару", callback_data='clb_update_trading_pair')], + [InlineKeyboardButton(text="Совершить сделку", callback_data='clb_open_deal')] +]) + back_btn_list_settings = [InlineKeyboardButton(text="Назад", callback_data='clb_back_to_special_settings_message')] # Кнопка для возврата к списку каталога настроек back_btn_list_settings_markup = InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="Назад", callback_data='clb_back_to_special_settings_message')]]) # Клавиатура для возврата к списку каталога настроек @@ -85,4 +96,17 @@ margin_type_markup = InlineKeyboardMarkup(inline_keyboard=[ InlineKeyboardButton(text="Кросс", callback_data="margin_type_cross")], back_btn_list_settings +]) + +trigger_markup = InlineKeyboardMarkup(inline_keyboard=[ # ИЗМЕНИТЬ НА INLINE + [InlineKeyboardButton(text='Ручной', callback_data="clb_trigger_ruchnoy"), InlineKeyboardButton(text='TradingView', callback_data="clb_trigger_tradingview")], + [InlineKeyboardButton(text="Автоматический", callback_data="clb_trigger_auto")] +]) + +buttons_yes_no_markup = InlineKeyboardMarkup(inline_keyboard=[ # ИЗМЕНИТЬ НА INLINE + [InlineKeyboardButton(text='Да', callback_data="clb_yes"), InlineKeyboardButton(text='Нет', callback_data="clb_yes")] +]) + +buttons_on_off_markup = InlineKeyboardMarkup(inline_keyboard=[ # ИЗМЕНИТЬ НА INLINE + [InlineKeyboardButton(text='Включить', callback_data="clb_on"), InlineKeyboardButton(text='Выключить', callback_data="clb_off")] ]) \ No newline at end of file diff --git a/app/telegram/Keyboards/reply_keyboards.py b/app/telegram/Keyboards/reply_keyboards.py index e0fae5c..daf376f 100644 --- a/app/telegram/Keyboards/reply_keyboards.py +++ b/app/telegram/Keyboards/reply_keyboards.py @@ -3,17 +3,4 @@ base_buttons_markup = ReplyKeyboardMarkup(keyboard=[ [KeyboardButton(text="👤 Профиль")], # [KeyboardButton(text="Настройки")] -], resize_keyboard=True) - -trigger_markup = ReplyKeyboardMarkup(keyboard=[ # ИЗМЕНИТЬ НА INLINE - [KeyboardButton(text='Ручной'), KeyboardButton(text='TradingView')], - [KeyboardButton(text="Автоматический")] -], resize_keyboard=True) - -buttons_yes_no_markup = ReplyKeyboardMarkup(keyboard=[ # ИЗМЕНИТЬ НА INLINE - [KeyboardButton(text='Да'), KeyboardButton(text='Нет')] -], resize_keyboard=True) - -buttons_on_off_markup = ReplyKeyboardMarkup(keyboard=[ # ИЗМЕНИТЬ НА INLINE - [KeyboardButton(text='Включить'), KeyboardButton(text='Выключить')] ], resize_keyboard=True) \ No newline at end of file diff --git a/app/telegram/database/models.py b/app/telegram/database/models.py index 655f61c..69da607 100644 --- a/app/telegram/database/models.py +++ b/app/telegram/database/models.py @@ -21,6 +21,25 @@ class User_Telegram_Id(Base): tg_id = mapped_column(BigInteger) +class User_Bybit_API(Base): + __tablename__ = 'user_bybit_api' + + id: Mapped[int] = mapped_column(primary_key=True) + + tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id")) + + api_key = mapped_column(String(18), default='None') + secret_key = mapped_column(String(36), default='None') + +class User_Symbol(Base): + __tablename__ = 'user_symbols' + + id: Mapped[int] = mapped_column(primary_key=True) + + tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id")) + + symbol = mapped_column(String(18), default='PENGUUSDT') + class Trading_Mode(Base): __tablename__ = 'trading_modes' @@ -65,7 +84,7 @@ class User_Risk_Management_Settings(Base): price_profit = mapped_column(Integer(), default=1) price_loss = mapped_column(Integer(), default=1) - max_risk_deal = mapped_column(Integer(), default=1) + max_risk_deal = mapped_column(Integer(), default=100) class User_Condition_Settings(Base): __tablename__ = 'user_condition_settings' @@ -105,7 +124,7 @@ async def async_main(): logger.info("Заполение таблицы режима торговли") await conn.execute(Trading_Mode.__table__.insert().values(mode=mode)) - types = ['Изолированный', 'Кросс'] + types = ['Isolated', 'Cross'] for type in types: result = await conn.execute(select(Margin_type).where(Margin_type.type == type)) if not result.first(): diff --git a/app/telegram/database/requests.py b/app/telegram/database/requests.py index 6cd01a0..4b67b5e 100644 --- a/app/telegram/database/requests.py +++ b/app/telegram/database/requests.py @@ -4,6 +4,8 @@ logger = logging.getLogger(__name__) 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 @@ -27,6 +29,32 @@ async def save_tg_id_new_user(tg_id): await session.commit() +async def set_new_user_bybit_api(tg_id): + async with async_session() as session: + user = await session.scalar(select(UBA).where(UBA.tg_id == tg_id)) + + if not user: + session.add(UBA( + tg_id=tg_id, + )) + + logger.info(f"Bybit был успешно подключен") + + await session.commit() + +async def set_new_user_symbol(tg_id): + async with async_session() as session: + user = await session.scalar(select(User_Symbol).where(User_Symbol.tg_id == tg_id)) + + if not user: + session.add(User_Symbol( + tg_id=tg_id + )) + + logger.info(f"Symbol был успешно добавлен") + + await session.commit() + async def set_new_user_default_main_settings(tg_id, trading_mode, margin_type) -> None: async with async_session() as session: settings = await session.scalar(select(UMS).where(UMS.tg_id == tg_id)) @@ -86,7 +114,22 @@ async def set_new_user_default_additional_settings(tg_id) -> None: async def check_user(tg_id): async with async_session() as session: 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 with async_session() as session: + api_key = await session.scalar(select(UBA.api_key).where(UBA.tg_id == tg_id)) + return api_key + +async def get_bybit_secret_key(tg_id): + async with async_session() as session: + secret_key = await session.scalar(select(UBA.secret_key).where(UBA.tg_id == tg_id)) + return secret_key + +async def get_symbol(tg_id): + async with async_session() as session: + symbol = await session.scalar(select(User_Symbol.symbol).where(User_Symbol.tg_id == tg_id)) + return symbol async def get_for_registration_trading_mode(): async with async_session() as session: @@ -128,7 +171,45 @@ async def get_user_main_settings(tg_id): return data -# UPDATE_DB +async def get_user_risk_management_settings(tg_id): + async with async_session() as session: + user = await session.scalar(select(URMS).where(URMS.tg_id == tg_id)) + + if user: + logger.info("Получение риск-менеджмента настроек пользователя") + + price_profit = await session.scalar(select(URMS.price_profit).where(URMS.tg_id == tg_id)) + price_loss = await session.scalar(select(URMS.price_loss).where(URMS.tg_id == tg_id)) + max_risk_deal = await session.scalar(select(URMS.max_risk_deal).where(URMS.tg_id == tg_id)) + + data = { + 'price_profit': price_profit, + 'price_loss': price_loss, + 'max_risk_deal': max_risk_deal + } + + 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)) @@ -171,4 +252,24 @@ async def update_maximal_quantity(tg_id, num): async with async_session() as session: await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(maximal_quantity = num)) + await session.commit() + +# UPDATE_RISK_MANAGEMENT_SETTINGS_DB + +async def update_price_profit(tg_id, num): + async with async_session() as session: + await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(price_profit = num)) + + await session.commit() + +async def update_price_loss(tg_id, num): + async with async_session() as session: + await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(price_loss = num)) + + await session.commit() + +async def update_max_risk_deal(tg_id, num): + async with async_session() as session: + await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(max_risk_deal = num)) + await session.commit() \ No newline at end of file diff --git a/app/telegram/functions/additional_settings/settings.py b/app/telegram/functions/additional_settings/settings.py index c1f5069..77b6c14 100644 --- a/app/telegram/functions/additional_settings/settings.py +++ b/app/telegram/functions/additional_settings/settings.py @@ -1,5 +1,4 @@ import app.telegram.Keyboards.inline_keyboards as inline_markup -import app.telegram.Keyboards.reply_keyboards as reply_markup import app.telegram.database.requests as rq @@ -8,34 +7,32 @@ async def reg_new_user_default_additional_settings(id, message): await rq.set_new_user_default_additional_settings(tg_id) -async def main_settings_message(message): +async def main_settings_message(id, message, state): text = '''Дополнительные параметры -Сохранить как шаблон стратегии: да / нет +- Сохранить как шаблон стратегии: да / нет +- Автозапуск после сохранения: да / нет +- Уведомления в Telegram: включено / отключено ''' -Автозапуск после сохранения: да / нет - -Уведомления в Telegram: включено / отключено ''' - - await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.additional_settings_markup) + await message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.additional_settings_markup) async def save_pattern_message(message, state): text = '''Сохранение шаблона - + Описание... ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.buttons_yes_no_markup) + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup) async def auto_start_message(message, state): text = '''Автозапуск Описание... ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.buttons_yes_no_markup) + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup) async def notifications_message(message, state): - text = '''Уведомления + text = '''Уведомления Описание... ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.buttons_on_off_markup) \ No newline at end of file + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_on_off_markup) \ No newline at end of file diff --git a/app/telegram/functions/condition_settings/settings.py b/app/telegram/functions/condition_settings/settings.py index 1f98a02..3d9e571 100644 --- a/app/telegram/functions/condition_settings/settings.py +++ b/app/telegram/functions/condition_settings/settings.py @@ -1,5 +1,4 @@ import app.telegram.Keyboards.inline_keyboards as inline_markup -import app.telegram.Keyboards.reply_keyboards as reply_markup import app.telegram.database.requests as rq @@ -10,25 +9,17 @@ async def reg_new_user_default_condition_settings(id, message): await rq.set_new_user_default_condition_settings(tg_id, trigger) -async def main_settings_message(message): +async def main_settings_message(id, message, state): text = """ Условия запуска -Триггер: Ручной запуск / Сигнал TradingView / Полностью автоматический - -Фильтр времени: диапазон по дням недели и времени суток - -Фильтр волатильности / объёма: включить/отключить - -Интеграции и внешние сигналы: - -Использовать сигналы TradingView: да / нет - -Использовать AI-аналитику от ChatGPT: да / нет - -Webhook URL для сигналов (если используется TradingView). - +- Триггер: Ручной запуск / Сигнал TradingView / Полностью автоматический +- Фильтр времени: диапазон по дням недели и времени суток +- Фильтр волатильности / объёма: включить/отключить +- Интеграции и внешние сигналы: +- Использовать сигналы TradingView: да / нет +- Использовать AI-аналитику от ChatGPT: да / не +- Webhook URL для сигналов (если используется TradingView): """ - await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.condition_settings_markup) async def trigger_message(message, state): @@ -36,7 +27,7 @@ async def trigger_message(message, state): Описание ручного запуска, сигналов, автоматического режима ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.trigger_markup) + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.trigger_markup) async def filter_time_message(message, state): text = '''Фильтр времени @@ -51,7 +42,7 @@ async def filter_volatility_message(message, state): Описание... ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.buttons_on_off_markup) + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_on_off_markup) async def external_cues_message(message, state): text = '''Внешние сигналы @@ -65,7 +56,7 @@ async def trading_cues_message(message, state): Описание... ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.buttons_yes_no_markup) + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup) async def webhook_message(message, state): text = '''Скиньте ссылку на webhook (если есть trading view): ''' @@ -77,6 +68,6 @@ async def ai_analytics_message(message, state): Описание... ''' - await message.answer(text=text, parse_mode='html', reply_markup=reply_markup.buttons_yes_no_markup) + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup) diff --git a/app/telegram/functions/functions.py b/app/telegram/functions/functions.py index 8b35365..28e9134 100644 --- a/app/telegram/functions/functions.py +++ b/app/telegram/functions/functions.py @@ -2,33 +2,29 @@ import app.telegram.Keyboards.reply_keyboards as reply_markup async def start_message(message): - await message.answer(f""" Привет {message.from_user.username}! 👋 - -Добро пожаловать в бот по трейдингу на Bibyt — вашего надежного помощника для анализа рынка и принятия взвешенных решений. Здесь вы получите: - -📊 Анализ текущих трендов -📈 Инструменты для прогнозирования и оценки рисков -⚡️ Сигналы и рекомендации по сделкам -🔔 Уведомления о важных изменениях и новостях - -Просто отправляйте интересующий вас инструмент или команду, и бот быстро предоставит актуальную информацию и аналитику. - -Начнем торговать умно и эффективно вместе! 🚀 + username = '' + + if message.from_user.first_name == None: + username = message.from_user.last_name + elif message.from_user.last_name == None: + username = message.from_user.first_name + else: + username = f'{message.from_user.first_name} {message.from_user.last_name}' + await message.answer(f""" Привет {username}! 👋 +Добро пожаловать в чат-робот для автоматизации трейдинга — вашего надежного помощника для анализа рынка и принятия взвешенных решений. """, parse_mode='html', reply_markup=inline_markup.start_markup) async def profile_message(username, message): - await message.answer(f""" {username} + await message.answer(f""" @{username} -Баланс: +Баланс ⭐️ 0 -Описание: -Активный трейдер на платформе Bibyt с индивидуальной стратегией и аналитикой в реальном времени. Постоянно улучшает навыки и следит за рыночными тенденциями для максимальной прибыли. """, parse_mode='html', reply_markup=inline_markup.settings_markup) -async def check_profile_message(message): - await message.answer(f'Добро пожаловать {message.from_user.username}!', reply_markup=reply_markup.base_buttons_markup) +async def check_profile_message(message, username): + await message.answer(f'С возвращением, {username}!', reply_markup=reply_markup.base_buttons_markup) async def settings_message(message): await message.edit_text("Выберите что настроить", reply_markup=inline_markup.special_settings_markup) \ No newline at end of file diff --git a/app/telegram/functions/main_settings/settings.py b/app/telegram/functions/main_settings/settings.py index 13c1a5d..632c234 100644 --- a/app/telegram/functions/main_settings/settings.py +++ b/app/telegram/functions/main_settings/settings.py @@ -12,12 +12,12 @@ from aiogram.fsm.state import State, StatesGroup router_main_settings = Router() class update_main_settings(StatesGroup): - trading_mode = State() # + - size_leverage = State() # - margin_type = State() # - martingale_factor = State() # - starting_quantity = State() # - maximal_quantity = State() # + trading_mode = State() + size_leverage = State() + margin_type = State() + martingale_factor = State() + starting_quantity = State() + maximal_quantity = State() async def reg_new_user_default_main_settings(id, message): tg_id = id @@ -31,18 +31,14 @@ async def reg_new_user_default_main_settings(id, message): async def main_settings_message(id, message, state): data = await rq.get_user_main_settings(id) - await message.answer(f"""Основные настройки -Режим торговли: {data['trading_mode']} - -Тип маржи: {data['margin_type']} - -Размер кредитного плеча: х{data['size_leverage']} - -Начальная ставка: {data['starting_quantity']} - -Коэффициент мартингейла: {data['martingale_factor']} - -Максимальное количесиво ставок в серии: {data['maximal_quantity']} + await message.answer(f"""Основные настройки + +- Режим торговли: {data['trading_mode']} +- Тип маржи: {data['margin_type']} +- Размер кредитного плеча: х{data['size_leverage']} +- Начальная ставка: {data['starting_quantity']} +- Коэффициент мартингейла: {data['martingale_factor']} +- Максимальное количесиво ставок в серии: {data['maximal_quantity']} """, parse_mode='html', reply_markup=inline_markup.main_settings_markup) async def trading_mode_message(message, state): @@ -66,30 +62,34 @@ async def state_trading_mode(callback: CallbackQuery, state): await callback.answer() id = callback.from_user.id - print(f"sdljfngdjklfg ## {callback.data}") + data_settings = await rq.get_user_main_settings(id) try: match callback.data: case 'trade_mode_long': + await callback.message.answer(f"✅ Изменено: {data_settings['trading_mode']} → Long") await rq.update_trade_mode_user(id, 'Long') await main_settings_message(id, callback.message, state) await state.clear() case 'trade_mode_short': + await callback.message.answer(f"✅ Изменено: {data_settings['trading_mode']} → Short") await rq.update_trade_mode_user(id, 'Short') await main_settings_message(id, callback.message, state) await state.clear() case 'trade_mode_switch': + await callback.message.answer(f"✅ Изменено: {data_settings['trading_mode']} → Switch") await rq.update_trade_mode_user(id, 'Switch') await main_settings_message(id, callback.message, state) await state.clear() case 'trade_mode_smart': - await rq.update_trade_mode_user(id, 'Smart') - await main_settings_message(id, callback.message, state) + await callback.message.answer(f"✅ Изменено: {data_settings['trading_mode']} → Smart") + await rq.update_trade_mode_user(id, 'Smart') + await main_settings_message(id, callback.message, state) - await state.clear() + await state.clear() except Exception as e: print(f"error: {e}") @@ -103,32 +103,42 @@ async def state_size_leverage(message: Message, state): await state.update_data(size_leverage = message.text) data = await state.get_data() + data_settings = await rq.get_user_main_settings(message.from_user.id) if data['size_leverage'].isdigit() and int(data['size_leverage']) <= 100: + await message.answer(f"✅ Изменено: {data_settings['size_leverage']} → {data['size_leverage']}") + await rq.update_size_leverange(message.from_user.id, data['size_leverage']) await main_settings_message(message.from_user.id, message, state) await state.clear() else: + await message.answer(f'⛔️ Ошибка: ваше значение ({data['size_leverage']}) или выше лимита (100) или вы вводите неверные символы') + await main_settings_message(message.from_user.id, message, state) async def martingale_factor_message(message, state): await state.set_state(update_main_settings.martingale_factor) await message.edit_text("Введите коэффициент Мартингейла:", parse_mode='html', reply_markup=inline_markup.back_btn_list_settings_markup) - + @router_main_settings.message(update_main_settings.martingale_factor) async def state_martingale_factor(message: Message, state): await state.update_data(martingale_factor = message.text) data = await state.get_data() + data_settings = await rq.get_user_main_settings(message.from_user.id) if data['martingale_factor'].isdigit() and int(data['martingale_factor']) <= 100: + await message.answer(f"✅ Изменено: {data_settings['martingale_factor']} → {data['martingale_factor']}") + await rq.update_martingale_factor(message.from_user.id, data['martingale_factor']) await main_settings_message(message.from_user.id, message, state) await state.clear() else: + await message.answer(f'⛔️ Ошибка: ваше значение ({data['martingale_factor']}) или выше лимита (100) или вы вводите неверные символы') + await main_settings_message(message.from_user.id, message, state) async def margin_type_message(message, state): @@ -155,17 +165,21 @@ async def state_margin_type(callback: CallbackQuery, state): await callback.answer() id = callback.from_user.id - print(f"sdljfngdjklfg ## {callback.data}") + data_settings = await rq.get_user_main_settings(id) try: match callback.data: case 'margin_type_isolated': - await rq.update_margin_type(id, 'Изолированный') + await callback.message.answer(f"✅ Изменено: {data_settings['margin_type']} → Isolated") + + await rq.update_margin_type(id, 'Isolated') await main_settings_message(id, callback.message, state) await state.clear() case 'margin_type_cross': - await rq.update_margin_type(id, 'Кросс') + await callback.message.answer(f"✅ Изменено: {data_settings['margin_type']} → Cross") + + await rq.update_margin_type(id, 'Cross') await main_settings_message(id, callback.message, state) await state.clear() @@ -182,30 +196,40 @@ async def state_starting_quantity(message: Message, state): await state.update_data(starting_quantity = message.text) data = await state.get_data() + data_settings = await rq.get_user_main_settings(message.from_user.id) + + if data['starting_quantity'].isdigit(): + await message.answer(f"✅ Изменено: {data_settings['starting_quantity']} → {data['starting_quantity']}") - if data['starting_quantity'].isdigit() and int(data['starting_quantity']) <= 100: await rq.update_starting_quantity(message.from_user.id, data['starting_quantity']) await main_settings_message(message.from_user.id, message, state) await state.clear() else: + await message.answer(f'⛔️ Ошибка: вы вводите неверные символы') + await main_settings_message(message.from_user.id, message, state) async def maximum_quantity_message(message, state): await state.set_state(update_main_settings.maximal_quantity) - await message.edit_text("Введите максимальное количество ставок:", parse_mode='html', reply_markup=inline_markup.back_btn_list_settings_markup) + await message.edit_text("Введите максимальное количество серии ставок:", parse_mode='html', reply_markup=inline_markup.back_btn_list_settings_markup) @router_main_settings.message(update_main_settings.maximal_quantity) async def state_maximal_quantity(message: Message, state): await state.update_data(maximal_quantity = message.text) data = await state.get_data() + data_settings = await rq.get_user_main_settings(message.from_user.id) if data['maximal_quantity'].isdigit() and int(data['maximal_quantity']) <= 100: + await message.answer(f"✅ Изменено: {data_settings['maximal_quantity']} → {data['maximal_quantity']}") + await rq.update_maximal_quantity(message.from_user.id, data['maximal_quantity']) await main_settings_message(message.from_user.id, message, state) await state.clear() else: + await message.answer(f'⛔️ Ошибка: ваше значение ({data['maximal_quantity']}) или выше лимита (100) или вы вводите неверные символы') + await main_settings_message(message.from_user.id, message, state) \ No newline at end of file diff --git a/app/telegram/functions/risk_management_settings/settings.py b/app/telegram/functions/risk_management_settings/settings.py index 541672f..859451e 100644 --- a/app/telegram/functions/risk_management_settings/settings.py +++ b/app/telegram/functions/risk_management_settings/settings.py @@ -1,37 +1,110 @@ -import app.telegram.Keyboards.inline_keyboards as inline_markup +from aiogram import Router +import app.telegram.Keyboards.inline_keyboards as inline_markup import app.telegram.Keyboards.reply_keyboards as reply_markup import app.telegram.database.requests as rq +from aiogram.types import Message, CallbackQuery + +# FSM - Механизм состояния +from aiogram.fsm.state import State, StatesGroup + +router_risk_management_settings = Router() + +class update_risk_management_settings(StatesGroup): + price_profit = State() + price_loss = State() + max_risk_deal = State() async def reg_new_user_default_risk_management_settings(id, message): tg_id = id - await rq.set_new_user_default_risk_management_settings(tg_id) + await rq.set_new_user_default_risk_management_settings(tg_id) +async def main_settings_message(id, message, state): + data = await rq.get_user_risk_management_settings(id) -async def main_settings_message(message): text = f"""Риск менеджмент, - Процент изменения цены для фиксации прибыли: 0 - - Процент изменения цены для фиксации убытков: 0 - - Максимальный риск на сделку (в % от баланса): 0 - """ - - await message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.risk_management_settings_markup) +- Процент изменения цены для фиксации прибыли: {data['price_profit']}% +- Процент изменения цены для фиксации убытков: {data['price_loss']}% +- Максимальный риск на сделку (в % от баланса): {data['max_risk_deal']}% +""" + await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.risk_management_settings_markup) async def price_profit_message(message, state): + await state.set_state(update_risk_management_settings.price_profit) + text = 'Введите число изменения цены для фиксации прибыли: ' await message.answer(text=text, parse_mode='html', reply_markup=None) +@router_risk_management_settings.message(update_risk_management_settings.price_profit) +async def state_price_profit(message: Message, state): + await state.update_data(price_profit = message.text) + + data = await state.get_data() + data_settings = await rq.get_user_risk_management_settings(message.from_user.id) + + if data['price_profit'].isdigit() and int(data['price_profit']) <= 100: + await message.answer(f"✅ Изменено: {data_settings['price_profit']}% → {data['price_profit']}%") + + await rq.update_price_profit(message.from_user.id, data['price_profit']) + await main_settings_message(message.from_user.id, message, state) + + await state.clear() + else: + await message.answer(f'⛔️ Ошибка: ваше значение ({data['price_profit']}%) или выше лимита (100) или вы вводите неверные символы') + + await main_settings_message(message.from_user.id, message, state) + async def price_loss_message(message, state): + await state.set_state(update_risk_management_settings.price_loss) + text = 'Введите число изменения цены для фиксации убытков: ' await message.answer(text=text, parse_mode='html', reply_markup=None) +@router_risk_management_settings.message(update_risk_management_settings.price_loss) +async def state_price_loss(message: Message, state): + await state.update_data(price_loss = message.text) + + data = await state.get_data() + data_settings = await rq.get_user_risk_management_settings(message.from_user.id) + + if data['price_loss'].isdigit() and int(data['price_loss']) <= 100: + await message.answer(f"✅ Изменено: {data_settings['price_loss']}% → {data['price_loss']}%") + + await rq.update_price_loss(message.from_user.id, data['price_loss']) + await main_settings_message(message.from_user.id, message, state) + + await state.clear() + else: + await message.answer(f'⛔️ Ошибка: ваше значение ({data['price_loss']}%) или выше лимита (100) или вы вводите неверные символы') + + await main_settings_message(message.from_user.id, message, state) + async def max_risk_deal_message(message, state): + await state.set_state(update_risk_management_settings.max_risk_deal) + text = 'Введите число (процент от баланса) для изменения максимального риска на сделку: ' - await message.answer(text=text, parse_mode='html', reply_markup=None) \ No newline at end of file + await message.answer(text=text, parse_mode='html', reply_markup=None) + +@router_risk_management_settings.message(update_risk_management_settings.max_risk_deal) +async def state_max_risk_deal(message: Message, state): + await state.update_data(max_risk_deal = message.text) + + data = await state.get_data() + data_settings = await rq.get_user_risk_management_settings(message.from_user.id) + + if data['max_risk_deal'].isdigit() and int(data['max_risk_deal']) <= 100: + await message.answer(f"✅ Изменено: {data_settings['max_risk_deal']}% → {data['max_risk_deal']}%") + + await rq.update_max_risk_deal(message.from_user.id, data['max_risk_deal']) + await main_settings_message(message.from_user.id, message, state) + + await state.clear() + else: + await message.answer(f'⛔️ Ошибка: ваше значение ({data['max_risk_deal']}%) или выше лимита (100) или вы вводите неверные символы') + + await main_settings_message(message.from_user.id, message, state) \ No newline at end of file diff --git a/app/telegram/handlers/handlers.py b/app/telegram/handlers/handlers.py index a5b6533..8ea7fa3 100644 --- a/app/telegram/handlers/handlers.py +++ b/app/telegram/handlers/handlers.py @@ -19,6 +19,7 @@ router = Router() @router.message(CommandStart()) async def start_message(message: Message): + await rq.set_new_user_bybit_api(message.from_user.id) await func.start_message(message) @router.message(F.text == "👤 Профиль") @@ -35,26 +36,34 @@ async def settings_msg(message: Message): if user: await func.settings_message(message) -@router.callback_query(F.data == "callback_registration") -async def clb_func_reg (callback: CallbackQuery): - await rq.save_tg_id_new_user(callback.from_user.id) - print(callback.from_user.id) - - await func_main_settings.reg_new_user_default_main_settings(callback.from_user.id, callback.message) - await func_rmanagement_settings.reg_new_user_default_risk_management_settings(callback.from_user.id, callback.message) - await func_condition_settings.reg_new_user_default_condition_settings(callback.from_user.id, callback.message) - await func_additional_settings.reg_new_user_default_additional_settings(callback.from_user.id, callback.message) - - await callback.message.answer(f'Регистрация прошла успешно, здравствуйте {callback.from_user.username}!', reply_markup=reply_markup.base_buttons_markup) - - await callback.answer() - -@router.callback_query(F.data == "callback_autorisation") -async def clb_func_reg (callback: CallbackQuery): +@router.callback_query(F.data == "clb_start_chatbot_message") +async def clb_profile_msg (callback: CallbackQuery): user = await rq.check_user(callback.from_user.id) - if user: + username = '' + + if callback.from_user.first_name == None: + username = callback.from_user.last_name + elif callback.from_user.last_name == None: + username = callback.from_user.first_name + else: + username = f'{callback.from_user.first_name} {callback.from_user.last_name}' + + if user: await func.profile_message(callback.from_user.username, callback.message) + else: + await rq.save_tg_id_new_user(callback.from_user.id) + + await func_main_settings.reg_new_user_default_main_settings(callback.from_user.id, callback.message) + await func_rmanagement_settings.reg_new_user_default_risk_management_settings(callback.from_user.id, callback.message) + await func_condition_settings.reg_new_user_default_condition_settings(callback.from_user.id, callback.message) + await func_additional_settings.reg_new_user_default_additional_settings(callback.from_user.id, callback.message) + + await callback.message.answer(f'Здравствуйте, {username}!', reply_markup=reply_markup.base_buttons_markup) + + await func.profile_message(username, callback.message) + + await callback.answer() # Настройки торговли @router.callback_query(F.data == "clb_settings_message")