From ed67ed78c05bf8d11004534ca252e40c8bcf446b Mon Sep 17 00:00:00 2001 From: Kirill Strelnikov Date: Mon, 21 Jul 2025 13:40:33 +0700 Subject: [PATCH 1/5] version 1 STCS --- BibytBot_API.py | 10 +- BibytBot_API.pyproj | 10 + app/services/Bybit/config.py | 9 + app/services/Bybit/functions/Add_Bybit_API.py | 73 ++++ app/services/Bybit/functions/Futures.py | 348 ++++++++++++++++++ app/services/Bybit/functions/balance.py | 38 ++ app/services/Bybit/functions/func_min_qty.py | 37 ++ app/services/Bybit/functions/functions.py | 105 ++++++ app/services/Bybit/functions/min_qty.py | 23 ++ app/services/Bybit/functions/price_symbol.py | 40 ++ app/telegram/Keyboards/inline_keyboards.py | 34 +- app/telegram/Keyboards/reply_keyboards.py | 13 - app/telegram/database/models.py | 21 +- app/telegram/database/requests.py | 105 +++++- .../functions/additional_settings/settings.py | 23 +- .../functions/condition_settings/settings.py | 33 +- app/telegram/functions/functions.py | 8 +- .../functions/main_settings/settings.py | 41 +-- .../risk_management_settings/settings.py | 82 ++++- app/telegram/handlers/handlers.py | 33 +- 20 files changed, 976 insertions(+), 110 deletions(-) create mode 100644 app/services/Bybit/config.py create mode 100644 app/services/Bybit/functions/Add_Bybit_API.py create mode 100644 app/services/Bybit/functions/Futures.py create mode 100644 app/services/Bybit/functions/balance.py create mode 100644 app/services/Bybit/functions/func_min_qty.py create mode 100644 app/services/Bybit/functions/functions.py create mode 100644 app/services/Bybit/functions/min_qty.py create mode 100644 app/services/Bybit/functions/price_symbol.py 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..5d12a4f 100644 --- a/BibytBot_API.pyproj +++ b/BibytBot_API.pyproj @@ -21,6 +21,13 @@ false + + + + + + + @@ -37,6 +44,9 @@ + + + diff --git a/app/services/Bybit/config.py b/app/services/Bybit/config.py new file mode 100644 index 0000000..1153414 --- /dev/null +++ b/app/services/Bybit/config.py @@ -0,0 +1,9 @@ +API_KEY='' +API_SECRET='' +SYMBOL='' + +''' +API_KEY = 'o5854uk3qBD4lySnjv' +SECRET_KEY = 'aMFPbs0AKyOSLTgXyrqCfREDi7byjnsOd0Kj' +SYMBOL = "SHIB1000USDT" +''' \ No newline at end of file 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..b116213 --- /dev/null +++ b/app/services/Bybit/functions/Futures.py @@ -0,0 +1,348 @@ +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: + print(f''' + ===================== + =====Сделка========= + ===уСПЕШНЕАЯ================ + =================== + ================= + + {realised_pnl} + + =============== + =============== + ============= + =============== + ============== + ''') + 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 + + print(f''' + ======СДЕЛКА=============== + =====УБЫТОЧНАЯ============== + =================== + =================== + ================= + + {realised_pnl} + + =============== + =============== + ============= + =============== + ============== + ''') + 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) + + print(f''' + ===================== + =================== + =================== + =================== + ================= + + {r} + + =============== + =============== + ============= + =============== + ============== + ''') + + 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: + print(f''' + ===================== + =====Сделка========= + ===уСПЕШНЕАЯ================ + =================== + ================= + + {realised_pnl} + + =============== + =============== + ============= + =============== + ============== + ''') + 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 + + print(f''' + ======СДЕЛКА=============== + =====УБЫТОЧНАЯ============== + =================== + =================== + ================= + + {realised_pnl} + + =============== + =============== + ============= + =============== + ============== + ''') + 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) + + print(f''' + ===================== + =================== + =================== + =================== + ================= + + {r} + + =============== + =============== + ============= + =============== + ============== + ''') + + 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..a9c4eb2 --- /dev/null +++ b/app/services/Bybit/functions/balance.py @@ -0,0 +1,38 @@ +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 + ) + + try: + balance = client.get_wallet_balance(accountType='UNIFIED', coin='USDT')['result']['list'][0]['coin'][0]['walletBalance'] + + print(f''' + ===================== + =====BALANCE========= + ======USDT============= + =================== + ================= + + {balance} + + =============== + =============== + ============= + =============== + ============== + ''') + + return balance + except Exception as e: + await message.answer('Баланс не был получен') + 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..2275894 --- /dev/null +++ b/app/services/Bybit/functions/func_min_qty.py @@ -0,0 +1,37 @@ +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) + + print(f''' + ===================== + =====MIN========= + =====QTY============== + =================== + ================= + + {min_qty} + + =============== + =============== + ============= + =============== + ============== + ''') + + 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..8aae247 --- /dev/null +++ b/app/services/Bybit/functions/functions.py @@ -0,0 +1,105 @@ +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) + + if api and secret: + balance = await get_balance(callback.from_user.id, callback.message) + 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) + else: + callback.message.answer('Перед началом работы, в настройках подключите bybit') + +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) + + if api and secret: + balance = await get_balance(message.from_user.id, message) + 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) + else: + await message.answer('Перед началом работы, в настройках подключите bybit') + +@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 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': + print('====================================LONG=========================================') + await Futures.contract_long(callback.from_user.id, callback.message, margin_mode) + case 'Short': + print('====================================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..0921aa4 --- /dev/null +++ b/app/services/Bybit/functions/price_symbol.py @@ -0,0 +1,40 @@ +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')) + + print(f''' + ===================== + =====PRICE========= + =================== + =================== + ================= + + {price} + + =============== + =============== + ============= + =============== + ============== + ''') + + 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..826568c 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="callback_profile")] ]) 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='callback_profile')] 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..a6d28ce 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' @@ -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..290dfcf 100644 --- a/app/telegram/functions/functions.py +++ b/app/telegram/functions/functions.py @@ -20,11 +20,13 @@ async def start_message(message): async def profile_message(username, message): await message.answer(f""" {username} -Баланс: +Баланс ⭐️ 0 -Описание: -Активный трейдер на платформе Bibyt с индивидуальной стратегией и аналитикой в реальном времени. Постоянно улучшает навыки и следит за рыночными тенденциями для максимальной прибыли. +О себе +🚀 Профессиональный трейдер на платформе Bibyt с авторской стратегией и аналитикой в реальном времени. +📊 Постоянно улучшаю навыки и адаптируюсь к рыночным изменениям, чтобы максимально увеличить прибыль. +🔥 Всегда в поиске новых возможностей для роста и стабильного успеха! """, parse_mode='html', reply_markup=inline_markup.settings_markup) async def check_profile_message(message): diff --git a/app/telegram/functions/main_settings/settings.py b/app/telegram/functions/main_settings/settings.py index 13c1a5d..2829b09 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,7 +62,6 @@ async def state_trading_mode(callback: CallbackQuery, state): await callback.answer() id = callback.from_user.id - print(f"sdljfngdjklfg ## {callback.data}") try: match callback.data: @@ -116,7 +111,7 @@ 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) @@ -160,12 +155,12 @@ async def state_margin_type(callback: CallbackQuery, state): try: match callback.data: case 'margin_type_isolated': - await rq.update_margin_type(id, 'Изолированный') + 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 rq.update_margin_type(id, 'Cross') await main_settings_message(id, callback.message, state) await state.clear() @@ -183,7 +178,7 @@ async def state_starting_quantity(message: Message, state): data = await state.get_data() - if data['starting_quantity'].isdigit() and int(data['starting_quantity']) <= 100: + if data['starting_quantity'].isdigit(): await rq.update_starting_quantity(message.from_user.id, data['starting_quantity']) await main_settings_message(message.from_user.id, message, state) diff --git a/app/telegram/functions/risk_management_settings/settings.py b/app/telegram/functions/risk_management_settings/settings.py index 541672f..7d1268c 100644 --- a/app/telegram/functions/risk_management_settings/settings.py +++ b/app/telegram/functions/risk_management_settings/settings.py @@ -1,37 +1,95 @@ -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() + + if data['price_profit'].isdigit() and int(data['price_profit']) <= 100: + 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 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() + + if data['price_loss'].isdigit() and int(data['price_loss']) <= 100: + 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 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() + + if data['max_risk_deal'].isdigit() and int(data['max_risk_deal']) <= 100: + 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 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..1ad2f4e 100644 --- a/app/telegram/handlers/handlers.py +++ b/app/telegram/handlers/handlers.py @@ -19,6 +19,8 @@ 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 +37,27 @@ 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") +@router.callback_query(F.data == "callback_profile") async def clb_func_reg (callback: CallbackQuery): user = await rq.check_user(callback.from_user.id) if user: + await callback.message.answer(f'С возвращением, {callback.from_user.username}!', reply_markup=reply_markup.base_buttons_markup) + 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'Регистрация прошла успешно, здравствуйте {callback.from_user.username}!', reply_markup=reply_markup.base_buttons_markup) + + await func.profile_message(callback.from_user.username, callback.message) + + await callback.answer() # Настройки торговли @router.callback_query(F.data == "clb_settings_message") From fb0c14aba13a4626f186e48962306fed718510e4 Mon Sep 17 00:00:00 2001 From: Kirill Strelnikov Date: Mon, 21 Jul 2025 15:05:50 +0700 Subject: [PATCH 2/5] Update Readme.md --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) 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 *(настроено)* From 242be34a973d5cec2f6ee96f2cc3775f9176ad35 Mon Sep 17 00:00:00 2001 From: Kirill Strelnikov Date: Mon, 21 Jul 2025 16:55:30 +0700 Subject: [PATCH 3/5] =?UTF-8?q?fix=20app/telegram/handlers/handlers.py,=20?= =?UTF-8?q?fix=20app/telegram/functions/functions.py=20||=20change=20two?= =?UTF-8?q?=20buttons=20"=D0=9D=D0=B0=D1=87=D0=B0=D1=82=D1=8C=20=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B3=D0=BE=D0=B2=D0=BB=D1=8E"=20||=20fix=20text?= =?UTF-8?q?=20registration=20message,=20fix=20text=20profile=20||=20delete?= =?UTF-8?q?=20app/services/Bybit/config.py=20||=20delete=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/Bybit/config.py | 9 --- app/services/Bybit/functions/Futures.py | 74 ++------------------ app/services/Bybit/functions/balance.py | 18 +---- app/services/Bybit/functions/func_min_qty.py | 16 ----- app/services/Bybit/functions/functions.py | 2 - app/services/Bybit/functions/price_symbol.py | 16 ----- app/telegram/Keyboards/inline_keyboards.py | 4 +- app/telegram/functions/functions.py | 25 +++---- app/telegram/handlers/handlers.py | 15 +++- 9 files changed, 34 insertions(+), 145 deletions(-) delete mode 100644 app/services/Bybit/config.py diff --git a/app/services/Bybit/config.py b/app/services/Bybit/config.py deleted file mode 100644 index 1153414..0000000 --- a/app/services/Bybit/config.py +++ /dev/null @@ -1,9 +0,0 @@ -API_KEY='' -API_SECRET='' -SYMBOL='' - -''' -API_KEY = 'o5854uk3qBD4lySnjv' -SECRET_KEY = 'aMFPbs0AKyOSLTgXyrqCfREDi7byjnsOd0Kj' -SYMBOL = "SHIB1000USDT" -''' \ No newline at end of file diff --git a/app/services/Bybit/functions/Futures.py b/app/services/Bybit/functions/Futures.py index b116213..25e60a2 100644 --- a/app/services/Bybit/functions/Futures.py +++ b/app/services/Bybit/functions/Futures.py @@ -71,7 +71,7 @@ async def contract_long(tg_id, message, margin_mode): setMarginMode=margin_mode # margin_type ) - martingale_factor = float(data_main_stgs['martingale_factor']) # Исправлено: было maximal_quantity + martingale_factor = float(data_main_stgs['martingale_factor']) 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']) @@ -172,23 +172,7 @@ async def contract_long(tg_id, message, margin_mode): 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) - - print(f''' - ===================== - =================== - =================== - =================== - ================= - - {r} - - =============== - =============== - ============= - =============== - ============== - ''') + 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('Недостаточно баланса') @@ -225,7 +209,7 @@ async def contract_short(tg_id, message, margin_mode): setMarginMode=margin_mode # margin_type ) - martingale_factor = float(data_main_stgs['martingale_factor']) # Исправлено: было maximal_quantity + martingale_factor = float(data_main_stgs['martingale_factor']) 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']) @@ -251,47 +235,17 @@ async def contract_short(tg_id, message, margin_mode): realised_pnl = float(position['unrealisedPnl']) - if realised_pnl > 0: - print(f''' - ===================== - =====Сделка========= - ===уСПЕШНЕАЯ================ - =================== - ================= - - {realised_pnl} - - =============== - =============== - ============= - =============== - ============== - ''') + 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: + else: # Убыточная сделка current_martingale_step += 1 next_quantity = last_quantity * martingale_factor starting_quantity = next_quantity - print(f''' - ======СДЕЛКА=============== - =====УБЫТОЧНАЯ============== - =================== - =================== - ================= - - {realised_pnl} - - =============== - =============== - ============= - =============== - ============== - ''') except Exception as e: print("Не получены позиции") next_quantity = starting_quantity @@ -324,23 +278,7 @@ async def contract_short(tg_id, message, margin_mode): 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) - - print(f''' - ===================== - =================== - =================== - =================== - ================= - - {r} - - =============== - =============== - ============= - =============== - ============== - ''') + 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('Недостаточно баланса') diff --git a/app/services/Bybit/functions/balance.py b/app/services/Bybit/functions/balance.py index a9c4eb2..f0518f1 100644 --- a/app/services/Bybit/functions/balance.py +++ b/app/services/Bybit/functions/balance.py @@ -16,23 +16,7 @@ async def get_balance(tg_id, message): try: balance = client.get_wallet_balance(accountType='UNIFIED', coin='USDT')['result']['list'][0]['coin'][0]['walletBalance'] - print(f''' - ===================== - =====BALANCE========= - ======USDT============= - =================== - ================= - - {balance} - - =============== - =============== - ============= - =============== - ============== - ''') - return balance except Exception as e: - await message.answer('Баланс не был получен') + await message.answer('Баланс не был получен, подключите платформу') 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 index 2275894..0544b64 100644 --- a/app/services/Bybit/functions/func_min_qty.py +++ b/app/services/Bybit/functions/func_min_qty.py @@ -18,20 +18,4 @@ async def get_min_qty(tg_id, message): price = await price_s.get_price(tg_id, message) min_qty = int(5 / price * 1.1) - print(f''' - ===================== - =====MIN========= - =====QTY============== - =================== - ================= - - {min_qty} - - =============== - =============== - ============= - =============== - ============== - ''') - 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 index 8aae247..87aca78 100644 --- a/app/services/Bybit/functions/functions.py +++ b/app/services/Bybit/functions/functions.py @@ -94,10 +94,8 @@ async def make_deal_bybit (callback: CallbackQuery): else: match trade_mode: case 'Long': - print('====================================LONG=========================================') await Futures.contract_long(callback.from_user.id, callback.message, margin_mode) case 'Short': - print('====================================SHORT=========================================') await Futures.contract_short(callback.from_user.id, callback.message, margin_mode) case 'Switch': await callback.message.edit_text('Режим Switch пока недоступен') diff --git a/app/services/Bybit/functions/price_symbol.py b/app/services/Bybit/functions/price_symbol.py index 0921aa4..8971a66 100644 --- a/app/services/Bybit/functions/price_symbol.py +++ b/app/services/Bybit/functions/price_symbol.py @@ -18,22 +18,6 @@ async def get_price(tg_id, message): try: price = float(client.get_tickers(category='linear', symbol=SYMBOL).get('result').get('list')[0].get('ask1Price')) - print(f''' - ===================== - =====PRICE========= - =================== - =================== - ================= - - {price} - - =============== - =============== - ============= - =============== - ============== - ''') - return price except exceptions.InvalidRequestError as e: await message.answer('Неверно указана торговая пара') diff --git a/app/telegram/Keyboards/inline_keyboards.py b/app/telegram/Keyboards/inline_keyboards.py index 826568c..5ca4fd6 100644 --- a/app/telegram/Keyboards/inline_keyboards.py +++ b/app/telegram/Keyboards/inline_keyboards.py @@ -1,12 +1,12 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup start_markup = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Торговать", callback_data="callback_profile")] + [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_start_trading')] + [InlineKeyboardButton(text="Запуск", callback_data='clb_start_trading')] ]) back_btn_profile = [InlineKeyboardButton(text="Назад", callback_data='callback_profile')] diff --git a/app/telegram/functions/functions.py b/app/telegram/functions/functions.py index 290dfcf..1a7d761 100644 --- a/app/telegram/functions/functions.py +++ b/app/telegram/functions/functions.py @@ -2,35 +2,36 @@ import app.telegram.Keyboards.reply_keyboards as reply_markup async def start_message(message): - await message.answer(f""" Привет {message.from_user.username}! 👋 + 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}! 👋 -Добро пожаловать в бот по трейдингу на Bibyt — вашего надежного помощника для анализа рынка и принятия взвешенных решений. Здесь вы получите: +Добро пожаловать в чат-робот по трейдингу на Bybit — вашего надежного помощника для анализа рынка и принятия взвешенных решений. +Здесь вы получите: 📊 Анализ текущих трендов 📈 Инструменты для прогнозирования и оценки рисков ⚡️ Сигналы и рекомендации по сделкам 🔔 Уведомления о важных изменениях и новостях -Просто отправляйте интересующий вас инструмент или команду, и бот быстро предоставит актуальную информацию и аналитику. - -Начнем торговать умно и эффективно вместе! 🚀 - """, 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) + await message.answer(f'Добро пожаловать {message.from_user.first_name} {message.from_user.last_name}!', 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/handlers/handlers.py b/app/telegram/handlers/handlers.py index 1ad2f4e..b56cd4e 100644 --- a/app/telegram/handlers/handlers.py +++ b/app/telegram/handlers/handlers.py @@ -37,7 +37,7 @@ async def settings_msg(message: Message): if user: await func.settings_message(message) -@router.callback_query(F.data == "callback_profile") +@router.callback_query(F.data == "clb_start_chatbot_message") async def clb_func_reg (callback: CallbackQuery): user = await rq.check_user(callback.from_user.id) @@ -53,11 +53,20 @@ async def clb_func_reg (callback: CallbackQuery): 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.message.answer(f'Регистрация прошла успешно, перейдите в профиль нажав на кнопку!', reply_markup=reply_markup.base_buttons_markup) await func.profile_message(callback.from_user.username, callback.message) - await callback.answer() + await callback.answer() + +@router.callback_query(F.data == "callback_profile") +async def clb_profile_message (callback: CallbackQuery): + user = await rq.check_user(callback.from_user.id) + + if user: + await func.profile_message(callback.from_user.username, callback.message) + + await callback.answer() # Настройки торговли @router.callback_query(F.data == "clb_settings_message") From e555bfa8fb1ecf42f0ece76739dcc8a0b750ab04 Mon Sep 17 00:00:00 2001 From: Kirill Strelnikov Date: Tue, 22 Jul 2025 12:54:23 +0700 Subject: [PATCH 4/5] The text of the welcome message has been changed, the text of the risk management settings has been changed, the default value for "maximum_trade_risk" in the database has been changed from 1 to 100. The message upon re-clicking the "Start Trading" button has been removed. --- app/telegram/Keyboards/inline_keyboards.py | 2 +- app/telegram/database/models.py | 2 +- app/telegram/functions/functions.py | 13 ++------- .../risk_management_settings/settings.py | 6 ++-- app/telegram/handlers/handlers.py | 29 +++++++++---------- 5 files changed, 21 insertions(+), 31 deletions(-) diff --git a/app/telegram/Keyboards/inline_keyboards.py b/app/telegram/Keyboards/inline_keyboards.py index 5ca4fd6..e9c034d 100644 --- a/app/telegram/Keyboards/inline_keyboards.py +++ b/app/telegram/Keyboards/inline_keyboards.py @@ -9,7 +9,7 @@ settings_markup = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Запуск", callback_data='clb_start_trading')] ]) -back_btn_profile = [InlineKeyboardButton(text="Назад", callback_data='callback_profile')] +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'), diff --git a/app/telegram/database/models.py b/app/telegram/database/models.py index a6d28ce..69da607 100644 --- a/app/telegram/database/models.py +++ b/app/telegram/database/models.py @@ -84,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' diff --git a/app/telegram/functions/functions.py b/app/telegram/functions/functions.py index 1a7d761..28e9134 100644 --- a/app/telegram/functions/functions.py +++ b/app/telegram/functions/functions.py @@ -12,14 +12,7 @@ async def start_message(message): username = f'{message.from_user.first_name} {message.from_user.last_name}' await message.answer(f""" Привет {username}! 👋 -Добро пожаловать в чат-робот по трейдингу на Bybit — вашего надежного помощника для анализа рынка и принятия взвешенных решений. -Здесь вы получите: - -📊 Анализ текущих трендов -📈 Инструменты для прогнозирования и оценки рисков -⚡️ Сигналы и рекомендации по сделкам -🔔 Уведомления о важных изменениях и новостях - +Добро пожаловать в чат-робот для автоматизации трейдинга — вашего надежного помощника для анализа рынка и принятия взвешенных решений. """, parse_mode='html', reply_markup=inline_markup.start_markup) async def profile_message(username, message): @@ -30,8 +23,8 @@ async def profile_message(username, message): """, parse_mode='html', reply_markup=inline_markup.settings_markup) -async def check_profile_message(message): - await message.answer(f'Добро пожаловать {message.from_user.first_name} {message.from_user.last_name}!', 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/risk_management_settings/settings.py b/app/telegram/functions/risk_management_settings/settings.py index 7d1268c..40b533c 100644 --- a/app/telegram/functions/risk_management_settings/settings.py +++ b/app/telegram/functions/risk_management_settings/settings.py @@ -25,9 +25,9 @@ async def main_settings_message(id, message, state): text = f"""Риск менеджмент, -- Процент изменения цены для фиксации прибыли: {data['price_profit']} -- Процент изменения цены для фиксации убытков: {data['price_loss']} -- Максимальный риск на сделку (в % от баланса): {data['max_risk_deal']} +- Процент изменения цены для фиксации прибыли: {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) diff --git a/app/telegram/handlers/handlers.py b/app/telegram/handlers/handlers.py index b56cd4e..8ea7fa3 100644 --- a/app/telegram/handlers/handlers.py +++ b/app/telegram/handlers/handlers.py @@ -20,7 +20,6 @@ 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 == "👤 Профиль") @@ -38,12 +37,19 @@ async def settings_msg(message: Message): await func.settings_message(message) @router.callback_query(F.data == "clb_start_chatbot_message") -async def clb_func_reg (callback: CallbackQuery): +async def clb_profile_msg (callback: CallbackQuery): user = await rq.check_user(callback.from_user.id) - if user: - await callback.message.answer(f'С возвращением, {callback.from_user.username}!', reply_markup=reply_markup.base_buttons_markup) - + 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) @@ -53,18 +59,9 @@ async def clb_func_reg (callback: CallbackQuery): 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'Регистрация прошла успешно, перейдите в профиль нажав на кнопку!', reply_markup=reply_markup.base_buttons_markup) + await callback.message.answer(f'Здравствуйте, {username}!', reply_markup=reply_markup.base_buttons_markup) - await func.profile_message(callback.from_user.username, callback.message) - - await callback.answer() - -@router.callback_query(F.data == "callback_profile") -async def clb_profile_message (callback: CallbackQuery): - user = await rq.check_user(callback.from_user.id) - - if user: - await func.profile_message(callback.from_user.username, callback.message) + await func.profile_message(username, callback.message) await callback.answer() From 1997b9d1c04550dd8f6028c23e4e2e9c7d62793a Mon Sep 17 00:00:00 2001 From: Kirill Strelnikov Date: Tue, 22 Jul 2025 16:08:23 +0700 Subject: [PATCH 5/5] The message about the Bybit profile output has been corrected when clicking the "Start" button, and messages regarding the requirement to connect the platform and incorrect API entries have been added. Messages about successful and erroneous changes to user settings have been added. --- BibytBot_API.pyproj | 1 - app/services/Bybit/functions/Futures.py | 40 ++----------------- app/services/Bybit/functions/balance.py | 19 +++++++-- app/services/Bybit/functions/functions.py | 28 ++++++------- .../functions/main_settings/settings.py | 39 +++++++++++++++--- .../risk_management_settings/settings.py | 15 +++++++ 6 files changed, 80 insertions(+), 62 deletions(-) diff --git a/BibytBot_API.pyproj b/BibytBot_API.pyproj index 5d12a4f..595308b 100644 --- a/BibytBot_API.pyproj +++ b/BibytBot_API.pyproj @@ -21,7 +21,6 @@ false - diff --git a/app/services/Bybit/functions/Futures.py b/app/services/Bybit/functions/Futures.py index 25e60a2..1f68dc0 100644 --- a/app/services/Bybit/functions/Futures.py +++ b/app/services/Bybit/functions/Futures.py @@ -71,7 +71,7 @@ async def contract_long(tg_id, message, margin_mode): setMarginMode=margin_mode # margin_type ) - martingale_factor = float(data_main_stgs['martingale_factor']) + 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']) @@ -98,21 +98,6 @@ async def contract_long(tg_id, message, margin_mode): realised_pnl = float(position['unrealisedPnl']) if realised_pnl > 0: - print(f''' - ===================== - =====Сделка========= - ===уСПЕШНЕАЯ================ - =================== - ================= - - {realised_pnl} - - =============== - =============== - ============= - =============== - ============== - ''') starting_quantity = next_quantity current_martingale_step = 0 elif not realised_pnl: @@ -122,22 +107,6 @@ async def contract_long(tg_id, message, margin_mode): current_martingale_step += 1 next_quantity = last_quantity * martingale_factor starting_quantity = next_quantity - - print(f''' - ======СДЕЛКА=============== - =====УБЫТОЧНАЯ============== - =================== - =================== - ================= - - {realised_pnl} - - =============== - =============== - ============= - =============== - ============== - ''') except Exception as e: print("Не получены позиции") next_quantity = starting_quantity @@ -209,7 +178,7 @@ async def contract_short(tg_id, message, margin_mode): setMarginMode=margin_mode # margin_type ) - martingale_factor = float(data_main_stgs['martingale_factor']) + 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']) @@ -235,17 +204,16 @@ async def contract_short(tg_id, message, margin_mode): realised_pnl = float(position['unrealisedPnl']) - if realised_pnl > 0: # Прибыльная сделка + 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: # Убыточная сделка + else: current_martingale_step += 1 next_quantity = last_quantity * martingale_factor starting_quantity = next_quantity - except Exception as e: print("Не получены позиции") next_quantity = starting_quantity diff --git a/app/services/Bybit/functions/balance.py b/app/services/Bybit/functions/balance.py index f0518f1..db3d74d 100644 --- a/app/services/Bybit/functions/balance.py +++ b/app/services/Bybit/functions/balance.py @@ -13,10 +13,21 @@ async def get_balance(tg_id, message): api_secret=secret_key ) - try: - balance = client.get_wallet_balance(accountType='UNIFIED', coin='USDT')['result']['list'][0]['coin'][0]['walletBalance'] + if api_key == 'None' or secret_key == 'None': + await message.answer('⚠️ Подключите платформу для торговли') + return 0 - return balance + 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('Баланс не был получен, подключите платформу') + await message.answer('⚠️ Неверные данные API, перепроверьте их') return 0 \ No newline at end of file diff --git a/app/services/Bybit/functions/functions.py b/app/services/Bybit/functions/functions.py index 87aca78..86ff692 100644 --- a/app/services/Bybit/functions/functions.py +++ b/app/services/Bybit/functions/functions.py @@ -20,9 +20,9 @@ class state_update_symbol(StatesGroup): 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 api and secret: - balance = await get_balance(callback.from_user.id, callback.message) + if balance: symbol = await rq.get_symbol(callback.from_user.id) text = f'''💎 Торговля на Bybit @@ -30,38 +30,33 @@ async def clb_start_bybit_trade_message(callback: CallbackQuery, state: FSMConte ⚖️ Ваш баланс (USDT): {balance} 📊 Текущая торговая пара: {symbol} ---- - Как начать торговлю? 1️⃣ Проверьте и тщательно настройте все параметры в вашем профиле. 2️⃣ Нажмите ниже кнопку 'Указать торговую пару' и введите торговую пару заглавными буквами, без лишних символов (например: BTCUSDT). ''' await callback.message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.trading_markup) - else: - callback.message.answer('Перед началом работы, в настройках подключите bybit') 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 api and secret: - balance = await get_balance(message.from_user.id, message) + if balance: symbol = await rq.get_symbol(message.from_user.id) - text = f'''Торговля на Bybit + text = f'''💎 Торговля на Bybit + +⚖️ Ваш баланс (USDT): {balance} +📊 Текущая торговая пара: {symbol} -ваш баланс (USDT): {balance} -Текущая торговая пара: {symbol} - Как начать торговлю? -1. Внимательно проверьте и настройте все параметры в вашем профиле -2. Ниже нажмите 'Указать торговую пару' и отправьте торговую пару заглавными буквами, указав два актива без всяких лишних символов! (Пример: BTCUSDT) + +1️⃣ Проверьте и тщательно настройте все параметры в вашем профиле. +2️⃣ Нажмите ниже кнопку 'Указать торговую пару' и введите торговую пару заглавными буквами, без лишних символов (например: BTCUSDT). ''' await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.trading_markup) - else: - await message.answer('Перед началом работы, в настройках подключите bybit') @router_functions_bybit_trade.callback_query(F.data == 'clb_update_trading_pair') async def update_symbol_for_trade_message(callback: CallbackQuery, state: FSMContext): @@ -75,6 +70,7 @@ async def update_symbol_for_trade(message: Message, state: FSMContext): 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) diff --git a/app/telegram/functions/main_settings/settings.py b/app/telegram/functions/main_settings/settings.py index 2829b09..632c234 100644 --- a/app/telegram/functions/main_settings/settings.py +++ b/app/telegram/functions/main_settings/settings.py @@ -62,29 +62,34 @@ async def state_trading_mode(callback: CallbackQuery, state): await callback.answer() id = callback.from_user.id + 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}") @@ -98,13 +103,18 @@ 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): @@ -117,13 +127,18 @@ 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): @@ -150,16 +165,20 @@ 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 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 callback.message.answer(f"✅ Изменено: {data_settings['margin_type']} → Cross") + await rq.update_margin_type(id, 'Cross') await main_settings_message(id, callback.message, state) @@ -177,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']}") + 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 40b533c..859451e 100644 --- a/app/telegram/functions/risk_management_settings/settings.py +++ b/app/telegram/functions/risk_management_settings/settings.py @@ -43,13 +43,18 @@ 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): @@ -64,13 +69,18 @@ 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): @@ -85,11 +95,16 @@ 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