|
@@ -148,7 +148,7 @@ class RiskCleanupManager:
|
|
logger.info(f"Skipping position {symbol}: contracts={contracts}, entry_price={entry_price}")
|
|
logger.info(f"Skipping position {symbol}: contracts={contracts}, entry_price={entry_price}")
|
|
continue
|
|
continue
|
|
|
|
|
|
- logger.info(f"[RiskMgmt] {symbol}: ROE={roe_percentage:+.2f}%, Threshold=-{Config.STOP_LOSS_PERCENTAGE}% (Trigger: {roe_percentage <= -Config.STOP_LOSS_PERCENTAGE})")
|
|
|
|
|
|
+ logger.debug(f"[RiskMgmt] {symbol}: ROE={roe_percentage:+.2f}%, Threshold=-{Config.STOP_LOSS_PERCENTAGE}% (Trigger: {roe_percentage <= -Config.STOP_LOSS_PERCENTAGE})")
|
|
|
|
|
|
if roe_percentage <= -Config.STOP_LOSS_PERCENTAGE:
|
|
if roe_percentage <= -Config.STOP_LOSS_PERCENTAGE:
|
|
token = symbol.split('/')[0] if '/' in symbol else symbol.split(':')[0]
|
|
token = symbol.split('/')[0] if '/' in symbol else symbol.split(':')[0]
|
|
@@ -175,40 +175,33 @@ Safety Threshold: -{Config.STOP_LOSS_PERCENTAGE}% ROE
|
|
Action: Executing emergency exit order..."""
|
|
Action: Executing emergency exit order..."""
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+ # Execute emergency exit order
|
|
exit_result = await self.trading_engine.execute_exit_order(token)
|
|
exit_result = await self.trading_engine.execute_exit_order(token)
|
|
-
|
|
|
|
- if exit_result.get('success'):
|
|
|
|
- placed_order_details = exit_result.get('order_placed_details', {})
|
|
|
|
- logger.info(f"✅ Emergency exit order placed for {token} (Lifecycle: {lifecycle_id_str}). Order details: {placed_order_details}")
|
|
|
|
-
|
|
|
|
- if self.notification_manager:
|
|
|
|
- await self.notification_manager.send_generic_notification(
|
|
|
|
- f"""✅ <b>Emergency Exit Initiated</b>
|
|
|
|
-
|
|
|
|
-📊 <b>Position:</b> {token} {position_side}
|
|
|
|
-🆔 <b>Lifecycle ID:</b> {lifecycle_id_str}
|
|
|
|
-📉 <b>Loss at Trigger:</b> {roe_percentage:+.2f}% ROE (${unrealized_pnl:+.2f})
|
|
|
|
-⚠️ <b>Threshold:</b> -{Config.STOP_LOSS_PERCENTAGE}% ROE
|
|
|
|
-✅ <b>Action:</b> Market exit order placed successfully
|
|
|
|
-🆔 <b>Exit Order ID:</b> {placed_order_details.get('exchange_order_id', 'N/A')}
|
|
|
|
-
|
|
|
|
-🛡️ The system will confirm closure and P&L once the exit order fill is processed."""
|
|
|
|
- )
|
|
|
|
- else:
|
|
|
|
|
|
+ if not exit_result.get('success'):
|
|
error_msg = exit_result.get('error', 'Unknown error')
|
|
error_msg = exit_result.get('error', 'Unknown error')
|
|
- logger.error(f"❌ Failed to execute emergency exit order for {token} (Lifecycle: {lifecycle_id_str}): {error_msg}")
|
|
|
|
|
|
+ logger.error(f"❌ Failed to execute emergency exit order for {token} (Lifecycle: {lifecycle_id_str}): {error_msg}")
|
|
if self.notification_manager:
|
|
if self.notification_manager:
|
|
await self.notification_manager.send_generic_notification(
|
|
await self.notification_manager.send_generic_notification(
|
|
- f"""❌ <b>CRITICAL: Emergency Exit Failed!</b>
|
|
|
|
-
|
|
|
|
-📊 <b>Position:</b> {token} {position_side}
|
|
|
|
-🆔 <b>Lifecycle ID:</b> {lifecycle_id_str}
|
|
|
|
-📉 <b>Loss:</b> {roe_percentage:+.2f}% ROE
|
|
|
|
-❌ <b>Error Placing Order:</b> {error_msg}
|
|
|
|
-
|
|
|
|
-⚠️ <b>MANUAL INTERVENTION REQUIRED</b>
|
|
|
|
-Please close this position manually via /exit {token}"""
|
|
|
|
|
|
+ f"⚠️ <b>Emergency Exit Failed</b>\n\n"
|
|
|
|
+ f"Token: {token}\n"
|
|
|
|
+ f"Position: {position_side.upper()}\n"
|
|
|
|
+ f"ROE: {roe_percentage:.2f}%\n"
|
|
|
|
+ f"Error: {error_msg}\n\n"
|
|
|
|
+ f"Please check the position and close it manually if needed."
|
|
|
|
+ )
|
|
|
|
+ continue
|
|
|
|
+
|
|
|
|
+ # Cancel any pending stop losses for this symbol
|
|
|
|
+ if self.trading_engine.stats and hasattr(self.trading_engine.stats.order_manager, 'cancel_pending_stop_losses_by_symbol'):
|
|
|
|
+ try:
|
|
|
|
+ cancelled_sl_count = self.trading_engine.stats.order_manager.cancel_pending_stop_losses_by_symbol(
|
|
|
|
+ symbol=symbol,
|
|
|
|
+ new_status='cancelled_automatic_exit'
|
|
)
|
|
)
|
|
|
|
+ if cancelled_sl_count > 0:
|
|
|
|
+ logger.info(f"Cancelled {cancelled_sl_count} pending stop losses for {symbol} after automatic exit")
|
|
|
|
+ except Exception as sl_error:
|
|
|
|
+ logger.error(f"Error cancelling pending stop losses for {symbol}: {sl_error}")
|
|
except Exception as pos_error:
|
|
except Exception as pos_error:
|
|
logger.error(f"Error processing position for automatic stop loss: {pos_error}")
|
|
logger.error(f"Error processing position for automatic stop loss: {pos_error}")
|
|
continue
|
|
continue
|