update
This commit is contained in:
parent
9f796d1efc
commit
20c9333b2f
@ -90,6 +90,22 @@ class CryptoAgent:
|
|||||||
await self.telegram.send_message(message)
|
await self.telegram.send_message(message)
|
||||||
logger.info(f"已发送挂单成交通知: {result.get('order_id')}")
|
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]):
|
async def _notify_order_closed(self, result: Dict[str, Any]):
|
||||||
"""发送订单平仓通知"""
|
"""发送订单平仓通知"""
|
||||||
status = result.get('status', '')
|
status = result.get('status', '')
|
||||||
@ -312,7 +328,15 @@ class CryptoAgent:
|
|||||||
if grade != 'D':
|
if grade != 'D':
|
||||||
# 转换信号格式以兼容 paper_trading
|
# 转换信号格式以兼容 paper_trading
|
||||||
paper_signal = self._convert_to_paper_signal(symbol, best_signal, current_price)
|
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:
|
if order:
|
||||||
logger.info(f" 📝 已创建模拟订单: {order.order_id}")
|
logger.info(f" 📝 已创建模拟订单: {order.order_id}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -61,7 +61,7 @@ class PaperTradingService:
|
|||||||
finally:
|
finally:
|
||||||
db.close()
|
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: 当前价格(用于市价单)
|
current_price: 当前价格(用于市价单)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
创建的订单或 None
|
包含 'order' 和 'cancelled_orders' 的字典
|
||||||
"""
|
"""
|
||||||
|
result = {'order': None, 'cancelled_orders': []}
|
||||||
|
|
||||||
action = signal.get('action')
|
action = signal.get('action')
|
||||||
if action not in ['buy', 'sell']:
|
if action not in ['buy', 'sell']:
|
||||||
return None
|
return result
|
||||||
|
|
||||||
symbol = signal.get('symbol', 'UNKNOWN')
|
symbol = signal.get('symbol', 'UNKNOWN')
|
||||||
side = OrderSide.LONG if action == 'buy' else OrderSide.SHORT
|
side = OrderSide.LONG if action == 'buy' else OrderSide.SHORT
|
||||||
@ -92,7 +94,8 @@ class PaperTradingService:
|
|||||||
|
|
||||||
# === 反向订单处理 ===
|
# === 反向订单处理 ===
|
||||||
# 1. 总是取消同一交易对的反向挂单(混合策略)
|
# 1. 总是取消同一交易对的反向挂单(混合策略)
|
||||||
self._cancel_opposite_pending_orders(symbol, side)
|
cancelled_orders = self._cancel_opposite_pending_orders(symbol, side)
|
||||||
|
result['cancelled_orders'] = cancelled_orders
|
||||||
|
|
||||||
# 2. 可选:智能平掉反向持仓(需要配置启用)
|
# 2. 可选:智能平掉反向持仓(需要配置启用)
|
||||||
if self.auto_close_opposite and current_price:
|
if self.auto_close_opposite and current_price:
|
||||||
@ -104,7 +107,7 @@ class PaperTradingService:
|
|||||||
total_orders = len(self.active_orders)
|
total_orders = len(self.active_orders)
|
||||||
if total_orders >= self.max_orders:
|
if total_orders >= self.max_orders:
|
||||||
logger.info(f"订单限制: 已达到最大订单数 {self.max_orders},跳过")
|
logger.info(f"订单限制: 已达到最大订单数 {self.max_orders},跳过")
|
||||||
return None
|
return result
|
||||||
|
|
||||||
# 2. 检查是否有接近的挂单(价格差距 < 1%)
|
# 2. 检查是否有接近的挂单(价格差距 < 1%)
|
||||||
same_direction_orders = [
|
same_direction_orders = [
|
||||||
@ -119,13 +122,13 @@ class PaperTradingService:
|
|||||||
price_diff = abs(pending.entry_price - entry_price) / pending.entry_price
|
price_diff = abs(pending.entry_price - entry_price) / pending.entry_price
|
||||||
if price_diff < 0.01: # 价格差距小于 1%
|
if price_diff < 0.01: # 价格差距小于 1%
|
||||||
logger.info(f"订单限制: {symbol} 已有接近的挂单 @ ${pending.entry_price:,.2f},新信号 @ ${entry_price:,.2f},跳过")
|
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')
|
grade = signal.get('signal_grade') or signal.get('grade', 'D')
|
||||||
if grade == 'D':
|
if grade == 'D':
|
||||||
logger.info(f"D级信号不开仓: {signal.get('symbol')}")
|
logger.info(f"D级信号不开仓: {signal.get('symbol')}")
|
||||||
return None
|
return result
|
||||||
|
|
||||||
# 固定使用保证金(不再根据等级区分)
|
# 固定使用保证金(不再根据等级区分)
|
||||||
margin = self.margin_per_order # 每单固定 1000 USDT 保证金
|
margin = self.margin_per_order # 每单固定 1000 USDT 保证金
|
||||||
@ -184,12 +187,13 @@ class PaperTradingService:
|
|||||||
status_text = "已开仓" if status == OrderStatus.OPEN else "等待触发"
|
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"创建模拟订单: {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}")
|
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:
|
except Exception as e:
|
||||||
logger.error(f"创建模拟订单失败: {e}")
|
logger.error(f"创建模拟订单失败: {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return None
|
return result
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
@ -485,7 +489,7 @@ class PaperTradingService:
|
|||||||
finally:
|
finally:
|
||||||
db.close()
|
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: 新信号的方向
|
new_side: 新信号的方向
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
取消的订单数量
|
被取消的订单信息列表
|
||||||
"""
|
"""
|
||||||
# 找出所有反向挂单
|
# 找出所有反向挂单
|
||||||
opposite_side = OrderSide.SHORT if new_side == OrderSide.LONG else OrderSide.LONG
|
opposite_side = OrderSide.SHORT if new_side == OrderSide.LONG else OrderSide.LONG
|
||||||
@ -506,19 +510,22 @@ class PaperTradingService:
|
|||||||
]
|
]
|
||||||
|
|
||||||
if not opposite_pending:
|
if not opposite_pending:
|
||||||
return 0
|
return []
|
||||||
|
|
||||||
cancelled_count = 0
|
cancelled_orders = []
|
||||||
for order in opposite_pending:
|
for order in opposite_pending:
|
||||||
result = self._cancel_pending_order(order)
|
result = self._cancel_pending_order(order)
|
||||||
if result:
|
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}")
|
logger.info(f"自动取消反向挂单: {order.order_id} | {symbol} {opposite_side.value} @ ${order.entry_price:,.2f}")
|
||||||
|
|
||||||
if cancelled_count > 0:
|
if cancelled_orders:
|
||||||
logger.info(f"已取消 {cancelled_count} 个反向挂单({symbol} {opposite_side.value}),新信号方向: {new_side.value}")
|
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:
|
def _close_opposite_positions(self, symbol: str, new_side: OrderSide, signal_grade: str, current_price: float) -> int:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user