2
0
forked from kodorvan/stcs

The currency of the coin is treason on USDT, unnecessary parameters are removed

This commit is contained in:
algizn97
2025-10-10 13:26:56 +05:00
parent 3533e7e99a
commit 9c1f289870

View File

@@ -1,89 +1,113 @@
import logging.config import logging.config
import math
from pybit.exceptions import InvalidRequestError from pybit.exceptions import InvalidRequestError
import database.request as rq import database.request as rq
from app.bybit import get_bybit_client from app.bybit import get_bybit_client
from app.bybit.get_functions.get_balance import get_balance
from app.bybit.get_functions.get_instruments_info import get_instruments_info 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.logger_bybit.logger_bybit import LOGGING_CONFIG from app.bybit.logger_bybit.logger_bybit import LOGGING_CONFIG
from app.bybit.set_functions.set_leverage import ( from app.bybit.set_functions.set_leverage import set_leverage
set_leverage,
set_leverage_to_buy_and_sell,
)
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.bybit.set_functions.set_switch_position_mode import set_switch_position_mode from app.helper_functions import get_liquidation_price, safe_float
from app.helper_functions import check_limit_price, get_liquidation_price, safe_float
logging.config.dictConfig(LOGGING_CONFIG) logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("open_positions") logger = logging.getLogger("open_positions")
async def start_trading_cycle( async def start_trading_cycle(
tg_id: int, side: str, switch_side_mode: bool tg_id: int
) -> str | None: ) -> str | None:
""" """
Start trading cycle Start trading cycle
:param tg_id: Telegram user ID :param tg_id: Telegram user ID
:param side: Buy or Sell
:param switch_side_mode: switch_side_mode
""" """
try: try:
client = await get_bybit_client(tg_id=tg_id)
symbol = await rq.get_user_symbol(tg_id=tg_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)
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
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
margin_type = additional_data.margin_type margin_type = additional_data.margin_type
leverage = additional_data.leverage leverage = additional_data.leverage
leverage_to_buy = additional_data.leverage_to_buy
leverage_to_sell = additional_data.leverage_to_sell
order_type = additional_data.order_type
conditional_order_type = additional_data.conditional_order_type
order_quantity = additional_data.order_quantity order_quantity = additional_data.order_quantity
limit_price = additional_data.limit_price
trigger_price = additional_data.trigger_price trigger_price = additional_data.trigger_price
martingale_factor = additional_data.martingale_factor martingale_factor = additional_data.martingale_factor
max_bets_in_series = additional_data.max_bets_in_series max_bets_in_series = additional_data.max_bets_in_series
take_profit_percent = risk_management_data.take_profit_percent take_profit_percent = risk_management_data.take_profit_percent
stop_loss_percent = risk_management_data.stop_loss_percent stop_loss_percent = risk_management_data.stop_loss_percent
max_risk_percent = risk_management_data.max_risk_percent
mode = 3 if trade_mode == "Both_Sides" else 0 get_side = "Buy"
await set_switch_position_mode(tg_id=tg_id, symbol=symbol, mode=mode)
await set_margin_mode(tg_id=tg_id, margin_mode=margin_type) if user_deals_data:
if trade_mode == "Both_Sides" and margin_type == "ISOLATED_MARGIN": get_side = user_deals_data.last_side or "Buy"
await set_leverage_to_buy_and_sell(
tg_id=tg_id, if trade_mode == "Switch":
symbol=symbol, if switch_side == "По направлению":
leverage_to_buy=leverage_to_buy, side = get_side
leverage_to_sell=leverage_to_sell, else:
) if get_side == "Buy":
side = "Sell"
else:
side = "Buy"
else: else:
await set_leverage( if trade_mode == "Long":
tg_id=tg_id, side = "Buy"
symbol=symbol, else:
leverage=leverage, side = "Sell"
# Get fee rates
fee_info = client.get_fee_rates(category="linear", symbol=symbol)
# Check if commission fee is enabled
commission_fee_percent = 0.0
if commission_fee == "Yes_commission_fee":
commission_fee_percent = safe_float(
fee_info["result"]["list"][0]["takerFeeRate"]
) )
get_ticker = await get_tickers(tg_id, symbol=symbol)
price_symbol = safe_float(get_ticker.get("lastPrice")) or 0
instruments_info = await get_instruments_info(tg_id=tg_id, symbol=symbol)
qty_step_str = instruments_info.get("lotSizeFilter").get("qtyStep")
qty_step = safe_float(qty_step_str)
qty = safe_float(order_quantity) / safe_float(price_symbol)
decimals = abs(int(round(math.log10(qty_step))))
qty_formatted = math.floor(qty / qty_step) * qty_step
qty_formatted = round(qty_formatted, decimals)
if trigger_price > 0:
po_trigger_price = str(trigger_price)
else:
po_trigger_price = None
price_for_cals = trigger_price if po_trigger_price is not None else price_symbol
total_commission = price_for_cals * qty_formatted * commission_fee_percent
await set_margin_mode(tg_id=tg_id, margin_mode=margin_type)
await set_leverage(
tg_id=tg_id,
symbol=symbol,
leverage=leverage,
)
res = await open_positions( res = await open_positions(
tg_id=tg_id, tg_id=tg_id,
symbol=symbol, symbol=symbol,
side=side, side=side,
order_type=order_type,
conditional_order_type=conditional_order_type,
order_quantity=order_quantity, order_quantity=order_quantity,
limit_price=limit_price,
trigger_price=trigger_price, trigger_price=trigger_price,
trade_mode=trade_mode,
margin_type=margin_type, margin_type=margin_type,
leverage=leverage, leverage=leverage,
leverage_to_buy=leverage_to_buy,
leverage_to_sell=leverage_to_sell,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
max_risk_percent=max_risk_percent, commission_fee_percent=total_commission
) )
if res == "OK": if res == "OK":
@@ -95,19 +119,13 @@ async def start_trading_cycle(
trade_mode=trade_mode, trade_mode=trade_mode,
margin_type=margin_type, margin_type=margin_type,
leverage=leverage, leverage=leverage,
leverage_to_buy=leverage_to_buy,
leverage_to_sell=leverage_to_sell,
order_type="Market",
conditional_order_type=conditional_order_type,
order_quantity=order_quantity, order_quantity=order_quantity,
limit_price=limit_price,
trigger_price=trigger_price, trigger_price=trigger_price,
martingale_factor=martingale_factor, martingale_factor=martingale_factor,
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,
max_risk_percent=max_risk_percent, base_quantity=order_quantity
switch_side_mode=switch_side_mode,
) )
return "OK" return "OK"
return ( return (
@@ -124,6 +142,7 @@ async def start_trading_cycle(
"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"
} }
else None else None
) )
@@ -134,43 +153,30 @@ async def start_trading_cycle(
async def trading_cycle( async def trading_cycle(
tg_id: int, symbol: str, reverse_side: str, size: str tg_id: int, symbol: str, reverse_side: str
) -> str | None: ) -> 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(tg_id=tg_id, symbol=symbol)
total_fee = user_auto_trading_data.total_fee
trade_mode = user_deals_data.trade_mode trade_mode = user_deals_data.trade_mode
order_type = user_deals_data.order_type
conditional_order_type = user_deals_data.conditional_order_type
margin_type = user_deals_data.margin_type margin_type = user_deals_data.margin_type
leverage = user_deals_data.leverage leverage = user_deals_data.leverage
leverage_to_buy = user_deals_data.leverage_to_buy trigger_price = 0
leverage_to_sell = user_deals_data.leverage_to_sell
limit_price = user_deals_data.limit_price
trigger_price = user_deals_data.trigger_price
take_profit_percent = user_deals_data.take_profit_percent take_profit_percent = user_deals_data.take_profit_percent
stop_loss_percent = user_deals_data.stop_loss_percent stop_loss_percent = user_deals_data.stop_loss_percent
max_risk_percent = user_deals_data.max_risk_percent
max_bets_in_series = user_deals_data.max_bets_in_series max_bets_in_series = user_deals_data.max_bets_in_series
martingale_factor = user_deals_data.martingale_factor martingale_factor = user_deals_data.martingale_factor
current_step = user_deals_data.current_step current_step = user_deals_data.current_step
switch_side_mode = user_deals_data.switch_side_mode order_quantity = user_deals_data.order_quantity
base_quantity = user_deals_data.base_quantity
mode = 3 if trade_mode == "Both_Sides" else 0
await set_switch_position_mode(tg_id=tg_id, symbol=symbol, mode=mode)
await set_margin_mode(tg_id=tg_id, margin_mode=margin_type) await set_margin_mode(tg_id=tg_id, margin_mode=margin_type)
if trade_mode == "Both_Sides" and margin_type == "ISOLATED_MARGIN": await set_leverage(
await set_leverage_to_buy_and_sell( tg_id=tg_id,
tg_id=tg_id, symbol=symbol,
symbol=symbol, leverage=leverage,
leverage_to_buy=leverage_to_buy, )
leverage_to_sell=leverage_to_sell,
)
else:
await set_leverage(
tg_id=tg_id,
symbol=symbol,
leverage=leverage,
)
if reverse_side == "Buy": if reverse_side == "Buy":
real_side = "Sell" real_side = "Sell"
@@ -179,11 +185,11 @@ async def trading_cycle(
side = real_side side = real_side
if switch_side_mode: if trade_mode == "Switch":
side = "Sell" if real_side == "Buy" else "Buy" side = "Sell" if real_side == "Buy" else "Buy"
next_quantity = safe_float(size) * ( next_quantity = safe_float(order_quantity) * (
safe_float(martingale_factor) ** current_step safe_float(martingale_factor)
) )
current_step += 1 current_step += 1
@@ -194,19 +200,13 @@ async def trading_cycle(
tg_id=tg_id, tg_id=tg_id,
symbol=symbol, symbol=symbol,
side=side, side=side,
order_type="Market",
conditional_order_type=conditional_order_type,
order_quantity=next_quantity, order_quantity=next_quantity,
limit_price=limit_price,
trigger_price=trigger_price, trigger_price=trigger_price,
trade_mode=trade_mode,
margin_type=margin_type, margin_type=margin_type,
leverage=leverage, leverage=leverage,
leverage_to_buy=leverage_to_buy,
leverage_to_sell=leverage_to_sell,
take_profit_percent=take_profit_percent, take_profit_percent=take_profit_percent,
stop_loss_percent=stop_loss_percent, stop_loss_percent=stop_loss_percent,
max_risk_percent=max_risk_percent, commission_fee_percent=total_fee
) )
if res == "OK": if res == "OK":
@@ -218,19 +218,13 @@ async def trading_cycle(
trade_mode=trade_mode, trade_mode=trade_mode,
margin_type=margin_type, margin_type=margin_type,
leverage=leverage, leverage=leverage,
leverage_to_buy=leverage_to_buy,
leverage_to_sell=leverage_to_sell,
order_type=order_type,
conditional_order_type=conditional_order_type,
order_quantity=next_quantity, order_quantity=next_quantity,
limit_price=limit_price,
trigger_price=trigger_price, trigger_price=trigger_price,
martingale_factor=martingale_factor, martingale_factor=martingale_factor,
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,
max_risk_percent=max_risk_percent, base_quantity=base_quantity
switch_side_mode=switch_side_mode,
) )
return "OK" return "OK"
@@ -255,123 +249,56 @@ async def open_positions(
tg_id: int, tg_id: int,
side: str, side: str,
symbol: str, symbol: str,
order_type: str,
conditional_order_type: str,
order_quantity: float, order_quantity: float,
limit_price: float,
trigger_price: float, trigger_price: float,
trade_mode: str,
margin_type: str, margin_type: str,
leverage: str, leverage: str,
leverage_to_buy: str,
leverage_to_sell: str,
take_profit_percent: float, take_profit_percent: float,
stop_loss_percent: float, stop_loss_percent: float,
max_risk_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)
risk_management_data = await rq.get_user_risk_management(tg_id=tg_id)
commission_fee = risk_management_data.commission_fee
wallet = await get_balance(tg_id=tg_id)
user_balance = wallet.get("totalWalletBalance", 0)
instruments_resp = await get_instruments_info(tg_id=tg_id, symbol=symbol)
get_order_prices = instruments_resp.get("priceFilter")
min_price = safe_float(get_order_prices.get("minPrice"))
max_price = safe_float(get_order_prices.get("maxPrice"))
get_ticker = await get_tickers(tg_id, symbol=symbol) get_ticker = await get_tickers(tg_id, symbol=symbol)
price_symbol = safe_float(get_ticker.get("lastPrice")) or 0 price_symbol = safe_float(get_ticker.get("lastPrice")) or 0
instruments_info = await get_instruments_info(tg_id=tg_id, symbol=symbol)
qty_step_str = instruments_info.get("lotSizeFilter").get("qtyStep")
qty_step = safe_float(qty_step_str)
qty = safe_float(order_quantity) / safe_float(price_symbol)
decimals = abs(int(round(math.log10(qty_step))))
qty_formatted = math.floor(qty / qty_step) * qty_step
qty_formatted = round(qty_formatted, decimals)
if order_type == "Conditional": if trigger_price > 0:
po_trigger_price = str(trigger_price) po_trigger_price = str(trigger_price)
trigger_direction = 1 if trigger_price > price_symbol else 2 trigger_direction = 1 if trigger_price > price_symbol else 2
if conditional_order_type == "Limit":
error = check_limit_price(limit_price, min_price, max_price)
if error in {
"Limit price is out min price",
"Limit price is out max price",
}:
return error
order_type = "Limit"
price_for_calc = limit_price
tpsl_mode = "Partial"
else:
order_type = "Market"
price_for_calc = trigger_price
tpsl_mode = "Full"
else: else:
if order_type == "Limit":
error = check_limit_price(limit_price, min_price, max_price)
if error in {
"Limit price is out min price",
"Limit price is out max price",
}:
return error
price_for_calc = limit_price
tpsl_mode = "Partial"
else:
order_type = "Market"
price_for_calc = price_symbol
tpsl_mode = "Full"
po_trigger_price = None po_trigger_price = None
trigger_direction = None trigger_direction = None
if trade_mode == "Both_Sides": get_leverage = safe_float(leverage)
po_position_idx = 1 if side == "Buy" else 2
if margin_type == "ISOLATED_MARGIN":
get_leverage = safe_float(
leverage_to_buy if side == "Buy" else leverage_to_sell
)
else:
get_leverage = safe_float(leverage)
else:
po_position_idx = 0
get_leverage = safe_float(leverage)
potential_loss = ( price_for_cals = trigger_price if po_trigger_price is not None else price_symbol
safe_float(order_quantity)
* safe_float(price_for_calc)
* (stop_loss_percent / 100)
)
adjusted_loss = potential_loss / get_leverage
allowed_loss = safe_float(user_balance) * (max_risk_percent / 100)
if adjusted_loss > allowed_loss:
return "Risk is too high for this trade"
# Get fee rates
fee_info = client.get_fee_rates(category="linear", symbol=symbol)
# Check if commission fee is enabled
commission_fee_percent = 0.0
if commission_fee == "Yes_commission_fee":
commission_fee_percent = safe_float(
fee_info["result"]["list"][0]["takerFeeRate"]
)
total_commission = price_for_calc * order_quantity * commission_fee_percent
tp_multiplier = 1 + (take_profit_percent / 100) tp_multiplier = 1 + (take_profit_percent / 100)
if total_commission > 0: if commission_fee_percent > 0:
tp_multiplier += total_commission tp_multiplier += commission_fee_percent
if margin_type == "ISOLATED_MARGIN": if margin_type == "ISOLATED_MARGIN":
liq_long, liq_short = await get_liquidation_price( liq_long, liq_short = await get_liquidation_price(
tg_id=tg_id, tg_id=tg_id,
entry_price=price_for_calc, entry_price=price_for_cals,
symbol=symbol, symbol=symbol,
leverage=get_leverage, 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_cals > 0:
if side == "Buy": if side == "Buy":
base_tp = price_for_calc + (price_for_calc - liq_long) base_tp = price_for_cals + (price_for_cals - liq_long)
take_profit_price = base_tp + total_commission take_profit_price = base_tp + commission_fee_percent
else: else:
base_tp = price_for_calc - (liq_short - price_for_calc) base_tp = price_for_cals - (liq_short - price_for_cals)
take_profit_price = base_tp - total_commission take_profit_price = base_tp - commission_fee_percent
take_profit_price = max(take_profit_price, 0) take_profit_price = max(take_profit_price, 0)
else: else:
take_profit_price = None take_profit_price = None
@@ -379,40 +306,38 @@ async def open_positions(
stop_loss_price = None stop_loss_price = None
else: else:
if side == "Buy": if side == "Buy":
take_profit_price = price_for_calc * tp_multiplier take_profit_price = price_for_cals * tp_multiplier
stop_loss_price = price_for_calc * (1 - stop_loss_percent / 100) stop_loss_price = price_for_cals * (1 - stop_loss_percent / 100)
else: else:
take_profit_price = price_for_calc * ( take_profit_price = price_for_cals * (
1 - (take_profit_percent / 100) - total_commission 1 - (take_profit_percent / 100) - commission_fee_percent
) )
stop_loss_price = price_for_calc * (1 + stop_loss_percent / 100) stop_loss_price = trigger_price * (1 + stop_loss_percent / 100)
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)
logger.info("Take profit price: %s", take_profit_price)
logger.info("Stop loss price: %s", stop_loss_price)
logger.info("Commission fee percent: %s", commission_fee_percent)
# Place order # Place order
order_params = { order_params = {
"category": "linear", "category": "linear",
"symbol": symbol, "symbol": symbol,
"side": side, "side": side,
"orderType": order_type, "orderType": "Market",
"qty": str(order_quantity), "qty": str(qty_formatted),
"triggerDirection": trigger_direction, "triggerDirection": trigger_direction,
"triggerPrice": po_trigger_price, "triggerPrice": po_trigger_price,
"triggerBy": "LastPrice", "triggerBy": "LastPrice",
"timeInForce": "GTC", "timeInForce": "GTC",
"positionIdx": po_position_idx, "positionIdx": 0,
"tpslMode": tpsl_mode, "tpslMode": "Full",
"takeProfit": str(take_profit_price) if take_profit_price else None, "takeProfit": str(take_profit_price) if take_profit_price else None,
"stopLoss": str(stop_loss_price) if stop_loss_price else None, "stopLoss": str(stop_loss_price) if stop_loss_price else None,
} }
if order_type == "Conditional":
if conditional_order_type == "Limit":
order_params["price"] = str(limit_price)
if order_type == "Limit":
order_params["price"] = str(limit_price)
response = client.place_order(**order_params) response = client.place_order(**order_params)
if response["retCode"] == 0: if response["retCode"] == 0:
@@ -430,6 +355,8 @@ async def open_positions(
"ab not enough for new order": "ab not enough for new order", "ab not enough for new order": "ab not enough for new order",
"position idx not match position mode": "position idx not match position mode", "position idx not match position mode": "position idx not match position mode",
"Qty invalid": "Qty invalid", "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",
} }
for key, msg in known_errors.items(): for key, msg in known_errors.items():
if key in error_text: if key in error_text: