From 20c9333b2fd80bede0589572048bbabf66115086 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Sun, 15 Feb 2026 13:54:46 +0800 Subject: [PATCH] update --- backend/app/crypto_agent/crypto_agent.py | 26 +++++++++++- backend/app/services/paper_trading_service.py | 41 +++++++++++-------- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/backend/app/crypto_agent/crypto_agent.py b/backend/app/crypto_agent/crypto_agent.py index 7ec204f..a97565f 100644 --- a/backend/app/crypto_agent/crypto_agent.py +++ b/backend/app/crypto_agent/crypto_agent.py @@ -90,6 +90,22 @@ class CryptoAgent: await self.telegram.send_message(message) logger.info(f"已发送挂单成交通知: {result.get('order_id')}") + async def _notify_pending_cancelled(self, result: Dict[str, Any]): + """发送挂单撤销通知""" + side_text = "做多" if result.get('side') == 'long' else "做空" + new_side_text = "做多" if result.get('new_side') == 'long' else "做空" + + message = f"""⚠️ 挂单撤销 + +交易对: {result.get('symbol')} +原方向: {side_text} +挂单价: ${result.get('entry_price', 0):,.2f} +原因: 收到反向{new_side_text}信号,自动撤销""" + + await self.feishu.send_text(message) + await self.telegram.send_message(message) + logger.info(f"已发送挂单撤销通知: {result.get('order_id')}") + async def _notify_order_closed(self, result: Dict[str, Any]): """发送订单平仓通知""" status = result.get('status', '') @@ -312,7 +328,15 @@ class CryptoAgent: if grade != 'D': # 转换信号格式以兼容 paper_trading paper_signal = self._convert_to_paper_signal(symbol, best_signal, current_price) - order = self.paper_trading.create_order_from_signal(paper_signal) + result = self.paper_trading.create_order_from_signal(paper_signal) + + # 发送被取消挂单的通知 + cancelled_orders = result.get('cancelled_orders', []) + for cancelled in cancelled_orders: + await self._notify_pending_cancelled(cancelled) + + # 记录新订单 + order = result.get('order') if order: logger.info(f" 📝 已创建模拟订单: {order.order_id}") else: diff --git a/backend/app/services/paper_trading_service.py b/backend/app/services/paper_trading_service.py index 65bd426..e42862e 100644 --- a/backend/app/services/paper_trading_service.py +++ b/backend/app/services/paper_trading_service.py @@ -61,7 +61,7 @@ class PaperTradingService: finally: db.close() - def create_order_from_signal(self, signal: Dict[str, Any], current_price: float = None) -> Optional[PaperOrder]: + def create_order_from_signal(self, signal: Dict[str, Any], current_price: float = None) -> Dict[str, Any]: """ 从交易信号创建模拟订单 @@ -80,11 +80,13 @@ class PaperTradingService: current_price: 当前价格(用于市价单) Returns: - 创建的订单或 None + 包含 'order' 和 'cancelled_orders' 的字典 """ + result = {'order': None, 'cancelled_orders': []} + action = signal.get('action') if action not in ['buy', 'sell']: - return None + return result symbol = signal.get('symbol', 'UNKNOWN') side = OrderSide.LONG if action == 'buy' else OrderSide.SHORT @@ -92,7 +94,8 @@ class PaperTradingService: # === 反向订单处理 === # 1. 总是取消同一交易对的反向挂单(混合策略) - self._cancel_opposite_pending_orders(symbol, side) + cancelled_orders = self._cancel_opposite_pending_orders(symbol, side) + result['cancelled_orders'] = cancelled_orders # 2. 可选:智能平掉反向持仓(需要配置启用) if self.auto_close_opposite and current_price: @@ -104,7 +107,7 @@ class PaperTradingService: total_orders = len(self.active_orders) if total_orders >= self.max_orders: logger.info(f"订单限制: 已达到最大订单数 {self.max_orders},跳过") - return None + return result # 2. 检查是否有接近的挂单(价格差距 < 1%) same_direction_orders = [ @@ -119,13 +122,13 @@ class PaperTradingService: price_diff = abs(pending.entry_price - entry_price) / pending.entry_price if price_diff < 0.01: # 价格差距小于 1% logger.info(f"订单限制: {symbol} 已有接近的挂单 @ ${pending.entry_price:,.2f},新信号 @ ${entry_price:,.2f},跳过") - return None + return result # 获取信号等级 grade = signal.get('signal_grade') or signal.get('grade', 'D') if grade == 'D': logger.info(f"D级信号不开仓: {signal.get('symbol')}") - return None + return result # 固定使用保证金(不再根据等级区分) margin = self.margin_per_order # 每单固定 1000 USDT 保证金 @@ -184,12 +187,13 @@ class PaperTradingService: status_text = "已开仓" if status == OrderStatus.OPEN else "等待触发" logger.info(f"创建模拟订单: {order_id} | {symbol} {side.value} [{entry_type_text}] @ ${entry_price:,.2f} | {status_text}") logger.info(f" 保证金: ${margin:,.0f} | 杠杆: {self.leverage}x | 持仓价值: ${position_value:,.0f} | 当前订单数: {len(self.active_orders)}/{self.max_orders}") - return order + result['order'] = order + return result except Exception as e: logger.error(f"创建模拟订单失败: {e}") db.rollback() - return None + return result finally: db.close() @@ -485,7 +489,7 @@ class PaperTradingService: finally: db.close() - def _cancel_opposite_pending_orders(self, symbol: str, new_side: OrderSide) -> int: + def _cancel_opposite_pending_orders(self, symbol: str, new_side: OrderSide) -> List[Dict[str, Any]]: """ 取消同一交易对的反向挂单 @@ -494,7 +498,7 @@ class PaperTradingService: new_side: 新信号的方向 Returns: - 取消的订单数量 + 被取消的订单信息列表 """ # 找出所有反向挂单 opposite_side = OrderSide.SHORT if new_side == OrderSide.LONG else OrderSide.LONG @@ -506,19 +510,22 @@ class PaperTradingService: ] if not opposite_pending: - return 0 + return [] - cancelled_count = 0 + cancelled_orders = [] for order in opposite_pending: result = self._cancel_pending_order(order) if result: - cancelled_count += 1 + result['event_type'] = 'pending_cancelled' + result['new_side'] = new_side.value + result['reason'] = f'收到反向{new_side.value}信号,自动撤销' + cancelled_orders.append(result) logger.info(f"自动取消反向挂单: {order.order_id} | {symbol} {opposite_side.value} @ ${order.entry_price:,.2f}") - if cancelled_count > 0: - logger.info(f"已取消 {cancelled_count} 个反向挂单({symbol} {opposite_side.value}),新信号方向: {new_side.value}") + if cancelled_orders: + logger.info(f"已取消 {len(cancelled_orders)} 个反向挂单({symbol} {opposite_side.value}),新信号方向: {new_side.value}") - return cancelled_count + return cancelled_orders def _close_opposite_positions(self, symbol: str, new_side: OrderSide, signal_grade: str, current_price: float) -> int: """