增加智能判断反向信号

This commit is contained in:
aaron 2026-02-13 23:07:27 +08:00
parent 8f4938f17a
commit 3f8b5fee23
2 changed files with 106 additions and 1 deletions

View File

@ -116,6 +116,7 @@ class Settings(BaseSettings):
paper_trading_leverage: int = 10 # 杠杆倍数
paper_trading_margin_per_order: float = 1000 # 每单保证金 (USDT)
paper_trading_max_orders: int = 10 # 最大持仓+挂单总数
paper_trading_auto_close_opposite: bool = False # 是否自动平掉反向持仓(智能策略)
# 废弃的配置(保留兼容性)
paper_trading_position_a: float = 1000 # A级信号仓位 (USDT)
paper_trading_position_b: float = 500 # B级信号仓位 (USDT)

View File

@ -24,6 +24,7 @@ class PaperTradingService:
self.leverage = self.settings.paper_trading_leverage # 杠杆倍数
self.margin_per_order = self.settings.paper_trading_margin_per_order # 每单保证金
self.max_orders = self.settings.paper_trading_max_orders # 最大订单数
self.auto_close_opposite = self.settings.paper_trading_auto_close_opposite # 是否自动平掉反向持仓
# 确保表已创建
self._ensure_table_exists()
@ -31,7 +32,7 @@ class PaperTradingService:
# 加载活跃订单到内存
self._load_active_orders()
logger.info("模拟交易服务初始化完成")
logger.info(f"模拟交易服务初始化完成(自动平反向持仓: {'启用' if self.auto_close_opposite else '禁用'}")
def _ensure_table_exists(self):
"""确保数据表已创建"""
@ -89,6 +90,15 @@ class PaperTradingService:
side = OrderSide.LONG if action == 'buy' else OrderSide.SHORT
entry_price = signal.get('entry_price') or signal.get('price', 0)
# === 反向订单处理 ===
# 1. 总是取消同一交易对的反向挂单(混合策略)
self._cancel_opposite_pending_orders(symbol, side)
# 2. 可选:智能平掉反向持仓(需要配置启用)
if self.auto_close_opposite and current_price:
grade = signal.get('signal_grade') or signal.get('grade', 'D')
self._close_opposite_positions(symbol, side, grade, current_price)
# === 限制检查 ===
# 1. 检查总订单数(持仓+挂单)是否超过最大限制
total_orders = len(self.active_orders)
@ -474,6 +484,100 @@ class PaperTradingService:
finally:
db.close()
def _cancel_opposite_pending_orders(self, symbol: str, new_side: OrderSide) -> int:
"""
取消同一交易对的反向挂单
Args:
symbol: 交易对
new_side: 新信号的方向
Returns:
取消的订单数量
"""
# 找出所有反向挂单
opposite_side = OrderSide.SHORT if new_side == OrderSide.LONG else OrderSide.LONG
opposite_pending = [
order for order in self.active_orders.values()
if order.symbol == symbol
and order.side == opposite_side
and order.status == OrderStatus.PENDING
]
if not opposite_pending:
return 0
cancelled_count = 0
for order in opposite_pending:
result = self._cancel_pending_order(order)
if result:
cancelled_count += 1
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}")
return cancelled_count
def _close_opposite_positions(self, symbol: str, new_side: OrderSide, signal_grade: str, current_price: float) -> int:
"""
智能平掉反向持仓可选策略
Args:
symbol: 交易对
new_side: 新信号的方向
signal_grade: 新信号等级
current_price: 当前价格
Returns:
平仓的订单数量
"""
# 找出所有反向持仓
opposite_side = OrderSide.SHORT if new_side == OrderSide.LONG else OrderSide.LONG
opposite_positions = [
order for order in self.active_orders.values()
if order.symbol == symbol
and order.side == opposite_side
and order.status == OrderStatus.OPEN
]
if not opposite_positions:
return 0
closed_count = 0
for order in opposite_positions:
# 计算当前盈亏
if order.side == OrderSide.LONG:
pnl_percent = ((current_price - order.filled_price) / order.filled_price) * 100
else:
pnl_percent = ((order.filled_price - current_price) / order.filled_price) * 100
# 智能决策:只在特定条件下平仓
should_close = False
reason = ""
# 条件1A级信号 + 反向持仓亏损超过3%
if signal_grade == 'A' and pnl_percent < -3:
should_close = True
reason = f"A级反向信号且当前亏损{pnl_percent:.2f}%,提前止损"
# 条件2A级信号 + 反向持仓盈利但接近止损(盈利<1%
elif signal_grade == 'A' and 0 < pnl_percent < 1:
should_close = True
reason = f"A级反向信号且盈利较小({pnl_percent:.2f}%),落袋为安"
if should_close:
result = self._close_order(order, OrderStatus.CLOSED_MANUAL, current_price)
if result:
closed_count += 1
logger.info(f"自动平掉反向持仓: {order.order_id} | {symbol} {opposite_side.value} | 原因: {reason}")
if closed_count > 0:
logger.info(f"已平掉 {closed_count} 个反向持仓({symbol} {opposite_side.value}")
return closed_count
def get_active_orders(self, symbol: Optional[str] = None) -> List[Dict[str, Any]]:
"""获取活跃订单"""
orders = list(self.active_orders.values())