2
0
forked from kodorvan/stcs
This commit is contained in:
algizn97
2025-10-01 15:20:18 +05:00
parent 66a566e6a3
commit e5a3de4ed8
26 changed files with 0 additions and 4405 deletions

View File

@@ -1,224 +0,0 @@
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
start_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="🔥 Начать торговлю", callback_data="clb_start_chatbot_message")]
])
settings_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Запуск", callback_data='clb_start_trading')]
])
cancel_start = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Отменить запуск", callback_data="clb_cancel_start")]
])
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')]]) # Клавиатура для возврата к списку каталога настроек
back_btn_to_main = [InlineKeyboardButton(text="На главную", callback_data='clb_back_to_main')]
back_btn_profile = [InlineKeyboardButton(text="Назад", callback_data='clb_start_chatbot_message')]
connect_bybit_api_message = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Подключить Bybit", callback_data='clb_new_user_connect_bybit_api_message')]
])
special_settings_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Основные настройки", callback_data='clb_change_main_settings'),
InlineKeyboardButton(text="Риск-менеджмент", callback_data='clb_change_risk_management_settings')],
[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_to_main
])
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_settings_message')],
[InlineKeyboardButton(text="Мои сделки", callback_data='clb_my_deals')],
[InlineKeyboardButton(text="Указать торговую пару", callback_data='clb_update_trading_pair')],
[InlineKeyboardButton(text="Начать торговать", callback_data='clb_start_chatbot_trading')],
[InlineKeyboardButton(text="Остановить торговлю", callback_data='clb_stop_trading')],
])
start_trading_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Начать торговлю", callback_data="clb_start_chatbot_trading")],
[InlineKeyboardButton(text="На главную", callback_data='back_to_main')],
])
cancel = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Отменить", callback_data="clb_cancel")]
])
entry_order_type_markup = InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(text="Маркет", callback_data="entry_order_type:Market"),
InlineKeyboardButton(text="Лимит", callback_data="entry_order_type:Limit"),
], back_btn_to_main
]
)
back_to_main = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="На главную", callback_data='back_to_main')],
])
main_settings_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Режим торговли', callback_data='clb_change_trading_mode'),
InlineKeyboardButton(text='Состояние свитча', callback_data='clb_change_switch_state'),
InlineKeyboardButton(text='Тип маржи', callback_data='clb_change_margin_type')],
[InlineKeyboardButton(text='Размер кредитного плеча', callback_data='clb_change_size_leverage'),
InlineKeyboardButton(text='Ставка', callback_data='clb_change_starting_quantity')],
[InlineKeyboardButton(text='Коэффициент Мартингейла', callback_data='clb_change_martingale_factor'),
InlineKeyboardButton(text='Сбросить шаги Мартингейла', callback_data='clb_change_martingale_reset')],
[InlineKeyboardButton(text='Максимальное кол-во ставок', callback_data='clb_change_maximum_quantity')],
back_btn_list_settings,
back_btn_to_main
])
risk_management_settings_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Изм. цены прибыли', callback_data='clb_change_price_profit'),
InlineKeyboardButton(text='Изм. цены убытков', callback_data='clb_change_price_loss')],
[InlineKeyboardButton(text='Макс. риск на сделку', callback_data='clb_change_max_risk_deal')],
[InlineKeyboardButton(text='Учитывать комиссию биржи (Да/Нет)', callback_data='commission_fee')],
back_btn_list_settings,
back_btn_to_main
])
condition_settings_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Таймер', callback_data='clb_change_timer'),
InlineKeyboardButton(text='Тип позиции', callback_data='clb_update_entry_type')],
[InlineKeyboardButton(text='Триггер цена', callback_data='clb_change_trigger_price'),
InlineKeyboardButton(text='Лимит цена', callback_data='clb_change_limit_price')],
#
# [InlineKeyboardButton(text='Фильтр волатильности', callback_data='clb_change_filter_volatility'),
# InlineKeyboardButton(text='Внешние сигналы', callback_data='clb_change_external_cues')],
#
# [InlineKeyboardButton(text='Сигналы TradingView', callback_data='clb_change_tradingview_cues'),
# InlineKeyboardButton(text='Webhook URL', callback_data='clb_change_webhook')],
#
# [InlineKeyboardButton(text='AI - аналитика', callback_data='clb_change_ai_analytics')],
back_btn_list_settings,
back_btn_to_main
])
back_to_condition_settings = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Назад', callback_data='clb_change_condition_settings')],
back_btn_to_main
])
additional_settings_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Сохранить шаблон', callback_data='clb_change_save_pattern'),
InlineKeyboardButton(text='Автозапуск', callback_data='clb_change_auto_start')],
[InlineKeyboardButton(text='Уведомления', callback_data='clb_change_notifications')],
back_btn_list_settings,
back_btn_to_main
])
trading_mode_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Лонг", callback_data="trade_mode_long"),
InlineKeyboardButton(text="Шорт", callback_data="trade_mode_short"),
InlineKeyboardButton(text="Свитч", callback_data="trade_mode_switch")],
# InlineKeyboardButton(text="Смарт", callback_data="trade_mode_smart")],
back_btn_list_settings,
back_btn_to_main
])
margin_type_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Изолированный", callback_data="margin_type_isolated"),
InlineKeyboardButton(text="Кросс", callback_data="margin_type_cross")],
back_btn_list_settings
])
trigger_markup = InlineKeyboardMarkup(inline_keyboard=[ # ИЗМЕНИТЬ НА INLINE
[InlineKeyboardButton(text='Ручной', callback_data="clb_trigger_manual")],
# [InlineKeyboardButton(text='TradingView', callback_data="clb_trigger_tradingview")],
[InlineKeyboardButton(text="Автоматический", callback_data="clb_trigger_auto")],
back_btn_list_settings,
back_btn_to_main
])
buttons_yes_no_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Да', callback_data="clb_yes"),
InlineKeyboardButton(text='Нет', callback_data="clb_no")],
])
buttons_on_off_markup = InlineKeyboardMarkup(inline_keyboard=[ # ИЗМЕНИТЬ НА INLINE
[InlineKeyboardButton(text='Включить', callback_data="clb_on"),
InlineKeyboardButton(text='Выключить', callback_data="clb_off")]
])
my_deals_select_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Позиции', callback_data="clb_open_deals"),
InlineKeyboardButton(text='Ордера', callback_data="clb_open_orders")],
back_btn_to_main
])
def create_trades_inline_keyboard(trades):
builder = InlineKeyboardBuilder()
for trade in trades:
builder.button(text=trade, callback_data=f"show_deal_{trade}")
builder.adjust(2)
return builder.as_markup()
def create_trades_inline_keyboard_limits(trades):
builder = InlineKeyboardBuilder()
for trade in trades:
builder.button(text=trade, callback_data=f"show_limit_{trade}")
builder.adjust(2)
return builder.as_markup()
def create_close_deal_markup(symbol: str) -> InlineKeyboardMarkup:
return InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Закрыть сделку", callback_data=f"close_deal:{symbol}")],
[InlineKeyboardButton(text="Закрыть по таймеру", callback_data=f"close_deal_by_timer:{symbol}")],
[InlineKeyboardButton(text="Установить TP/SL", callback_data="clb_set_tp_sl")],
back_btn_to_main
])
def create_close_limit_markup(symbol: str) -> InlineKeyboardMarkup:
return InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Закрыть ордер", callback_data=f"close_limit:{symbol}")],
back_btn_to_main
])
timer_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Установить таймер", callback_data="clb_set_timer")],
[InlineKeyboardButton(text="Удалить таймер", callback_data="clb_delete_timer")],
back_btn_to_main
])
stop_choice_markup = InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(text="Остановить сразу", callback_data="stop_immediately"),
InlineKeyboardButton(text="Остановить по таймеру", callback_data="stop_with_timer"),
]
]
)
switch_state_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='По направлению', callback_data="clb_long_switch"),
InlineKeyboardButton(text='Против направления', callback_data="clb_short_switch")],
])

View File

@@ -1,6 +0,0 @@
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
base_buttons_markup = ReplyKeyboardMarkup(keyboard=[
[KeyboardButton(text="👤 Профиль")],
# [KeyboardButton(text="Настройки")]
], resize_keyboard=True, one_time_keyboard=False)

View File

