fix(position_manager): 增强止损和止盈同步逻辑及日志记录
在持仓管理中,优化了止损和止盈的同步逻辑,确保在同步失败时记录详细的异常信息。同时,增加了对止损和止盈为空的警告日志,提升了系统的可用性和风险控制能力。此外,调整了移动止损的配置逻辑,确保在未设置时使用默认值。这一改动旨在提升交易策略的稳定性与用户友好性。
This commit is contained in:
parent
d7ccbe38e4
commit
41b2a21c3d
|
|
@ -1444,9 +1444,13 @@ class PositionManager:
|
|||
take_profit = None
|
||||
|
||||
if not stop_loss or not take_profit:
|
||||
logger.warning(f"{symbol} 止损或止盈价格为空,跳过挂保护单: stop_loss={stop_loss}, take_profit={take_profit}")
|
||||
logger.warning(f"[账号{self.account_id}] {symbol} 同步跳过: 止损或止盈为空 stop_loss={stop_loss} take_profit={take_profit}")
|
||||
return
|
||||
|
||||
logger.info(
|
||||
f"[账号{self.account_id}] {symbol} 开始同步止损/止盈至交易所: SL={float(stop_loss):.4f} TP={float(take_profit):.4f}"
|
||||
)
|
||||
|
||||
# 验证止损价格是否合理。保本/移动止损时:多单止损可≥入场价、空单止损可≤入场价,不得被改回亏损价
|
||||
entry_price = position_info.get("entryPrice")
|
||||
if entry_price:
|
||||
|
|
@ -1503,8 +1507,9 @@ class PositionManager:
|
|||
await self.client.cancel_open_algo_orders_by_order_types(
|
||||
symbol, {"STOP_MARKET", "TAKE_PROFIT_MARKET", "TRAILING_STOP_MARKET"}
|
||||
)
|
||||
logger.info(f"[账号{self.account_id}] {symbol} 已取消旧保护单,准备挂新单")
|
||||
except Exception as e:
|
||||
logger.debug(f"{symbol} 取消旧保护单时出错(可忽略): {e}")
|
||||
logger.warning(f"[账号{self.account_id}] {symbol} 取消旧保护单异常: {e},继续尝试挂新单")
|
||||
|
||||
# 获取当前价格(如果未提供):优先 WS 缓存(bookTicker/ticker24h)→ 持仓 markPrice → REST ticker
|
||||
if current_price is None:
|
||||
|
|
@ -1854,6 +1859,9 @@ class PositionManager:
|
|||
f"SL={position_info.get('exchangeSlOrderId') or '-'} "
|
||||
f"TP={position_info.get('exchangeTpOrderId') or '-'}"
|
||||
)
|
||||
logger.info(f"[账号{self.account_id}] {symbol} 止损/止盈同步至交易所完成")
|
||||
else:
|
||||
logger.warning(f"[账号{self.account_id}] {symbol} 同步结束但未挂上保护单(止损或止盈挂单均失败),将依赖 WebSocket 监控")
|
||||
|
||||
async def check_stop_loss_take_profit(self) -> List[str]:
|
||||
"""
|
||||
|
|
@ -1965,7 +1973,7 @@ class PositionManager:
|
|||
|
||||
# 检查是否启用移动止损(默认False,需要显式启用)
|
||||
profit_protection_enabled = bool(config.TRADING_CONFIG.get('PROFIT_PROTECTION_ENABLED', True))
|
||||
use_trailing = profit_protection_enabled and bool(config.TRADING_CONFIG.get('USE_TRAILING_STOP', False))
|
||||
use_trailing = profit_protection_enabled and bool(config.TRADING_CONFIG.get('USE_TRAILING_STOP', True))
|
||||
if use_trailing:
|
||||
logger.debug(f"{symbol} [移动止损] 已启用,将检查移动止损逻辑")
|
||||
else:
|
||||
|
|
@ -1983,7 +1991,9 @@ class PositionManager:
|
|||
trailing_activation = trailing_activation / 100.0
|
||||
if trailing_protect > 1:
|
||||
trailing_protect = trailing_protect / 100.0
|
||||
lock_pct = config.TRADING_CONFIG.get('LOCK_PROFIT_AT_BREAKEVEN_AFTER_PCT') or 0
|
||||
lock_pct = config.TRADING_CONFIG.get('LOCK_PROFIT_AT_BREAKEVEN_AFTER_PCT')
|
||||
if lock_pct is None:
|
||||
lock_pct = 0.03
|
||||
if lock_pct and lock_pct > 1:
|
||||
lock_pct = lock_pct / 100.0
|
||||
|
||||
|
|
@ -1997,10 +2007,14 @@ class PositionManager:
|
|||
position_info['stopLoss'] = breakeven
|
||||
position_info['breakevenStopSet'] = True
|
||||
logger.info(f"{symbol} [定时检查] 盈利{pnl_percent_margin:.2f}%≥{lock_pct*100:.0f}%,止损已移至含手续费保本价 {breakeven:.4f}")
|
||||
logger.info(f"{symbol} [定时检查] 尝试将保本止损同步至交易所")
|
||||
try:
|
||||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price)
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步保本止损至交易所失败: {sync_e}")
|
||||
logger.warning(
|
||||
f"{symbol} [定时检查] 同步保本止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
# 盈利超过阈值后(相对于保证金),激活移动止损
|
||||
if pnl_percent_margin > trailing_activation * 100:
|
||||
position_info['trailingStopActivated'] = True
|
||||
|
|
@ -2010,11 +2024,15 @@ class PositionManager:
|
|||
f"{symbol} 移动止损激活: 止损移至含手续费保本价 {breakeven:.4f} (入场: {entry_price:.4f}) "
|
||||
f"(盈利: {pnl_percent_margin:.2f}% of margin)"
|
||||
)
|
||||
logger.info(f"{symbol} [定时检查] 尝试将移动止损同步至交易所")
|
||||
try:
|
||||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price)
|
||||
logger.info(f"{symbol} [定时检查] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败: {sync_e}")
|
||||
logger.warning(
|
||||
f"{symbol} [定时检查] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
else:
|
||||
# 盈利超过阈值后,止损移至保护利润位(基于保证金)
|
||||
# 如果已经部分止盈,使用剩余仓位计算
|
||||
|
|
@ -2041,7 +2059,10 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price)
|
||||
logger.info(f"{symbol} [定时检查] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败: {sync_e}")
|
||||
logger.warning(
|
||||
f"{symbol} [定时检查] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
else:
|
||||
new_stop_loss = entry_price + (remaining_pnl - protect_amount) / remaining_quantity
|
||||
new_stop_loss = min(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL'))
|
||||
|
|
@ -2057,7 +2078,10 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price)
|
||||
logger.info(f"{symbol} [定时检查] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败: {sync_e}")
|
||||
logger.warning(
|
||||
f"{symbol} [定时检查] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
else:
|
||||
# 未部分止盈,使用原始仓位计算;保护金额至少覆盖手续费
|
||||
protect_amount = max(margin * trailing_protect, self._min_protect_amount_for_fees(margin, leverage))
|
||||
|
|
@ -2075,7 +2099,10 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price)
|
||||
logger.info(f"{symbol} [定时检查] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败: {sync_e}")
|
||||
logger.warning(
|
||||
f"{symbol} [定时检查] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
else:
|
||||
# 做空:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量
|
||||
# 注意:对于做空,止损价应该高于开仓价,所以用加法
|
||||
|
|
@ -2094,8 +2121,11 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price)
|
||||
logger.info(f"{symbol} [定时检查] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败: {sync_e}")
|
||||
|
||||
logger.warning(
|
||||
f"{symbol} [定时检查] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
|
||||
# 检查止损(使用更新后的止损价,基于保证金收益比)
|
||||
# ⚠️ 重要:止损检查应该在时间锁之前,止损必须立即执行
|
||||
stop_loss_raw = position_info.get('stopLoss')
|
||||
|
|
@ -3982,9 +4012,9 @@ class PositionManager:
|
|||
# 4) 及时执行止损/止盈可以保护资金和利润
|
||||
# 注意:如果需要防止秒级平仓,可以通过提高入场信号质量(MIN_SIGNAL_STRENGTH)来实现
|
||||
|
||||
# 检查是否启用移动止损(默认False,需要显式启用)
|
||||
# 检查是否启用移动止损/保本(默认 True,与 config.py 一致;显式设为 False 才关闭)
|
||||
profit_protection_enabled = bool(config.TRADING_CONFIG.get('PROFIT_PROTECTION_ENABLED', True))
|
||||
use_trailing = profit_protection_enabled and bool(config.TRADING_CONFIG.get('USE_TRAILING_STOP', False))
|
||||
use_trailing = profit_protection_enabled and bool(config.TRADING_CONFIG.get('USE_TRAILING_STOP', True))
|
||||
if use_trailing:
|
||||
logger.debug(f"[账号{self.account_id}] {symbol} [实时监控-移动止损] 已启用,将检查移动止损逻辑")
|
||||
else:
|
||||
|
|
@ -3993,9 +4023,11 @@ class PositionManager:
|
|||
else:
|
||||
logger.debug(f"[账号{self.account_id}] {symbol} [实时监控-移动止损] 已禁用(USE_TRAILING_STOP=False),跳过移动止损检查")
|
||||
if use_trailing:
|
||||
trailing_activation = config.TRADING_CONFIG.get('TRAILING_STOP_ACTIVATION', 0.01) # 相对于保证金
|
||||
trailing_protect = config.TRADING_CONFIG.get('TRAILING_STOP_PROTECT', 0.01) # 相对于保证金
|
||||
lock_pct = config.TRADING_CONFIG.get('LOCK_PROFIT_AT_BREAKEVEN_AFTER_PCT') or 0
|
||||
trailing_activation = config.TRADING_CONFIG.get('TRAILING_STOP_ACTIVATION', 0.10) # 相对于保证金,默认 10%
|
||||
trailing_protect = config.TRADING_CONFIG.get('TRAILING_STOP_PROTECT', 0.02) # 相对于保证金,默认 2%
|
||||
lock_pct = config.TRADING_CONFIG.get('LOCK_PROFIT_AT_BREAKEVEN_AFTER_PCT')
|
||||
if lock_pct is None:
|
||||
lock_pct = 0.03 # 未配置时默认 3% 移至保本
|
||||
if lock_pct and lock_pct > 1:
|
||||
lock_pct = lock_pct / 100.0
|
||||
|
||||
|
|
@ -4016,10 +4048,14 @@ class PositionManager:
|
|||
logger.info(
|
||||
f"[账号{self.account_id}] {symbol} [实时监控] 盈利{pnl_percent_margin:.2f}%≥{lock_pct*100:.0f}%,止损已移至含手续费保本价 {breakeven:.4f}(留住盈利)"
|
||||
)
|
||||
logger.info(f"[账号{self.account_id}] {symbol} [实时监控] 尝试将保本止损同步至交易所")
|
||||
try:
|
||||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price_float)
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步保本止损至交易所失败: {sync_e}")
|
||||
logger.warning(
|
||||
f"[账号{self.account_id}] {symbol} [实时监控] 同步保本止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
# 盈利超过阈值后(相对于保证金),激活移动止损
|
||||
if pnl_percent_margin > trailing_activation * 100:
|
||||
position_info['trailingStopActivated'] = True
|
||||
|
|
@ -4040,11 +4076,15 @@ class PositionManager:
|
|||
f"(盈利: {pnl_percent_margin:.2f}% of margin, 保护: {trailing_protect*100:.1f}% of margin)"
|
||||
)
|
||||
# 同步至交易所:取消原止损单并按新止损价重挂,使移动止损也有交易所保护
|
||||
logger.info(f"[账号{self.account_id}] {symbol} [实时监控] 尝试将移动止损同步至交易所")
|
||||
try:
|
||||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price_float)
|
||||
logger.info(f"[账号{self.account_id}] {symbol} [实时监控] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败(不影响本地监控): {sync_e}")
|
||||
logger.warning(
|
||||
f"[账号{self.account_id}] {symbol} [实时监控] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
else:
|
||||
# ⚠️ 优化:如果分步止盈第一目标已触发,移动止损不再更新剩余仓位的止损价
|
||||
# 原因:分步止盈第一目标触发后,剩余50%仓位止损已移至成本价(保本),等待第二目标
|
||||
|
|
@ -4068,7 +4108,10 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price_float)
|
||||
logger.info(f"[账号{self.account_id}] {symbol} [实时监控] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败(不影响本地监控): {sync_e}")
|
||||
logger.warning(
|
||||
f"[账号{self.account_id}] {symbol} [实时监控] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
else: # SELL
|
||||
new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity
|
||||
new_stop_loss = min(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL'))
|
||||
|
|
@ -4082,7 +4125,10 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price_float)
|
||||
logger.info(f"[账号{self.account_id}] {symbol} [实时监控] 已同步移动止损至交易所")
|
||||
except Exception as sync_e:
|
||||
logger.warning(f"{symbol} 同步移动止损至交易所失败(不影响本地监控): {sync_e}")
|
||||
logger.warning(
|
||||
f"[账号{self.account_id}] {symbol} [实时监控] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}",
|
||||
exc_info=False,
|
||||
)
|
||||
|
||||
# 检查止损(基于保证金收益比)
|
||||
# ⚠️ 重要:止损检查应该在时间锁之前,止损必须立即执行
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user