diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index 590a565..4b03b4a 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -2146,11 +2146,23 @@ class PositionManager: except Exception: pass - pnl_percent = float(trade.get("pnl_percent", 0) or 0) + # ⚠️ 关键修复:使用基于保证金的盈亏百分比判断盈利/亏损,而不是价格涨跌幅 + # 因为价格涨跌幅(如2.35%)和基于保证金的盈亏百分比(如18.82%)差异很大 + # 对于SELL单,价格从0.119跌到0.1162,价格涨跌幅只有2.35%,但基于保证金的盈亏百分比是18.82% + pnl_percent_price = float(trade.get("pnl_percent", 0) or 0) # 价格涨跌幅(数据库可能存储的是这个) + + # 重新计算基于保证金的盈亏百分比(更准确) + leverage = float(trade.get("leverage", 8) or 8) + entry_value = entry_price * quantity + margin = entry_value / leverage if leverage > 0 else entry_value + pnl_percent_margin = (pnl / margin * 100) if margin > 0 else 0 + + # 使用基于保证金的盈亏百分比判断(与实时监控逻辑一致) + pnl_percent_for_judge = pnl_percent_margin # ⚠️ 2026-01-27关键修复:优先检查盈亏情况,避免盈利单被错误标记为止损 - # 1. 优先检查盈亏情况 - if pnl_percent > 0: + # 1. 优先检查盈亏情况(使用基于保证金的盈亏百分比) + if pnl_percent_for_judge > 0: # 盈利单:优先检查止盈价格匹配 if tp is not None and _close_to(ep, float(tp), max_pct=0.10): exit_reason = "take_profit" @@ -2175,9 +2187,10 @@ class PositionManager: # 方向匹配:BUY时平仓价 < 止损价,SELL时平仓价 > 止损价 elif (trade.get("side") == "BUY" and ep < sl_val) or (trade.get("side") == "SELL" and ep > sl_val): # 如果价格在止损方向,且亏损比例较大,更可能是止损触发 - if pnl_percent < -5.0: # 亏损超过5% + # ⚠️ 关键修复:使用基于保证金的盈亏百分比判断 + if pnl_percent_for_judge < -5.0: # 亏损超过5%(基于保证金) exit_reason = "stop_loss" - logger.info(f"{trade.get('symbol')} [同步] 价格方向匹配止损,且亏损{pnl_percent:.2f}%,标记为止损") + logger.info(f"{trade.get('symbol')} [同步] 价格方向匹配止损,且亏损{pnl_percent_for_judge:.2f}% of margin,标记为止损") # 2. 如果仍未确定,检查止盈价格匹配(作为备选) if exit_reason == "sync" and ep > 0: @@ -2191,13 +2204,14 @@ class PositionManager: # 3. 特征判断:如果价格不匹配,但满足止损特征,也标记为止损 if exit_reason == "sync" and entry_price_val > 0 and ep > 0: # 特征1:持仓时间短(< 30分钟)且亏损 - if duration_minutes and duration_minutes < 30 and pnl_percent < -5.0: + # ⚠️ 关键修复:使用基于保证金的盈亏百分比判断 + if duration_minutes and duration_minutes < 30 and pnl_percent_for_judge < -5.0: # 特征2:价格在止损方向 if sl is not None: sl_val = float(sl) if (trade.get("side") == "BUY" and ep < sl_val) or (trade.get("side") == "SELL" and ep > sl_val): exit_reason = "stop_loss" - logger.info(f"{trade.get('symbol')} [同步] 特征判断:持仓{duration_minutes:.1f}分钟,亏损{pnl_percent:.2f}%,价格在止损方向,标记为止损") + logger.info(f"{trade.get('symbol')} [同步] 特征判断:持仓{duration_minutes:.1f}分钟,亏损{pnl_percent_for_judge:.2f}% of margin,价格在止损方向,标记为止损") # 4. 如果之前标记为 sync 且是 reduceOnly 订单,但价格不匹配止损/止盈,可能是其他自动平仓(如移动止损) if exit_reason == "sync" and is_reduce_only: @@ -2223,9 +2237,10 @@ class PositionManager: # 只有在价格和特征都不匹配,且不是 reduceOnly 时,才标记为手动平仓 if not is_reduce_only: # 再次检查:如果亏损很大,更可能是止损触发(币安API可能不准确) - if pnl_percent < -10.0: + # ⚠️ 关键修复:使用基于保证金的盈亏百分比判断 + if pnl_percent_for_judge < -10.0: exit_reason = "stop_loss" # 大额亏损,更可能是止损 - logger.warning(f"{trade.get('symbol')} [同步] 大额亏损{pnl_percent:.2f}%,即使reduceOnly=false也标记为止损") + logger.warning(f"{trade.get('symbol')} [同步] 大额亏损{pnl_percent_for_judge:.2f}% of margin,即使reduceOnly=false也标记为止损") else: exit_reason = "manual" except Exception as e: @@ -2256,12 +2271,13 @@ class PositionManager: strategy_type = 'trend_following' # 默认策略类型 + # ⚠️ 关键修复:使用基于保证金的盈亏百分比更新数据库(与实时监控逻辑一致) Trade.update_exit( trade_id=trade_id, exit_price=exit_price, exit_reason=exit_reason, pnl=pnl, - pnl_percent=pnl_percent, + pnl_percent=pnl_percent_margin, # 使用基于保证金的盈亏百分比 exit_order_id=exit_order_id, # 保存币安平仓订单号 strategy_type=strategy_type, duration_minutes=duration_minutes,