@@ -1,316 +0,0 @@
from datetime import datetime
import logging.config
from sqlalchemy.sql.sqltypes import DateTime, Numeric
from sqlalchemy import BigInteger, Boolean, Integer, String, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, create_async_engine
from logger_helper.logger_helper import LOGGING_CONFIG
from sqlalchemy import select, insert
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("models")
engine = create_async_engine(url='sqlite+aiosqlite:///data/db.sqlite3')
async_session = async_sessionmaker(engine)
class Base(AsyncAttrs, DeclarativeBase):
"""Базовый класс для declarative моделей SQLAlchemy с поддержкой async."""
pass
class User_Telegram_Id(Base):
"""
Модель таблицы user_telegram_id.
Хранит идентификаторы Telegram пользователей.
Атрибуты:
id (int): Внутренний первичный ключ записи.
tg_id (int): Уникальный идентификатор пользователя Telegram.
"""
__tablename__ = 'user_telegram_id'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(BigInteger)
class User_Bybit_API(Base):
"""
Модель таблицы user_bybit_api.
Хранит API ключи и секреты Bybit для каждого Telegram пользователя.
Атрибуты:
id (int): Внутренний первичный ключ записи.
tg_id (int): Внешний ключ на Telegram пользователя (user_telegram_id.tg_id).
api_key (str): API ключ Bybit (уникальный для пользователя).
secret_key (str): Секретный ключ Bybit (уникальный для пользователя).
"""
__tablename__ = 'user_bybit_api'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
api_key = mapped_column(String(18), unique=True, nullable=True)
secret_key = mapped_column(String(36), unique=True, nullable=True)
class User_Symbol(Base):
"""
Модель таблицы user_main_settings.
Хранит основные настройки торговли для пользователя.
"""
__tablename__ = 'user_symbols'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
symbol = mapped_column(String(18), default='PENGUUSDT')
class Trading_Mode(Base):
"""
Справочник доступных режимов торговли.
Атрибуты:
id (int): Первичный ключ.
mode (str): Уникальный режим (например, 'Long', 'Short', 'Switch).
"""
__tablename__ = 'trading_modes'
id: Mapped[int] = mapped_column(primary_key=True)
mode = mapped_column(String(10), unique=True)
class Margin_type(Base):
"""
Справочник типов маржинальной торговли.
Атрибуты:
id (int): Первичный ключ.
type (str): Тип маржи (например, 'Isolated', 'Cross').
"""
__tablename__ = 'margin_types'
id: Mapped[int] = mapped_column(primary_key=True)
type = mapped_column(String(15), unique=True)
class Trigger(Base):
"""
Справочник триггеров для сделок.
Атрибуты:
id (int): Первичный ключ.
"""
__tablename__ = 'triggers'
id: Mapped[int] = mapped_column(primary_key=True)
trigger_price = mapped_column(Integer(), default=0)
class User_Main_Settings(Base):
"""
Основные настройки пользователя для торговли.
Атрибуты:
id (int): Первичный ключ.
tg_id (int): Внешний ключ на Telegram пользователя.
trading_mode (str): Режим торговли, FK на trading_modes.mode.
margin_type (str): Тип маржи, FK на margin_types.type.
size_leverage (int): Кредитное плечо.
starting_quantity (int): Начальный объем позиции.
martingale_factor (int): Коэффициент мартингейла.
martingale_step (int): Текущий шаг мартингейла.
maximal_quantity (int): Максимальное число шагов мартингейла.
entry_order_type (str): Тип ордера входа (Market/Limit).
limit_order_price (Optional[str]): Цена лимитного ордера, если есть.
last_side (str): Последняя сторона ордера.
"""
__tablename__ = 'user_main_settings'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
trading_mode = mapped_column(ForeignKey("trading_modes.mode"))
margin_type = mapped_column(ForeignKey("margin_types.type"))
switch_state = mapped_column(String(10), default='По направлению')
size_leverage = mapped_column(Integer(), default=1)
starting_quantity = mapped_column(Integer(), default=1)
base_quantity = mapped_column(Integer(), default=1)
martingale_factor = mapped_column(Integer(), default=1)
martingale_step = mapped_column(Integer(), default=1)
maximal_quantity = mapped_column(Integer(), default=10)
entry_order_type = mapped_column(String(10), default='Market')
limit_order_price = mapped_column(Numeric(18, 15), nullable=True, default=0)
trigger_price = mapped_column(Numeric(18, 15), nullable=True, default=0)
last_side = mapped_column(String(10), default='Buy')
trading_start_stop = mapped_column(Integer(), default=0)
class User_Risk_Management_Settings(Base):
"""
Настройки управления рисками пользователя.
Атрибуты:
id (int): Первичный ключ.
tg_id (int): Внешний ключ на Telegram пользователя.
price_profit (int): Процент прибыли для трейда.
price_loss (int): Процент убытка для трейда.
max_risk_deal (int): Максимально допустимый риск по сделке в процентах.
commission_fee (str): Учитывать ли комиссию в расчетах ("Да"/"Нет").
"""
__tablename__ = 'user_risk_management_settings'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
price_profit = mapped_column(Integer(), default=1)
price_loss = mapped_column(Integer(), default=1)
max_risk_deal = mapped_column(Integer(), default=100)
commission_fee = mapped_column(String(), default="Да")
class User_Condition_Settings(Base):
"""
Дополнительные пользовательские условия для торговли.
Атрибуты:
id (int): Первичный ключ.
tg_id (int): Внешний ключ на Telegram пользователя.
trigger (str): Тип триггера, FK на triggers.trigger.
filter_time (str): Временной фильтр.
filter_volatility (bool): Фильтр по волатильности.
external_cues (bool): Внешние сигналы.
tradingview_cues (bool): Сигналы TradingView.
webhook (str): URL webhook.
ai_analytics (bool): Использование AI для аналитики.
"""
__tablename__ = 'user_condition_settings'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
trigger = mapped_column(String(15), default='Автоматический')
filter_time = mapped_column(String(25), default='???')
filter_volatility = mapped_column(Boolean, default=False)
external_cues = mapped_column(Boolean, default=False)
tradingview_cues = mapped_column(Boolean, default=False)
webhook = mapped_column(String(40), default='')
ai_analytics = mapped_column(Boolean, default=False)
class User_Additional_Settings(Base):
"""
Прочие дополнительные настройки пользователя.
Атрибуты:
id (int): Первичный ключ.
tg_id (int): Внешний ключ на Telegram пользователя.
pattern_save (bool): Сохранять ли шаблоны.
autostart (bool): Автоматический запуск.
notifications (bool): Получение уведомлений.
"""
__tablename__ = 'user_additional_settings'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
pattern_save = mapped_column(Boolean, default=False)
autostart = mapped_column(Boolean, default=False)
notifications = mapped_column(Boolean, default=False)
class USER_DEALS(Base):
"""
Таблица сделок пользователя.
Атрибуты:
id (int): Первичный ключ.
tg_id (int): Внешний ключ на Telegram пользователя.
symbol (str): Торговая пара.
side (str): Направление сделки (Buy/Sell).
open_price (int): Цена открытия.
positive_percent (int): Процент доходности.
"""
__tablename__ = 'user_deals'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
symbol = mapped_column(String(18), default='PENGUUSDT')
side = mapped_column(String(10), nullable=False)
open_price = mapped_column(Integer(), nullable=False)
positive_percent = mapped_column(Integer(), nullable=False)
class UserTimer(Base):
"""
Таймер пользователя для отсроченного запуска сделок.
Атрибуты:
id (int): Первичный ключ.
tg_id (int): Внешний ключ на Telegram пользователя.
timer_minutes (int): Количество минут таймера.
timer_start (datetime): Время начала таймера.
timer_end (Optional[datetime]): Время окончания таймера (если установлено).
"""
__tablename__ = 'user_timers'
id: Mapped[int] = mapped_column(primary_key=True)
tg_id = mapped_column(ForeignKey("user_telegram_id.tg_id"), unique=True, nullable=True)
timer_minutes = mapped_column(Integer, nullable=False, default=0)
timer_start = mapped_column(DateTime, default=datetime.utcnow)
timer_end = mapped_column(DateTime, nullable=True)
async def async_main():
"""
Асинхронное создание всех таблиц и заполнение справочников начальными данными.
"""
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# Заполнение таблиц
modes = ['Long', 'Short', 'Switch', 'Smart']
for mode in modes:
result = await conn.execute(select(Trading_Mode).where(Trading_Mode.mode == mode))
if not result.first():
logger.info("Заполение таблицы режима торговли")
await conn.execute(Trading_Mode.__table__.insert().values(mode=mode))
types = ['Isolated', 'Cross']
for type in types:
result = await conn.execute(select(Margin_type).where(Margin_type.type == type))
if not result.first():
logger.info("Заполение таблицы типов маржи")
await conn.execute(Margin_type.__table__.insert().values(type=type))
last_side = ['Buy', 'Sell']
for side in last_side:
result = await conn.execute(select(User_Main_Settings).where(User_Main_Settings.last_side == side))
if not result.first():
logger.info("Заполение таблицы последнего направления")
await conn.execute(User_Main_Settings.__table__.insert().values(last_side=side))
order_type = ['Limit', 'Market']
for typ in order_type:
result = await conn.execute(select(User_Main_Settings).where(User_Main_Settings.entry_order_type == typ))
if not result.first():
logger.info("Заполение таблицы типов ордеров")
await conn.execute(User_Main_Settings.__table__.insert().values(entry_order_type=typ))

