Update functions

This commit is contained in:
algizn97
2025-08-22 16:47:33 +05:00
parent 812920f46d
commit 6ec99dc9a7
3 changed files with 379 additions and 403 deletions

View File

@@ -1,10 +1,13 @@
from aiogram import F, Router
import asyncio
from aiogram import F, Router
from app.services.Bybit.functions import Futures, func_min_qty
from app.services.Bybit.functions.Futures import open_market_order, open_limit_order
from app.services.Bybit.functions.Futures import open_position, close_user_trade, get_active_positions, trading_cycle
from app.services.Bybit.functions.balance import get_balance
import app.telegram.Keyboards.inline_keyboards as inline_markup
import app.telegram.Keyboards.reply_keyboards as reply_markup
from pybit.unified_trading import HTTP
import app.telegram.database.requests as rq
from aiogram.types import Message, CallbackQuery
@@ -14,13 +17,21 @@ from aiogram.fsm.context import FSMContext
router_functions_bybit_trade = Router()
class state_update_symbol(StatesGroup):
symbol = State()
class state_update_entry_type(StatesGroup):
entry_type = State()
@router_functions_bybit_trade.callback_query(F.data.in_(['clb_start_trading', 'clb_back_to_main']))
class TradeSetup(StatesGroup):
waiting_for_timer = State()
waiting_for_positive_percent = State()
@router_functions_bybit_trade.callback_query(F.data.in_(['clb_start_trading', 'clb_back_to_main', 'back_to_main']))
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)
@@ -30,7 +41,7 @@ async def clb_start_bybit_trade_message(callback: CallbackQuery, state: FSMConte
symbol = await rq.get_symbol(callback.from_user.id)
text = f'''💎 Торговля на Bybit
⚖️ Ваш баланс (USDT): {balance}
📊 Текущая торговая пара: {symbol}
@@ -41,16 +52,17 @@ async def clb_start_bybit_trade_message(callback: CallbackQuery, state: FSMConte
'''
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:
if balance:
symbol = await rq.get_symbol(message.from_user.id)
text = f'''💎 Торговля на Bybit
⚖️ Ваш баланс (USDT): {balance}
📊 Текущая торговая пара: {symbol}
@@ -62,15 +74,18 @@ async def start_bybit_trade_message(message, state):
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): ')
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)
await state.update_data(symbol=message.text)
data = await state.get_data()
@@ -96,116 +111,161 @@ async def entry_order_type_callback(callback: CallbackQuery, state: FSMContext):
await callback.answer("Ошибка выбора", show_alert=True)
return
await state.update_data(entry_order_type=order_type)
await rq.update_entry_order_type(callback.from_user.id, order_type)
if order_type == 'Limit':
await callback.answer("Вы выбрали Limit. Введите цену для лимитного ордера.")
await callback.message.answer("Введите цену лимитного ордера:")
await state.update_data(awaiting_limit_price=True)
else:
await callback.answer("Вы выбрали Market. Нажмите кнопку ниже, чтобы открыть сделку.")
await callback.message.answer("Нажмите кнопку, чтобы открыть сделку.",
reply_markup=inline_markup.open_deal_markup)
await callback.message.delete()
@router_functions_bybit_trade.message()
async def process_limit_price_message(message: Message, state: FSMContext):
data = await state.get_data()
if not data.get('awaiting_limit_price'):
return
try:
price = float(message.text)
if price <= 0:
raise ValueError()
except ValueError:
await message.answer("Ошибка: введите корректное положительное число для цены.")
return
await state.update_data(limit_price=price, awaiting_limit_price=False)
await message.answer(f"Цена лимитного ордера установлена: {price}. Нажмите кнопку ниже, чтобы открыть сделку.",
reply_markup=inline_markup.open_deal_markup)
@router_functions_bybit_trade.callback_query(F.data == "clb_open_deal")
async def open_deal(callback: CallbackQuery, state: FSMContext):
data_main_stgs = await rq.get_user_main_settings(callback.from_user.id)
data = await state.get_data()
order_type = await rq.get_entry_order_type(callback.from_user.id)
api = await rq.get_bybit_api_key(callback.from_user.id)
secret = await rq.get_bybit_secret_key(callback.from_user.id)
qty = data_main_stgs['starting_quantity']
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}) для данной торговой пары")
await callback.answer()
return
if order_type == 'Market':
await open_market_order(callback.from_user.id, callback.message, api_key=api, secret_key=secret)
await rq.update_user_trades(callback.from_user.id, symbol=data.get('symbol'), side=order_type)
elif order_type == 'Limit':
price = data.get('limit_price')
if not price:
await callback.answer("Цена для лимитного ордера не задана. Введите сначала цену.")
return
await open_limit_order(callback.from_user.id, callback.message, price, api_key=api, secret_key=secret)
else:
await callback.answer("Неизвестный тип ордера.")
await callback.message.edit_reply_markup()
await state.update_data(entry_order_type=order_type)
await rq.update_entry_order_type(callback.from_user.id, order_type)
await callback.answer("Тип входа в позицию был успешно обновлен")
except Exception as e:
await callback.message.answer("Произошла ошибка при обновлении типа входа в позицию")
await state.clear()
@router_functions_bybit_trade.callback_query(F.data == "clb_my_deals")
async def show_my_trades_callback(callback: CallbackQuery):
tg_id = callback.from_user.id
trades = await rq.get_user_trades(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)
trades = await get_active_positions(callback.message, api_key, secret_key, symbol)
if not trades:
await callback.message.answer("У вас ещё нет сделок.")
await callback.message.answer("Нет активных позиций.")
await callback.answer()
return
grouped = {}
for trade in trades:
symbol = trade['symbol'] if isinstance(trade, dict) else trade.symbol
grouped.setdefault(symbol, []).append(trade)
keyboard = inline_markup.create_trades_inline_keyboard(trades)
text_response = "Ваши сделки по валютным парам:\n\n"
for symbol, trade_list in grouped.items():
text_response += f"<b>{symbol}</b>\n"
for t in trade_list:
side = t['side'] if isinstance(t, dict) else t.side
text_response += f" - {side}\n"
text_response += "\n"
await callback.message.answer(text_response, parse_mode='html')
await callback.message.answer(
"Выберите сделку из списка:",
reply_markup=keyboard
)
await callback.answer()
# @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 пока недоступен')
@router_functions_bybit_trade.callback_query(lambda c: c.data and c.data.startswith('select_trade:'))
async def on_trade_selected(callback: CallbackQuery):
symbol = callback.data.split(':')[1]
tg_id = callback.from_user.id
api_key = await rq.get_bybit_api_key(tg_id)
secret_key = await rq.get_bybit_secret_key(tg_id)
positions = await get_active_positions(callback.message, api_key, secret_key, symbol)
# Если несколько позиций по символу, можно выбрать нужную или взять первую
if not positions:
await callback.message.answer("Позиция не найдена")
await callback.answer()
return
pos = positions[0]
symbol = pos.get('symbol')
side = pos.get('side')
entry_price = pos.get('entryPrice') # Цена открытия позиции
current_price = pos.get('price') # Текущая цена (если есть)
text = (f"Информация по позиции:\n"
f"Название: {symbol}\n"
f"Направление: {side}\n"
f"Цена покупки: {entry_price}\n"
f"Текущая цена: {current_price if current_price else 'N/A'}")
keyboard = inline_markup.create_close_deal_markup(symbol)
await callback.message.answer(text, reply_markup=keyboard)
await callback.answer()
@router_functions_bybit_trade.callback_query(lambda c: c.data and c.data.startswith("close_deal:"))
async def close_trade_callback(callback: CallbackQuery):
symbol = callback.data.split(':')[1]
tg_id = callback.from_user.id
result = await close_user_trade(tg_id, symbol)
if result:
await callback.message.answer(f"Сделка {symbol} успешно закрыта.")
else:
await callback.message.answer(f"Не удалось закрыть сделку {symbol}.")
await callback.answer()
@router_functions_bybit_trade.callback_query(F.data == "clb_start_chatbot_trading")
async def start_trading_process(callback: CallbackQuery, state: FSMContext):
tg_id = callback.from_user.id
message = callback.message
# Получаем настройки пользователя
data_main_stgs = await rq.get_user_main_settings(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)
margin_mode = data_main_stgs.get('margin_type', 'Isolated')
trading_mode = data_main_stgs.get('trading_mode')
# Проверка API ключей
if not api_key or not secret_key:
await message.answer("❗️ У вас не настроены API ключи для Bybit.")
await callback.answer()
return
# Проверка режима торговли
if trading_mode not in ['Long', 'Short', 'Smart', 'Switch']:
await message.answer(f"❗️ Некорректный торговый режим: {trading_mode}")
await callback.answer()
return
# Проверка допустимости маржинального режима
if margin_mode not in ['Isolated', 'Cross']:
margin_mode = 'Isolated'
# Проверяем открытые позиции и маржинальный режим
client = HTTP(api_key=api_key, api_secret=secret_key)
try:
positions_resp = client.get_positions(category='linear', symbol=symbol)
positions = positions_resp.get('result', {}).get('list', [])
except Exception:
positions = []
for pos in positions:
size = pos.get('size')
existing_margin_mode = pos.get('margin_mode')
if size and float(size) > 0 and existing_margin_mode and existing_margin_mode != margin_mode:
await callback.answer(
f"⚠️ Маржинальный режим нельзя менять при открытой позиции "
f"(текущий режим: {existing_margin_mode})", show_alert=True)
return
# Определяем сторону для открытия позиции
if trading_mode == 'Long':
side = 'Buy'
elif trading_mode == 'Short':
side = 'Sell'
else:
await message.answer(f"Режим торговли '{trading_mode}' пока не поддерживается.")
await callback.answer()
return
# Сообщаем о начале торговли
await message.answer("Начинаю торговлю с использованием текущих настроек...")
# Открываем позицию (вызывает Futures.open_position)
await open_position(tg_id, message, side=side, margin_mode=margin_mode)
# Проверяем таймер и информируем пользователя
timer_minutes = await rq.get_user_timer(tg_id)
if timer_minutes and timer_minutes > 0:
await message.answer(f"Торговля будет работать по таймеру: {timer_minutes} мин.")
asyncio.create_task(trading_cycle(tg_id, message))
else:
await message.answer(
"Торговля начата без ограничения по времени. Для остановки нажмите кнопку 'Закрыть сделку'.",
reply_markup=inline_markup.create_close_deal_markup(symbol)
)
await callback.answer()