Fixed
This commit is contained in:
@@ -22,7 +22,7 @@ async def get_active_positions(tg_id: int) -> list | None:
|
|||||||
]
|
]
|
||||||
if active_symbols:
|
if active_symbols:
|
||||||
logger.info("Active positions for user: %s", tg_id)
|
logger.info("Active positions for user: %s", tg_id)
|
||||||
return active_symbols
|
return positions
|
||||||
else:
|
else:
|
||||||
logger.warning("No active positions found for user: %s", tg_id)
|
logger.warning("No active positions found for user: %s", tg_id)
|
||||||
return ["No active positions found"]
|
return ["No active positions found"]
|
||||||
@@ -50,7 +50,7 @@ async def get_active_positions_by_symbol(tg_id: int, symbol: str) -> dict | None
|
|||||||
positions = response.get("result", {}).get("list", [])
|
positions = response.get("result", {}).get("list", [])
|
||||||
if positions:
|
if positions:
|
||||||
logger.info("Active positions for user: %s", tg_id)
|
logger.info("Active positions for user: %s", tg_id)
|
||||||
return positions[0]
|
return positions
|
||||||
else:
|
else:
|
||||||
logger.warning("No active positions found for user: %s", tg_id)
|
logger.warning("No active positions found for user: %s", tg_id)
|
||||||
return None
|
return None
|
||||||
@@ -85,7 +85,7 @@ async def get_active_orders(tg_id: int) -> list | None:
|
|||||||
]
|
]
|
||||||
if active_orders:
|
if active_orders:
|
||||||
logger.info("Active orders for user: %s", tg_id)
|
logger.info("Active orders for user: %s", tg_id)
|
||||||
return active_orders
|
return orders
|
||||||
else:
|
else:
|
||||||
logger.warning("No active orders found for user: %s", tg_id)
|
logger.warning("No active orders found for user: %s", tg_id)
|
||||||
return ["No active orders found"]
|
return ["No active orders found"]
|
||||||
@@ -115,7 +115,7 @@ async def get_active_orders_by_symbol(tg_id: int, symbol: str) -> dict | None:
|
|||||||
orders = response.get("result", {}).get("list", [])
|
orders = response.get("result", {}).get("list", [])
|
||||||
if orders:
|
if orders:
|
||||||
logger.info("Active orders for user: %s", tg_id)
|
logger.info("Active orders for user: %s", tg_id)
|
||||||
return orders[0]
|
return orders
|
||||||
else:
|
else:
|
||||||
logger.warning("No active orders found for user: %s", tg_id)
|
logger.warning("No active orders found for user: %s", tg_id)
|
||||||
return None
|
return None
|
||||||
|
@@ -169,6 +169,7 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str, size: str) -
|
|||||||
leverage=leverage,
|
leverage=leverage,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if reverse_side == "Buy":
|
if reverse_side == "Buy":
|
||||||
real_side = "Sell"
|
real_side = "Sell"
|
||||||
else:
|
else:
|
||||||
@@ -219,7 +220,7 @@ async def trading_cycle(tg_id: int, symbol: str, reverse_side: str, size: str) -
|
|||||||
leverage_to_sell=leverage_to_sell,
|
leverage_to_sell=leverage_to_sell,
|
||||||
order_type=order_type,
|
order_type=order_type,
|
||||||
conditional_order_type=conditional_order_type,
|
conditional_order_type=conditional_order_type,
|
||||||
order_quantity=current_step,
|
order_quantity=next_quantity,
|
||||||
limit_price=limit_price,
|
limit_price=limit_price,
|
||||||
trigger_price=trigger_price,
|
trigger_price=trigger_price,
|
||||||
martingale_factor=martingale_factor,
|
martingale_factor=martingale_factor,
|
||||||
@@ -258,9 +259,9 @@ async def open_positions(
|
|||||||
trigger_price: float,
|
trigger_price: float,
|
||||||
trade_mode: str,
|
trade_mode: str,
|
||||||
margin_type: str,
|
margin_type: str,
|
||||||
leverage: float,
|
leverage: str,
|
||||||
leverage_to_buy: float,
|
leverage_to_buy: str,
|
||||||
leverage_to_sell: float,
|
leverage_to_sell: str,
|
||||||
take_profit_percent: float,
|
take_profit_percent: float,
|
||||||
stop_loss_percent: float,
|
stop_loss_percent: float,
|
||||||
max_risk_percent: float,
|
max_risk_percent: float,
|
||||||
@@ -317,19 +318,22 @@ async def open_positions(
|
|||||||
|
|
||||||
if trade_mode == "Both_Sides":
|
if trade_mode == "Both_Sides":
|
||||||
po_position_idx = 1 if side == "Buy" else 2
|
po_position_idx = 1 if side == "Buy" else 2
|
||||||
leverage = safe_float(
|
if margin_type == "ISOLATED_MARGIN":
|
||||||
|
get_leverage = safe_float(
|
||||||
leverage_to_buy if side == "Buy" else leverage_to_sell
|
leverage_to_buy if side == "Buy" else leverage_to_sell
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
get_leverage = safe_float(leverage)
|
||||||
else:
|
else:
|
||||||
po_position_idx = 0
|
po_position_idx = 0
|
||||||
leverage = safe_float(leverage)
|
get_leverage = safe_float(leverage)
|
||||||
|
|
||||||
potential_loss = (
|
potential_loss = (
|
||||||
safe_float(order_quantity)
|
safe_float(order_quantity)
|
||||||
* safe_float(price_for_calc)
|
* safe_float(price_for_calc)
|
||||||
* (stop_loss_percent / 100)
|
* (stop_loss_percent / 100)
|
||||||
)
|
)
|
||||||
adjusted_loss = potential_loss / leverage
|
adjusted_loss = potential_loss / get_leverage
|
||||||
allowed_loss = safe_float(user_balance) * (max_risk_percent / 100)
|
allowed_loss = safe_float(user_balance) * (max_risk_percent / 100)
|
||||||
|
|
||||||
if adjusted_loss > allowed_loss:
|
if adjusted_loss > allowed_loss:
|
||||||
@@ -356,10 +360,11 @@ async def open_positions(
|
|||||||
entry_price=price_for_calc,
|
entry_price=price_for_calc,
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
order_quantity=order_quantity,
|
order_quantity=order_quantity,
|
||||||
|
leverage=get_leverage,
|
||||||
)
|
)
|
||||||
|
|
||||||
if liq_long > 0 or liq_short > 0 and price_for_calc > 0:
|
if (liq_long > 0 or liq_short > 0) and price_for_calc > 0:
|
||||||
if side.lower() == "buy":
|
if side == "Buy":
|
||||||
base_tp = price_for_calc + (price_for_calc - liq_long)
|
base_tp = price_for_calc + (price_for_calc - liq_long)
|
||||||
take_profit_price = base_tp + total_commission
|
take_profit_price = base_tp + total_commission
|
||||||
else:
|
else:
|
||||||
@@ -371,7 +376,7 @@ async def open_positions(
|
|||||||
|
|
||||||
stop_loss_price = None
|
stop_loss_price = None
|
||||||
else:
|
else:
|
||||||
if side.lower() == "buy":
|
if side == "Buy":
|
||||||
take_profit_price = price_for_calc * tp_multiplier
|
take_profit_price = price_for_calc * tp_multiplier
|
||||||
stop_loss_price = price_for_calc * (1 - stop_loss_percent / 100)
|
stop_loss_price = price_for_calc * (1 - stop_loss_percent / 100)
|
||||||
else:
|
else:
|
||||||
@@ -383,6 +388,7 @@ async def open_positions(
|
|||||||
take_profit_price = max(take_profit_price, 0)
|
take_profit_price = max(take_profit_price, 0)
|
||||||
stop_loss_price = max(stop_loss_price, 0)
|
stop_loss_price = max(stop_loss_price, 0)
|
||||||
|
|
||||||
|
|
||||||
# Place order
|
# Place order
|
||||||
order_params = {
|
order_params = {
|
||||||
"category": "linear",
|
"category": "linear",
|
||||||
|
@@ -43,6 +43,12 @@ async def set_switch_position_mode(tg_id: int, symbol: str, mode: int) -> str |
|
|||||||
tg_id,
|
tg_id,
|
||||||
)
|
)
|
||||||
return "You have an existing position, so position mode cannot be switched"
|
return "You have an existing position, so position mode cannot be switched"
|
||||||
|
if str(e).startswith("Open orders exist, so you cannot change position mode"):
|
||||||
|
logger.debug(
|
||||||
|
"Open orders exist, so you cannot change position mode for user: %s",
|
||||||
|
tg_id,
|
||||||
|
)
|
||||||
|
return "Open orders exist, so you cannot change position mode"
|
||||||
else:
|
else:
|
||||||
logger.error("Error connecting to Bybit for user %s: %s", tg_id, e)
|
logger.error("Error connecting to Bybit for user %s: %s", tg_id, e)
|
||||||
return False
|
return False
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import logging.config
|
import logging.config
|
||||||
|
|
||||||
from app.bybit import get_bybit_client
|
from app.bybit import get_bybit_client
|
||||||
from app.bybit.get_functions.get_positions import get_active_positions_by_symbol
|
|
||||||
from app.bybit.logger_bybit.logger_bybit import LOGGING_CONFIG
|
from app.bybit.logger_bybit.logger_bybit import LOGGING_CONFIG
|
||||||
|
|
||||||
logging.config.dictConfig(LOGGING_CONFIG)
|
logging.config.dictConfig(LOGGING_CONFIG)
|
||||||
@@ -13,6 +12,7 @@ async def set_tp_sl_for_position(
|
|||||||
symbol: str,
|
symbol: str,
|
||||||
take_profit_price: float,
|
take_profit_price: float,
|
||||||
stop_loss_price: float,
|
stop_loss_price: float,
|
||||||
|
position_idx: int,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Set take profit and stop loss for a symbol.
|
Set take profit and stop loss for a symbol.
|
||||||
@@ -20,14 +20,11 @@ async def set_tp_sl_for_position(
|
|||||||
:param symbol: Symbol to set take profit and stop loss for
|
:param symbol: Symbol to set take profit and stop loss for
|
||||||
:param take_profit_price: Take profit price
|
:param take_profit_price: Take profit price
|
||||||
:param stop_loss_price: Stop loss price
|
:param stop_loss_price: Stop loss price
|
||||||
|
:param position_idx: Position index
|
||||||
:return: bool
|
:return: bool
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
client = await get_bybit_client(tg_id)
|
client = await get_bybit_client(tg_id)
|
||||||
user_positions = await get_active_positions_by_symbol(
|
|
||||||
tg_id=tg_id, symbol=symbol
|
|
||||||
)
|
|
||||||
position_idx = user_positions.get("positionIdx")
|
|
||||||
resp = client.set_trading_stop(
|
resp = client.set_trading_stop(
|
||||||
category="linear",
|
category="linear",
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
|
@@ -106,12 +106,27 @@ class TelegramMessageHandler:
|
|||||||
if side == "Buy"
|
if side == "Buy"
|
||||||
else "Продажа" if side == "Sell" else "Нет данных"
|
else "Продажа" if side == "Sell" else "Нет данных"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if safe_float(closed_size) == 0:
|
||||||
|
await rq.set_fee_user_auto_trading(
|
||||||
|
tg_id=tg_id, symbol=symbol, side=side, fee=safe_float(exec_fee)
|
||||||
|
)
|
||||||
|
|
||||||
|
user_auto_trading = await rq.get_user_auto_trading(
|
||||||
|
tg_id=tg_id, symbol=symbol
|
||||||
|
)
|
||||||
|
|
||||||
|
if user_auto_trading is not None and user_auto_trading.fee is not None:
|
||||||
|
fee = user_auto_trading.fee
|
||||||
|
else:
|
||||||
|
fee = 0
|
||||||
|
|
||||||
exec_pnl = format_value(execution.get("execPnl"))
|
exec_pnl = format_value(execution.get("execPnl"))
|
||||||
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
|
||||||
|
|
||||||
if commission_fee == "Yes_commission_fee":
|
if commission_fee == "Yes_commission_fee":
|
||||||
total_pnl = safe_float(exec_pnl) - safe_float(exec_fee)
|
total_pnl = safe_float(exec_pnl) - safe_float(exec_fee) - fee
|
||||||
else:
|
else:
|
||||||
total_pnl = safe_float(exec_pnl)
|
total_pnl = safe_float(exec_pnl)
|
||||||
|
|
||||||
@@ -138,13 +153,12 @@ class TelegramMessageHandler:
|
|||||||
chat_id=tg_id, text=text, reply_markup=kbi.profile_bybit
|
chat_id=tg_id, text=text, reply_markup=kbi.profile_bybit
|
||||||
)
|
)
|
||||||
|
|
||||||
user_auto_trading = await rq.get_user_auto_trading(
|
|
||||||
tg_id=tg_id, symbol=symbol
|
|
||||||
)
|
|
||||||
auto_trading = (
|
auto_trading = (
|
||||||
user_auto_trading.auto_trading if user_auto_trading else False
|
user_auto_trading.auto_trading if user_auto_trading else False
|
||||||
)
|
)
|
||||||
user_symbols = await rq.get_user_deal_by_symbol(tg_id=tg_id, symbol=symbol)
|
user_symbols = (
|
||||||
|
user_auto_trading.symbol if user_auto_trading else None
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
auto_trading
|
auto_trading
|
||||||
@@ -152,20 +166,22 @@ class TelegramMessageHandler:
|
|||||||
and user_symbols is not None
|
and user_symbols is not None
|
||||||
):
|
):
|
||||||
if safe_float(total_pnl) > 0:
|
if safe_float(total_pnl) > 0:
|
||||||
await rq.set_auto_trading(
|
|
||||||
tg_id=tg_id, symbol=symbol, auto_trading=False
|
|
||||||
)
|
|
||||||
profit_text = "📈 Прибыль достигнута\n"
|
profit_text = "📈 Прибыль достигнута\n"
|
||||||
await self.telegram_bot.send_message(
|
await self.telegram_bot.send_message(
|
||||||
chat_id=tg_id, text=profit_text, reply_markup=kbi.profile_bybit
|
chat_id=tg_id, text=profit_text, reply_markup=kbi.profile_bybit
|
||||||
)
|
)
|
||||||
|
if side == "Buy":
|
||||||
|
r_side = "Sell"
|
||||||
|
else:
|
||||||
|
r_side = "Buy"
|
||||||
|
await rq.set_auto_trading(tg_id=tg_id, symbol=symbol, auto_trading=False, side=r_side)
|
||||||
else:
|
else:
|
||||||
open_order_text = "\n❗️ Сделка закрылась в минус, открываю новую сделку с увеличенной ставкой.\n"
|
open_order_text = "\n❗️ Сделка закрылась в минус, открываю новую сделку с увеличенной ставкой.\n"
|
||||||
await self.telegram_bot.send_message(
|
await self.telegram_bot.send_message(
|
||||||
chat_id=tg_id, text=open_order_text
|
chat_id=tg_id, text=open_order_text
|
||||||
)
|
)
|
||||||
res = await trading_cycle(
|
res = await trading_cycle(
|
||||||
tg_id=tg_id, symbol=symbol, reverse_side=side
|
tg_id=tg_id, symbol=symbol, reverse_side=side, size=closed_size
|
||||||
)
|
)
|
||||||
|
|
||||||
if res == "OK":
|
if res == "OK":
|
||||||
@@ -180,8 +196,12 @@ class TelegramMessageHandler:
|
|||||||
error_text = errors.get(
|
error_text = errors.get(
|
||||||
res, "❗️ Не удалось открыть новую сделку"
|
res, "❗️ Не удалось открыть новую сделку"
|
||||||
)
|
)
|
||||||
|
if side == "Buy":
|
||||||
|
r_side = "Sell"
|
||||||
|
else:
|
||||||
|
r_side = "Buy"
|
||||||
await rq.set_auto_trading(
|
await rq.set_auto_trading(
|
||||||
tg_id=tg_id, symbol=symbol, auto_trading=False
|
tg_id=tg_id, symbol=symbol, auto_trading=False, side=r_side
|
||||||
)
|
)
|
||||||
await self.telegram_bot.send_message(
|
await self.telegram_bot.send_message(
|
||||||
chat_id=tg_id,
|
chat_id=tg_id,
|
||||||
|
@@ -64,7 +64,6 @@ class WebSocketBot:
|
|||||||
channel_type="private",
|
channel_type="private",
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
api_secret=api_secret,
|
api_secret=api_secret,
|
||||||
restart_on_error=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.user_sockets[tg_id] = self.ws_private
|
self.user_sockets[tg_id] = self.ws_private
|
||||||
|
@@ -5,7 +5,7 @@ from aiogram.fsm.context import FSMContext
|
|||||||
from aiogram.types import CallbackQuery
|
from aiogram.types import CallbackQuery
|
||||||
|
|
||||||
import app.telegram.keyboards.inline as kbi
|
import app.telegram.keyboards.inline as kbi
|
||||||
import database.request as rq
|
|
||||||
from app.bybit.get_functions.get_positions import (
|
from app.bybit.get_functions.get_positions import (
|
||||||
get_active_orders,
|
get_active_orders,
|
||||||
get_active_orders_by_symbol,
|
get_active_orders_by_symbol,
|
||||||
@@ -22,7 +22,7 @@ router_get_positions_handlers = Router(name="get_positions_handlers")
|
|||||||
|
|
||||||
@router_get_positions_handlers.callback_query(F.data == "my_deals")
|
@router_get_positions_handlers.callback_query(F.data == "my_deals")
|
||||||
async def get_positions_handlers(
|
async def get_positions_handlers(
|
||||||
callback_query: CallbackQuery, state: FSMContext
|
callback_query: CallbackQuery, state: FSMContext
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Gets the user's active positions.
|
Gets the user's active positions.
|
||||||
@@ -43,7 +43,7 @@ async def get_positions_handlers(
|
|||||||
|
|
||||||
@router_get_positions_handlers.callback_query(F.data == "change_position")
|
@router_get_positions_handlers.callback_query(F.data == "change_position")
|
||||||
async def get_positions_handler(
|
async def get_positions_handler(
|
||||||
callback_query: CallbackQuery, state: FSMContext
|
callback_query: CallbackQuery, state: FSMContext
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Gets the user's active positions.
|
Gets the user's active positions.
|
||||||
@@ -64,9 +64,17 @@ async def get_positions_handler(
|
|||||||
await callback_query.answer(text="Нет активных позиций.")
|
await callback_query.answer(text="Нет активных позиций.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
active_positions = [pos for pos in res if float(pos.get("size", 0)) > 0]
|
||||||
|
|
||||||
|
if not active_positions:
|
||||||
|
await callback_query.answer(text="Нет активных позиций.")
|
||||||
|
return
|
||||||
|
|
||||||
|
active_symbols_sides = [(pos.get("symbol"), pos.get("side")) for pos in active_positions]
|
||||||
|
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text="Ваши активные позиции:",
|
text="Ваши активные позиции:",
|
||||||
reply_markup=kbi.create_active_positions_keyboard(res),
|
reply_markup=kbi.create_active_positions_keyboard(symbols=active_symbols_sides),
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error in get_positions_handler: %s", e)
|
logger.error("Error in get_positions_handler: %s", e)
|
||||||
@@ -82,7 +90,10 @@ async def get_positions_handler(
|
|||||||
)
|
)
|
||||||
async def get_position_handler(callback_query: CallbackQuery, state: FSMContext):
|
async def get_position_handler(callback_query: CallbackQuery, state: FSMContext):
|
||||||
try:
|
try:
|
||||||
symbol = callback_query.data.split("_", 2)[2]
|
data = callback_query.data
|
||||||
|
parts = data.split("_")
|
||||||
|
symbol = parts[2]
|
||||||
|
get_side = parts[3]
|
||||||
res = await get_active_positions_by_symbol(
|
res = await get_active_positions_by_symbol(
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol
|
tg_id=callback_query.from_user.id, symbol=symbol
|
||||||
)
|
)
|
||||||
@@ -93,26 +104,48 @@ async def get_position_handler(callback_query: CallbackQuery, state: FSMContext)
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
symbol = res.get("symbol") or "Нет данных"
|
position = next((pos for pos in res if pos.get("side") == get_side), None)
|
||||||
avg_price = res.get("avgPrice") or "Нет данных"
|
|
||||||
size = res.get("size") or "Нет данных"
|
if position:
|
||||||
side = res.get("side") or ""
|
side = position.get("side")
|
||||||
|
symbol = position.get("symbol") or "Нет данных"
|
||||||
|
avg_price = position.get("avgPrice") or "Нет данных"
|
||||||
|
size = position.get("size") or "Нет данных"
|
||||||
|
take_profit = position.get("takeProfit") or "Нет данных"
|
||||||
|
stop_loss = position.get("stopLoss") or "Нет данных"
|
||||||
|
position_idx = position.get("positionIdx")
|
||||||
|
else:
|
||||||
|
side = "Нет данных"
|
||||||
|
symbol = "Нет данных"
|
||||||
|
avg_price = "Нет данных"
|
||||||
|
size = "Нет данных"
|
||||||
|
take_profit = "Нет данных"
|
||||||
|
stop_loss = "Нет данных"
|
||||||
|
position_idx = "Нет данных"
|
||||||
|
|
||||||
side_rus = (
|
side_rus = (
|
||||||
"Покупка"
|
"Покупка"
|
||||||
if side == "Buy"
|
if side == "Buy"
|
||||||
else "Продажа" if side == "Sell" else "Нет данных"
|
else "Продажа" if side == "Sell" else "Нет данных"
|
||||||
)
|
)
|
||||||
take_profit = res.get("takeProfit") or "Нет данных"
|
|
||||||
stop_loss = res.get("stopLoss") or "Нет данных"
|
position_idx_rus = ("Односторонний" if position_idx == 0
|
||||||
|
else "Покупка в режиме хеджирования" if position_idx == 1
|
||||||
|
else "Продажа в режиме хеджирования" if position_idx == 2
|
||||||
|
else "Нет данных")
|
||||||
|
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text=f"Торговая пара: {symbol}\n"
|
text=f"Торговая пара: {symbol}\n"
|
||||||
f"Цена входа: {avg_price}\n"
|
f"Режим позиции: {position_idx_rus}\n"
|
||||||
f"Количество: {size}\n"
|
f"Цена входа: {avg_price}\n"
|
||||||
f"Движение: {side_rus}\n"
|
f"Количество: {size}\n"
|
||||||
f"Тейк-профит: {take_profit}\n"
|
f"Движение: {side_rus}\n"
|
||||||
f"Стоп-лосс: {stop_loss}\n",
|
f"Тейк-профит: {take_profit}\n"
|
||||||
reply_markup=kbi.make_close_position_keyboard(symbol_pos=symbol),
|
f"Стоп-лосс: {stop_loss}\n",
|
||||||
|
reply_markup=kbi.make_close_position_keyboard(symbol_pos=symbol,
|
||||||
|
side=side,
|
||||||
|
position_idx=position_idx,
|
||||||
|
qty=size),
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -126,7 +159,7 @@ async def get_position_handler(callback_query: CallbackQuery, state: FSMContext)
|
|||||||
|
|
||||||
@router_get_positions_handlers.callback_query(F.data == "open_orders")
|
@router_get_positions_handlers.callback_query(F.data == "open_orders")
|
||||||
async def get_open_orders_handler(
|
async def get_open_orders_handler(
|
||||||
callback_query: CallbackQuery, state: FSMContext
|
callback_query: CallbackQuery, state: FSMContext
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Gets the user's open orders.
|
Gets the user's open orders.
|
||||||
@@ -147,9 +180,17 @@ async def get_open_orders_handler(
|
|||||||
await callback_query.answer(text="Нет активных ордеров.")
|
await callback_query.answer(text="Нет активных ордеров.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
active_positions = [pos for pos in res if pos.get("orderStatus", 0) == "New"]
|
||||||
|
|
||||||
|
if not active_positions:
|
||||||
|
await callback_query.answer(text="Нет активных ордеров.")
|
||||||
|
return
|
||||||
|
|
||||||
|
active_orders_sides = [(pos.get("symbol"), pos.get("side")) for pos in active_positions]
|
||||||
|
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text="Ваши активные ордера:",
|
text="Ваши активные ордера:",
|
||||||
reply_markup=kbi.create_active_orders_keyboard(res),
|
reply_markup=kbi.create_active_orders_keyboard(orders=active_orders_sides),
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error in get_open_orders_handler: %s", e)
|
logger.error("Error in get_open_orders_handler: %s", e)
|
||||||
@@ -163,7 +204,10 @@ async def get_open_orders_handler(
|
|||||||
@router_get_positions_handlers.callback_query(lambda c: c.data.startswith("get_order_"))
|
@router_get_positions_handlers.callback_query(lambda c: c.data.startswith("get_order_"))
|
||||||
async def get_order_handler(callback_query: CallbackQuery, state: FSMContext):
|
async def get_order_handler(callback_query: CallbackQuery, state: FSMContext):
|
||||||
try:
|
try:
|
||||||
symbol = callback_query.data.split("_", 2)[2]
|
data = callback_query.data
|
||||||
|
parts = data.split("_")
|
||||||
|
symbol = parts[2]
|
||||||
|
get_side = parts[3]
|
||||||
res = await get_active_orders_by_symbol(
|
res = await get_active_orders_by_symbol(
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol
|
tg_id=callback_query.from_user.id, symbol=symbol
|
||||||
)
|
)
|
||||||
@@ -174,37 +218,52 @@ async def get_order_handler(callback_query: CallbackQuery, state: FSMContext):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
symbol = res.get("symbol") or "Нет данных"
|
orders = next((pos for pos in res if pos.get("side") == get_side), None)
|
||||||
price = res.get("price") or "Нет данных"
|
|
||||||
qty = res.get("qty") or "Нет данных"
|
if orders:
|
||||||
side = res.get("side") or ""
|
side = orders.get("side")
|
||||||
|
symbol = orders.get("symbol") or "Нет данных"
|
||||||
|
price = orders.get("price") or "Нет данных"
|
||||||
|
qty = orders.get("qty") or "Нет данных"
|
||||||
|
order_type = orders.get("orderType") or ""
|
||||||
|
trigger_price = orders.get("triggerPrice") or "Нет данных"
|
||||||
|
take_profit = orders.get("takeProfit") or "Нет данных"
|
||||||
|
stop_loss = orders.get("stopLoss") or "Нет данных"
|
||||||
|
order_id = orders.get("orderId")
|
||||||
|
else:
|
||||||
|
side = "Нет данных"
|
||||||
|
symbol = "Нет данных"
|
||||||
|
price = "Нет данных"
|
||||||
|
qty = "Нет данных"
|
||||||
|
order_type = "Нет данных"
|
||||||
|
trigger_price = "Нет данных"
|
||||||
|
take_profit = "Нет данных"
|
||||||
|
stop_loss = "Нет данных"
|
||||||
|
order_id = "Нет данных"
|
||||||
|
|
||||||
side_rus = (
|
side_rus = (
|
||||||
"Покупка"
|
"Покупка"
|
||||||
if side == "Buy"
|
if side == "Buy"
|
||||||
else "Продажа" if side == "Sell" else "Нет данных"
|
else "Продажа" if side == "Sell" else "Нет данных"
|
||||||
)
|
)
|
||||||
order_type = res.get("orderType") or ""
|
|
||||||
order_type_rus = (
|
order_type_rus = (
|
||||||
"Рыночный"
|
"Рыночный"
|
||||||
if order_type == "Market"
|
if order_type == "Market"
|
||||||
else "Лимитный" if order_type == "Limit" else "Нет данных"
|
else "Лимитный" if order_type == "Limit" else "Нет данных"
|
||||||
)
|
)
|
||||||
trigger_price = res.get("triggerPrice") or "Нет данных"
|
|
||||||
take_profit = res.get("takeProfit") or "Нет данных"
|
|
||||||
stop_loss = res.get("stopLoss") or "Нет данных"
|
|
||||||
|
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text=f"Торговая пара: {symbol}\n"
|
text=f"Торговая пара: {symbol}\n"
|
||||||
f"Цена: {price}\n"
|
f"Цена: {price}\n"
|
||||||
f"Количество: {qty}\n"
|
f"Количество: {qty}\n"
|
||||||
f"Движение: {side_rus}\n"
|
f"Движение: {side_rus}\n"
|
||||||
f"Тип ордера: {order_type_rus}\n"
|
f"Тип ордера: {order_type_rus}\n"
|
||||||
f"Триггер цена: {trigger_price}\n"
|
f"Триггер цена: {trigger_price}\n"
|
||||||
f"Тейк-профит: {take_profit}\n"
|
f"Тейк-профит: {take_profit}\n"
|
||||||
f"Стоп-лосс: {stop_loss}\n",
|
f"Стоп-лосс: {stop_loss}\n",
|
||||||
reply_markup=kbi.make_close_orders_keyboard(symbol_order=symbol),
|
reply_markup=kbi.make_close_orders_keyboard(symbol_order=symbol, order_id=order_id),
|
||||||
)
|
)
|
||||||
await rq.set_user_symbol(tg_id=callback_query.from_user.id, symbol=symbol)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error in get_order_handler: %s", e)
|
logger.error("Error in get_order_handler: %s", e)
|
||||||
await callback_query.answer(
|
await callback_query.answer(
|
||||||
|
@@ -124,6 +124,13 @@ async def trade_mode(callback_query: CallbackQuery, state: FSMContext) -> None:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if response == "Open orders exist, so you cannot change position mode":
|
||||||
|
await callback_query.answer(
|
||||||
|
text="У вас есть открытые ордера, "
|
||||||
|
"поэтому режим позиции не может быть изменен."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if callback_query.data.startswith("Merged_Single"):
|
if callback_query.data.startswith("Merged_Single"):
|
||||||
await callback_query.answer(text="Выбран режим позиции: Односторонний")
|
await callback_query.answer(text="Выбран режим позиции: Односторонний")
|
||||||
await set_leverage(
|
await set_leverage(
|
||||||
|
@@ -5,6 +5,8 @@ from aiogram import F, Router
|
|||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.types import CallbackQuery
|
from aiogram.types import CallbackQuery
|
||||||
|
|
||||||
|
from app.telegram.tasks.tasks import add_start_task_merged, cancel_start_task_merged, add_start_task_switch, \
|
||||||
|
cancel_start_task_switch
|
||||||
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_positions import get_active_positions_by_symbol
|
from app.bybit.get_functions.get_positions import get_active_positions_by_symbol
|
||||||
@@ -17,8 +19,6 @@ logger = logging.getLogger("start_trading")
|
|||||||
|
|
||||||
router_start_trading = Router(name="start_trading")
|
router_start_trading = Router(name="start_trading")
|
||||||
|
|
||||||
user_trade_tasks = {}
|
|
||||||
|
|
||||||
|
|
||||||
@router_start_trading.callback_query(F.data == "start_trading")
|
@router_start_trading.callback_query(F.data == "start_trading")
|
||||||
async def start_trading(callback_query: CallbackQuery, state: FSMContext) -> None:
|
async def start_trading(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||||
@@ -39,36 +39,41 @@ async def start_trading(callback_query: CallbackQuery, state: FSMContext) -> Non
|
|||||||
deals = await get_active_positions_by_symbol(
|
deals = await get_active_positions_by_symbol(
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol
|
tg_id=callback_query.from_user.id, symbol=symbol
|
||||||
)
|
)
|
||||||
size = deals.get("size") or 0
|
position = next((d for d in deals if d.get("symbol") == symbol), None)
|
||||||
position_idx = deals.get("positionIdx")
|
if position:
|
||||||
|
size = position.get("size", 0)
|
||||||
|
position_idx = position.get("positionIdx")
|
||||||
|
else:
|
||||||
|
size = 0
|
||||||
|
position_idx = None
|
||||||
|
|
||||||
if position_idx != 0 and safe_float(size) > 0 and trade_mode == "Merged_Single":
|
if position_idx != 0 and safe_float(size) > 0 and trade_mode == "Merged_Single":
|
||||||
await callback_query.answer(
|
await callback_query.answer(
|
||||||
text="У вас есть активная позиция в режиме хеджирования. "
|
text="У вас есть активная позиция в режиме хеджирования. "
|
||||||
"Открытие сделки в одностороннем режиме невозможно.",
|
"Открытие сделки в одностороннем режиме невозможно.",
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if position_idx == 0 and safe_float(size) > 0 and trade_mode == "Both_Sides":
|
if position_idx == 0 and safe_float(size) > 0 and trade_mode == "Both_Sides":
|
||||||
await callback_query.answer(
|
await callback_query.answer(
|
||||||
text="У вас есть активная позиция в одностороннем режиме. "
|
text="У вас есть активная позиция в одностороннем режиме. "
|
||||||
"Открытие сделки в режиме хеджирования невозможно.",
|
"Открытие сделки в режиме хеджирования невозможно.",
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if trade_mode == "Merged_Single":
|
if trade_mode == "Merged_Single":
|
||||||
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.merged_start_trading,
|
reply_markup=kbi.merged_start_trading,
|
||||||
)
|
)
|
||||||
else: # trade_mode == "Both_Sides":
|
else: # trade_mode == "Both_Sides":
|
||||||
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.both_start_trading,
|
reply_markup=kbi.both_start_trading,
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@@ -106,8 +111,13 @@ async def start_trading_long(callback_query: CallbackQuery, state: FSMContext) -
|
|||||||
deals = await get_active_positions_by_symbol(
|
deals = await get_active_positions_by_symbol(
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol
|
tg_id=callback_query.from_user.id, symbol=symbol
|
||||||
)
|
)
|
||||||
size = deals.get("size") or 0
|
position = next((d for d in deals if d.get("symbol") == symbol), None)
|
||||||
position_idx = deals.get("positionIdx")
|
if position:
|
||||||
|
size = position.get("size", 0)
|
||||||
|
position_idx = position.get("positionIdx")
|
||||||
|
else:
|
||||||
|
size = 0
|
||||||
|
position_idx = None
|
||||||
|
|
||||||
if position_idx == 0 and safe_float(size) > 0:
|
if position_idx == 0 and safe_float(size) > 0:
|
||||||
await callback_query.answer(
|
await callback_query.answer(
|
||||||
@@ -120,19 +130,22 @@ async def start_trading_long(callback_query: CallbackQuery, state: FSMContext) -
|
|||||||
)
|
)
|
||||||
timer_start = conditional_data.timer_start
|
timer_start = conditional_data.timer_start
|
||||||
|
|
||||||
if callback_query.from_user.id in user_trade_tasks:
|
cancel_start_task_merged(user_id=callback_query.from_user.id)
|
||||||
task = user_trade_tasks[callback_query.from_user.id]
|
|
||||||
if not task.done():
|
|
||||||
task.cancel()
|
|
||||||
del user_trade_tasks[callback_query.from_user.id]
|
|
||||||
|
|
||||||
async def delay_start():
|
async def delay_start():
|
||||||
if timer_start > 0:
|
if timer_start > 0:
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text=f"Торговля будет запущена с задержкой {timer_start} мин.",
|
text=f"Торговля будет запущена с задержкой {timer_start} мин.",
|
||||||
reply_markup=kbi.cancel_timer,
|
reply_markup=kbi.cancel_timer_merged,
|
||||||
|
)
|
||||||
|
await rq.set_start_timer(
|
||||||
|
tg_id=callback_query.from_user.id, timer_start=0
|
||||||
)
|
)
|
||||||
await asyncio.sleep(timer_start * 60)
|
await asyncio.sleep(timer_start * 60)
|
||||||
|
|
||||||
|
await rq.set_auto_trading(
|
||||||
|
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True, side=side
|
||||||
|
)
|
||||||
res = await start_trading_cycle(
|
res = await start_trading_cycle(
|
||||||
tg_id=callback_query.from_user.id,
|
tg_id=callback_query.from_user.id,
|
||||||
side=side,
|
side=side,
|
||||||
@@ -146,27 +159,24 @@ async def start_trading_long(callback_query: CallbackQuery, state: FSMContext) -
|
|||||||
"estimated will trigger liq": "Лимитный ордер может вызвать мгновенную ликвидацию. Проверьте параметры ордера.",
|
"estimated will trigger liq": "Лимитный ордер может вызвать мгновенную ликвидацию. Проверьте параметры ордера.",
|
||||||
"ab not enough for new order": "Недостаточно средств для создания нового ордера",
|
"ab not enough for new order": "Недостаточно средств для создания нового ордера",
|
||||||
"InvalidRequestError": "Произошла ошибка при запуске торговли.",
|
"InvalidRequestError": "Произошла ошибка при запуске торговли.",
|
||||||
"Order does not meet minimum order value": "Сумма ордера не sufficientдля запуска торговли",
|
"Order does not meet minimum order value": "Сумма ордера не достаточна для запуска торговли",
|
||||||
"position idx not match position mode": "Торговля уже запущена в режиме хеджирования на продажу для данного инструмента",
|
"position idx not match position mode": "Торговля уже запущена в режиме хеджирования на продажу для данного инструмента",
|
||||||
"Qty invalid": "Некорректное значение ордера для данного инструмента",
|
"Qty invalid": "Некорректное значение ордера для данного инструмента",
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == "OK":
|
if res == "OK":
|
||||||
await rq.set_start_timer(
|
|
||||||
tg_id=callback_query.from_user.id, timer_start=0
|
|
||||||
)
|
|
||||||
await rq.set_auto_trading(
|
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True
|
|
||||||
)
|
|
||||||
await callback_query.answer(text="Торговля запущена")
|
await callback_query.answer(text="Торговля запущена")
|
||||||
await state.clear()
|
await state.clear()
|
||||||
else:
|
else:
|
||||||
# Получаем сообщение из таблицы, или дефолтный текст
|
await rq.set_auto_trading(
|
||||||
|
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, side=side
|
||||||
|
)
|
||||||
text = error_messages.get(res, "Произошла ошибка при запуске торговли")
|
text = error_messages.get(res, "Произошла ошибка при запуске торговли")
|
||||||
await callback_query.answer(text=text)
|
await callback_query.answer(text=text)
|
||||||
|
|
||||||
|
await callback_query.message.edit_text("Запуск торговли...")
|
||||||
task = asyncio.create_task(delay_start())
|
task = asyncio.create_task(delay_start())
|
||||||
user_trade_tasks[callback_query.from_user.id] = task
|
await add_start_task_merged(user_id=callback_query.from_user.id, task=task)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await callback_query.answer(text="Произошла ошибка при запуске торговли")
|
await callback_query.answer(text="Произошла ошибка при запуске торговли")
|
||||||
@@ -181,7 +191,7 @@ async def start_trading_long(callback_query: CallbackQuery, state: FSMContext) -
|
|||||||
|
|
||||||
@router_start_trading.callback_query(lambda c: c.data == "switch")
|
@router_start_trading.callback_query(lambda c: c.data == "switch")
|
||||||
async def start_trading_switch(
|
async def start_trading_switch(
|
||||||
callback_query: CallbackQuery, state: FSMContext
|
callback_query: CallbackQuery, state: FSMContext
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Handles the "switch" callback query.
|
Handles the "switch" callback query.
|
||||||
@@ -194,10 +204,10 @@ async def start_trading_switch(
|
|||||||
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"
|
||||||
"Противоположно - сделка открывается в противоположном направлении последней сделки предыдущей серии.\n",
|
"Противоположно - сделка открывается в противоположном направлении последней сделки предыдущей серии.\n",
|
||||||
reply_markup=kbi.switch_side,
|
reply_markup=kbi.switch_side,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -211,7 +221,7 @@ async def start_trading_switch(
|
|||||||
|
|
||||||
@router_start_trading.callback_query(
|
@router_start_trading.callback_query(
|
||||||
lambda c: c.data
|
lambda c: c.data
|
||||||
in {"switch_long", "switch_short", "switch_direction", "switch_opposite"}
|
in {"switch_long", "switch_short", "switch_direction", "switch_opposite"}
|
||||||
)
|
)
|
||||||
async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None:
|
async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -249,8 +259,13 @@ async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None
|
|||||||
deals = await get_active_positions_by_symbol(
|
deals = await get_active_positions_by_symbol(
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol
|
tg_id=callback_query.from_user.id, symbol=symbol
|
||||||
)
|
)
|
||||||
size = deals.get("size") or 0
|
position = next((d for d in deals if d.get("symbol") == symbol), None)
|
||||||
position_idx = deals.get("positionIdx")
|
if position:
|
||||||
|
size = position.get("size", 0)
|
||||||
|
position_idx = position.get("positionIdx")
|
||||||
|
else:
|
||||||
|
size = 0
|
||||||
|
position_idx = None
|
||||||
|
|
||||||
if position_idx == 1 and safe_float(size) > 0 and side == "Buy":
|
if position_idx == 1 and safe_float(size) > 0 and side == "Buy":
|
||||||
await callback_query.answer(
|
await callback_query.answer(
|
||||||
@@ -269,19 +284,21 @@ async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None
|
|||||||
)
|
)
|
||||||
timer_start = conditional_data.timer_start
|
timer_start = conditional_data.timer_start
|
||||||
|
|
||||||
if callback_query.from_user.id in user_trade_tasks:
|
cancel_start_task_switch(user_id=callback_query.from_user.id)
|
||||||
task = user_trade_tasks[callback_query.from_user.id]
|
|
||||||
if not task.done():
|
|
||||||
task.cancel()
|
|
||||||
del user_trade_tasks[callback_query.from_user.id]
|
|
||||||
|
|
||||||
async def delay_start():
|
async def delay_start():
|
||||||
if timer_start > 0:
|
if timer_start > 0:
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text=f"Торговля будет запущена с задержкой {timer_start} мин.",
|
text=f"Торговля будет запущена с задержкой {timer_start} мин.",
|
||||||
reply_markup=kbi.cancel_timer,
|
reply_markup=kbi.cancel_timer_switch,
|
||||||
|
)
|
||||||
|
await rq.set_start_timer(
|
||||||
|
tg_id=callback_query.from_user.id, timer_start=0
|
||||||
)
|
)
|
||||||
await asyncio.sleep(timer_start * 60)
|
await asyncio.sleep(timer_start * 60)
|
||||||
|
await rq.set_auto_trading(
|
||||||
|
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True, side=side
|
||||||
|
)
|
||||||
res = await start_trading_cycle(
|
res = await start_trading_cycle(
|
||||||
tg_id=callback_query.from_user.id,
|
tg_id=callback_query.from_user.id,
|
||||||
side=side,
|
side=side,
|
||||||
@@ -295,26 +312,24 @@ async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None
|
|||||||
"estimated will trigger liq": "Лимитный ордер может вызвать мгновенную ликвидацию. Проверьте параметры ордера.",
|
"estimated will trigger liq": "Лимитный ордер может вызвать мгновенную ликвидацию. Проверьте параметры ордера.",
|
||||||
"ab not enough for new order": "Недостаточно средств для создания нового ордера",
|
"ab not enough for new order": "Недостаточно средств для создания нового ордера",
|
||||||
"InvalidRequestError": "Произошла ошибка при запуске торговли.",
|
"InvalidRequestError": "Произошла ошибка при запуске торговли.",
|
||||||
"Order does not meet minimum order value": "Сумма ордера не sufficientдля запуска торговли",
|
"Order does not meet minimum order value": "Сумма ордера не достаточна для запуска торговли",
|
||||||
"position idx not match position mode": "Торговля уже запущена в режиме хеджирования на продажу для данного инструмента",
|
"position idx not match position mode": "Торговля уже запущена в режиме хеджирования на продажу для данного инструмента",
|
||||||
"Qty invalid": "Некорректное значение ордера для данного инструмента",
|
"Qty invalid": "Некорректное значение ордера для данного инструмента",
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == "OK":
|
if res == "OK":
|
||||||
await rq.set_start_timer(
|
|
||||||
tg_id=callback_query.from_user.id, timer_start=0
|
|
||||||
)
|
|
||||||
await rq.set_auto_trading(
|
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=True
|
|
||||||
)
|
|
||||||
await callback_query.answer(text="Торговля запущена")
|
await callback_query.answer(text="Торговля запущена")
|
||||||
await state.clear()
|
await state.clear()
|
||||||
else:
|
else:
|
||||||
|
await rq.set_auto_trading(
|
||||||
|
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, side=side
|
||||||
|
)
|
||||||
text = error_messages.get(res, "Произошла ошибка при запуске торговли")
|
text = error_messages.get(res, "Произошла ошибка при запуске торговли")
|
||||||
await callback_query.answer(text=text)
|
await callback_query.answer(text=text)
|
||||||
|
|
||||||
|
await callback_query.message.edit_text("Запуск торговли...")
|
||||||
task = asyncio.create_task(delay_start())
|
task = asyncio.create_task(delay_start())
|
||||||
user_trade_tasks[callback_query.from_user.id] = task
|
await add_start_task_switch(user_id=callback_query.from_user.id, task=task)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.error("Cancelled timer for user %s", callback_query.from_user.id)
|
logger.error("Cancelled timer for user %s", callback_query.from_user.id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -326,9 +341,9 @@ async def start_switch(callback_query: CallbackQuery, state: FSMContext) -> None
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router_start_trading.callback_query(F.data == "cancel_timer")
|
@router_start_trading.callback_query(lambda c: c.data == "cancel_timer_merged" or c.data == "cancel_timer_switch")
|
||||||
async def cancel_start_trading(
|
async def cancel_start_trading(
|
||||||
callback_query: CallbackQuery, state: FSMContext
|
callback_query: CallbackQuery, state: FSMContext
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Handles the "cancel_timer" callback query.
|
Handles the "cancel_timer" callback query.
|
||||||
@@ -338,21 +353,12 @@ async def cancel_start_trading(
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
task = user_trade_tasks.get(callback_query.from_user.id)
|
await state.clear()
|
||||||
if task and not task.done():
|
if callback_query.data == "cancel_timer_merged":
|
||||||
task.cancel()
|
cancel_start_task_merged(user_id=callback_query.from_user.id)
|
||||||
try:
|
elif callback_query.data == "cancel_timer_switch":
|
||||||
await task
|
cancel_start_task_switch(user_id=callback_query.from_user.id)
|
||||||
except asyncio.CancelledError:
|
await callback_query.message.edit_text(text="Запуск торговли отменен", reply_markup=kbi.profile_bybit)
|
||||||
pass
|
|
||||||
user_trade_tasks.pop(callback_query.from_user.id, None)
|
|
||||||
await callback_query.message.edit_text(
|
|
||||||
"Таймер отменён.", reply_markup=kbi.profile_bybit
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await callback_query.message.edit_text(
|
|
||||||
"Таймер не запущен.", reply_markup=kbi.profile_bybit
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await callback_query.answer("Произошла ошибка при отмене запуска торговли")
|
await callback_query.answer("Произошла ошибка при отмене запуска торговли")
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -360,5 +366,3 @@ async def cancel_start_trading(
|
|||||||
callback_query.from_user.id,
|
callback_query.from_user.id,
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
finally:
|
|
||||||
await state.clear()
|
|
||||||
|
@@ -7,7 +7,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.close_positions import cancel_order, close_position
|
from app.telegram.tasks.tasks import add_stop_task, cancel_stop_task
|
||||||
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)
|
||||||
@@ -15,50 +15,46 @@ logger = logging.getLogger("stop_trading")
|
|||||||
|
|
||||||
router_stop_trading = Router(name="stop_trading")
|
router_stop_trading = Router(name="stop_trading")
|
||||||
|
|
||||||
user_trade_tasks = {}
|
|
||||||
|
|
||||||
|
|
||||||
@router_stop_trading.callback_query(F.data == "stop_trading")
|
@router_stop_trading.callback_query(F.data == "stop_trading")
|
||||||
async def stop_trading(callback_query: CallbackQuery, state: FSMContext):
|
async def stop_all_trading(callback_query: CallbackQuery, state: FSMContext):
|
||||||
try:
|
try:
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
if callback_query.from_user.id in user_trade_tasks:
|
cancel_stop_task(callback_query.from_user.id)
|
||||||
task = user_trade_tasks[callback_query.from_user.id]
|
|
||||||
if not task.done():
|
|
||||||
task.cancel()
|
|
||||||
del user_trade_tasks[callback_query.from_user.id]
|
|
||||||
|
|
||||||
conditional_data = await rq.get_user_conditional_settings(
|
conditional_data = await rq.get_user_conditional_settings(
|
||||||
tg_id=callback_query.from_user.id
|
tg_id=callback_query.from_user.id
|
||||||
)
|
)
|
||||||
timer_end = conditional_data.timer_end
|
timer_end = conditional_data.timer_end
|
||||||
symbols = await rq.get_all_symbols(tg_id=callback_query.from_user.id)
|
|
||||||
|
|
||||||
async def delay_start():
|
async def delay_start():
|
||||||
if timer_end > 0:
|
if timer_end > 0:
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
text=f"Торговля будет остановлена с задержкой {timer_end} мин.",
|
text=f"Торговля будет остановлена с задержкой {timer_end} мин.",
|
||||||
reply_markup=kbi.cancel_timer,
|
reply_markup=kbi.cancel_timer_stop,
|
||||||
)
|
)
|
||||||
|
await rq.set_stop_timer(tg_id=callback_query.from_user.id, timer_end=0)
|
||||||
await asyncio.sleep(timer_end * 60)
|
await asyncio.sleep(timer_end * 60)
|
||||||
|
|
||||||
for symbol in symbols:
|
user_auto_trading_list = await rq.get_all_user_auto_trading(tg_id=callback_query.from_user.id)
|
||||||
auto_trading_data = await rq.get_user_auto_trading(
|
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol
|
|
||||||
)
|
|
||||||
if auto_trading_data is not None and auto_trading_data.auto_trading:
|
|
||||||
await close_position(tg_id=callback_query.from_user.id, symbol=symbol)
|
|
||||||
await cancel_order(tg_id=callback_query.from_user.id, symbol=symbol)
|
|
||||||
await rq.set_auto_trading(
|
|
||||||
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False
|
|
||||||
)
|
|
||||||
|
|
||||||
await callback_query.answer(text="Торговля остановлена")
|
for active_auto_trading in user_auto_trading_list:
|
||||||
await rq.set_stop_timer(tg_id=callback_query.from_user.id, timer_end=0)
|
if active_auto_trading.auto_trading:
|
||||||
|
symbol = active_auto_trading.symbol
|
||||||
|
get_side = active_auto_trading.side
|
||||||
|
req = await rq.set_auto_trading(
|
||||||
|
tg_id=callback_query.from_user.id, symbol=symbol, auto_trading=False, side=get_side
|
||||||
|
)
|
||||||
|
if not req:
|
||||||
|
await callback_query.edit_text(text="Произошла ошибка при остановке торговли",
|
||||||
|
reply_markup=kbi.profile_bybit)
|
||||||
|
return
|
||||||
|
|
||||||
|
await callback_query.message.edit_text(text="Торговля остановлена", reply_markup=kbi.profile_bybit)
|
||||||
|
|
||||||
task = asyncio.create_task(delay_start())
|
task = asyncio.create_task(delay_start())
|
||||||
user_trade_tasks[callback_query.from_user.id] = task
|
await add_stop_task(user_id=callback_query.from_user.id, task=task)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Command stop_trading processed successfully for user: %s",
|
"Command stop_trading processed successfully for user: %s",
|
||||||
@@ -71,3 +67,18 @@ async def stop_trading(callback_query: CallbackQuery, state: FSMContext):
|
|||||||
callback_query.from_user.id,
|
callback_query.from_user.id,
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router_stop_trading.callback_query(F.data == "cancel_timer_stop")
|
||||||
|
async def cancel_stop_trading(callback_query: CallbackQuery, state: FSMContext):
|
||||||
|
try:
|
||||||
|
await state.clear()
|
||||||
|
cancel_stop_task(callback_query.from_user.id)
|
||||||
|
await callback_query.message.edit_text(text="Таймер отменён.", reply_markup=kbi.profile_bybit)
|
||||||
|
except Exception as e:
|
||||||
|
await callback_query.answer(text="Произошла ошибка при отмене остановки торговли")
|
||||||
|
logger.error(
|
||||||
|
"Error processing command cancel_timer_stop for user %s: %s",
|
||||||
|
callback_query.from_user.id,
|
||||||
|
e,
|
||||||
|
)
|
@@ -29,9 +29,14 @@ async def set_tp_sl_handler(callback_query: CallbackQuery, state: FSMContext) ->
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await state.clear()
|
await state.clear()
|
||||||
symbol = callback_query.data.split("_", 3)[3]
|
data = callback_query.data
|
||||||
|
parts = data.split("_")
|
||||||
|
symbol = parts[3]
|
||||||
|
position_idx = int(parts[4])
|
||||||
|
|
||||||
await state.set_state(SetTradingStopState.take_profit_state)
|
await state.set_state(SetTradingStopState.take_profit_state)
|
||||||
await state.update_data(symbol=symbol)
|
await state.update_data(symbol=symbol)
|
||||||
|
await state.update_data(position_idx=position_idx)
|
||||||
msg = await callback_query.message.answer(
|
msg = await callback_query.message.answer(
|
||||||
text="Введите тейк-профит:", reply_markup=kbi.cancel
|
text="Введите тейк-профит:", reply_markup=kbi.cancel
|
||||||
)
|
)
|
||||||
@@ -142,11 +147,13 @@ async def set_stop_loss_handler(message: Message, state: FSMContext) -> None:
|
|||||||
data = await state.get_data()
|
data = await state.get_data()
|
||||||
symbol = data["symbol"]
|
symbol = data["symbol"]
|
||||||
take_profit = data["take_profit"]
|
take_profit = data["take_profit"]
|
||||||
|
position_idx = data["position_idx"]
|
||||||
res = await set_tp_sl_for_position(
|
res = await set_tp_sl_for_position(
|
||||||
tg_id=message.from_user.id,
|
tg_id=message.from_user.id,
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
take_profit_price=float(take_profit),
|
take_profit_price=float(take_profit),
|
||||||
stop_loss_price=float(stop_loss),
|
stop_loss_price=float(stop_loss),
|
||||||
|
position_idx=position_idx,
|
||||||
)
|
)
|
||||||
|
|
||||||
if res:
|
if res:
|
||||||
|
@@ -39,7 +39,7 @@ main_menu = InlineKeyboardMarkup(
|
|||||||
[InlineKeyboardButton(text="Начать торговлю", callback_data="start_trading")],
|
[InlineKeyboardButton(text="Начать торговлю", callback_data="start_trading")],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text="Остановить торговлю", callback_data="stop_trading"
|
text="Остановить торговлю", callback_data="trading_stop"
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
@@ -327,58 +327,57 @@ change_position = InlineKeyboardMarkup(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_active_positions_keyboard(symbols):
|
def create_active_positions_keyboard(symbols: list):
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
for sym in symbols:
|
for sym, side in symbols:
|
||||||
builder.button(text=f"{sym}", callback_data=f"get_position_{sym}")
|
builder.button(text=f"{sym}:{side}", callback_data=f"get_position_{sym}_{side}")
|
||||||
builder.button(text="Назад", callback_data="my_deals")
|
builder.button(text="Назад", callback_data="my_deals")
|
||||||
builder.button(text="На главную", callback_data="profile_bybit")
|
builder.button(text="На главную", callback_data="profile_bybit")
|
||||||
builder.adjust(2)
|
builder.adjust(2)
|
||||||
return builder.as_markup()
|
return builder.as_markup()
|
||||||
|
|
||||||
|
|
||||||
def make_close_position_keyboard(symbol_pos: str):
|
def make_close_position_keyboard(symbol_pos: str, side: str, position_idx: int, qty: int):
|
||||||
return InlineKeyboardMarkup(
|
return InlineKeyboardMarkup(
|
||||||
inline_keyboard=[
|
inline_keyboard=[
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text="Закрыть позицию", callback_data=f"close_position_{symbol_pos}"
|
text="Закрыть позицию", callback_data=f"close_position_{symbol_pos}_{side}_{position_idx}_{qty}"
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text="Установить TP/SL", callback_data=f"pos_tp_sl_{symbol_pos}"
|
text="Установить TP/SL", callback_data=f"pos_tp_sl_{symbol_pos}_{position_idx}"
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(text="Назад", callback_data="my_deals"),
|
InlineKeyboardButton(text="Назад", callback_data="change_position"),
|
||||||
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_active_orders_keyboard(orders):
|
def create_active_orders_keyboard(orders:list):
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
for order in orders:
|
for order, side in orders:
|
||||||
builder.button(text=f"{order}", callback_data=f"get_order_{order}")
|
builder.button(text=f"{order}", callback_data=f"get_order_{order}_{side}")
|
||||||
builder.button(text="Закрыть все ордера", callback_data="cancel_all_orders")
|
|
||||||
builder.button(text="Назад", callback_data="my_deals")
|
builder.button(text="Назад", callback_data="my_deals")
|
||||||
builder.button(text="На главную", callback_data="profile_bybit")
|
builder.button(text="На главную", callback_data="profile_bybit")
|
||||||
builder.adjust(2)
|
builder.adjust(2)
|
||||||
return builder.as_markup()
|
return builder.as_markup()
|
||||||
|
|
||||||
|
|
||||||
def make_close_orders_keyboard(symbol_order: str):
|
def make_close_orders_keyboard(symbol_order: str, order_id: str):
|
||||||
return InlineKeyboardMarkup(
|
return InlineKeyboardMarkup(
|
||||||
inline_keyboard=[
|
inline_keyboard=[
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text="Закрыть ордер", callback_data=f"close_order_{symbol_order}"
|
text="Закрыть ордер", callback_data=f"close_order_{symbol_order}_{order_id}"
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(text="Назад", callback_data="my_deals"),
|
InlineKeyboardButton(text="Назад", callback_data="open_orders"),
|
||||||
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
@@ -438,12 +437,31 @@ back_to_start_trading = InlineKeyboardMarkup(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
cancel_timer = InlineKeyboardMarkup(
|
cancel_timer_merged = InlineKeyboardMarkup(
|
||||||
inline_keyboard=[
|
inline_keyboard=[
|
||||||
[InlineKeyboardButton(text="Отменить таймер", callback_data="cancel_timer")],
|
[InlineKeyboardButton(text="Отменить таймер", callback_data="cancel_timer_merged")],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(text="Назад", callback_data="conditions"),
|
|
||||||
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cancel_timer_switch = InlineKeyboardMarkup(
|
||||||
|
inline_keyboard=[
|
||||||
|
[InlineKeyboardButton(text="Отменить таймер", callback_data="cancel_timer_switch")],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# STOP TRADING
|
||||||
|
|
||||||
|
cancel_timer_stop = InlineKeyboardMarkup(
|
||||||
|
inline_keyboard=[
|
||||||
|
[InlineKeyboardButton(text="Отменить таймер", callback_data="cancel_timer_stop")],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(text="На главную", callback_data="profile_bybit"),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
)
|
@@ -166,7 +166,6 @@ class UserDeals(Base):
|
|||||||
switch_side_mode = Column(Boolean, nullable=True)
|
switch_side_mode = Column(Boolean, nullable=True)
|
||||||
limit_price = Column(Float, nullable=True)
|
limit_price = Column(Float, nullable=True)
|
||||||
trigger_price = Column(Float, nullable=True)
|
trigger_price = Column(Float, nullable=True)
|
||||||
fee = Column(Float, nullable=True)
|
|
||||||
|
|
||||||
user = relationship("User", back_populates="user_deals")
|
user = relationship("User", back_populates="user_deals")
|
||||||
|
|
||||||
@@ -185,9 +184,7 @@ class UserAutoTrading(Base):
|
|||||||
nullable=False)
|
nullable=False)
|
||||||
symbol = Column(String, nullable=True)
|
symbol = Column(String, nullable=True)
|
||||||
auto_trading = Column(Boolean, nullable=True)
|
auto_trading = Column(Boolean, nullable=True)
|
||||||
|
side = Column(String, nullable=True)
|
||||||
|
fee = Column(Float, nullable=True)
|
||||||
|
|
||||||
user = relationship("User", back_populates="user_auto_trading")
|
user = relationship("User", back_populates="user_auto_trading")
|
||||||
|
|
||||||
__table_args__ = (
|
|
||||||
UniqueConstraint('user_id', 'symbol', name='uq_user_auto_trading_symbol'),
|
|
||||||
)
|
|
@@ -446,7 +446,7 @@ async def set_leverage(tg_id: int, leverage: str) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
async def set_leverage_to_buy_and_sell(
|
async def set_leverage_to_buy_and_sell(
|
||||||
tg_id: int, leverage_to_buy: str, leverage_to_sell: str
|
tg_id: int, leverage_to_buy: str, leverage_to_sell: str
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Set leverage for a user in the database.
|
Set leverage for a user in the database.
|
||||||
@@ -1066,26 +1066,26 @@ 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,
|
||||||
leverage_to_buy: str,
|
leverage_to_buy: str,
|
||||||
leverage_to_sell: str,
|
leverage_to_sell: str,
|
||||||
order_type: str,
|
order_type: str,
|
||||||
conditional_order_type: str,
|
conditional_order_type: str,
|
||||||
order_quantity: float,
|
order_quantity: float,
|
||||||
limit_price: float,
|
limit_price: 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,
|
||||||
max_risk_percent: int,
|
max_risk_percent: int,
|
||||||
switch_side_mode: bool,
|
switch_side_mode: bool,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Set the user deal in the database.
|
Set the user deal in the database.
|
||||||
@@ -1249,6 +1249,25 @@ async def set_fee_user_deal_by_symbol(tg_id: int, symbol: str, fee: float):
|
|||||||
|
|
||||||
# USER AUTO TRADING
|
# USER AUTO TRADING
|
||||||
|
|
||||||
|
async def get_all_user_auto_trading(tg_id: int):
|
||||||
|
"""Get all user auto trading from the database asynchronously."""
|
||||||
|
try:
|
||||||
|
async with async_session() as session:
|
||||||
|
result_user = await session.execute(select(User).filter_by(tg_id=tg_id))
|
||||||
|
user = result_user.scalars().first()
|
||||||
|
if not user:
|
||||||
|
return []
|
||||||
|
|
||||||
|
result_auto_trading = await session.execute(
|
||||||
|
select(UserAutoTrading).filter_by(user_id=user.id)
|
||||||
|
)
|
||||||
|
auto_trading = result_auto_trading.scalars().all()
|
||||||
|
return auto_trading
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error getting auto trading for user %s: %s", tg_id, e)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
async def get_user_auto_trading(tg_id: int, symbol: str):
|
async def get_user_auto_trading(tg_id: int, symbol: str):
|
||||||
"""Get user auto trading from the database asynchronously."""
|
"""Get user auto trading from the database asynchronously."""
|
||||||
try:
|
try:
|
||||||
@@ -1268,12 +1287,13 @@ async def get_user_auto_trading(tg_id: int, symbol: str):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def set_auto_trading(tg_id: int, symbol: str, auto_trading: bool) -> bool:
|
async def set_auto_trading(tg_id: int, symbol: str, auto_trading: bool, side: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Set the auto trading for a user in the database.
|
Set the auto trading for a user in the database.
|
||||||
:param tg_id: Telegram user ID
|
:param tg_id: Telegram user ID
|
||||||
:param symbol: Symbol
|
:param symbol: Symbol
|
||||||
:param auto_trading: Auto trading
|
:param auto_trading: Auto trading
|
||||||
|
:param side: Side
|
||||||
:return: bool
|
:return: bool
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@@ -1285,7 +1305,7 @@ async def set_auto_trading(tg_id: int, symbol: str, auto_trading: bool) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(UserAutoTrading).filter_by(user_id=user.id, symbol=symbol)
|
select(UserAutoTrading).filter_by(user_id=user.id, symbol=symbol, side=side)
|
||||||
)
|
)
|
||||||
record = result.scalars().first()
|
record = result.scalars().first()
|
||||||
if record:
|
if record:
|
||||||
@@ -1294,7 +1314,8 @@ async def set_auto_trading(tg_id: int, symbol: str, auto_trading: bool) -> bool:
|
|||||||
new_record = UserAutoTrading(
|
new_record = UserAutoTrading(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
auto_trading=auto_trading
|
auto_trading=auto_trading,
|
||||||
|
side=side
|
||||||
)
|
)
|
||||||
session.add(new_record)
|
session.add(new_record)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
@@ -1302,4 +1323,44 @@ async def set_auto_trading(tg_id: int, symbol: str, auto_trading: bool) -> bool:
|
|||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error setting auto_trading for user %s and symbol %s: %s", tg_id, symbol, e)
|
logger.error("Error setting auto_trading for user %s and symbol %s: %s", tg_id, symbol, e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def set_fee_user_auto_trading(tg_id: int, symbol: str, side: str, fee: float) -> bool:
|
||||||
|
"""
|
||||||
|
Set the fee for a user auto trading in the database.
|
||||||
|
:param tg_id:
|
||||||
|
:param symbol:
|
||||||
|
:param side:
|
||||||
|
:param fee:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
async with async_session() as session:
|
||||||
|
result = await session.execute(select(User).filter_by(tg_id=tg_id))
|
||||||
|
user = result.scalars().first()
|
||||||
|
if user is None:
|
||||||
|
logger.error(f"User with tg_id={tg_id} not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
result = await session.execute(
|
||||||
|
select(UserAutoTrading).filter_by(user_id=user.id, symbol=symbol, side=side)
|
||||||
|
)
|
||||||
|
record = result.scalars().first()
|
||||||
|
|
||||||
|
if record:
|
||||||
|
record.fee = fee
|
||||||
|
else:
|
||||||
|
user_fee = UserAutoTrading(
|
||||||
|
user_id=user.id,
|
||||||
|
symbol=symbol,
|
||||||
|
fee=fee,
|
||||||
|
side=side
|
||||||
|
)
|
||||||
|
session.add(user_fee)
|
||||||
|
await session.commit()
|
||||||
|
logger.info("Set fee for user %s and symbol %s", tg_id, symbol)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error setting user auto trading fee for user %s and symbol %s: %s", tg_id, symbol, e)
|
||||||
|
return False
|
||||||
|
@@ -110,6 +110,11 @@ LOGGING_CONFIG = {
|
|||||||
"level": "DEBUG",
|
"level": "DEBUG",
|
||||||
"propagate": False,
|
"propagate": False,
|
||||||
},
|
},
|
||||||
|
"stop_trading": {
|
||||||
|
"handlers": ["console", "timed_rotating_file", "error_file"],
|
||||||
|
"level": "DEBUG",
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
"changing_the_symbol": {
|
"changing_the_symbol": {
|
||||||
"handlers": ["console", "timed_rotating_file", "error_file"],
|
"handlers": ["console", "timed_rotating_file", "error_file"],
|
||||||
"level": "DEBUG",
|
"level": "DEBUG",
|
||||||
@@ -135,5 +140,10 @@ LOGGING_CONFIG = {
|
|||||||
"level": "DEBUG",
|
"level": "DEBUG",
|
||||||
"propagate": False,
|
"propagate": False,
|
||||||
},
|
},
|
||||||
|
"tasks": {
|
||||||
|
"handlers": ["console", "timed_rotating_file", "error_file"],
|
||||||
|
"level": "DEBUG",
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user