View File

@@ -1,621 +0,0 @@
import logging.config
from logger_helper.logger_helper import LOGGING_CONFIG
from datetime import datetime, timedelta
from typing import Any
from app.telegram.database.models import (
async_session,
User_Telegram_Id as UTi,
User_Main_Settings as UMS,
User_Bybit_API as UBA,
User_Symbol,
User_Risk_Management_Settings as URMS,
User_Condition_Settings as UCS,
User_Additional_Settings as UAS,
Trading_Mode,
Margin_type,
Trigger,
USER_DEALS,
UserTimer,
)
from sqlalchemy import select, update
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("requests")
# --- Функции сохранения в БД ---
async def save_tg_id_new_user(tg_id) -> None:
"""
Сохраняет Telegram ID нового пользователя в базу, если такого ещё нет.
Args:
tg_id (int): Telegram ID пользователя.
"""
async with async_session() as session:
user = await session.scalar(select(UTi).where(UTi.tg_id == tg_id))
if not user:
session.add(UTi(tg_id=tg_id))
logger.info("Новый пользователь был добавлен в бд %s", tg_id)
await session.commit()
async def set_new_user_bybit_api(tg_id) -> None:
"""
Создаёт запись API пользователя Bybit, если её ещё нет.
Args:
tg_id (int): Telegram 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))
await session.commit()
async def set_new_user_symbol(tg_id) -> None:
"""
Создаёт запись торгового символа пользователя, если её нет.
Args:
tg_id (int): Telegram 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 был успешно добавлен %s", tg_id)
await session.commit()
async def set_new_user_default_main_settings(tg_id, trading_mode, margin_type) -> None:
"""
Создаёт основные настройки пользователя по умолчанию.
Args:
tg_id (int): Telegram ID пользователя.
trading_mode (str): Режим торговли.
margin_type (str): Тип маржи.
"""
async with async_session() as session:
settings = await session.scalar(select(UMS).where(UMS.tg_id == tg_id))
if not settings:
session.add(UMS(
tg_id=tg_id,
trading_mode=trading_mode,
margin_type=margin_type,
))
logger.info("Основные настройки нового пользователя были заполнены%s", tg_id)
await session.commit()
async def set_new_user_default_risk_management_settings(tg_id) -> None:
"""
Создаёт настройки риск-менеджмента по умолчанию.
Args:
tg_id (int): Telegram ID пользователя.
"""
async with async_session() as session:
settings = await session.scalar(select(URMS).where(URMS.tg_id == tg_id))
if not settings:
session.add(URMS(
tg_id=tg_id
))
logger.info("Риск-Менеджмент настройки нового пользователя были заполнены %s", tg_id)
await session.commit()
async def set_new_user_default_condition_settings(tg_id, trigger) -> None:
"""
Создаёт условные настройки по умолчанию.
Args:
tg_id (int): Telegram ID пользователя.
trigger (Any): Значение триггера по умолчанию.
"""
async with async_session() as session:
settings = await session.scalar(select(UCS).where(UCS.tg_id == tg_id))
if not settings:
session.add(UCS(
tg_id=tg_id,
trigger=trigger
))
logger.info("Условные настройки нового пользователя были заполнены %s", tg_id)
await session.commit()
async def set_new_user_default_additional_settings(tg_id) -> None:
"""
Создаёт дополнительные настройки по умолчанию.
Args:
tg_id (int): Telegram ID пользователя.
"""
async with async_session() as session:
settings = await session.scalar(select(UAS).where(UAS.tg_id == tg_id))
if not settings:
session.add(UAS(
tg_id=tg_id,
))
logger.info("Дополнительные настройки нового пользователя были заполнены %s", tg_id)
await session.commit()
# --- Функции получения данных из БД ---
async def check_user(tg_id):
"""
Проверяет наличие пользователя в базе.
Args:
tg_id (int): Telegram ID пользователя.
Returns:
Optional[UTi]: Пользователь или None.
"""
async with async_session() as session:
user = await session.scalar(select(UTi).where(UTi.tg_id == tg_id))
return user
async def get_bybit_api_key(tg_id):
"""Получить API ключ Bybit пользователя."""
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):
"""Получить секретный ключ Bybit пользователя."""
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_user_trades(tg_id):
"""Получить сделки пользователя."""
async with async_session() as session:
query = select(USER_DEALS.symbol, USER_DEALS.side).where(USER_DEALS.tg_id == tg_id)
result = await session.execute(query)
trades = result.all()
return trades
async def get_entry_order_type(tg_id: object) -> str | None | Any:
"""Получить тип входного ордера пользователя."""
async with async_session() as session:
order_type = await session.scalar(
select(UMS.entry_order_type).where(UMS.tg_id == tg_id)
)
# Если в базе не установлен тип — возвращаем значение по умолчанию
return order_type or 'Market'
# --- Функции обновления данных ---
async def update_user_trades(tg_id, **kwargs):
"""Обновить сделки пользователя."""
async with async_session() as session:
query = update(USER_DEALS).where(USER_DEALS.tg_id == tg_id).values(**kwargs)
await session.execute(query)
await session.commit()
async def update_symbol(tg_id: int, symbol: str) -> 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 upsert_api_keys(tg_id: int, api_key: str, secret_key: str) -> None:
"""Обновить API ключ пользователя."""
async with async_session() as session:
result = await session.execute(select(UBA).where(UBA.tg_id == tg_id))
user = result.scalars().first()
if user:
if api_key is not None:
user.api_key = api_key
if secret_key is not None:
user.secret_key = secret_key
logger.info(f"Обновлены ключи для пользователя {tg_id}")
else:
new_user = UBA(tg_id=tg_id, api_key=api_key, secret_key=secret_key)
session.add(new_user)
logger.info(f"Добавлен новый пользователь {tg_id} с ключами")
await session.commit()
# --- Более мелкие обновления и запросы по настройкам ---
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))
if mode:
logger.info("Изменён торговый режим для пользователя %s", tg_id)
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(trading_mode=mode))
await session.commit()
async def delete_user_trade(tg_id: int, symbol: str):
"""Удалить сделку пользователя."""
async with async_session() as session:
await session.execute(
USER_DEALS.__table__.delete().where(
(USER_DEALS.tg_id == tg_id) & (USER_DEALS.symbol == symbol)
)
)
await session.commit()
async def get_for_registration_trading_mode():
"""Получить режим торговли по умолчанию."""
async with async_session() as session:
mode = await session.scalar(select(Trading_Mode.mode).where(Trading_Mode.id == 1))
return mode
async def get_for_registration_margin_type():
"""Получить тип маржи по умолчанию."""
async with async_session() as session:
type = await session.scalar(select(Margin_type.type).where(Margin_type.id == 1))
return type
async def get_for_registration_trigger(tg_id):
"""Получить триггер по умолчанию."""
async with async_session() as session:
trigger = await session.scalar(select(UCS.trigger).where(tg_id == tg_id))
return trigger
async def get_user_main_settings(tg_id):
"""Получить основные настройки пользователя."""
async with async_session() as session:
user = await session.scalar(select(UMS).where(UMS.tg_id == tg_id))
if user:
data = {
'trading_mode': user.trading_mode,
'margin_type': user.margin_type,
'switch_state': user.switch_state,
'size_leverage': user.size_leverage,
'starting_quantity': user.starting_quantity,
'martingale_factor': user.martingale_factor,
'maximal_quantity': user.maximal_quantity,
'entry_order_type': user.entry_order_type,
'limit_order_price': user.limit_order_price,
'trigger_price': user.trigger_price,
'martingale_step': user.martingale_step,
'last_side': user.last_side,
'trading_start_stop': user.trading_start_stop,
'base_quantity': user.base_quantity,
}
return data
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("Получение риск-менеджмента настроек пользователя %s", tg_id)
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))
commission_fee = await session.scalar(select(URMS.commission_fee).where(URMS.tg_id == tg_id))
data = {
'price_profit': price_profit,
'price_loss': price_loss,
'max_risk_deal': max_risk_deal,
'commission_fee': commission_fee,
}
return data
async def update_margin_type(tg_id, margin_type) -> None:
"""Обновить тип маржи пользователя."""
async with async_session() as session:
type = await session.scalar(select(Margin_type.type).where(Margin_type.type == margin_type))
if type:
logger.info("Изменен тип маржи %s", tg_id)
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(margin_type=type))
await session.commit()
async def update_size_leverange(tg_id, num):
"""Обновить размер левеража пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(size_leverage=num))
await session.commit()
async def update_starting_quantity(tg_id, num):
"""Обновить размер начальной ставки пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(starting_quantity=num))
await session.commit()
async def update_base_quantity(tg_id, num):
"""Обновить размер следующей ставки пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(base_quantity=num))
await session.commit()
async def update_martingale_factor(tg_id, num):
"""Обновить шаг мартингейла пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(martingale_factor=num))
await session.commit()
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()
# ОБНОВЛЕНИЕ НАСТРОЕК РИСК-МЕНЕДЖМЕНТА
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()
async def update_entry_order_type(tg_id, order_type):
"""Обновить тип входного ордера пользователя."""
async with async_session() as session:
await session.execute(
update(UMS)
.where(UMS.tg_id == tg_id)
.values(entry_order_type=order_type)
)
await session.commit()
async def update_trigger_price(tg_id, price):
"""Обновить условную цену пользователя."""
async with async_session() as session:
await session.execute(
update(UMS)
.where(UMS.tg_id == tg_id)
.values(trigger_price=str(price))
)
await session.commit()
async def get_trigger_price(tg_id):
"""Получить условную цену пользователя как float, либо None."""
async with async_session() as session:
result = await session.execute(
select(UMS.trigger_price)
.where(UMS.tg_id == tg_id)
)
price = result.scalar_one_or_none()
if price:
try:
return float(price)
except ValueError:
return None
return None
async def get_limit_price(tg_id):
"""Получить лимитную цену пользователя как float, либо None."""
async with async_session() as session:
result = await session.execute(
select(UMS.limit_order_price)
.where(UMS.tg_id == tg_id)
)
price = result.scalar_one_or_none()
if price:
try:
return float(price)
except ValueError:
return None
return None
async def update_limit_price(tg_id, price):
"""Обновить лимитную цену пользователя."""
async with async_session() as session:
await session.execute(
update(UMS)
.where(UMS.tg_id == tg_id)
.values(limit_order_price=str(price))
)
await session.commit()
async def update_commission_fee(tg_id, num):
"""Обновить комиссию пользователя."""
async with async_session() as session:
await session.execute(update(URMS).where(URMS.tg_id == tg_id).values(commission_fee=num))
await session.commit()
async def get_user_timer(tg_id):
"""Получить данные о таймере пользователя."""
async with async_session() as session:
result = await session.execute(select(UserTimer).where(UserTimer.tg_id == tg_id))
user_timer = result.scalars().first()
if not user_timer:
logging.info(f"No timer found for user {tg_id}")
return None
timer_minutes = user_timer.timer_minutes
timer_start = user_timer.timer_start
timer_end = user_timer.timer_end
logging.info(f"Timer data for tg_id={tg_id}: "
f"timer_minutes={timer_minutes}, "
f"timer_start={timer_start}, "
f"timer_end={timer_end}")
remaining = None
if timer_end:
remaining = max(0, int((timer_end - datetime.utcnow()).total_seconds() // 60))
return {
"timer_minutes": timer_minutes,
"timer_start": timer_start,
"timer_end": timer_end,
"remaining_minutes": remaining
}
async def update_user_timer(tg_id, minutes: int):
"""Обновить данные о таймере пользователя."""
async with async_session() as session:
try:
timer_start = None
timer_end = None
if minutes > 0:
timer_start = datetime.utcnow()
timer_end = timer_start + timedelta(minutes=minutes)
result = await session.execute(select(UserTimer).where(UserTimer.tg_id == tg_id))
user_timer = result.scalars().first()
if user_timer:
user_timer.timer_minutes = minutes
user_timer.timer_start = timer_start
user_timer.timer_end = timer_end
else:
user_timer = UserTimer(
tg_id=tg_id,
timer_minutes=minutes,
timer_start=timer_start,
timer_end=timer_end
)
session.add(user_timer)
await session.commit()
except Exception as e:
logging.error(f"Ошибка обновления таймера пользователя {tg_id}: {e}")
async def get_martingale_step(tg_id):
"""Получить шаг мартингейла пользователя."""
async with async_session() as session:
result = await session.execute(select(UMS).where(UMS.tg_id == tg_id))
user_settings = result.scalars().first()
return user_settings.martingale_step
async def update_martingale_step(tg_id, step):
"""Обновить шаг мартингейла пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(martingale_step=step))
await session.commit()
async def update_switch_mode_enabled(tg_id, switch_mode):
"""Обновить режим переключения пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(switch_mode_enabled=switch_mode))
await session.commit()
async def update_switch_state(tg_id, switch_state):
"""Обновить состояние переключения пользователя."""
async with async_session() as session:
await session.execute(update(UMS).where(UMS.tg_id == tg_id).values(switch_state=switch_state))
await session.commit()
async def update_trigger(tg_id, trigger):
"""Обновить триггер пользователя."""
async with async_session() as session:
await session.execute(update(UCS).where(UCS.tg_id == tg_id).values(trigger=trigger))
await session.commit()
async def set_last_series_info(tg_id: int, last_side: str):
async with async_session() as session:
async with session.begin():
# Обновляем запись
result = await session.execute(
update(UMS)
.where(UMS.tg_id == tg_id)
.values(last_side=last_side)
)
if result.rowcount == 0:
# Если запись не существует, создаём новую
new_entry = UMS(
tg_id=tg_id,
last_side=last_side,
)
session.add(new_entry)
await session.commit()

View File

@@ -1,38 +0,0 @@
import app.telegram.Keyboards.inline_keyboards as inline_markup
import app.telegram.database.requests as rq
async def reg_new_user_default_additional_settings(id, message):
tg_id = id
await rq.set_new_user_default_additional_settings(tg_id)
async def main_settings_message(id, message):
text = '''<b>Дополнительные параметры</b>
<b>- Сохранить как шаблон стратегии:</b> да / нет
<b>- Автозапуск после сохранения:</b> да / нет
<b>- Уведомления в Telegram:</b> включено / отключено '''
await message.edit_text(text=text, parse_mode='html', reply_markup=inline_markup.additional_settings_markup)
async def save_pattern_message(message, state):
text = '''<b>Сохранение шаблона</b>
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup)
async def auto_start_message(message, state):
text = '''<b>Автозапуск</b>
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup)
async def notifications_message(message, state):
text = '''<b>Уведомления</b>
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_on_off_markup)

View File

@@ -1,208 +0,0 @@
import logging.config
import app.telegram.Keyboards.inline_keyboards as inline_markup
from aiogram import Router, F
from aiogram.types import Message, CallbackQuery
from aiogram.fsm.context import FSMContext
import app.telegram.database.requests as rq
from app.states.States import condition_settings
from app.states.States import state_limit_price, state_update_entry_type, state_trigger_price
from logger_helper.logger_helper import LOGGING_CONFIG
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("condition_settings")
condition_settings_router = Router()
async def reg_new_user_default_condition_settings(id):
tg_id = id
trigger = await rq.get_for_registration_trigger(tg_id)
await rq.set_new_user_default_condition_settings(tg_id, trigger)
async def main_settings_message(id, message):
data = await rq.get_user_main_settings(id)
entry_order_type = data['entry_order_type']
if entry_order_type == "Market":
entry_order_type_rus = "Маркет"
elif entry_order_type == "Limit":
entry_order_type_rus = "Лимит"
else:
entry_order_type_rus = "Условный"
trigger_price = data['trigger_price'] or 0.0
limit_price = data['limit_order_price'] or 0.0
text = f""" <b>Условия запуска</b>
<b>- Таймер: </b> установить таймер / удалить таймер
<b>- Тип позиции:</b> {entry_order_type_rus}
<b>- Триггер цена: </b> {trigger_price:,.4f}
<b>- Лимит цена: </b> {limit_price:,.4f}
"""
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.condition_settings_markup)
async def timer_message(id, message: Message, state: FSMContext):
await state.set_state(condition_settings.timer)
timer_info = await rq.get_user_timer(id)
if timer_info is None:
await message.answer("Таймер не установлен.", reply_markup=inline_markup.timer_markup)
return
await message.answer(
f"Таймер установлен на: {timer_info['timer_minutes']} мин\n",
reply_markup=inline_markup.timer_markup
)
@condition_settings_router.callback_query(F.data == "clb_set_timer")
async def set_timer_callback(callback: CallbackQuery, state: FSMContext):
await state.set_state(condition_settings.timer) # состояние для ввода времени
await callback.message.answer("Введите время работы в минутах (например, 60):", reply_markup=inline_markup.cancel)
await callback.answer()
@condition_settings_router.message(condition_settings.timer)
async def process_timer_input(message: Message, state: FSMContext):
try:
minutes = int(message.text)
if minutes <= 0:
await message.reply("Введите число больше нуля.")
return
await rq.update_user_timer(message.from_user.id, minutes)
logger.info("Timer set for user %s: %s minutes", message.from_user.id, minutes)
await timer_message(message.from_user.id, message, state)
await state.clear()
except ValueError:
await message.reply("Пожалуйста, введите корректное число.")
@condition_settings_router.callback_query(F.data == "clb_delete_timer")
async def delete_timer_callback(callback: CallbackQuery, state: FSMContext):
await state.clear()
await rq.update_user_timer(callback.from_user.id, 0)
logger.info("Timer deleted for user %s", callback.from_user.id)
await timer_message(callback.from_user.id, callback.message, state)
await callback.answer()
@condition_settings_router.callback_query(F.data == 'clb_update_entry_type')
async def update_entry_type_message(callback: CallbackQuery, state: FSMContext) -> None:
"""
Запрашивает у пользователя тип входа в позицию (Market или Limit).
"""
await state.set_state(state_update_entry_type.entry_type)
await callback.message.answer("Выберите тип входа в позицию:", reply_markup=inline_markup.entry_order_type_markup)
await callback.answer()
@condition_settings_router.callback_query(lambda c: c.data and c.data.startswith('entry_order_type:'))
async def entry_order_type_callback(callback: CallbackQuery, state: FSMContext) -> None:
"""
Обработка выбора типа входа в позицию.
Если Limit, запрашивает цену лимитного ордера.
Если Market — обновляет настройки.
"""
order_type = callback.data.split(':')[1]
if order_type not in ['Market', 'Limit']:
await callback.answer("Ошибка выбора", show_alert=True)
return
if order_type == 'Limit':
order_type_rus = 'Лимит'
else:
order_type_rus = 'Маркет'
try:
await state.update_data(entry_order_type=order_type)
await rq.update_entry_order_type(callback.from_user.id, order_type)
await callback.message.answer(f"Выбран тип входа {order_type_rus}",
reply_markup=inline_markup.back_to_condition_settings)
await callback.answer()
except Exception as e:
logger.error("Произошла ошибка при обновлении типа входа в позицию: %s", e)
await callback.message.answer("Произошла ошибка при обновлении типа входа в позицию",
reply_markup=inline_markup.back_to_condition_settings)
await state.clear()
@condition_settings_router.callback_query(F.data == 'clb_change_limit_price')
async def set_limit_price_callback(callback: CallbackQuery, state: FSMContext) -> None:
await state.set_state(state_limit_price.price)
await callback.message.answer("Введите цену лимитного ордера:", reply_markup=inline_markup.cancel)
await callback.answer()
@condition_settings_router.message(state_limit_price.price)
async def process_limit_price_input(message: Message, state: FSMContext) -> None:
try:
price = float(message.text)
await state.update_data(price=price)
await rq.update_limit_price(tg_id=message.from_user.id, price=price)
await message.answer(f"Цена лимитного ордера установлена: {price}", reply_markup=inline_markup.back_to_condition_settings)
await state.clear()
except ValueError:
await message.reply("Пожалуйста, введите корректную цену.")
@condition_settings_router.callback_query(F.data == 'clb_change_trigger_price')
async def change_trigger_price_callback(callback: CallbackQuery, state: FSMContext) -> None:
await state.set_state(state_trigger_price.price)
await callback.message.answer("Введите цену триггера:", reply_markup=inline_markup.cancel)
await callback.answer()
@condition_settings_router.message(state_trigger_price.price)
async def process_trigger_price_input(message: Message, state: FSMContext) -> None:
try:
price = float(message.text)
await state.update_data(price=price)
await rq.update_trigger_price(tg_id=message.from_user.id, price=price)
await message.answer(f"Цена триггера установлена: {price}", reply_markup=inline_markup.back_to_condition_settings)
await state.clear()
except ValueError:
await message.reply("Пожалуйста, введите корректную цену.")
async def filter_volatility_message(message, state):
text = '''Фильтр волатильности
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_on_off_markup)
async def external_cues_message(message, state):
text = '''<b>Внешние сигналы</b>
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=None)
async def trading_cues_message(message, state):
text = '''<b>Использование сигналов</b>
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup)
async def webhook_message(message, state):
text = '''Скиньте ссылку на <b>webhook</b> (если есть trading view): '''
await message.answer(text=text, parse_mode='html')
async def ai_analytics_message(message, state):
text = '''<b>ИИ - Аналитика</b>
Описание... '''
await message.answer(text=text, parse_mode='html', reply_markup=inline_markup.buttons_yes_no_markup)

