2
0
forked from kodorvan/stcs

42 Commits

Author SHA1 Message Date
f0732607e2 Merge pull request 'The instruction has been corrected' (#13) from Alex/stcs:devel into stable
Reviewed-on: kodorvan/stcs#13
2025-10-11 16:36:48 +07:00
algizn97
458b34fcec The instruction has been corrected 2025-10-11 14:14:27 +05:00
56af1d8f3b Merge pull request 'Added migrations for the database' (#12) from Alex/stcs:devel into stable
Reviewed-on: kodorvan/stcs#12
2025-10-11 15:49:40 +07:00
algizn97
4a7577b977 Added migrations for the database 2025-10-11 13:36:38 +05:00
9f069df68a Merge pull request 'devel' (#11) from Alex/stcs:devel into stable
Reviewed-on: kodorvan/stcs#11
2025-10-11 11:58:36 +07:00
algizn97
6e0a170f4b Merge branch 'devel' of https://git.svoboda.works/Alex/stcs into devel 2025-10-10 15:21:09 +05:00
algizn97
c7b4a08a6a Merge branch 'stable' of https://git.svoboda.works/Alex/stcs into devel 2025-10-10 15:19:31 +05:00
algizn97
d0971f59b4 Added environments 2025-10-10 14:42:47 +05:00
b92376d2da merge upstream 2025-10-10 16:35:16 +07:00
630f2002d3 Удалить alembic.ini 2025-10-10 16:24:01 +07:00
0784cbb54a Удалить alembic/versions/fd8581c0cc87_updated_leverage.py 2025-10-10 16:23:51 +07:00
eeb7f81440 Удалить alembic/versions/f00a94ccdf01_updated_deals.py 2025-10-10 16:23:47 +07:00
b03d05bb75 Удалить alembic/versions/ef38c90eed55_added_last_side_the_conditional_data.py 2025-10-10 16:23:43 +07:00
e0e4ad5d4b Удалить alembic/versions/ef342b38e17b_added_fee_user_deals.py 2025-10-10 16:23:39 +07:00
fab8ff5040 Удалить alembic/versions/dbffe818030c_added_last_side_and_auto_trading_for_.py 2025-10-10 16:23:35 +07:00
8071f8c896 Удалить alembic/versions/d3c85bad8c98_added_limit_and_trigger_price_for_user_.py 2025-10-10 16:23:30 +07:00
3db001bd19 Удалить alembic/versions/ccdc5764eb4f_added_userdeals.py 2025-10-10 16:23:26 +07:00
99c59be9ed Удалить alembic/versions/acbcc95de48d_updated_userdeals.py 2025-10-10 16:23:21 +07:00
37b7b6effd Удалить alembic/versions/c98b9dc36d15_fixed_auto_trade.py 2025-10-10 16:23:17 +07:00
ee285523f2 Удалить alembic/versions/8f1476c68efa_added_position_idx_for_user_deals_table.py 2025-10-10 16:23:12 +07:00
b426eb2136 Удалить alembic/versions/968f8121104f_updated_user_deals_and_user_conditional_.py 2025-10-10 16:23:07 +07:00
2df3b8b40d Удалить alembic/versions/c710f4e2259c_unnecessary_data_has_been_deleted.py 2025-10-10 16:23:03 +07:00
8c08451d82 Удалить alembic/versions/863d6215e1eb_updated_deals.py 2025-10-10 16:22:52 +07:00
d81a47b669 Удалить alembic/versions/77197715747c_deleted_position_idx_for_user_deals_.py 2025-10-10 16:22:48 +07:00
2cdfba3537 Удалить alembic/versions/73a00faa4f7f_added_user_auto_trading_table.py 2025-10-10 16:22:43 +07:00
c89c2ad803 Удалить alembic/versions/70094ba27e80_create_user_conditional_setting.py 2025-10-10 16:22:39 +07:00
3986989dbd Удалить alembic/versions/42c66cfe8d4e_updated_martingale_factor.py 2025-10-10 16:22:35 +07:00
c0e40dc205 Удалить alembic/versions/3534adf891fc_update_last_side_the_conditional_data.py 2025-10-10 16:22:30 +07:00
6c6f0dbb7b Удалить alembic/versions/10bf073c71f9_added_fee_for_user_auto_trading.py 2025-10-10 16:22:26 +07:00
44c4fde036 Удалить alembic/versions/45977e9d8558_updated_order_quantity.py 2025-10-10 16:22:21 +07:00
21a93d47d4 Удалить alembic/versions/2b9572b49ecd_added_side_for_user_auto_trading.py 2025-10-10 16:22:18 +07:00
3f43d42651 Удалить alembic/versions/0eed68eddcdb_added_conditional_order_type.py 2025-10-10 16:22:13 +07:00
aab05994ce Удалить alembic/versions/09db71875980_updated_user_deals_table.py 2025-10-10 16:22:08 +07:00
a58ebe6a46 Удалить alembic/README 2025-10-10 16:21:38 +07:00
1ec1f1784d Удалить alembic/script.py.mako 2025-10-10 16:21:33 +07:00
7901af86af Удалить alembic/env.py 2025-10-10 16:21:24 +07:00
fedfa00c10 Merge pull request 'devel' (#3) from devel into stable
Reviewed-on: #3
2025-10-10 16:18:23 +07:00
algizn97
fc8ab19ae9 Fixed the budget calculation function 2025-10-10 14:14:46 +05:00
898ff91392 Merge pull request 'added the exc_info flag' (#10) from Alex/stcs:dev into stable
Reviewed-on: kodorvan/stcs#10
2025-10-07 12:10:58 +07:00
2047dd5ac6 Merge pull request 'dev' (#9) from Alex/stcs:dev into stable
Reviewed-on: kodorvan/stcs#9
2025-10-06 21:33:56 +07:00
fec367cc1d Merge pull request 'dev' (#8) from Alex/stcs:dev into stable
Reviewed-on: kodorvan/stcs#8
2025-09-19 17:17:25 +07:00
aebcc9dff2 Merge pull request 'dev' (#7) from Alex/stcs:dev into stable
Reviewed-on: kodorvan/stcs#7
2025-09-18 22:49:55 +07:00
21 changed files with 265 additions and 269 deletions

2
.gitignore vendored
View File

@@ -146,6 +146,8 @@ myenv
ENV/ ENV/
env.bak/ env.bak/
venv.bak/ venv.bak/
/logger_helper/loggers
/app/bybit/logger_bybit/loggers
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject
.spyproject .spyproject

View File

@@ -55,7 +55,12 @@ cp .env.sample .env
nvim .env nvim .env
``` ```
5. Запустите бота: 5. Для применения миграций выполните команду:
```bash
alembic upgrade head
```
6. Запустите бота:
```bash ```bash
python run.py python run.py

View File

@@ -0,0 +1,40 @@
"""fixed switch_side type
Revision ID: 07020b2808d3
Revises: c710f4e2259c
Create Date: 2025-10-09 14:36:07.393387
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '07020b2808d3'
down_revision: Union[str, Sequence[str], None] = 'c710f4e2259c'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('user_additional_settings', 'switch_side',
existing_type=sa.BOOLEAN(),
type_=sa.String(),
existing_nullable=False,
existing_server_default=sa.text('false'))
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('user_additional_settings', 'switch_side',
existing_type=sa.String(),
type_=sa.BOOLEAN(),
existing_nullable=False,
existing_server_default=sa.text('false'))
# ### end Alembic commands ###

View File

@@ -0,0 +1,34 @@
"""added base_quantity
Revision ID: baf03ce269e0
Revises: 07020b2808d3
Create Date: 2025-10-09 16:49:52.979556
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'baf03ce269e0'
down_revision: Union[str, Sequence[str], None] = '07020b2808d3'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('user_deals', sa.Column('base_quantity', sa.Float(), nullable=True))
op.drop_column('user_deals', 'trading_type')
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('user_deals', sa.Column('trading_type', sa.VARCHAR(), autoincrement=False, nullable=True))
op.drop_column('user_deals', 'base_quantity')
# ### end Alembic commands ###

View File

@@ -16,7 +16,9 @@ logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("open_positions") logger = logging.getLogger("open_positions")
async def start_trading_cycle(tg_id: int) -> str | None: async def start_trading_cycle(
tg_id: int
) -> str | None:
""" """
Start trading cycle Start trading cycle
:param tg_id: Telegram user ID :param tg_id: Telegram user ID
@@ -27,7 +29,9 @@ async def start_trading_cycle(tg_id: int) -> str | None:
additional_data = await rq.get_user_additional_settings(tg_id=tg_id) additional_data = await rq.get_user_additional_settings(tg_id=tg_id)
risk_management_data = await rq.get_user_risk_management(tg_id=tg_id) risk_management_data = await rq.get_user_risk_management(tg_id=tg_id)
commission_fee = risk_management_data.commission_fee commission_fee = risk_management_data.commission_fee
user_deals_data = await rq.get_user_deal_by_symbol(tg_id=tg_id, symbol=symbol) user_deals_data = await rq.get_user_deal_by_symbol(
tg_id=tg_id, symbol=symbol
)
trade_mode = additional_data.trade_mode trade_mode = additional_data.trade_mode
switch_side = additional_data.switch_side switch_side = additional_data.switch_side
margin_type = additional_data.margin_type margin_type = additional_data.margin_type
@@ -103,7 +107,7 @@ async def start_trading_cycle(tg_id: int) -> str | None:
leverage=leverage, leverage=leverage,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
commission_fee_percent=total_commission, commission_fee_percent=total_commission
) )
if res == "OK": if res == "OK":
@@ -121,7 +125,7 @@ async def start_trading_cycle(tg_id: int) -> str | None:
max_bets_in_series=max_bets_in_series, max_bets_in_series=max_bets_in_series,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
base_quantity=order_quantity, base_quantity=order_quantity
) )
return "OK" return "OK"
return ( return (
@@ -138,7 +142,7 @@ async def start_trading_cycle(tg_id: int) -> str | None:
"position idx not match position mode", "position idx not match position mode",
"Qty invalid", "Qty invalid",
"The number of contracts exceeds maximum limit allowed", "The number of contracts exceeds maximum limit allowed",
"The number of contracts exceeds minimum limit allowed", "The number of contracts exceeds minimum limit allowed"
} }
else None else None
) )
@@ -148,12 +152,12 @@ async def start_trading_cycle(tg_id: int) -> str | None:
return None return None
async def trading_cycle(tg_id: int, symbol: str, reverse_side: str) -> str | None: async def trading_cycle(
tg_id: int, symbol: str, reverse_side: str
) -> str | None:
try: try:
user_deals_data = await rq.get_user_deal_by_symbol(tg_id=tg_id, symbol=symbol) user_deals_data = await rq.get_user_deal_by_symbol(tg_id=tg_id, symbol=symbol)
user_auto_trading_data = await rq.get_user_auto_trading( user_auto_trading_data = await rq.get_user_auto_trading(tg_id=tg_id, symbol=symbol)
tg_id=tg_id, symbol=symbol
)
total_fee = user_auto_trading_data.total_fee total_fee = user_auto_trading_data.total_fee
trade_mode = user_deals_data.trade_mode trade_mode = user_deals_data.trade_mode
margin_type = user_deals_data.margin_type margin_type = user_deals_data.margin_type
@@ -184,7 +188,9 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str) -> str | Non
if trade_mode == "Switch": if trade_mode == "Switch":
side = "Sell" if real_side == "Buy" else "Buy" side = "Sell" if real_side == "Buy" else "Buy"
next_quantity = safe_float(order_quantity) * (safe_float(martingale_factor)) next_quantity = safe_float(order_quantity) * (
safe_float(martingale_factor)
)
current_step += 1 current_step += 1
if max_bets_in_series < current_step: if max_bets_in_series < current_step:
@@ -200,7 +206,7 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str) -> str | Non
leverage=leverage, leverage=leverage,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
commission_fee_percent=total_fee, commission_fee_percent=total_fee
) )
if res == "OK": if res == "OK":
@@ -218,7 +224,7 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str) -> str | Non
max_bets_in_series=max_bets_in_series, max_bets_in_series=max_bets_in_series,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
base_quantity=base_quantity, base_quantity=base_quantity
) )
return "OK" return "OK"
@@ -249,7 +255,7 @@ async def open_positions(
leverage: str, leverage: str,
take_profit_percent: float, take_profit_percent: float,
stop_loss_percent: float, stop_loss_percent: float,
commission_fee_percent: float, commission_fee_percent: float
) -> str | None: ) -> str | None:
try: try:
client = await get_bybit_client(tg_id=tg_id) client = await get_bybit_client(tg_id=tg_id)

