Merge pull request 'разъебаться по полной' (#21) from Alex/stcs:devel into stable
Reviewed-on: #21
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
"""Added column side for additional_setiings
|
||||
|
||||
Revision ID: e5d612e44563
|
||||
Revises: fbf4e3658310
|
||||
Create Date: 2025-10-25 18:25:52.746250
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'e5d612e44563'
|
||||
down_revision: Union[str, Sequence[str], None] = 'fbf4e3658310'
|
||||
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_additional_settings',
|
||||
sa.Column('side', sa.String(), nullable=False, server_default='')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('user_additional_settings', 'side')
|
||||
# ### end Alembic commands ###
|
||||
@@ -28,11 +28,9 @@ async def start_trading_cycle(
|
||||
symbol = await rq.get_user_symbol(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)
|
||||
user_deals_data = await rq.get_user_deal_by_symbol(
|
||||
tg_id=tg_id, symbol=symbol
|
||||
)
|
||||
trade_mode = additional_data.trade_mode
|
||||
switch_side = additional_data.switch_side
|
||||
side= additional_data.side
|
||||
margin_type = additional_data.margin_type
|
||||
leverage = additional_data.leverage
|
||||
order_quantity = additional_data.order_quantity
|
||||
@@ -43,19 +41,8 @@ async def start_trading_cycle(
|
||||
stop_loss_percent = risk_management_data.stop_loss_percent
|
||||
total_commission = 0
|
||||
|
||||
get_side = "Buy"
|
||||
|
||||
if user_deals_data:
|
||||
get_side = user_deals_data.last_side or "Buy"
|
||||
|
||||
if trade_mode == "Switch":
|
||||
if switch_side == "По направлению":
|
||||
side = get_side
|
||||
else:
|
||||
if get_side == "Buy":
|
||||
side = "Sell"
|
||||
else:
|
||||
side = "Buy"
|
||||
side = side
|
||||
else:
|
||||
if trade_mode == "Long":
|
||||
side = "Buy"
|
||||
|
||||
@@ -105,10 +105,10 @@ async def trade_mode(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||
await state.clear()
|
||||
|
||||
|
||||
@router_additional_settings.callback_query(F.data == "switch_side_start")
|
||||
async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||
@router_additional_settings.callback_query(F.data == "switch_side_second")
|
||||
async def switch_side_second(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||
"""
|
||||
Handles the 'switch_side_start' callback query.
|
||||
Handles the 'switch_side_second' callback query.
|
||||
|
||||
Clears the current FSM state, edits the message text to display the switch side start message,
|
||||
and shows an inline keyboard for selection.
|
||||
@@ -123,13 +123,13 @@ async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) ->
|
||||
try:
|
||||
await state.clear()
|
||||
await callback_query.message.edit_text(
|
||||
text="Выберите направление первой сделки серии:\n\n"
|
||||
text="Выберите направление первой сделки последующих серии:\n\n"
|
||||
"По направлению - сделка открывается в направлении последней сделки предыдущей серии.\n"
|
||||
"Противоположно - сделка открывается в противоположном направлении последней сделки предыдущей серии.\n",
|
||||
reply_markup=kbi.switch_side,
|
||||
)
|
||||
logger.debug(
|
||||
"Command switch_side_start processed successfully for user: %s",
|
||||
"Command switch_side_second processed successfully for user: %s",
|
||||
callback_query.from_user.id,
|
||||
)
|
||||
except Exception as e:
|
||||
@@ -137,7 +137,7 @@ async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) ->
|
||||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||||
)
|
||||
logger.error(
|
||||
"Error processing command switch_side_start for user %s: %s",
|
||||
"Error processing command switch_side_second for user %s: %s",
|
||||
callback_query.from_user.id,
|
||||
e,
|
||||
)
|
||||
@@ -193,6 +193,89 @@ async def switch_side_handler(callback_query: CallbackQuery, state: FSMContext)
|
||||
await state.clear()
|
||||
|
||||
|
||||
@router_additional_settings.callback_query(F.data == "switch_side_start")
|
||||
async def switch_side_start(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||
"""
|
||||
Handles the 'switch_side_start' callback query.
|
||||
|
||||
Clears the current FSM state, edits the message text to display the switch side second message,
|
||||
and shows an inline keyboard for selection.
|
||||
|
||||
Args:
|
||||
callback_query (CallbackQuery): Incoming callback query from Telegram inline keyboard.
|
||||
state (FSMContext): Finite State Machine context for the current user session.
|
||||
|
||||
Logs:
|
||||
Success or error messages with user identification.
|
||||
"""
|
||||
try:
|
||||
await state.clear()
|
||||
await callback_query.message.edit_text(
|
||||
text="Выберите направление первой сделки:\n\n", reply_markup=kbi.side_for_switch
|
||||
)
|
||||
logger.debug(
|
||||
"Command switch_side_start processed successfully for user: %s",
|
||||
callback_query.from_user.id,
|
||||
)
|
||||
except Exception as e:
|
||||
await callback_query.answer(
|
||||
text="Произошла ошибка. Пожалуйста, попробуйте позже."
|
||||
)
|
||||
logger.error(
|
||||
"Error processing command switch_side_start for user %s: %s",
|
||||
callback_query.from_user.id,
|
||||
e,
|
||||
)
|
||||
|
||||
|
||||
@router_additional_settings.callback_query(lambda c: c.data == "buy_switch" or c.data == "sell_switch")
|
||||
async def switch_side_handler_2(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||
"""
|
||||
Handles callback queries related to switch side selection.
|
||||
|
||||
Updates FSM context with selected switch side and persists the choice in database.
|
||||
Sends an acknowledgement to user and clears FSM state afterward.
|
||||
|
||||
Args:
|
||||
callback_query (CallbackQuery): Incoming callback query indicating selected switch side.
|
||||
state (FSMContext): Finite State Machine context for the current user session.
|
||||
|
||||
Logs:
|
||||
Success or error messages with user identification.
|
||||
"""
|
||||
try:
|
||||
if callback_query.data == "sell_switch":
|
||||
side = "Sell"
|
||||
side_rus = "Продажа"
|
||||
else:
|
||||
side = "Buy"
|
||||
side_rus = "Покупка"
|
||||
|
||||
req = await rq.set_side(
|
||||
tg_id=callback_query.from_user.id, side=side
|
||||
)
|
||||
|
||||
if not req:
|
||||
await callback_query.answer(
|
||||
text="Произошла ошибка при смене направления. Пожалуйста, попробуйте позже."
|
||||
)
|
||||
return
|
||||
|
||||
await callback_query.answer(text=f"Выбрано: {side_rus}")
|
||||
logger.debug(
|
||||
"Switch side changed successfully for user: %s", callback_query.from_user.id
|
||||
)
|
||||
except Exception as e:
|
||||
await callback_query.answer(text="Произошла ошибка при смене направления.")
|
||||
logger.error(
|
||||
"Error processing set switch_side for user %s: %s",
|
||||
callback_query.from_user.id,
|
||||
e,
|
||||
)
|
||||
finally:
|
||||
await state.clear()
|
||||
|
||||
|
||||
@router_additional_settings.callback_query(F.data == "margin_type")
|
||||
async def settings_for_margin_type(
|
||||
callback_query: CallbackQuery, state: FSMContext
|
||||
|
||||
@@ -62,10 +62,19 @@ async def additional_settings(callback_query: CallbackQuery, state: FSMContext)
|
||||
max_bets = additional_data.max_bets_in_series
|
||||
quantity = f(additional_data.order_quantity)
|
||||
trigger_price = f(additional_data.trigger_price) or 0
|
||||
side = additional_data.side
|
||||
|
||||
side_map = {
|
||||
"Buy": "Лонг",
|
||||
"Sell": "Шорт",
|
||||
}
|
||||
side_rus = side_map.get(side, side)
|
||||
|
||||
switch_side_mode = ""
|
||||
side = ""
|
||||
if trade_mode == "Switch":
|
||||
switch_side_mode = f"- Направление первой сделки: {switch_side}\n"
|
||||
side = f"- Направление первой сделки: {side_rus}\n"
|
||||
switch_side_mode = f"- Направление первой сделки последующих серии: {switch_side}\n"
|
||||
|
||||
total_budget = await calculate_total_budget(
|
||||
quantity=quantity,
|
||||
@@ -75,6 +84,7 @@ async def additional_settings(callback_query: CallbackQuery, state: FSMContext)
|
||||
text = (
|
||||
f"Основные настройки:\n\n"
|
||||
f"- Режим торговли: {trade_mode_rus}\n"
|
||||
f"{side}"
|
||||
f"{switch_side_mode}"
|
||||
f"- Тип маржи: {margin_type_rus}\n"
|
||||
f"- Размер кредитного плеча: {leverage:.2f}\n"
|
||||
|
||||
@@ -94,7 +94,10 @@ def get_additional_settings_keyboard(mode: str
|
||||
|
||||
if mode == "Switch":
|
||||
buttons.append(
|
||||
[InlineKeyboardButton(text="Направление первой сделки", callback_data="switch_side_start")]
|
||||
[InlineKeyboardButton(text="Направление первой сделки первой серии", callback_data="switch_side_start")]
|
||||
)
|
||||
buttons.append(
|
||||
[InlineKeyboardButton(text="Направление первой сделки последующих серии", callback_data="switch_side_second")]
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
@@ -148,6 +151,19 @@ switch_side = InlineKeyboardMarkup(
|
||||
]
|
||||
)
|
||||
|
||||
side_for_switch = InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
InlineKeyboardButton(text="Лонг", callback_data="buy_switch"),
|
||||
InlineKeyboardButton(text="Шорт", callback_data="sell_switch"),
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton(text="Назад", callback_data="additional_settings"),
|
||||
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
margin_type = InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
|
||||
@@ -92,6 +92,7 @@ class UserAdditionalSettings(Base):
|
||||
nullable=False, unique=True)
|
||||
trade_mode = Column(String, nullable=False, default="Merged_Single")
|
||||
switch_side = Column(String, nullable=False, default="По направлению")
|
||||
side = Column(String, nullable=False, default="Buy")
|
||||
trigger_price = Column(Float, nullable=False, default=0.0)
|
||||
margin_type = Column(String, nullable=False, default="ISOLATED_MARGIN")
|
||||
leverage = Column(String, nullable=False, default="10")
|
||||
|
||||
@@ -358,6 +358,45 @@ async def set_switch_side(tg_id: int, switch_side: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
async def set_side(tg_id: int, side: str) -> bool:
|
||||
"""
|
||||
Set side for a user in the database.
|
||||
:param tg_id: Telegram user ID
|
||||
:param side: "BUY" or "SELL"
|
||||
:return: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
async with async_session() as session:
|
||||
result = await session.execute(
|
||||
select(User)
|
||||
.options(joinedload(User.user_additional_settings))
|
||||
.filter_by(tg_id=tg_id)
|
||||
)
|
||||
user = result.scalars().first()
|
||||
|
||||
if user:
|
||||
if user.user_additional_settings:
|
||||
# Updating existing record
|
||||
user.user_additional_settings.side = side
|
||||
else:
|
||||
# Creating new record
|
||||
user_additional_settings = UserAdditionalSettings(
|
||||
side=side,
|
||||
user=user,
|
||||
)
|
||||
session.add(user_additional_settings)
|
||||
|
||||
await session.commit()
|
||||
logger.info("User side updated for user: %s", tg_id)
|
||||
return True
|
||||
else:
|
||||
logger.error("User not found with tg_id: %s", tg_id)
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error("Error adding/updating user side for user %s: %s", tg_id, e)
|
||||
return False
|
||||
|
||||
|
||||
async def set_leverage(tg_id: int, leverage: str) -> bool:
|
||||
"""
|
||||
Set leverage for a user in the database.
|
||||
|
||||
Reference in New Issue
Block a user