|
@@ -684,33 +684,38 @@ class TradingEngine:
|
|
|
elif position_type == "SHORT" and stop_price <= entry_price:
|
|
|
return {"success": False, "error": "Stop loss price should be above entry price for short positions"}
|
|
|
|
|
|
- order_type_for_stats = 'limit' # MODIFICATION: SL from /sl command is now a direct limit order
|
|
|
+ order_type_for_stats = 'stop_market'
|
|
|
|
|
|
# 1. Generate bot_order_ref_id and record order placement intent
|
|
|
bot_order_ref_id = uuid.uuid4().hex
|
|
|
- # For a direct limit SL, the 'price' recorded is the limit price.
|
|
|
+ # For a stop-market, the 'price' is the trigger price.
|
|
|
order_db_id = self.stats.record_order_placed(
|
|
|
symbol=symbol, side=exit_side, order_type=order_type_for_stats,
|
|
|
- amount_requested=contracts, price=stop_price, # price here is the limit price for the SL
|
|
|
+ amount_requested=contracts, price=stop_price, # price here is the trigger price for the SL
|
|
|
bot_order_ref_id=bot_order_ref_id, status='pending_submission'
|
|
|
)
|
|
|
|
|
|
if not order_db_id:
|
|
|
- logger.error(f"Failed to record SL limit order intent in DB for {symbol} (direct /sl command) with bot_ref {bot_order_ref_id}")
|
|
|
- return {"success": False, "error": "Failed to record SL limit order intent in database."}
|
|
|
+ logger.error(f"Failed to record SL stop-market order intent in DB for {symbol} (direct /sl command) with bot_ref {bot_order_ref_id}")
|
|
|
+ return {"success": False, "error": "Failed to record SL stop-market order intent in database."}
|
|
|
|
|
|
- # 2. Place a direct LIMIT order for the stop loss
|
|
|
- logger.info(f"Placing direct LIMIT STOP LOSS ({exit_side.upper()}) order ({bot_order_ref_id}) for {await formatter.format_amount(contracts, token)} {symbol} at limit price {await formatter.format_price_with_symbol(stop_price, token)}")
|
|
|
- exchange_order_data, error_msg = self.client.place_limit_order(symbol, exit_side, contracts, price=stop_price)
|
|
|
+ # 2. Place a STOP-MARKET order for the stop loss
|
|
|
+ logger.info(f"Placing STOP-MARKET STOP LOSS ({exit_side.upper()}) order ({bot_order_ref_id}) for {await formatter.format_amount(contracts, token)} {symbol} with trigger price {await formatter.format_price_with_symbol(stop_price, token)}")
|
|
|
+ exchange_order_data, error_msg = self.client.place_stop_loss_order(
|
|
|
+ symbol=symbol,
|
|
|
+ side=exit_side,
|
|
|
+ amount=contracts,
|
|
|
+ stop_price_arg=stop_price
|
|
|
+ )
|
|
|
|
|
|
if error_msg:
|
|
|
- logger.error(f"Direct SL Limit order placement failed for {symbol} ({bot_order_ref_id}): {error_msg}")
|
|
|
+ logger.error(f"Direct SL Stop-Market order placement failed for {symbol} ({bot_order_ref_id}): {error_msg}")
|
|
|
self.stats.update_order_status(order_db_id=order_db_id, new_status='failed_submission', bot_order_ref_id=bot_order_ref_id)
|
|
|
- return {"success": False, "error": f"Direct SL Limit order placement failed: {error_msg}"}
|
|
|
+ return {"success": False, "error": f"Direct SL Stop-Market order placement failed: {error_msg}"}
|
|
|
if not exchange_order_data:
|
|
|
- logger.error(f"Direct SL Limit order placement call failed for {symbol} ({bot_order_ref_id}). Client returned no data/error.")
|
|
|
+ logger.error(f"Direct SL Stop-Market order placement call failed for {symbol} ({bot_order_ref_id}). Client returned no data/error.")
|
|
|
self.stats.update_order_status(order_db_id=order_db_id, new_status='failed_submission_no_data', bot_order_ref_id=bot_order_ref_id)
|
|
|
- return {"success": False, "error": "Direct SL Limit order placement failed (no order object or error from client)."}
|
|
|
+ return {"success": False, "error": "Direct SL Stop-Market order placement failed (no order object or error from client)."}
|
|
|
|
|
|
exchange_oid = exchange_order_data.get('id')
|
|
|
|
|
@@ -718,11 +723,11 @@ class TradingEngine:
|
|
|
if exchange_oid:
|
|
|
self.stats.update_order_status(
|
|
|
order_db_id=order_db_id,
|
|
|
- new_status='open', # Limit orders are 'open' until filled
|
|
|
+ new_status='open', # Stop orders are 'open' until triggered
|
|
|
set_exchange_order_id=exchange_oid
|
|
|
)
|
|
|
else:
|
|
|
- logger.warning(f"No exchange_order_id received for SL limit order {order_db_id} ({bot_order_ref_id}).")
|
|
|
+ logger.warning(f"No exchange_order_id received for SL stop-market order {order_db_id} ({bot_order_ref_id}).")
|
|
|
|
|
|
# NOTE: Stop loss orders are protective orders for existing positions
|
|
|
# They do not create new trade cycles - they protect existing trade cycles
|
|
@@ -739,7 +744,7 @@ class TradingEngine:
|
|
|
# it might need to be cancelled first. However, current flow assumes this /sl places a new/updated one.
|
|
|
# For simplicity, link_stop_loss_to_trade will update if one already exists or insert.
|
|
|
await self.stats.link_stop_loss_to_trade(lifecycle_id, exchange_oid, stop_price)
|
|
|
- logger.info(f"🛡️ Linked SL limit order {exchange_oid} to lifecycle {lifecycle_id} for {symbol} (from /sl command)")
|
|
|
+ logger.info(f"🛡️ Linked SL stop-market order {exchange_oid} to lifecycle {lifecycle_id} for {symbol} (from /sl command)")
|
|
|
|
|
|
return {
|
|
|
"success": True,
|