diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index 3e523b1..43b3798 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -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} ❌ 所有重试都失败,保护单挂单失败") diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index b0ecf70..0cbfcd2 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -1591,6 +1591,25 @@ class PositionManager: except Exception as e: logger.warning(f"{symbol} 验证止损价格时出错: {e}") + # ⚠️ 关键修复:挂单前先检查持仓是否真的存在,避免 -4509(没有持仓)和 -4061(positionSide 不匹配) + 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(