279 lines
12 KiB
Python
279 lines
12 KiB
Python
import logging.config
|
||
|
||
from aiogram import F, Router
|
||
from aiogram.fsm.context import FSMContext
|
||
from aiogram.types import CallbackQuery
|
||
|
||
import app.telegram.keyboards.inline as kbi
|
||
import database.request as rq
|
||
from app.bybit import get_bybit_client
|
||
from app.bybit.get_functions.get_tickers import get_tickers
|
||
from app.helper_functions import calculate_total_budget, get_base_currency, safe_float
|
||
from logger_helper.logger_helper import LOGGING_CONFIG
|
||
|
||
logging.config.dictConfig(LOGGING_CONFIG)
|
||
logger = logging.getLogger("settings")
|
||
|
||
router_settings = Router(name="settings")
|
||
|
||
|
||
@router_settings.callback_query(F.data == "additional_settings")
|
||
async def additional_settings(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handler for the "additional_settings" command.
|
||
Sends a message with additional settings options.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
tg_id = callback_query.from_user.id
|
||
symbol = await rq.get_user_symbol(tg_id=tg_id)
|
||
additional_data = await rq.get_user_additional_settings(tg_id=tg_id)
|
||
|
||
if not additional_data:
|
||
await rq.create_user(
|
||
tg_id=tg_id, username=callback_query.from_user.username
|
||
)
|
||
await rq.create_user_additional_settings(tg_id=tg_id)
|
||
await rq.create_user_risk_management(tg_id=tg_id)
|
||
await rq.create_user_conditional_settings(tg_id=tg_id)
|
||
await additional_settings(callback_query=callback_query, state=state)
|
||
return
|
||
|
||
trade_mode_map = {
|
||
"Merged_Single": "Односторонний режим",
|
||
"Both_Sides": "Хеджирование",
|
||
}
|
||
margin_type_map = {
|
||
"ISOLATED_MARGIN": "Изолированная",
|
||
"REGULAR_MARGIN": "Кросс",
|
||
}
|
||
order_type_map = {"Market": "Рыночный", "Limit": "Лимитный"}
|
||
|
||
trade_mode = additional_data.trade_mode or ""
|
||
margin_type = additional_data.margin_type or ""
|
||
order_type = additional_data.order_type or ""
|
||
|
||
trade_mode_rus = trade_mode_map.get(trade_mode, trade_mode)
|
||
margin_type_rus = margin_type_map.get(margin_type, margin_type)
|
||
order_type_rus = order_type_map.get(order_type, "Условный")
|
||
|
||
def f(x):
|
||
return safe_float(x)
|
||
|
||
leverage = f(additional_data.leverage)
|
||
leverage_to_buy = f(additional_data.leverage_to_buy)
|
||
leverage_to_sell = f(additional_data.leverage_to_sell)
|
||
martingale = f(additional_data.martingale_factor)
|
||
max_bets = additional_data.max_bets_in_series
|
||
quantity = f(additional_data.order_quantity)
|
||
limit_price = f(additional_data.limit_price)
|
||
trigger_price = f(additional_data.trigger_price) or 0
|
||
|
||
tickers = await get_tickers(tg_id=tg_id, symbol=symbol)
|
||
price_symbol = safe_float(tickers.get("lastPrice")) or 0
|
||
bid = f(tickers.get("bid1Price")) or 0
|
||
ask = f(tickers.get("ask1Price")) or 0
|
||
|
||
sym = get_base_currency(symbol)
|
||
|
||
if trade_mode == "Merged_Single":
|
||
leverage_str = f"{leverage:.2f}x"
|
||
else:
|
||
if margin_type == "ISOLATED_MARGIN":
|
||
leverage_str = f"{leverage_to_buy:.2f}x:{leverage_to_sell:.2f}x"
|
||
else:
|
||
leverage_str = f"{leverage:.2f}x"
|
||
|
||
conditional_order_type = additional_data.conditional_order_type or ""
|
||
conditional_order_type_rus = (
|
||
"Лимитный"
|
||
if conditional_order_type == "Limit"
|
||
else (
|
||
"Рыночный"
|
||
if conditional_order_type == "Market"
|
||
else conditional_order_type
|
||
)
|
||
)
|
||
|
||
conditional_order_type_text = (
|
||
f"- Тип условного ордера: {conditional_order_type_rus}\n"
|
||
if order_type == "Conditional"
|
||
else ""
|
||
)
|
||
|
||
limit_price_text = ""
|
||
trigger_price_text = ""
|
||
|
||
if order_type == "Limit":
|
||
limit_price_text = f"- Цена лимитного ордера: {limit_price:.4f} USDT\n"
|
||
elif order_type == "Conditional":
|
||
if conditional_order_type == "Limit":
|
||
limit_price_text = f"- Цена лимитного ордера: {limit_price:.4f} USDT\n"
|
||
trigger_price_text = f"- Триггер цена: {trigger_price:.4f} USDT\n"
|
||
|
||
risk_management_data = await rq.get_user_risk_management(tg_id=tg_id)
|
||
commission_fee = risk_management_data.commission_fee
|
||
client = await get_bybit_client(tg_id=tg_id)
|
||
fee_info = client.get_fee_rates(category="linear", symbol=symbol)
|
||
|
||
if commission_fee == "Yes_commission_fee":
|
||
commission_fee_percent = safe_float(
|
||
fee_info["result"]["list"][0]["takerFeeRate"]
|
||
)
|
||
|
||
else:
|
||
commission_fee_percent = 0.0
|
||
|
||
if order_type == "Conditional":
|
||
if conditional_order_type == "Limit":
|
||
entry_price = limit_price
|
||
ask_price = limit_price
|
||
bid_price = limit_price
|
||
else:
|
||
ask_price = trigger_price
|
||
bid_price = trigger_price
|
||
entry_price = trigger_price
|
||
else:
|
||
if order_type == "Limit":
|
||
entry_price = limit_price
|
||
ask_price = limit_price
|
||
bid_price = limit_price
|
||
else:
|
||
entry_price = price_symbol
|
||
ask_price = ask
|
||
bid_price = bid
|
||
|
||
durability_buy = quantity * bid_price
|
||
durability_sell = quantity * ask_price
|
||
quantity_price = quantity * entry_price
|
||
total_commission = quantity_price * commission_fee_percent
|
||
total_budget = await calculate_total_budget(
|
||
quantity=durability_buy,
|
||
martingale_factor=martingale,
|
||
max_steps=max_bets,
|
||
commission_fee_percent=total_commission,
|
||
)
|
||
text = (
|
||
f"Основные настройки:\n\n"
|
||
f"- Режим позиции: {trade_mode_rus}\n"
|
||
f"- Тип маржи: {margin_type_rus}\n"
|
||
f"- Размер кредитного плеча: {leverage_str}\n"
|
||
f"- Тип ордера: {order_type_rus}\n"
|
||
f"- Количество ордера: {quantity} {sym}\n"
|
||
f"- Коэффициент мартингейла: {martingale:.2f}\n"
|
||
f"{conditional_order_type_text}"
|
||
f"{trigger_price_text}"
|
||
f"{limit_price_text}"
|
||
f"- Максимальное кол-во ставок в серии: {max_bets}\n\n"
|
||
f"- Стоимость: {durability_buy:.2f}/{durability_sell:.2f} USDT\n"
|
||
f"- Рекомендуемый бюджет: {total_budget:.4f} USDT\n"
|
||
)
|
||
|
||
keyboard = kbi.get_additional_settings_keyboard(
|
||
current_order_type=order_type, conditional_order=conditional_order_type
|
||
)
|
||
await callback_query.message.edit_text(text=text, reply_markup=keyboard)
|
||
logger.debug(
|
||
"Command additional_settings processed successfully for user: %s", tg_id
|
||
)
|
||
except Exception as e:
|
||
await callback_query.message.edit_text(
|
||
text="Произошла ошибка. Пожалуйста, попробуйте ещё раз.",
|
||
reply_markup=kbi.profile_bybit,
|
||
)
|
||
logger.error(
|
||
"Error processing command additional_settings for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_settings.callback_query(F.data == "risk_management")
|
||
async def risk_management(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handler for the "risk_management" command.
|
||
Sends a message with risk management options.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
risk_management_data = await rq.get_user_risk_management(
|
||
tg_id=callback_query.from_user.id
|
||
)
|
||
if risk_management_data:
|
||
take_profit_percent = risk_management_data.take_profit_percent or ""
|
||
stop_loss_percent = risk_management_data.stop_loss_percent or ""
|
||
max_risk_percent = risk_management_data.max_risk_percent or ""
|
||
commission_fee = risk_management_data.commission_fee or ""
|
||
commission_fee_rus = (
|
||
"Да" if commission_fee == "Yes_commission_fee" else "Нет"
|
||
)
|
||
|
||
await callback_query.message.edit_text(
|
||
text=f"Риск-менеджмент:\n\n"
|
||
f"- Процент изменения цены для фиксации прибыли: {take_profit_percent}%\n"
|
||
f"- Процент изменения цены для фиксации убытка: {stop_loss_percent}%\n\n"
|
||
f"- Максимальный риск на сделку (в % от баланса): {max_risk_percent}%\n\n"
|
||
f"- Комиссия биржи для расчета прибыли: {commission_fee_rus}\n\n",
|
||
reply_markup=kbi.risk_management,
|
||
)
|
||
logger.debug(
|
||
"Command main_settings processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
else:
|
||
await rq.create_user(
|
||
tg_id=callback_query.from_user.id,
|
||
username=callback_query.from_user.username,
|
||
)
|
||
await rq.create_user_additional_settings(tg_id=callback_query.from_user.id)
|
||
await rq.create_user_risk_management(tg_id=callback_query.from_user.id)
|
||
await rq.create_user_conditional_settings(tg_id=callback_query.from_user.id)
|
||
await risk_management(callback_query=callback_query, state=state)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command main_settings for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|
||
|
||
|
||
@router_settings.callback_query(F.data == "conditional_settings")
|
||
async def conditions(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||
"""
|
||
Handler for the "conditions" command.
|
||
Sends a message with trading conditions options.
|
||
"""
|
||
try:
|
||
await state.clear()
|
||
conditional_settings_data = await rq.get_user_conditional_settings(
|
||
tg_id=callback_query.from_user.id
|
||
)
|
||
if conditional_settings_data:
|
||
start_timer = conditional_settings_data.timer_start or 0
|
||
stop_timer = conditional_settings_data.timer_end or 0
|
||
await callback_query.message.edit_text(
|
||
text="Условия торговли:\n\n"
|
||
f"- Таймер для старта: {start_timer} мин.\n"
|
||
f"- Таймер для остановки: {stop_timer} мин.\n",
|
||
reply_markup=kbi.conditions,
|
||
)
|
||
logger.debug(
|
||
"Command main_settings processed successfully for user: %s",
|
||
callback_query.from_user.id,
|
||
)
|
||
else:
|
||
await rq.create_user(
|
||
tg_id=callback_query.from_user.id,
|
||
username=callback_query.from_user.username,
|
||
)
|
||
await rq.create_user_additional_settings(tg_id=callback_query.from_user.id)
|
||
await rq.create_user_risk_management(tg_id=callback_query.from_user.id)
|
||
await rq.create_user_conditional_settings(tg_id=callback_query.from_user.id)
|
||
await conditions(callback_query=callback_query, state=state)
|
||
except Exception as e:
|
||
logger.error(
|
||
"Error processing command main_settings for user %s: %s",
|
||
callback_query.from_user.id,
|
||
e,
|
||
)
|