View File

@@ -1,29 +0,0 @@
import app.telegram.Keyboards.inline_keyboards as inline_markup
import app.telegram.Keyboards.reply_keyboards as reply_markup
async def start_message(message):
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""" Привет <b>{username}</b>! 👋""", parse_mode='html')
await message.answer("Добро пожаловать в чат-робот для автоматизации трейдинга — вашего надежного помощника для анализа рынка и принятия взвешенных решений.",
parse_mode='html', reply_markup=inline_markup.start_markup)
async def profile_message(username, message):
await message.answer(f""" <b>@{username}</b>
Баланс
⭐️ 0
""", parse_mode='html', reply_markup=inline_markup.settings_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)

View File

@@ -1,375 +0,0 @@
from aiogram import Router
import logging.config
import app.telegram.Keyboards.inline_keyboards as inline_markup
import app.telegram.database.requests as rq
from aiogram.types import Message, CallbackQuery
from app.services.Bybit.functions.Futures import safe_float, calculate_total_budget, get_bybit_client
from app.states.States import update_main_settings
from logger_helper.logger_helper import LOGGING_CONFIG
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("main_settings")
router_main_settings = Router()
def is_number(value: str) -> bool:
"""
Checks if a given string represents a number.
Args:
value (str): The string to check.
Returns:
bool: True if the string represents a number, False otherwise.
"""
try:
# Convert the string to a float
num = float(value)
# Check if the number is positive
if num <= 0:
return False
# Check if the string contains "+" or "-"
if "+" in value or "-" in value:
return False
# Check if the string contains only digits
allowed_chars = set("0123456789.")
if not all(ch in allowed_chars for ch in value):
return False
return True
except ValueError:
return False
async def reg_new_user_default_main_settings(id, message):
tg_id = id
trading_mode = await rq.get_for_registration_trading_mode()
margin_type = await rq.get_for_registration_margin_type()
await rq.set_new_user_default_main_settings(tg_id, trading_mode, margin_type)
async def main_settings_message(id, message):
try:
data = await rq.get_user_main_settings(id)
tg_id = id
data_main_stgs = await rq.get_user_main_settings(id)
data_risk_stgs = await rq.get_user_risk_management_settings(id)
client = await get_bybit_client(tg_id)
symbol = await rq.get_symbol(tg_id)
max_martingale_steps = (data_main_stgs or {}).get('maximal_quantity', 0)
commission_fee = (data_risk_stgs or {}).get('commission_fee')
starting_quantity = safe_float((data_main_stgs or {}).get('starting_quantity'))
martingale_factor = safe_float((data_main_stgs or {}).get('martingale_factor'))
fee_info = client.get_fee_rates(category='linear', symbol=symbol)
if commission_fee == "Да":
commission_fee_percent = safe_float(fee_info['result']['list'][0]['takerFeeRate'])
else:
commission_fee_percent = 0.0
total_budget = await calculate_total_budget(
starting_quantity=starting_quantity,
martingale_factor=martingale_factor,
max_steps=max_martingale_steps,
commission_fee_percent=commission_fee_percent,
)
await message.answer(f"""<b>Основные настройки</b>
<b>- Режим торговли:</b> {data['trading_mode']}
<b>- Состояние свитча:</b> {data['switch_state']}
<b>- Направление последней сделки:</b> {data['last_side']}
<b>- Тип маржи:</b> {data['margin_type']}
<b>- Размер кредитного плеча:</b> х{data['size_leverage']}
<b>- Ставка:</b> {data['starting_quantity']}
<b>- Коэффициент мартингейла:</b> {data['martingale_factor']}
<b>- Текущий шаг:</b> {data['martingale_step']}
<b>- Максимальное количество ставок в серии:</b> {data['maximal_quantity']}
<b>- Требуемый бюджет:</b> {total_budget:.2f} USDT
""", parse_mode='html', reply_markup=inline_markup.main_settings_markup)
except PermissionError as e:
logger.error("Authenticated endpoints require keys: %s", e)
await message.answer("Вы не авторизованы.", reply_markup=inline_markup.connect_bybit_api_message)
async def trading_mode_message(message, state):
await state.set_state(update_main_settings.trading_mode)
await message.edit_text("""<b>Режим торговли</b>
<b>Лонг</b> — стратегия, ориентированная на покупку актива с целью заработать на повышении его стоимости.
<b>Шорт</b> — метод продажи активов, взятых в кредит, чтобы получить прибыль от снижения цены.
<b>Свитч</b> — динамическое переключение между торговыми режимами для максимизации эффективности.
<em>Выберите ниже для изменений:</em>
""", parse_mode='html', reply_markup=inline_markup.trading_mode_markup)
@router_main_settings.callback_query(update_main_settings.trading_mode)
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)
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)
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)
await state.clear()
case 'trade_mode_smart':
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)
await state.clear()
except Exception as e:
logger.error("Ошибка при обновлении режима торговли: %s", e)
async def switch_mode_enabled_message(message, state):
await state.set_state(update_main_settings.switch_mode_enabled)
await message.edit_text(
f"""<b> Состояние свитча</b>
<b>По направлению</b> - по направлению последней сделки предыдущей серии
<b>Против направления</b> - против направления последней сделки предыдущей серии
<em>По умолчанию при первом запуске бота, направление сделки установлено на "Buy".</em>
<em>Выберите ниже для изменений:</em>""", parse_mode='html',
reply_markup=inline_markup.switch_state_markup)
@router_main_settings.callback_query(lambda c: c.data in ["clb_long_switch", "clb_short_switch"])
async def state_switch_mode_enabled(callback: CallbackQuery, state):
await callback.answer()
tg_id = callback.from_user.id
val = "По направлению" if callback.data == "clb_long_switch" else "Против направления"
if val == "По направлению":
await rq.update_switch_state(tg_id, "По направлению")
await callback.message.answer(f"Состояние свитча: {val}")
await main_settings_message(tg_id, callback.message)
else:
await rq.update_switch_state(tg_id, "Против направления")
await callback.message.answer(f"Состояние свитча: {val}")
await main_settings_message(tg_id, callback.message)
await state.clear()
async def size_leverage_message(message, state):
await state.set_state(update_main_settings.size_leverage)
await message.edit_text("Введите размер <b>кредитного плеча</b> (от 1 до 100): ", parse_mode='html',
reply_markup=inline_markup.back_btn_list_settings_markup)
@router_main_settings.message(update_main_settings.size_leverage)
async def state_size_leverage(message: Message, state):
try:
leverage = float(message.text)
if leverage <= 0:
raise ValueError("Неверное значение")
except ValueError:
await message.answer(
"Ошибка: пожалуйста, введите положительное число для кредитного плеча."
"\nПопробуйте снова."
)
return
await state.update_data(size_leverage=message.text)
data = await state.get_data()
tg_id = message.from_user.id
symbol = await rq.get_symbol(tg_id)
leverage = data['size_leverage']
client = await get_bybit_client(tg_id)
instruments_resp = client.get_instruments_info(category="linear", symbol=symbol)
info = instruments_resp.get("result", {}).get("list", [])
max_leverage = safe_float(info[0].get("leverageFilter", {}).get("maxLeverage", 0))
if safe_float(leverage) > max_leverage:
await message.answer(
f"Запрошенное кредитное плечо {leverage} превышает максимальное {max_leverage} для {symbol}. "
f"Устанавливаю максимальное.",
reply_markup=inline_markup.back_to_main,
)
logger.info(
f"Запрошенное кредитное плечо {leverage} превышает максимальное {max_leverage} для {symbol}. Устанавливаю максимальное.")
await rq.update_size_leverange(message.from_user.id, max_leverage)
await main_settings_message(message.from_user.id, message)
await state.clear()
else:
await message.answer(f"✅ Изменено: {leverage}")
await rq.update_size_leverange(message.from_user.id, safe_float(leverage))
await main_settings_message(message.from_user.id, message)
await state.clear()
async def martingale_factor_message(message, state):
await state.set_state(update_main_settings.martingale_factor)
await message.edit_text("Введите <b>коэффициент Мартингейла:</b>", parse_mode='html',
reply_markup=inline_markup.back_btn_list_settings_markup)
@router_main_settings.message(update_main_settings.martingale_factor)
async def state_martingale_factor(message: Message, state):
await state.update_data(martingale_factor=message.text)
data = await state.get_data()
data_settings = await rq.get_user_main_settings(message.from_user.id)
if data['martingale_factor'].isdigit() and int(data['martingale_factor']) <= 100:
await message.answer(f"✅ Изменено: {data_settings['martingale_factor']}{data['martingale_factor']}")
await rq.update_martingale_factor(message.from_user.id, data['martingale_factor'])
await main_settings_message(message.from_user.id, message)
await state.clear()
else:
val = data['martingale_factor']
await message.answer(
f"⛔️ Ошибка: ваше значение ({val}) или выше лимита (100) или вы вводите неверные символы")
await main_settings_message(message.from_user.id, message)
async def margin_type_message(message, state):
await state.set_state(update_main_settings.margin_type)
await message.edit_text("""<b>Тип маржи</b>
<b>Изолированная маржа</b>
Этот тип маржи позволяет ограничить риск конкретной позиции.
При использовании изолированной маржи вы выделяете определённую сумму средств только для одной позиции.
Если позиция начинает приносить убытки, ваши потери ограничиваются этой суммой,
и остальные средства на счёте не затрагиваются.
<b>Кросс-маржа</b>
Кросс-маржа объединяет весь маржинальный баланс на счёте и использует все доступные средства для поддержания открытых позиций.
В случае убытков средства с других позиций или баланса автоматически покрывают дефицит,
снижая риск ликвидации, но увеличивая общий риск потери капитала.
<em>Выберите ниже для изменений:</em>
""", parse_mode='html', reply_markup=inline_markup.margin_type_markup)
@router_main_settings.callback_query(update_main_settings.margin_type)
async def state_margin_type(callback: CallbackQuery, state):
callback_data = callback.data
if callback_data in ['margin_type_isolated', 'margin_type_cross']:
tg_id = callback.from_user.id
data_settings = await rq.get_user_main_settings(tg_id)
try:
match callback.data:
case 'margin_type_isolated':
await callback.answer()
await callback.message.answer(f"✅ Изменено: {data_settings['margin_type']} → Isolated")
await rq.update_margin_type(tg_id, 'Isolated')
await main_settings_message(tg_id, callback.message)
await state.clear()
case 'margin_type_cross':
await callback.answer()
await callback.message.answer(f"✅ Изменено: {data_settings['margin_type']} → Cross")
await rq.update_margin_type(tg_id, 'Cross')
await main_settings_message(tg_id, callback.message)
await state.clear()
except Exception as e:
logger.error("Ошибка при изменении типа маржи: %s", e)
else:
await callback.answer()
await main_settings_message(callback.from_user.id, callback.message)
await state.clear()
async def starting_quantity_message(message, state):
await state.set_state(update_main_settings.starting_quantity)
await message.edit_text("Введите <b>ставку:</b>", parse_mode='html',
reply_markup=inline_markup.back_btn_list_settings_markup)
@router_main_settings.message(update_main_settings.starting_quantity)
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 is_number(data['starting_quantity']):
await message.answer(f"✅ Изменено: {data_settings['starting_quantity']}{data['starting_quantity']}")
await rq.update_starting_quantity(message.from_user.id, data['starting_quantity'])
await rq.update_base_quantity(tg_id=message.from_user.id, num=data['starting_quantity'])
await main_settings_message(message.from_user.id, message)
await state.clear()
else:
await message.answer("⛔️ Ошибка: вы вводите неверные символы")
await main_settings_message(message.from_user.id, message)
async def maximum_quantity_message(message, state):
await state.set_state(update_main_settings.maximal_quantity)
await message.edit_text("Введите максимальное количество серии ставок:",
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)
await state.clear()
else:
val = data['maximal_quantity']
await message.answer(
f'⛔️ Ошибка: ваше значение ({val}) или выше лимита (100) или вы вводите неверные символы')
logger.error(f'⛔️ Ошибка: ваше значение ({val}) или выше лимита (100) или вы вводите неверные символы')
await main_settings_message(message.from_user.id, message)

