Files
stcs/app/services/Bybit/functions/Futures.py
2025-08-21 13:35:42 +05:00

320 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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'])
commission_fee = float(data_risk_management_stgs.get('commission_fee', 0))
takeProfit_raw = takeprofit
takeProfit = takeProfit_raw - commission_fee # уменьшаем TP на комиссию
if takeProfit < 0:
takeProfit = 0
# Инициализация переменных
next_quantity = starting_quantity
last_quantity = starting_quantity
realised_pnl = 0.0
current_martingale_step = 0 # Текущая ставка в серии
next_quantity = 0
realised_pnl = 0
last_quantity = starting_quantity
# Пример расчёта следующего размера позиции
try:
position_info = client.get_positions(category='linear', symbol=SYMBOL)
position = position_info['result']['list'][0] # или другой нужный индекс
realised_pnl = float(position['unrealisedPnl'])
if realised_pnl > 0:
starting_quantity = next_quantity
current_martingale_step = 0
elif not realised_pnl:
next_quantity = starting_quantity
current_martingale_step += 1
else:
current_martingale_step += 1
next_quantity = last_quantity * martingale_factor
starting_quantity = next_quantity
except Exception as e:
print("Не получены позиции")
next_quantity = starting_quantity
potential_loss = (next_quantity * float(price)) * (loss_profit / 100)
allowed_loss = float(balance) * (max_risk_percent / 100)
if current_martingale_step >= max_martingale_steps:
print("Достигнут максимум ставок в серии (8)!")
print("Торговля не продолжится")
await error_max_step(message)
else:
if potential_loss > allowed_loss:
print(f"ОШИБКА: Риск превышен!")
print(f"Ручной qty = {next_quantity} → Убыток = {potential_loss} USDT")
print(f"Разрешено = {allowed_loss} USDT (1% от баланса)")
await error_max_risk(message)
else:
print(f"Риск в допустимых пределах. Qty = {next_quantity}")
r = client.place_order(
category='linear',
symbol=SYMBOL,
side='Buy',
orderType="Market",
leverage=int(data_main_stgs['size_leverage']),
qty=next_quantity,
takeProfit=takeProfit, # TP - закрывает позицию, когда цена достигает нужного уровня
stopProfit=float(data_risk_management_stgs['price_loss']), # SL - закрывает позицию, когда убыток достигает нужного уровня
orderLinkId=f"deal_{SYMBOL}_{time.time()}"
)
await info_access_open_deal(message, SYMBOL, data_main_stgs['trading_mode'], margin_mode, data_main_stgs['size_leverage'], next_quantity)
except exceptions.InvalidRequestError as e:
logging.error(f"Неверно указана торговая пара: {e}")
await message.answer('Недостаточно баланса')
except Exception as e:
logging.error(f"Ошибка при совершении сделки: {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'])
commission_fee = float(data_risk_management_stgs.get('commission_fee', 0))
takeProfit_raw = takeprofit
takeProfit = takeProfit_raw - commission_fee # уменьшаем TP на комиссию
if takeProfit < 0:
takeProfit = 0
# Инициализация переменных
next_quantity = starting_quantity
last_quantity = starting_quantity
realised_pnl = 0.0
current_martingale_step = 0 # Текущая ставка в серии
next_quantity = 0
realised_pnl = 0
last_quantity = starting_quantity
# Пример расчёта следующего размера позиции
try:
position_info = client.get_positions(category='linear', symbol=SYMBOL)
position = position_info['result']['list'][0] # или другой нужный индекс
realised_pnl = float(position['unrealisedPnl'])
if realised_pnl > 0:
starting_quantity = next_quantity
current_martingale_step = 0
elif not realised_pnl:
next_quantity = starting_quantity
current_martingale_step += 1
else:
current_martingale_step += 1
next_quantity = last_quantity * martingale_factor
starting_quantity = next_quantity
except Exception as e:
print("Не получены позиции")
next_quantity = starting_quantity
potential_loss = (next_quantity * float(price)) * (loss_profit / 100)
allowed_loss = float(balance) * (max_risk_percent / 100)
if current_martingale_step >= max_martingale_steps:
print("Достигнут максимум ставок в серии (8)!")
print("Торговля не продолжится")
await error_max_step(message)
else:
if potential_loss > allowed_loss:
print(f"ОШИБКА: Риск превышен!")
print(f"Ручной qty = {next_quantity} → Убыток = {potential_loss} USDT")
print(f"Разрешено = {allowed_loss} USDT (1% от баланса)")
await error_max_risk(message)
else:
print(f"Риск в допустимых пределах. Qty = {next_quantity}")
r = client.place_order(
category='linear',
symbol=SYMBOL,
side='Sell',
orderType="Market",
leverage=int(data_main_stgs['size_leverage']),
qty=next_quantity,
orderLinkId=f"deal_{SYMBOL}_{time.time()}"
)
await info_access_open_deal(message, SYMBOL, data_main_stgs['trading_mode'], margin_mode, data_main_stgs['size_leverage'], next_quantity)
except exceptions.InvalidRequestError as e:
logging.error(f"Error in open_deal: {e}")
await message.answer('Недостаточно баланса')
except Exception as e:
logging.error(f"Error in open_deal: {e}")
await message.answer('⚠️ Ошибка при совершении сделки')
async def open_market_order(tg_id, message, api_key, secret_key):
data_main_stgs = await rq.get_user_main_settings(tg_id)
trading_mode = data_main_stgs['trading_mode']
margin_mode = data_main_stgs.get('margin_type')
if trading_mode == 'Long':
await contract_long(tg_id, message, margin_mode)
elif trading_mode == 'Short':
await contract_short(tg_id, message, margin_mode)
else:
await message.answer("Неизвестный режим торговли: выберите Long или Short.")
async def open_limit_order(tg_id, message, price, api_key, secret_key):
data_main_stgs = await rq.get_user_main_settings(tg_id)
trading_mode = data_main_stgs['trading_mode']
margin_mode = data_main_stgs.get('margin_type')
client = HTTP(
api_key=api_key,
api_secret=secret_key
)
symbol = await rq.get_symbol(tg_id)
qty = float(data_main_stgs['starting_quantity'])
side = 'Buy' if trading_mode == 'Long' else 'Sell'
try:
response = client.place_order(
category='linear',
symbol=symbol,
side=side,
orderType='Limit',
qty=qty,
price=price,
timeInForce='GTC',
orderLinkId=f"order_{int(time.time())}"
)
if response.get('retCode') == 0:
await message.answer(f"Limit ордер открыт: {side} {qty} {symbol} по цене {price}")
else:
await message.answer(f"Ошибка открытия ордера: {response.get('retMsg')}")
except Exception as e:
logging.error(f"Ошибка при открытии лимитного ордера: {e}")
await message.answer("Ошибка при открытии ордера")