feat(binance_client, position_manager): 优化对冲模式处理与持仓检查逻辑

在 `binance_client.py` 中增强了对冲模式的处理逻辑,添加了对对冲模式检测失败的处理,确保在尝试单向模式失败后再尝试对冲模式。同时,在 `position_manager.py` 中引入了持仓存在性检查,避免因持仓不存在或方向不匹配导致的错误,提升了系统的稳定性与风险控制能力。
This commit is contained in:
薇薇安 2026-02-20 00:36:09 +08:00
parent d31c44a22a
commit bfe3d8ec75
2 changed files with 46 additions and 1 deletions

View File

@ -2472,8 +2472,12 @@ class BinanceClient:
}
# 对冲模式:必须指定 positionSide
# ⚠️ 优化如果对冲模式检测失败dual is None先尝试不传 positionSide单向模式失败再尝试传 positionSide
if dual is True:
params["positionSide"] = "LONG" if pd == "BUY" else "SHORT"
elif dual is None:
# 对冲模式检测失败:先尝试单向模式(不传 positionSide如果失败再尝试对冲模式
logger.debug(f"{symbol} 对冲模式检测失败dual=None先尝试单向模式不传 positionSide")
# 走 Algo Order 接口(避免 -4120
order = await self.futures_create_algo_order(params)
@ -2493,7 +2497,8 @@ class BinanceClient:
if retry_order:
logger.info(f"{symbol} ✓ 重试成功(移除 positionSide")
return retry_order
else:
elif dual is False:
# 单向模式首次失败:尝试添加 positionSide可能是对冲模式但检测失败
retry = dict(params)
retry["positionSide"] = "LONG" if pd == "BUY" else "SHORT"
# 关键修复:重试时必须清除之前的 timestamp 和 signature
@ -2504,6 +2509,27 @@ class BinanceClient:
if retry_order:
logger.info(f"{symbol} ✓ 重试成功(添加 positionSide")
return retry_order
elif dual is None:
# 对冲模式检测失败:先尝试单向模式失败后,再尝试对冲模式
retry = dict(params)
if "positionSide" in retry:
retry.pop("positionSide", None)
retry.pop("timestamp", None)
retry.pop("signature", None)
logger.debug(f"{symbol} 重试1: 移除 positionSide对冲模式检测失败 -> 单向模式)")
retry_order = await self.futures_create_algo_order(retry)
if retry_order:
logger.info(f"{symbol} ✓ 重试成功(移除 positionSide")
return retry_order
else:
retry["positionSide"] = "LONG" if pd == "BUY" else "SHORT"
retry.pop("timestamp", None)
retry.pop("signature", None)
logger.debug(f"{symbol} 重试2: 添加 positionSide={retry['positionSide']}(单向模式失败 -> 对冲模式)")
retry_order = await self.futures_create_algo_order(retry)
if retry_order:
logger.info(f"{symbol} ✓ 重试成功(添加 positionSide")
return retry_order
# 如果还是失败,记录详细参数用于调试
logger.error(f"{symbol} ❌ 所有重试都失败,保护单挂单失败")

View File

@ -1591,6 +1591,25 @@ class PositionManager:
except Exception as e:
logger.warning(f"{symbol} 验证止损价格时出错: {e}")
# ⚠️ 关键修复:挂单前先检查持仓是否真的存在,避免 -4509没有持仓和 -4061positionSide 不匹配)
try:
positions = await self._get_open_positions()
live_position = next((p for p in positions if p.get('symbol') == symbol), None)
if not live_position:
logger.warning(f"{symbol} ⚠️ 持仓已不存在(可能已平仓),跳过挂止损/止盈单,避免 -4509/-4061 错误")
return
position_amt = float(live_position.get('positionAmt', 0) or 0)
if abs(position_amt) <= 0:
logger.warning(f"{symbol} ⚠️ 持仓数量为0跳过挂止损/止盈单")
return
# 验证持仓方向是否匹配(对冲模式下需要检查 positionSide
live_side = "BUY" if position_amt > 0 else "SELL"
if live_side != side:
logger.warning(f"{symbol} ⚠️ 持仓方向不匹配(本地记录: {side}, 实际: {live_side}),跳过挂单,避免 -4061")
return
except Exception as e:
logger.warning(f"{symbol} 检查持仓存在性时出错,继续尝试挂单(可能误报): {e}")
# 防重复:先取消旧的保护单(仅取消特定类型,避免误伤普通挂单)
try:
await self.client.cancel_open_algo_orders_by_order_types(