View File

@@ -1,160 +0,0 @@
from aiogram import Router
import app.telegram.Keyboards.inline_keyboards as inline_markup
import logging.config
import app.telegram.database.requests as rq
from aiogram.types import Message, CallbackQuery
from app.states.States import update_risk_management_settings
from logger_helper.logger_helper import LOGGING_CONFIG
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("risk_management_settings")
router_risk_management_settings = Router()
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)
async def main_settings_message(id, message):
data = await rq.get_user_risk_management_settings(id)
text = f"""<b>Риск менеджмент</b>,
<b>- Процент изменения цены для фиксации прибыли:</b> {data.get('price_profit', 0)}%
<b>- Процент изменения цены для фиксации убытков:</b> {data.get('price_loss', 0)}%
<b>- Максимальный риск на сделку (в % от баланса):</b> {data.get('max_risk_deal', 0)}%
<b>- Комиссия биржи для расчета прибыли:</b> {data.get('commission_fee', "Да")}
"""
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=inline_markup.cancel)
@router_risk_management_settings.message(update_risk_management_settings.price_profit)
async def state_price_profit(message: Message, state):
await state.update_data(price_profit=message.text)
data = await state.get_data()
data_settings = await rq.get_user_risk_management_settings(message.from_user.id)
if data['price_profit'].isdigit() and int(data['price_profit']) <= 100:
await message.answer(f"✅ Изменено: {data_settings['price_profit']}% → {data['price_profit']}%")
await rq.update_price_profit(message.from_user.id, data['price_profit'])
await main_settings_message(message.from_user.id, message)
await state.clear()
else:
val = data['price_profit']
await message.answer(
f'⛔️ Ошибка: ваше значение ({val}%) или выше лимита (100) или вы вводите неверные символы')
await main_settings_message(message.from_user.id, message)
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=inline_markup.cancel)
@router_risk_management_settings.message(update_risk_management_settings.price_loss)
async def state_price_loss(message: Message, state):
await state.update_data(price_loss=message.text)
data = await state.get_data()
data_settings = await rq.get_user_risk_management_settings(message.from_user.id)
if data['price_loss'].isdigit() and int(data['price_loss']) <= 100:
new_price_loss = int(data['price_loss'])
old_price_loss = int(data_settings.get('price_loss', 0))
current_price_profit = data_settings.get('price_profit')
# Пробуем перевести price_profit в число, если это возможно
try:
current_price_profit_num = int(current_price_profit)
except Exception as e:
logger.error(e)
current_price_profit_num = 0
# Флаг, если price_profit изначально равен 0 или совпадает со старым стоп-лоссом
should_update_profit = (current_price_profit_num == 0) or (current_price_profit_num == abs(old_price_loss))
# Обновляем стоп-лосс
await rq.update_price_loss(message.from_user.id, new_price_loss)
# Если нужно, меняем тейк-профит
if should_update_profit:
new_price_profit = abs(new_price_loss)
await rq.update_price_profit(message.from_user.id, new_price_profit)
await message.answer(f"✅ Стоп-лосс изменён: {old_price_loss}% → {new_price_loss}%\n"
f"Тейк-профит автоматически установлен в: {new_price_profit}%")
else:
await message.answer(f"✅ Стоп-лосс изменён: {old_price_loss}% → {new_price_loss}%")
await main_settings_message(message.from_user.id, message)
await state.clear()
else:
val = data['price_loss']
await message.answer(
f'⛔️ Ошибка: ваше значение ({val}%) выше лимита (100) или содержит неверные символы')
await main_settings_message(message.from_user.id, message)
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=inline_markup.cancel)
@router_risk_management_settings.message(update_risk_management_settings.max_risk_deal)
async def state_max_risk_deal(message: Message, state):
await state.update_data(max_risk_deal=message.text)
data = await state.get_data()
data_settings = await rq.get_user_risk_management_settings(message.from_user.id)
if data['max_risk_deal'].isdigit() and int(data['max_risk_deal']) <= 100:
await message.answer(f"✅ Изменено: {data_settings['max_risk_deal']}% → {data['max_risk_deal']}%")
await rq.update_max_risk_deal(message.from_user.id, data['max_risk_deal'])
await main_settings_message(message.from_user.id, message)
await state.clear()
else:
val = data['max_risk_deal']
await message.answer(
f'⛔️ Ошибка: ваше значение ({val}%) или выше лимита (100) или вы вводите неверные символы')
await main_settings_message(message.from_user.id, message)
async def commission_fee_message(message, state):
await state.set_state(update_risk_management_settings.commission_fee)
await message.answer(text="Хотите учитывать комиссию биржи:", parse_mode='html',
reply_markup=inline_markup.buttons_yes_no_markup)
@router_risk_management_settings.callback_query(lambda c: c.data in ["clb_yes", "clb_no"])
async def process_commission_fee_callback(callback: CallbackQuery, state):
val = "Да" if callback.data == "clb_yes" else "Нет"
await rq.update_commission_fee(callback.from_user.id, val)
await callback.message.answer(f"✅ Изменено: {val}")
await callback.answer()
await main_settings_message(callback.from_user.id, callback.message)
await state.clear()