View File

@@ -23,12 +23,12 @@ async def user_profile_bybit(tg_id: int, message: Message, state: FSMContext) ->
symbol = await rq.get_user_symbol(tg_id=tg_id) symbol = await rq.get_user_symbol(tg_id=tg_id)
await message.answer( await message.answer(
text=f"💎Ваш профиль:\n\n" text=f"💎Ваш профиль:\n\n"
f"⚖️ Баланс: {float(balance):,.2f} USD\n" f"⚖️ Баланс: {float(balance):,.2f} USD\n"
f"📊Торговая пара: {symbol}\n\n" f"📊Торговая пара: {symbol}\n\n"
f"Краткая инструкция:\n" f"Краткая инструкция:\n"
f"1. Укажите торговую пару (например: BTCUSDT).\n" f"1. Укажите торговую пару (например: BTCUSDT).\n"
f"2. В настройках выставьте все необходимые параметры.\n" f"2. В настройках выставьте все необходимые параметры.\n"
f"3. Нажмите кнопку 'Начать торговлю'.\n", f"3. Нажмите кнопку 'Начать торговлю'.\n",
reply_markup=kbi.main_menu, reply_markup=kbi.main_menu,
) )
else: else:

View File

@@ -135,9 +135,9 @@ class TelegramMessageHandler:
user_symbols = user_auto_trading.symbol if user_auto_trading else None user_symbols = user_auto_trading.symbol if user_auto_trading else None
if ( if (
auto_trading auto_trading
and safe_float(closed_size) > 0 and safe_float(closed_size) > 0
and user_symbols is not None and user_symbols is not None
): ):
if safe_float(total_pnl) > 0: if safe_float(total_pnl) > 0:
profit_text = "📈 Прибыль достигнута\n" profit_text = "📈 Прибыль достигнута\n"

