|
@@ -591,97 +591,78 @@ class TradingEngine:
|
|
|
logger.error(f"Error executing take profit order: {e}")
|
|
|
return {"success": False, "error": str(e)}
|
|
|
|
|
|
- async def cancel_all_orders(self, token: str) -> Dict[str, Any]:
|
|
|
- """Cancel all orders for a token."""
|
|
|
+ def cancel_all_orders(self, symbol: str) -> Tuple[List[Dict[str, Any]], Optional[str]]:
|
|
|
+ """Cancel all open orders for a specific symbol. Returns (cancelled_orders, error_message)."""
|
|
|
try:
|
|
|
- symbol = f"{token}/USDC:USDC"
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- cancelled_orders_info, error_msg = self.client.cancel_all_orders(symbol)
|
|
|
-
|
|
|
- if error_msg:
|
|
|
-
|
|
|
-
|
|
|
- logger.error(f"Error cancelling all orders for {symbol}: {error_msg}")
|
|
|
- return {"success": False, "error": f"Failed to cancel orders: {error_msg}"}
|
|
|
-
|
|
|
- if cancelled_orders_info is None:
|
|
|
- cancelled_orders_info = []
|
|
|
- logger.info(f"No orders found or reported as cancelled for {symbol} by the client.")
|
|
|
-
|
|
|
- successful_cancellations_db = []
|
|
|
- failed_cancellations_db_update = []
|
|
|
-
|
|
|
- for order_info in cancelled_orders_info:
|
|
|
- exchange_oid_to_update = order_info.get('id')
|
|
|
- if exchange_oid_to_update:
|
|
|
- success = self.stats.update_order_status(exchange_order_id=exchange_oid_to_update, new_status='cancelled')
|
|
|
- if success:
|
|
|
- successful_cancellations_db.append(exchange_oid_to_update)
|
|
|
- else:
|
|
|
- failed_cancellations_db_update.append(exchange_oid_to_update)
|
|
|
-
|
|
|
-
|
|
|
- total_cancelled_linked = 0
|
|
|
- if self.stats and successful_cancellations_db:
|
|
|
- for exchange_oid in successful_cancellations_db:
|
|
|
-
|
|
|
- order_in_db = self.stats.get_order_by_exchange_id(exchange_oid)
|
|
|
- if order_in_db and order_in_db.get('bot_order_ref_id'):
|
|
|
- cancelled_linked = self.stats.cancel_linked_orders(
|
|
|
- parent_bot_order_ref_id=order_in_db['bot_order_ref_id'],
|
|
|
- new_status='cancelled_parent_cancelled'
|
|
|
- )
|
|
|
- total_cancelled_linked += cancelled_linked
|
|
|
- if cancelled_linked > 0:
|
|
|
- logger.info(f"🛑 Cancelled {cancelled_linked} linked stop losses for order {exchange_oid}")
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"Cancellation request processed for {symbol}. {len(successful_cancellations_db)} marked in DB.",
|
|
|
- "cancelled_on_exchange_ids": [info.get('id') for info in cancelled_orders_info if info.get('id')],
|
|
|
- "db_updates_successful_ids": successful_cancellations_db,
|
|
|
- "db_updates_failed_ids": failed_cancellations_db_update,
|
|
|
- "cancelled_linked_stop_losses": total_cancelled_linked
|
|
|
- }
|
|
|
-
|
|
|
+ logger.info(f"Attempting to cancel all orders for {symbol}")
|
|
|
+
|
|
|
+
|
|
|
+ all_orders = self.client.get_open_orders()
|
|
|
+ if all_orders is None:
|
|
|
+ error_msg = f"Could not fetch orders to cancel {symbol} orders"
|
|
|
+ logger.error(error_msg)
|
|
|
+ return [], error_msg
|
|
|
+
|
|
|
+
|
|
|
+ symbol_orders = [order for order in all_orders if order.get('symbol') == symbol]
|
|
|
+
|
|
|
+ if not symbol_orders:
|
|
|
+ logger.info(f"No open orders found for {symbol}")
|
|
|
+ return [], None
|
|
|
+
|
|
|
+
|
|
|
+ cancelled_orders = []
|
|
|
+ failed_orders = []
|
|
|
+
|
|
|
+ for order in symbol_orders:
|
|
|
+ order_id = order.get('id')
|
|
|
+ if order_id:
|
|
|
+ try:
|
|
|
+ success = self.client.cancel_order(order_id, symbol)
|
|
|
+ if success:
|
|
|
+ cancelled_orders.append(order)
|
|
|
+ logger.info(f"Successfully cancelled order {order_id} for {symbol}")
|
|
|
+ else:
|
|
|
+ failed_orders.append(order)
|
|
|
+ logger.warning(f"Failed to cancel order {order_id} for {symbol}")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Exception cancelling order {order_id}: {e}")
|
|
|
+ failed_orders.append(order)
|
|
|
+
|
|
|
+
|
|
|
+ if self.stats:
|
|
|
+ for order in cancelled_orders:
|
|
|
+ order_id = order.get('id')
|
|
|
+ if order_id:
|
|
|
+
|
|
|
+ db_order = self.stats.get_order_by_exchange_id(order_id)
|
|
|
+ if db_order:
|
|
|
+ self.stats.update_order_status(
|
|
|
+ exchange_order_id=order_id,
|
|
|
+ new_status='cancelled_manually'
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ cleanup_count = self.stats.cancel_pending_stop_losses_by_symbol(
|
|
|
+ symbol,
|
|
|
+ 'cancelled_manual_exit'
|
|
|
+ )
|
|
|
+ if cleanup_count > 0:
|
|
|
+ logger.info(f"Cleaned up {cleanup_count} pending stop losses for {symbol}")
|
|
|
+
|
|
|
+
|
|
|
+ if failed_orders:
|
|
|
+ error_msg = f"Cancelled {len(cancelled_orders)}/{len(symbol_orders)} orders. {len(failed_orders)} failed."
|
|
|
+ logger.warning(error_msg)
|
|
|
+ return cancelled_orders, error_msg
|
|
|
+ else:
|
|
|
+ logger.info(f"Successfully cancelled all {len(cancelled_orders)} orders for {symbol}")
|
|
|
+ return cancelled_orders, None
|
|
|
+
|
|
|
except Exception as e:
|
|
|
-
|
|
|
-
|
|
|
- error_message = str(e)
|
|
|
- if hasattr(self.client, '_extract_error_message'):
|
|
|
- error_message = self.client._extract_error_message(e)
|
|
|
- logger.error(f"Error cancelling orders for {token}: {error_message}", exc_info=True)
|
|
|
- return {"success": False, "error": f"Failed to cancel orders: {error_message}"}
|
|
|
+ error_msg = f"Error cancelling orders for {symbol}: {str(e)}"
|
|
|
+ logger.error(error_msg, exc_info=True)
|
|
|
+ return [], error_msg
|
|
|
|
|
|
|
|
|
async def execute_sl_order(self, token: str, stop_price: float) -> Dict[str, Any]:
|
|
@@ -693,8 +674,50 @@ class TradingEngine:
|
|
|
return await self.execute_take_profit_order(token, profit_price)
|
|
|
|
|
|
async def execute_coo_order(self, token: str) -> Dict[str, Any]:
|
|
|
- """Alias for cancel_all_orders."""
|
|
|
- return await self.cancel_all_orders(token)
|
|
|
+ """Cancel all orders for a token and format response like the old code expected."""
|
|
|
+ try:
|
|
|
+ symbol = f"{token}/USDC:USDC"
|
|
|
+
|
|
|
+
|
|
|
+ cancelled_orders, error_msg = self.cancel_all_orders(symbol)
|
|
|
+
|
|
|
+ if error_msg:
|
|
|
+ logger.error(f"Error cancelling all orders for {token}: {error_msg}")
|
|
|
+ return {"success": False, "error": error_msg}
|
|
|
+
|
|
|
+ if not cancelled_orders:
|
|
|
+ logger.info(f"No orders found to cancel for {token}")
|
|
|
+ return {
|
|
|
+ "success": True,
|
|
|
+ "message": f"No orders found for {token}",
|
|
|
+ "cancelled_orders": [],
|
|
|
+ "cancelled_count": 0,
|
|
|
+ "failed_count": 0,
|
|
|
+ "cancelled_linked_stop_losses": 0
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ cleanup_count = 0
|
|
|
+ if self.stats:
|
|
|
+ cleanup_count = self.stats.cancel_pending_stop_losses_by_symbol(
|
|
|
+ symbol,
|
|
|
+ 'cancelled_manual_exit'
|
|
|
+ )
|
|
|
+
|
|
|
+ logger.info(f"Successfully cancelled {len(cancelled_orders)} orders for {token}")
|
|
|
+
|
|
|
+ return {
|
|
|
+ "success": True,
|
|
|
+ "message": f"Successfully cancelled {len(cancelled_orders)} orders for {token}",
|
|
|
+ "cancelled_orders": cancelled_orders,
|
|
|
+ "cancelled_count": len(cancelled_orders),
|
|
|
+ "failed_count": 0,
|
|
|
+ "cancelled_linked_stop_losses": cleanup_count
|
|
|
+ }
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Error in execute_coo_order for {token}: {e}")
|
|
|
+ return {"success": False, "error": str(e)}
|
|
|
|
|
|
def is_bot_trade(self, exchange_order_id: str) -> bool:
|
|
|
"""Check if an order (by its exchange ID) was recorded by this bot in the orders table."""
|