This commit is contained in:
aaron 2026-02-15 13:54:46 +08:00
parent 9f796d1efc
commit 20c9333b2f
2 changed files with 49 additions and 18 deletions

View File

@ -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:

View File

@ -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:
"""