View File

@@ -46,7 +46,9 @@ class WebSocketBot:
self.user_sockets.clear() self.user_sockets.clear()
self.user_messages.clear() self.user_messages.clear()
self.user_keys.clear() self.user_keys.clear()
logger.info("Closed old websocket for user %s due to key change", tg_id) logger.info(
"Closed old websocket for user %s due to key change", tg_id
)
success = await self.try_connect_user(api_key, api_secret, tg_id) success = await self.try_connect_user(api_key, api_secret, tg_id)
if success: if success:

View File

@@ -134,7 +134,7 @@ def check_limit_price(limit_price, min_price, max_price) -> str | None:
async def get_liquidation_price( async def get_liquidation_price(
tg_id: int, symbol: str, entry_price: float, leverage: float tg_id: int, symbol: str, entry_price: float, leverage: float
) -> tuple[float, float]: ) -> tuple[float, float]:
""" """
Function to get liquidation price Function to get liquidation price
@@ -158,7 +158,7 @@ async def get_liquidation_price(
async def calculate_total_budget( async def calculate_total_budget(
quantity, martingale_factor, max_steps, commission_fee_percent quantity, martingale_factor, max_steps
) -> float: ) -> float:
""" """
Calculate the total budget for a series of trading steps. Calculate the total budget for a series of trading steps.
@@ -167,20 +167,15 @@ async def calculate_total_budget(
quantity (float): The initial quantity of the asset. quantity (float): The initial quantity of the asset.
martingale_factor (float): The factor by which the quantity is multiplied for each step. martingale_factor (float): The factor by which the quantity is multiplied for each step.
max_steps (int): The maximum number of trading steps. max_steps (int): The maximum number of trading steps.
commission_fee_percent (float): The commission fee percentage.
Returns: Returns:
float: The total budget for the series of trading steps. float: The total budget for the series of trading steps.
""" """
total = 0 total = 0
for step in range(max_steps): for step in range(max_steps):
set_quantity = quantity * (martingale_factor ** step) set_quantity = quantity * (martingale_factor**step)
if commission_fee_percent == 0:
# Commission fee is not added to the position size r_quantity = set_quantity
r_quantity = set_quantity
else:
# Commission fee is added to the position size
r_quantity = set_quantity * (1 + 2 * commission_fee_percent)
total += r_quantity total += r_quantity
return total return total

View File

@@ -6,10 +6,11 @@ from aiogram.types import CallbackQuery, Message
import app.telegram.keyboards.inline as kbi import app.telegram.keyboards.inline as kbi
import database.request as rq import database.request as rq
from app.bybit.get_functions.get_instruments_info import get_instruments_info
from app.bybit.get_functions.get_tickers import get_tickers from app.bybit.get_functions.get_tickers import get_tickers
from app.bybit.get_functions.get_instruments_info import get_instruments_info
from app.bybit.profile_bybit import user_profile_bybit from app.bybit.profile_bybit import user_profile_bybit
from app.bybit.set_functions.set_leverage import set_leverage from app.bybit.set_functions.set_leverage import set_leverage
from app.bybit.set_functions.set_margin_mode import set_margin_mode from app.bybit.set_functions.set_margin_mode import set_margin_mode
from app.helper_functions import safe_float from app.helper_functions import safe_float
from app.telegram.states.states import ChangingTheSymbolState from app.telegram.states.states import ChangingTheSymbolState
@@ -98,9 +99,7 @@ async def set_symbol(message: Message, state: FSMContext) -> None:
) )
return return
instruments_info = await get_instruments_info( instruments_info = await get_instruments_info(tg_id=message.from_user.id, symbol=symbol)
tg_id=message.from_user.id, symbol=symbol
)
max_leverage = instruments_info.get("leverageFilter").get("maxLeverage") max_leverage = instruments_info.get("leverageFilter").get("maxLeverage")
req = await rq.set_user_symbol(tg_id=message.from_user.id, symbol=symbol) req = await rq.set_user_symbol(tg_id=message.from_user.id, symbol=symbol)
@@ -124,8 +123,7 @@ async def set_symbol(message: Message, state: FSMContext) -> None:
await rq.set_leverage(tg_id=message.from_user.id, leverage=str(max_leverage)) await rq.set_leverage(tg_id=message.from_user.id, leverage=str(max_leverage))
risk_percent = 100 / safe_float(max_leverage) risk_percent = 100 / safe_float(max_leverage)
await rq.set_stop_loss_percent( await rq.set_stop_loss_percent(
tg_id=message.from_user.id, stop_loss_percent=risk_percent tg_id=message.from_user.id, stop_loss_percent=risk_percent)
)
await rq.set_trigger_price(tg_id=message.from_user.id, trigger_price=0) await rq.set_trigger_price(tg_id=message.from_user.id, trigger_price=0)
await rq.set_order_quantity(tg_id=message.from_user.id, order_quantity=1.0) await rq.set_order_quantity(tg_id=message.from_user.id, order_quantity=1.0)

