a
This commit is contained in:
parent
8e365b3a9a
commit
8667c07134
|
|
@ -2147,20 +2147,38 @@ class PositionManager:
|
|||
|
||||
pnl_percent = float(trade.get("pnl_percent", 0) or 0)
|
||||
|
||||
# 1. 优先检查止损价格匹配(提高容忍度到10%)
|
||||
if sl is not None and entry_price_val > 0 and ep > 0:
|
||||
sl_val = float(sl)
|
||||
# 价格匹配:平仓价接近止损价
|
||||
if _close_to(ep, sl_val, max_pct=0.10):
|
||||
exit_reason = "stop_loss"
|
||||
# 方向匹配: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%
|
||||
# ⚠️ 2026-01-27关键修复:优先检查盈亏情况,避免盈利单被错误标记为止损
|
||||
# 1. 优先检查盈亏情况
|
||||
if pnl_percent > 0:
|
||||
# 盈利单:优先检查止盈价格匹配
|
||||
if tp is not None and _close_to(ep, float(tp), max_pct=0.10):
|
||||
exit_reason = "take_profit"
|
||||
elif tp1 is not None and _close_to(ep, float(tp1), max_pct=0.10):
|
||||
exit_reason = "take_profit"
|
||||
elif tp2 is not None and _close_to(ep, float(tp2), max_pct=0.10):
|
||||
exit_reason = "take_profit"
|
||||
# 如果盈利但没有匹配止盈价,可能是移动止损或手动平仓
|
||||
elif exit_reason == "sync":
|
||||
# 检查是否有移动止损标记
|
||||
if is_reduce_only:
|
||||
exit_reason = "trailing_stop" # 可能是移动止损
|
||||
else:
|
||||
exit_reason = "manual" # 可能是手动平仓
|
||||
else:
|
||||
# 亏损单:检查止损价格匹配
|
||||
if sl is not None and entry_price_val > 0 and ep > 0:
|
||||
sl_val = float(sl)
|
||||
# 价格匹配:平仓价接近止损价
|
||||
if _close_to(ep, sl_val, max_pct=0.10):
|
||||
exit_reason = "stop_loss"
|
||||
logger.info(f"{trade.get('symbol')} [同步] 价格方向匹配止损,且亏损{pnl_percent:.2f}%,标记为止损")
|
||||
# 方向匹配: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%
|
||||
exit_reason = "stop_loss"
|
||||
logger.info(f"{trade.get('symbol')} [同步] 价格方向匹配止损,且亏损{pnl_percent:.2f}%,标记为止损")
|
||||
|
||||
# 2. 检查止盈价格匹配
|
||||
# 2. 如果仍未确定,检查止盈价格匹配(作为备选)
|
||||
if exit_reason == "sync" and ep > 0:
|
||||
if tp is not None and _close_to(ep, float(tp), max_pct=0.10):
|
||||
exit_reason = "take_profit"
|
||||
|
|
@ -2732,11 +2750,27 @@ class PositionManager:
|
|||
# 盈利超过阈值后(相对于保证金),激活移动止损
|
||||
if pnl_percent_margin > trailing_activation * 100:
|
||||
position_info['trailingStopActivated'] = True
|
||||
# 将止损移至成本价(保本)
|
||||
position_info['stopLoss'] = entry_price
|
||||
# ⚠️ 2026-01-27修复:移动止损激活时,不应该将止损移至成本价
|
||||
# 应该设置为"保护利润"的价格(如盈利5%后,保护2.5%利润)
|
||||
# 计算需要保护的利润金额
|
||||
protect_amount = margin * trailing_protect
|
||||
# 计算对应的止损价(保护利润)
|
||||
if position_info['side'] == 'BUY':
|
||||
# 保护利润:当前盈亏 - 保护金额 = (止损价 - 开仓价) × 数量
|
||||
# 所以:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量
|
||||
new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity
|
||||
# 确保止损价不低于成本价(保本)
|
||||
new_stop_loss = max(new_stop_loss, entry_price)
|
||||
else: # SELL
|
||||
# 做空:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量
|
||||
new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity
|
||||
# 确保止损价不高于成本价(保本)
|
||||
new_stop_loss = min(new_stop_loss, entry_price)
|
||||
|
||||
position_info['stopLoss'] = new_stop_loss
|
||||
logger.info(
|
||||
f"{symbol} [实时监控] 移动止损激活: 止损移至成本价 {entry_price:.4f} "
|
||||
f"(盈利: {pnl_percent_margin:.2f}% of margin)"
|
||||
f"{symbol} [实时监控] 移动止损激活: 止损移至保护利润位 {new_stop_loss:.4f} "
|
||||
f"(盈利: {pnl_percent_margin:.2f}% of margin, 保护: {trailing_protect*100:.1f}% of margin)"
|
||||
)
|
||||
else:
|
||||
# ⚠️ 优化:如果分步止盈第一目标已触发,移动止损不再更新剩余仓位的止损价
|
||||
|
|
@ -2806,8 +2840,27 @@ class PositionManager:
|
|||
f"监控状态: {'运行中' if symbol in self._monitor_tasks else '未启动'}"
|
||||
)
|
||||
|
||||
# ⚠️ 2026-01-27关键修复:止损检查前,先检查是否盈利
|
||||
# 如果盈利,不应该触发止损(除非是移动止损或分步止盈后的剩余仓位)
|
||||
# 直接比较当前盈亏百分比与止损目标(基于保证金)
|
||||
if pnl_percent_margin <= -stop_loss_pct_margin:
|
||||
# ⚠️ 额外检查:如果盈利,可能是移动止损触发,应该标记为trailing_stop
|
||||
if pnl_percent_margin > 0:
|
||||
# 盈利单触发止损,应该是移动止损
|
||||
if position_info.get('trailingStopActivated'):
|
||||
exit_reason_sl = 'trailing_stop'
|
||||
logger.warning(f"{symbol} [实时监控] ⚠️ 盈利单触发止损,标记为移动止损(盈利: {pnl_percent_margin:.2f}% of margin)")
|
||||
else:
|
||||
# 盈利单但未激活移动止损,可能是分步止盈后的剩余仓位止损
|
||||
if partial_profit_taken:
|
||||
exit_reason_sl = 'take_profit_partial_then_stop'
|
||||
logger.info(f"{symbol} [实时监控] 第一目标止盈后,剩余仓位触发止损(保本)")
|
||||
else:
|
||||
# 异常情况:盈利单触发止损但未激活移动止损
|
||||
exit_reason_sl = 'trailing_stop' # 默认标记为移动止损
|
||||
logger.warning(f"{symbol} [实时监控] ⚠️ 异常:盈利单触发止损但未激活移动止损,标记为移动止损")
|
||||
else:
|
||||
# 正常止损逻辑
|
||||
should_close_due_to_sl = True
|
||||
# ⚠️ 2026-01-27优化:如果已部分止盈,细分状态
|
||||
if partial_profit_taken:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user