View File

@@ -1,316 +0,0 @@
import logging.config
from aiogram import F, Router
from aiogram.filters import CommandStart, Command
from aiogram.types import Message, CallbackQuery
from aiogram.fsm.context import FSMContext
import app.telegram.functions.functions as func
import app.telegram.functions.main_settings.settings as func_main_settings
import app.telegram.functions.risk_management_settings.settings as func_rmanagement_settings
import app.telegram.functions.condition_settings.settings as func_condition_settings
import app.telegram.functions.additional_settings.settings as func_additional_settings
import app.telegram.database.requests as rq
from app.services.Bybit.functions.balance import get_balance
from app.services.Bybit.functions.bybit_ws import run_ws_for_user
from logger_helper.logger_helper import LOGGING_CONFIG
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("handlers")
router = Router()
@router.message(Command("start"))
@router.message(CommandStart())
async def start_message(message: Message) -> None:
"""
Обработчик команды /start.
Инициализирует нового пользователя в БД.
Args:
message (Message): Входящее сообщение с командой /start.
"""
await rq.set_new_user_bybit_api(message.from_user.id)
await func.start_message(message)
@router.message(Command("profile"))
@router.message(F.text == "👤 Профиль")
async def profile_message(message: Message) -> None:
"""
Обработчик кнопки 'Профиль'.
Проверяет существование пользователя и отображает профиль.
Args:
message (Message): Сообщение с текстом кнопки.
"""
user = await rq.check_user(message.from_user.id)
tg_id = message.from_user.id
balance = await get_balance(message.from_user.id, message)
if user and balance:
await run_ws_for_user(tg_id, message)
await func.profile_message(message.from_user.username, message)
else:
await rq.save_tg_id_new_user(message.from_user.id)
await func_main_settings.reg_new_user_default_main_settings(message.from_user.id, message)
await func_rmanagement_settings.reg_new_user_default_risk_management_settings(message.from_user.id, message)
await func_condition_settings.reg_new_user_default_condition_settings(message.from_user.id)
await func_additional_settings.reg_new_user_default_additional_settings(message.from_user.id, message)
@router.callback_query(F.data == "clb_start_chatbot_message")
async def clb_profile_msg(callback: CallbackQuery) -> None:
"""
Обработчик колбэка 'clb_start_chatbot_message'.
Если пользователь есть в БД — показывает профиль,
иначе регистрирует нового пользователя и инициализирует настройки.
Args:
callback (CallbackQuery): Полученный колбэк.
"""
tg_id = callback.from_user.id
message = callback.message
user = await rq.check_user(callback.from_user.id)
balance = await get_balance(callback.from_user.id, callback.message)
first_name = callback.from_user.first_name or ""
last_name = callback.from_user.last_name or ""
username = f"{first_name} {last_name}".strip() or callback.from_user.username or "Пользователь"
if user and balance:
await run_ws_for_user(tg_id, message)
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)
await func_additional_settings.reg_new_user_default_additional_settings(callback.from_user.id, callback.message)
await callback.answer()
@router.callback_query(F.data == "clb_settings_message")
async def clb_settings_msg(callback: CallbackQuery) -> None:
"""
Показать главное меню настроек.
Args:
callback (CallbackQuery): полученный колбэк.
"""
await func.settings_message(callback.message)
await callback.answer()
@router.callback_query(F.data == "clb_back_to_special_settings_message")
async def clb_back_to_settings_msg(callback: CallbackQuery) -> None:
"""
Вернуть пользователя к меню специальных настроек.
Args:
callback (CallbackQuery): полученный колбэк.
"""
await func.settings_message(callback.message)
await callback.answer()
@router.callback_query(F.data == "clb_change_main_settings")
async def clb_change_main_settings_message(callback: CallbackQuery) -> None:
"""
Открыть меню изменения главных настроек.
Args:
callback (CallbackQuery): полученный колбэк.
"""
await func_main_settings.main_settings_message(callback.from_user.id, callback.message)
await callback.answer()
@router.callback_query(F.data == "clb_change_risk_management_settings")
async def clb_change_risk_management_message(callback: CallbackQuery) -> None:
"""
Открыть меню изменения настроек управления рисками.
Args:
callback (CallbackQuery): полученный колбэк.
"""
await func_rmanagement_settings.main_settings_message(callback.from_user.id, callback.message)
await callback.answer()
@router.callback_query(F.data == "clb_change_condition_settings")
async def clb_change_condition_message(callback: CallbackQuery) -> None:
"""
Открыть меню изменения настроек условий.
Args:
callback (CallbackQuery): полученный колбэк.
"""
await func_condition_settings.main_settings_message(callback.from_user.id, callback.message)
await callback.answer()
@router.callback_query(F.data == "clb_change_additional_settings")
async def clb_change_additional_message(callback: CallbackQuery) -> None:
"""
Открыть меню изменения дополнительных настроек.
Args:
callback (CallbackQuery): полученный колбэк.
"""
await func_additional_settings.main_settings_message(callback.from_user.id, callback.message)
await callback.answer()
# Конкретные настройки каталогов
list_main_settings = ['clb_change_trading_mode',
'clb_change_switch_state',
'clb_change_margin_type',
'clb_change_size_leverage',
'clb_change_starting_quantity',
'clb_change_martingale_factor',
'clb_change_maximum_quantity'
]
@router.callback_query(F.data.in_(list_main_settings))
async def clb_main_settings_msg(callback: CallbackQuery, state: FSMContext) -> None:
"""
Обработчик колбэков изменения главных настроек с dispatch через match-case.
Args:
callback (CallbackQuery): полученный колбэк.
state (FSMContext): текущее состояние FSM.
"""
await callback.answer()
try:
match callback.data:
case 'clb_change_trading_mode':
await func_main_settings.trading_mode_message(callback.message, state)
case 'clb_change_switch_state':
await func_main_settings.switch_mode_enabled_message(callback.message, state)
case 'clb_change_margin_type':
await func_main_settings.margin_type_message(callback.message, state)
case 'clb_change_size_leverage':
await func_main_settings.size_leverage_message(callback.message, state)
case 'clb_change_starting_quantity':
await func_main_settings.starting_quantity_message(callback.message, state)
case 'clb_change_martingale_factor':
await func_main_settings.martingale_factor_message(callback.message, state)
case 'clb_change_maximum_quantity':
await func_main_settings.maximum_quantity_message(callback.message, state)
except Exception as e:
logger.error("Error callback in main_settings match-case: %s", e)
list_risk_management_settings = ['clb_change_price_profit',
'clb_change_price_loss',
'clb_change_max_risk_deal',
'commission_fee',
]
@router.callback_query(F.data.in_(list_risk_management_settings))
async def clb_risk_management_settings_msg(callback: CallbackQuery, state: FSMContext) -> None:
"""
Обработчик изменений настроек управления рисками.
Args:
callback (CallbackQuery): полученный колбэк.
state (FSMContext): текущее состояние FSM.
"""
await callback.answer()
try:
match callback.data:
case 'clb_change_price_profit':
await func_rmanagement_settings.price_profit_message(callback.message, state)
case 'clb_change_price_loss':
await func_rmanagement_settings.price_loss_message(callback.message, state)
case 'clb_change_max_risk_deal':
await func_rmanagement_settings.max_risk_deal_message(callback.message, state)
case 'commission_fee':
await func_rmanagement_settings.commission_fee_message(callback.message, state)
except Exception as e:
logger.error("Error callback in risk_management match-case: %s", e)
list_condition_settings = ['clb_change_mode',
'clb_change_timer',
'clb_change_filter_volatility',
'clb_change_external_cues',
'clb_change_tradingview_cues',
'clb_change_webhook',
'clb_change_ai_analytics'
]
@router.callback_query(F.data.in_(list_condition_settings))
async def clb_condition_settings_msg(callback: CallbackQuery, state: FSMContext) -> None:
"""
Обработчик изменений настроек условий трейдинга.
Args:
callback (CallbackQuery): полученный колбэк.
state (FSMContext): текущее состояние FSM.
"""
await callback.answer()
try:
match callback.data:
case 'clb_change_mode':
await func_condition_settings.trigger_message(callback.from_user.id, callback.message, state)
case 'clb_change_timer':
await func_condition_settings.timer_message(callback.from_user.id, callback.message, state)
case 'clb_change_filter_volatility':
await func_condition_settings.filter_volatility_message(callback.message, state)
case 'clb_change_external_cues':
await func_condition_settings.external_cues_message(callback.message, state)
case 'clb_change_tradingview_cues':
await func_condition_settings.trading_cues_message(callback.message, state)
case 'clb_change_webhook':
await func_condition_settings.webhook_message(callback.message, state)
case 'clb_change_ai_analytics':
await func_condition_settings.ai_analytics_message(callback.message, state)
except Exception as e:
logger.error("Error callback in main_settings match-case: %s", e)
list_additional_settings = ['clb_change_save_pattern',
'clb_change_auto_start',
'clb_change_notifications',
]
@router.callback_query(F.data.in_(list_additional_settings))
async def clb_additional_settings_msg(callback: CallbackQuery, state: FSMContext) -> None:
"""
Обработчик дополнительных настроек бота.
Args:
callback (CallbackQuery): полученный колбэк.
state (FSMContext): текущее состояние FSM.
"""
await callback.answer()
try:
match callback.data:
case 'clb_change_save_pattern':
await func_additional_settings.save_pattern_message(callback.message, state)
case 'clb_change_auto_start':
await func_additional_settings.auto_start_message(callback.message, state)
case 'clb_change_notifications':
await func_additional_settings.notifications_message(callback.message, state)
except Exception as e:
logger.error("Error callback in additional_settings match-case: %s", e)