View File

@@ -53,7 +53,7 @@ async def cmd_start(message: Message, state: FSMContext) -> None:
await rq.create_user_conditional_settings(tg_id=tg_id) await rq.create_user_conditional_settings(tg_id=tg_id)
await message.answer( await message.answer(
text=f"Добро пожаловать, {full_name}!\n\n" text=f"Добро пожаловать, {full_name}!\n\n"
"Чат-робот для трейдинга - ваш надежный помощник для анализа рынка и принятия взвешенных решений.😉", "Чат-робот для трейдинга - ваш надежный помощник для анализа рынка и принятия взвешенных решений.😉",
reply_markup=kbi.connect_the_platform, reply_markup=kbi.connect_the_platform,
) )
logger.debug( logger.debug(
@@ -134,7 +134,7 @@ async def profile_bybit(message: Message, state: FSMContext) -> None:
@router_handlers_main.callback_query(F.data == "profile_bybit") @router_handlers_main.callback_query(F.data == "profile_bybit")
async def profile_bybit_callback( async def profile_bybit_callback(
callback_query: CallbackQuery, state: FSMContext callback_query: CallbackQuery, state: FSMContext
) -> None: ) -> None:
""" """
Handle callback query with data "profile_bybit". Handle callback query with data "profile_bybit".
@@ -279,10 +279,10 @@ async def cmd_help(message: Message, state: FSMContext) -> None:
await state.clear() await state.clear()
await message.answer( await message.answer(
text="Используйте одну из следующих команд:\n" text="Используйте одну из следующих команд:\n"
"/start - Запустить бота\n" "/start - Запустить бота\n"
"/profile - Профиль\n" "/profile - Профиль\n"
"/bybit - Панель Bybit\n" "/bybit - Панель Bybit\n"
"/connect - Подключиться к платформе\n", "/connect - Подключиться к платформе\n",
reply_markup=kbr.profile, reply_markup=kbr.profile,
) )
logger.debug( logger.debug(

View File

@@ -21,7 +21,7 @@ router_additional_settings = Router(name="additional_settings")
@router_additional_settings.callback_query(F.data == "trade_mode") @router_additional_settings.callback_query(F.data == "trade_mode")
async def settings_for_trade_mode( async def settings_for_trade_mode(
callback_query: CallbackQuery, state: FSMContext callback_query: CallbackQuery, state: FSMContext
) -> None: ) -> None:
""" """
Handles the 'trade_mode' callback query. Handles the 'trade_mode' callback query.
@@ -40,9 +40,9 @@ async def settings_for_trade_mode(
await state.clear() await state.clear()
await callback_query.message.edit_text( await callback_query.message.edit_text(
text="Выберите режим торговли:\n\n" text="Выберите режим торговли:\n\n"
"Лонг - все сделки серии открываются на покупку.\n" "Лонг - все сделки серии открываются на покупку.\n"
"Шорт - все сделки серии открываются на продажу.\n" "Шорт - все сделки серии открываются на продажу.\n"
"Свитч - направление каждой сделки серии меняется по переменно.\n", "Свитч - направление каждой сделки серии меняется по переменно.\n",
reply_markup=kbi.trade_mode, reply_markup=kbi.trade_mode,
) )
logger.debug( logger.debug(
@@ -123,8 +123,8 @@ async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) ->
await state.clear() await state.clear()
await callback_query.message.edit_text( await callback_query.message.edit_text(
text="Выберите направление первой сделки серии:\n\n" text="Выберите направление первой сделки серии:\n\n"
"По направлению - сделка открывается в направлении последней сделки предыдущей серии.\n" "По направлению - сделка открывается в направлении последней сделки предыдущей серии.\n"
"Противоположно - сделка открывается в противоположном направлении последней сделки предыдущей серии.\n", "Противоположно - сделка открывается в противоположном направлении последней сделки предыдущей серии.\n",
reply_markup=kbi.switch_side, reply_markup=kbi.switch_side,
) )
logger.debug( logger.debug(
@@ -142,9 +142,7 @@ async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) ->
) )
@router_additional_settings.callback_query( @router_additional_settings.callback_query(lambda c: c.data == "switch_direction" or c.data == "switch_opposite")
lambda c: c.data == "switch_direction" or c.data == "switch_opposite"
)
async def switch_side_handler(callback_query: CallbackQuery, state: FSMContext) -> None: async def switch_side_handler(callback_query: CallbackQuery, state: FSMContext) -> None:
""" """
Handles callback queries related to switch side selection. Handles callback queries related to switch side selection.
@@ -196,7 +194,7 @@ async def switch_side_handler(callback_query: CallbackQuery, state: FSMContext)
@router_additional_settings.callback_query(F.data == "margin_type") @router_additional_settings.callback_query(F.data == "margin_type")
async def settings_for_margin_type( async def settings_for_margin_type(
callback_query: CallbackQuery, state: FSMContext callback_query: CallbackQuery, state: FSMContext
) -> None: ) -> None:
""" """
Handles the 'margin_type' callback query. Handles the 'margin_type' callback query.
@@ -215,8 +213,8 @@ async def settings_for_margin_type(
await state.clear() await state.clear()
await callback_query.message.edit_text( await callback_query.message.edit_text(
text="Выберите тип маржи:\n\n" text="Выберите тип маржи:\n\n"
"Примечание: Если у вас есть открытые позиции, то маржа примениться ко всем позициям", "Примечание: Если у вас есть открытые позиции, то маржа примениться ко всем позициям",
reply_markup=kbi.margin_type, reply_markup=kbi.margin_type
) )
logger.debug( logger.debug(
"Command margin_type processed successfully for user: %s", "Command margin_type processed successfully for user: %s",
@@ -505,12 +503,12 @@ async def set_leverage_handler(message: Message, state: FSMContext) -> None:
if instruments_info is not None: if instruments_info is not None:
min_leverage = ( min_leverage = (
safe_float(instruments_info.get("leverageFilter").get("minLeverage")) safe_float(instruments_info.get("leverageFilter").get("minLeverage"))
or 1 or 1
) )
max_leverage = ( max_leverage = (
safe_float(instruments_info.get("leverageFilter").get("maxLeverage")) safe_float(instruments_info.get("leverageFilter").get("maxLeverage"))
or 100 or 100
) )
if leverage_float > max_leverage or leverage_float < min_leverage: if leverage_float > max_leverage or leverage_float < min_leverage:
@@ -555,8 +553,7 @@ async def set_leverage_handler(message: Message, state: FSMContext) -> None:
) )
risk_percent = 100 / safe_float(leverage_float) risk_percent = 100 / safe_float(leverage_float)
await rq.set_stop_loss_percent( await rq.set_stop_loss_percent(
tg_id=message.from_user.id, stop_loss_percent=risk_percent tg_id=message.from_user.id, stop_loss_percent=risk_percent)
)
logger.info( logger.info(
"User %s set leverage: %s", message.from_user.id, leverage_float "User %s set leverage: %s", message.from_user.id, leverage_float
) )
@@ -770,14 +767,9 @@ async def set_martingale_factor(message: Message, state: FSMContext) -> None:
martingale_factor_value_float = safe_float(martingale_factor_value) martingale_factor_value_float = safe_float(martingale_factor_value)
if martingale_factor_value_float < 0.1 or martingale_factor_value_float > 10: if martingale_factor_value_float < 0.1 or martingale_factor_value_float > 10:
await message.answer( await message.answer(text="Ошибка: коэффициент мартингейла должен быть в диапазоне от 0.1 до 10")
text="Ошибка: коэффициент мартингейла должен быть в диапазоне от 0.1 до 10" logger.debug("User %s input invalid (not in range 0.1 to 10): %s", message.from_user.id,
) martingale_factor_value_float)
logger.debug(
"User %s input invalid (not in range 0.1 to 10): %s",
message.from_user.id,
martingale_factor_value_float,
)
return return
req = await rq.set_martingale_factor( req = await rq.set_martingale_factor(
@@ -886,10 +878,7 @@ async def set_max_bets_in_series(message: Message, state: FSMContext) -> None:
) )
return return
if ( if safe_float(max_bets_in_series_value) < 1 or safe_float(max_bets_in_series_value) > 100:
safe_float(max_bets_in_series_value) < 1
or safe_float(max_bets_in_series_value) > 100
):
await message.answer( await message.answer(
"Ошибка: число должно быть в диапазоне от 1 до 100.", "Ошибка: число должно быть в диапазоне от 1 до 100.",
reply_markup=kbi.back_to_additional_settings, reply_markup=kbi.back_to_additional_settings,

View File

@@ -98,10 +98,7 @@ async def set_take_profit_percent(message: Message, state: FSMContext) -> None:
) )
return return
if ( if safe_float(take_profit_percent_value) < 1 or safe_float(take_profit_percent_value) > 100:
safe_float(take_profit_percent_value) < 1
or safe_float(take_profit_percent_value) > 100
):
await message.answer( await message.answer(
text="Ошибка: введите число от 1 до 100.", text="Ошибка: введите число от 1 до 100.",
reply_markup=kbi.back_to_risk_management, reply_markup=kbi.back_to_risk_management,
@@ -222,10 +219,7 @@ async def set_stop_loss_percent(message: Message, state: FSMContext) -> None:
) )
return return
if ( if safe_float(stop_loss_percent_value) < 1 or safe_float(stop_loss_percent_value) > 100:
safe_float(stop_loss_percent_value) < 1
or safe_float(stop_loss_percent_value) > 100
):
await message.answer( await message.answer(
text="Ошибка: введите число от 1 до 100.", text="Ошибка: введите число от 1 до 100.",
reply_markup=kbi.back_to_risk_management, reply_markup=kbi.back_to_risk_management,
@@ -238,8 +232,7 @@ async def set_stop_loss_percent(message: Message, state: FSMContext) -> None:
return return
req = await rq.set_stop_loss_percent( req = await rq.set_stop_loss_percent(
tg_id=message.from_user.id, tg_id=message.from_user.id, stop_loss_percent=safe_float(stop_loss_percent_value)
stop_loss_percent=safe_float(stop_loss_percent_value),
) )
if req: if req:

View File

@@ -6,7 +6,7 @@ from aiogram.types import CallbackQuery
import app.telegram.keyboards.inline as kbi import app.telegram.keyboards.inline as kbi
import database.request as rq import database.request as rq
from app.bybit import get_bybit_client
from app.helper_functions import calculate_total_budget, safe_float from app.helper_functions import calculate_total_budget, safe_float
from logger_helper.logger_helper import LOGGING_CONFIG from logger_helper.logger_helper import LOGGING_CONFIG
@@ -25,7 +25,6 @@ async def additional_settings(callback_query: CallbackQuery, state: FSMContext)
try: try:
await state.clear() await state.clear()
tg_id = callback_query.from_user.id 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) additional_data = await rq.get_user_additional_settings(tg_id=tg_id)
if not additional_data: if not additional_data:
@@ -63,30 +62,15 @@ async def additional_settings(callback_query: CallbackQuery, state: FSMContext)
max_bets = additional_data.max_bets_in_series max_bets = additional_data.max_bets_in_series
quantity = f(additional_data.order_quantity) quantity = f(additional_data.order_quantity)
trigger_price = f(additional_data.trigger_price) or 0 trigger_price = f(additional_data.trigger_price) or 0
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
switch_side_mode = "" switch_side_mode = ""
if trade_mode == "Switch": if trade_mode == "Switch":
switch_side_mode = f"- Направление первой сделки: {switch_side}\n" switch_side_mode = f"- Направление первой сделки: {switch_side}\n"
quantity_price = quantity * trigger_price
total_commission = quantity_price * commission_fee_percent
total_budget = await calculate_total_budget( total_budget = await calculate_total_budget(
quantity=quantity, quantity=quantity,
martingale_factor=martingale, martingale_factor=martingale,
max_steps=max_bets, max_steps=max_bets,
commission_fee_percent=total_commission,
) )
text = ( text = (
f"Основные настройки:\n\n" f"Основные настройки:\n\n"
@@ -98,7 +82,7 @@ async def additional_settings(callback_query: CallbackQuery, state: FSMContext)
f"- Коэффициент мартингейла: {martingale:.2f}\n" f"- Коэффициент мартингейла: {martingale:.2f}\n"
f"- Триггер цена: {trigger_price:.4f} USDT\n" f"- Триггер цена: {trigger_price:.4f} USDT\n"
f"- Максимальное кол-во ставок в серии: {max_bets}\n\n" f"- Максимальное кол-во ставок в серии: {max_bets}\n\n"
f"- Бюджет серии: {total_budget:.4f} USDT\n" f"- Бюджет серии: {total_budget:.2f} USDT\n"
) )
keyboard = kbi.get_additional_settings_keyboard(mode=trade_mode) keyboard = kbi.get_additional_settings_keyboard(mode=trade_mode)

View File

@@ -10,7 +10,10 @@ import database.request as rq
from app.bybit.get_functions.get_positions import get_active_positions_by_symbol from app.bybit.get_functions.get_positions import get_active_positions_by_symbol
from app.bybit.open_positions import start_trading_cycle from app.bybit.open_positions import start_trading_cycle
from app.helper_functions import safe_float from app.helper_functions import safe_float
from app.telegram.tasks.tasks import add_start_task_merged, cancel_start_task_merged from app.telegram.tasks.tasks import (
add_start_task_merged,
cancel_start_task_merged
)
from logger_helper.logger_helper import LOGGING_CONFIG from logger_helper.logger_helper import LOGGING_CONFIG
logging.config.dictConfig(LOGGING_CONFIG) logging.config.dictConfig(LOGGING_CONFIG)
@@ -117,7 +120,9 @@ async def start_trading(callback_query: CallbackQuery, state: FSMContext) -> Non
logger.error("Cancelled timer for user %s", callback_query.from_user.id) logger.error("Cancelled timer for user %s", callback_query.from_user.id)
@router_start_trading.callback_query(lambda c: c.data == "cancel_timer_merged") @router_start_trading.callback_query(
lambda c: c.data == "cancel_timer_merged"
)
async def cancel_start_trading( async def cancel_start_trading(
callback_query: CallbackQuery, state: FSMContext callback_query: CallbackQuery, state: FSMContext
) -> None: ) -> None:

View File

@@ -61,7 +61,8 @@ main_settings = InlineKeyboardMarkup(
# additional_settings # additional_settings
def get_additional_settings_keyboard(mode: str) -> InlineKeyboardMarkup: def get_additional_settings_keyboard(mode: str
) -> InlineKeyboardMarkup:
""" """
Create keyboard for additional settings Create keyboard for additional settings
:param mode: Trade mode :param mode: Trade mode
@@ -76,23 +77,23 @@ def get_additional_settings_keyboard(mode: str) -> InlineKeyboardMarkup:
InlineKeyboardButton( InlineKeyboardButton(
text="Размер кредитного плеча", callback_data="leverage" text="Размер кредитного плеча", callback_data="leverage"
), ),
InlineKeyboardButton(text="Базовая ставка", callback_data="order_quantity"), InlineKeyboardButton(
text="Базовая ставка", callback_data="order_quantity"),
], ],
[ [
InlineKeyboardButton( InlineKeyboardButton(
text="Коэффициент мартингейла", callback_data="martingale_factor" text="Коэффициент мартингейла", callback_data="martingale_factor"
), ),
InlineKeyboardButton(text="Триггер цена", callback_data="trigger_price"), InlineKeyboardButton(text="Триггер цена", callback_data="trigger_price"
),
], ],
] ]
if mode == "Switch": if mode == "Switch":
buttons.append( buttons.append(
[ [InlineKeyboardButton(text="Направление первой сделки", callback_data="switch_side_start")]
InlineKeyboardButton(
text="Направление первой сделки", callback_data="switch_side_start"
)
]
) )
buttons.append( buttons.append(
@@ -116,7 +117,9 @@ def get_additional_settings_keyboard(mode: str) -> InlineKeyboardMarkup:
trade_mode = InlineKeyboardMarkup( trade_mode = InlineKeyboardMarkup(
inline_keyboard=[ inline_keyboard=[
[ [
InlineKeyboardButton(text="Лонг", callback_data="Long"), InlineKeyboardButton(
text="Лонг", callback_data="Long"
),
InlineKeyboardButton(text="Шорт", callback_data="Short"), InlineKeyboardButton(text="Шорт", callback_data="Short"),
InlineKeyboardButton(text="Свитч", callback_data="Switch"), InlineKeyboardButton(text="Свитч", callback_data="Switch"),
], ],
@@ -185,7 +188,9 @@ risk_management = InlineKeyboardMarkup(
InlineKeyboardButton( InlineKeyboardButton(
text="Тейк-профит", callback_data="take_profit_percent" text="Тейк-профит", callback_data="take_profit_percent"
), ),
InlineKeyboardButton(text="Стоп-лосс", callback_data="stop_loss_percent"), InlineKeyboardButton(
text="Стоп-лосс", callback_data="stop_loss_percent"
),
], ],
[InlineKeyboardButton(text="Комиссия биржи", callback_data="commission_fee")], [InlineKeyboardButton(text="Комиссия биржи", callback_data="commission_fee")],
[ [

View File

@@ -1,8 +1,10 @@
from aiogram.types import KeyboardButton, ReplyKeyboardMarkup from aiogram.types import KeyboardButton, ReplyKeyboardMarkup
profile = ReplyKeyboardMarkup( profile = ReplyKeyboardMarkup(
keyboard=[[KeyboardButton(text="Панель Bybit"), KeyboardButton(text="Профиль")], keyboard=[
[KeyboardButton(text="Подключить платформу Bybit")]], [KeyboardButton(text="Панель Bybit"), KeyboardButton(text="Профиль")],
[KeyboardButton(text="Подключить платформу Bybit")],
],
resize_keyboard=True, resize_keyboard=True,
one_time_keyboard=True, one_time_keyboard=True,
input_field_placeholder="Выберите пункт меню...", input_field_placeholder="Выберите пункт меню...",

View File

@@ -12,9 +12,7 @@ logger = logging.getLogger("database")
async_engine = create_async_engine(DATABASE_URL, echo=False) async_engine = create_async_engine(DATABASE_URL, echo=False)
async_session = async_sessionmaker( async_session = async_sessionmaker(async_engine, class_=AsyncSession, expire_on_commit=False)
async_engine, class_=AsyncSession, expire_on_commit=False
)
async def init_db(): async def init_db():

View File

@@ -1,15 +1,6 @@
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.asyncio import AsyncAttrs from sqlalchemy.ext.asyncio import AsyncAttrs
from sqlalchemy import ( from sqlalchemy import Column, ForeignKey, Integer, String, BigInteger, Float, Boolean, UniqueConstraint
Column,
ForeignKey,
Integer,
String,
BigInteger,
Float,
Boolean,
UniqueConstraint,
)
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
Base = declarative_base(cls=AsyncAttrs) Base = declarative_base(cls=AsyncAttrs)
@@ -17,77 +8,61 @@ Base = declarative_base(cls=AsyncAttrs)
class User(Base): class User(Base):
"""User model.""" """User model."""
__tablename__ = "users" __tablename__ = "users"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
tg_id = Column(BigInteger, nullable=False, unique=True) tg_id = Column(BigInteger, nullable=False, unique=True)
username = Column(String, nullable=False) username = Column(String, nullable=False)
user_api = relationship( user_api = relationship("UserApi",
"UserApi", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True,
passive_deletes=True, uselist=False)
uselist=False,
)
user_symbol = relationship( user_symbol = relationship("UserSymbol",
"UserSymbol", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True,
passive_deletes=True, uselist=False)
uselist=False,
)
user_additional_settings = relationship( user_additional_settings = relationship("UserAdditionalSettings",
"UserAdditionalSettings", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True,
passive_deletes=True, uselist=False)
uselist=False,
)
user_risk_management = relationship( user_risk_management = relationship("UserRiskManagement",
"UserRiskManagement", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True,
passive_deletes=True, uselist=False)
uselist=False,
)
user_conditional_settings = relationship( user_conditional_settings = relationship("UserConditionalSettings",
"UserConditionalSettings", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True,
passive_deletes=True, uselist=False)
uselist=False,
)
user_deals = relationship( user_deals = relationship("UserDeals",
"UserDeals", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True)
passive_deletes=True,
)
user_auto_trading = relationship( user_auto_trading = relationship("UserAutoTrading",
"UserAutoTrading", back_populates="user",
back_populates="user", cascade="all, delete-orphan",
cascade="all, delete-orphan", passive_deletes=True)
passive_deletes=True,
)
class UserApi(Base): class UserApi(Base):
"""User API model.""" """User API model."""
__tablename__ = "user_api" __tablename__ = "user_api"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, unique=True ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False, unique=True)
api_key = Column(String, nullable=False) api_key = Column(String, nullable=False)
api_secret = Column(String, nullable=False) api_secret = Column(String, nullable=False)
@@ -96,13 +71,12 @@ class UserApi(Base):
class UserSymbol(Base): class UserSymbol(Base):
"""User symbol model.""" """User symbol model."""
__tablename__ = "user_symbol" __tablename__ = "user_symbol"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, unique=True ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False, unique=True)
symbol = Column(String, nullable=False, default="BTCUSDT") symbol = Column(String, nullable=False, default="BTCUSDT")
user = relationship("User", back_populates="user_symbol") user = relationship("User", back_populates="user_symbol")
@@ -110,13 +84,12 @@ class UserSymbol(Base):
class UserAdditionalSettings(Base): class UserAdditionalSettings(Base):
"""User additional settings model.""" """User additional settings model."""
__tablename__ = "user_additional_settings" __tablename__ = "user_additional_settings"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, unique=True ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False, unique=True)
trade_mode = Column(String, nullable=False, default="Merged_Single") trade_mode = Column(String, nullable=False, default="Merged_Single")
switch_side = Column(String, nullable=False, default="По направлению") switch_side = Column(String, nullable=False, default="По направлению")
trigger_price = Column(Float, nullable=False, default=0.0) trigger_price = Column(Float, nullable=False, default=0.0)
@@ -131,13 +104,12 @@ class UserAdditionalSettings(Base):
class UserRiskManagement(Base): class UserRiskManagement(Base):
"""User risk management model.""" """User risk management model."""
__tablename__ = "user_risk_management" __tablename__ = "user_risk_management"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, unique=True ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False, unique=True)
take_profit_percent = Column(Float, nullable=False, default=1) take_profit_percent = Column(Float, nullable=False, default=1)
stop_loss_percent = Column(Float, nullable=False, default=1) stop_loss_percent = Column(Float, nullable=False, default=1)
commission_fee = Column(String, nullable=False, default="Yes_commission_fee") commission_fee = Column(String, nullable=False, default="Yes_commission_fee")
@@ -147,13 +119,12 @@ class UserRiskManagement(Base):
class UserConditionalSettings(Base): class UserConditionalSettings(Base):
"""User conditional settings model.""" """User conditional settings model."""
__tablename__ = "user_conditional_settings" __tablename__ = "user_conditional_settings"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, unique=True ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False, unique=True)
timer_start = Column(Integer, nullable=False, default=0) timer_start = Column(Integer, nullable=False, default=0)
timer_end = Column(Integer, nullable=False, default=0) timer_end = Column(Integer, nullable=False, default=0)
@@ -163,13 +134,12 @@ class UserConditionalSettings(Base):
class UserDeals(Base): class UserDeals(Base):
"""User deals model.""" """User deals model."""
__tablename__ = "user_deals" __tablename__ = "user_deals"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False)
current_step = Column(Integer, nullable=True) current_step = Column(Integer, nullable=True)
symbol = Column(String, nullable=True) symbol = Column(String, nullable=True)
trade_mode = Column(String, nullable=True) trade_mode = Column(String, nullable=True)
@@ -187,18 +157,19 @@ class UserDeals(Base):
user = relationship("User", back_populates="user_deals") user = relationship("User", back_populates="user_deals")
__table_args__ = (UniqueConstraint("user_id", "symbol", name="uq_user_symbol"),) __table_args__ = (
UniqueConstraint('user_id', 'symbol', name='uq_user_symbol'),
)
class UserAutoTrading(Base): class UserAutoTrading(Base):
"""User auto trading model.""" """User auto trading model."""
__tablename__ = "user_auto_trading" __tablename__ = "user_auto_trading"
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column( user_id = Column(Integer,
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False ForeignKey("users.id", ondelete="CASCADE"),
) nullable=False)
symbol = Column(String, nullable=True) symbol = Column(String, nullable=True)
auto_trading = Column(Boolean, nullable=True) auto_trading = Column(Boolean, nullable=True)
fee = Column(Float, nullable=True) fee = Column(Float, nullable=True)

View File

@@ -893,20 +893,20 @@ async def set_stop_timer(tg_id: int, timer_end: int) -> bool:
# USER DEALS # USER DEALS
async def set_user_deal( async def set_user_deal(
tg_id: int, tg_id: int,
symbol: str, symbol: str,
last_side: str, last_side: str,
current_step: int, current_step: int,
trade_mode: str, trade_mode: str,
margin_type: str, margin_type: str,
leverage: str, leverage: str,
order_quantity: float, order_quantity: float,
trigger_price: float, trigger_price: float,
martingale_factor: float, martingale_factor: float,
max_bets_in_series: int, max_bets_in_series: int,
take_profit_percent: int, take_profit_percent: int,
stop_loss_percent: int, stop_loss_percent: int,
base_quantity: float, base_quantity: float
): ):
""" """
Set the user deal in the database. Set the user deal in the database.
@@ -969,7 +969,7 @@ async def set_user_deal(
max_bets_in_series=max_bets_in_series, max_bets_in_series=max_bets_in_series,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
base_quantity=base_quantity, base_quantity=base_quantity
) )
session.add(new_deal) session.add(new_deal)
@@ -978,9 +978,7 @@ async def set_user_deal(
return True return True
except Exception as e: except Exception as e:
logger.error( logger.error("Error setting user deal for user %s and symbol %s: %s", tg_id, symbol, e)
"Error setting user deal for user %s and symbol %s: %s", tg_id, symbol, e
)
return False return False
@@ -1000,9 +998,7 @@ async def get_user_deal_by_symbol(tg_id: int, symbol: str):
deal = result_deal.scalars().first() deal = result_deal.scalars().first()
return deal return deal
except Exception as e: except Exception as e:
logger.error( logger.error("Error getting deal for user %s and symbol %s: %s", tg_id, symbol, e)
"Error getting deal for user %s and symbol %s: %s", tg_id, symbol, e
)
return None return None
@@ -1044,26 +1040,18 @@ async def set_fee_user_deal_by_symbol(tg_id: int, symbol: str, fee: float):
if record: if record:
record.fee = fee record.fee = fee
else: else:
logger.error( logger.error(f"User deal with user_id={user.id} and symbol={symbol} not found")
f"User deal with user_id={user.id} and symbol={symbol} not found"
)
return False return False
await session.commit() await session.commit()
logger.info("Set fee for user %s and symbol %s", tg_id, symbol) logger.info("Set fee for user %s and symbol %s", tg_id, symbol)
return True return True
except Exception as e: except Exception as e:
logger.error( logger.error("Error setting user deal fee for user %s and symbol %s: %s", tg_id, symbol, e)
"Error setting user deal fee for user %s and symbol %s: %s",
tg_id,
symbol,
e,
)
return False return False
# USER AUTO TRADING # USER AUTO TRADING
async def get_all_user_auto_trading(tg_id: int): async def get_all_user_auto_trading(tg_id: int):
"""Get all user auto trading from the database asynchronously.""" """Get all user auto trading from the database asynchronously."""
try: try:
@@ -1098,9 +1086,7 @@ async def get_user_auto_trading(tg_id: int, symbol: str):
auto_trading = result_auto_trading.scalars().first() auto_trading = result_auto_trading.scalars().first()
return auto_trading return auto_trading
except Exception as e: except Exception as e:
logger.error( logger.error("Error getting auto trading for user %s and symbol %s: %s", tg_id, symbol, e)
"Error getting auto trading for user %s and symbol %s: %s", tg_id, symbol, e
)
return None return None
@@ -1134,17 +1120,10 @@ async def set_auto_trading(tg_id: int, symbol: str, auto_trading: bool) -> bool:
) )
session.add(new_record) session.add(new_record)
await session.commit() await session.commit()
logger.info( logger.info("Set auto_trading=%s for user %s and symbol %s", auto_trading, tg_id, symbol)
"Set auto_trading=%s for user %s and symbol %s",
auto_trading,
tg_id,
symbol,
)
return True return True
except Exception as e: except Exception as e:
logger.error( logger.error("Error setting auto_trading for user %s and symbol %s: %s", tg_id, symbol, e)
"Error setting auto_trading for user %s and symbol %s: %s", tg_id, symbol, e
)
return False return False
@@ -1182,18 +1161,11 @@ async def set_fee_user_auto_trading(tg_id: int, symbol: str, fee: float) -> bool
logger.info("Set fee for user %s and symbol %s", tg_id, symbol) logger.info("Set fee for user %s and symbol %s", tg_id, symbol)
return True return True
except Exception as e: except Exception as e:
logger.error( logger.error("Error setting user auto trading fee for user %s and symbol %s: %s", tg_id, symbol, e)
"Error setting user auto trading fee for user %s and symbol %s: %s",
tg_id,
symbol,
e,
)
return False return False
async def set_total_fee_user_auto_trading( async def set_total_fee_user_auto_trading(tg_id: int, symbol: str, total_fee: float) -> bool:
tg_id: int, symbol: str, total_fee: float
) -> bool:
""" """
Set the total fee for a user auto trading in the database. Set the total fee for a user auto trading in the database.
:param tg_id: Telegram user ID :param tg_id: Telegram user ID
@@ -1227,10 +1199,5 @@ async def set_total_fee_user_auto_trading(
logger.info("Set total fee for user %s and symbol %s", tg_id, symbol) logger.info("Set total fee for user %s and symbol %s", tg_id, symbol)
return True return True
except Exception as e: except Exception as e:
logger.error( logger.error("Error setting user auto trading total fee for user %s and symbol %s: %s", tg_id, symbol, e)
"Error setting user auto trading total fee for user %s and symbol %s: %s",
tg_id,
symbol,
e,
)
return False return False