From 69145c4345d3f754586b9b781394d1b79786f029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Sun, 18 Jan 2026 19:52:30 +0800 Subject: [PATCH] a --- trading_system/binance_client.py | 42 +++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index cf22fe2..711c874 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -978,8 +978,16 @@ class BinanceClient: # 如果是平仓订单,添加 reduceOnly 参数 # 根据币安API文档,reduceOnly 应该是字符串 "true" 或 "false" if reduce_only: - order_params['reduceOnly'] = "true" # 使用字符串格式,符合币安API要求 - logger.info(f"{symbol} 使用 reduceOnly=true 平仓订单") + # 实测:某些账户/模式下(尤其是对冲模式 + positionSide)会报: + # APIError(code=-1106): Parameter 'reduceonly' sent when not required. + # 因此:当我们已经明确指定 positionSide=LONG/SHORT 时,不再传 reduceOnly; + # 其余情况仍保留 reduceOnly 以避免反向开仓。 + if order_params.get("positionSide") in {"LONG", "SHORT"}: + logger.info(f"{symbol} 对冲模式平仓:已指定 positionSide,跳过 reduceOnly(避免 -1106)") + else: + # python-binance 可以接受 bool;同时后面也做 -1106 自动兜底重试 + order_params['reduceOnly'] = True + logger.info(f"{symbol} 使用 reduceOnly=true 平仓订单") async def _submit(params: Dict[str, Any]) -> Dict[str, Any]: if order_type == 'MARKET': @@ -991,19 +999,31 @@ class BinanceClient: params['price'] = price return await self.client.futures_create_order(**params) - # 提交订单;若遇到 -4061,则在“带/不带 positionSide”之间做一次兜底重试 + # 提交订单;若遇到: + # -4061: positionSide 与账户模式不匹配 → 在“带/不带 positionSide”之间兜底切换重试 + # -1106: reduceOnly not required → 去掉 reduceOnly 重试(避免自动平仓失败) try: order = await _submit(order_params) except BinanceAPIException as e: - if getattr(e, "code", None) == -4061: - logger.error(f"{symbol} 触发 -4061(持仓模式不匹配),尝试自动兜底重试一次") + code = getattr(e, "code", None) + if code in (-4061, -1106): retry_params = dict(order_params) - if "positionSide" in retry_params: - retry_params.pop("positionSide", None) - else: - ps = await self._resolve_position_side_for_order(symbol, side, reduce_only, position_side) - if ps: - retry_params["positionSide"] = ps + if code == -4061: + logger.error(f"{symbol} 触发 -4061(持仓模式不匹配),尝试自动兜底重试一次") + if "positionSide" in retry_params: + retry_params.pop("positionSide", None) + else: + ps = await self._resolve_position_side_for_order(symbol, side, reduce_only, position_side) + if ps: + retry_params["positionSide"] = ps + elif code == -1106: + # 常见:Parameter 'reduceonly' sent when not required. + msg = str(e).lower() + if "reduceonly" in msg or "reduce only" in msg: + logger.error(f"{symbol} 触发 -1106(reduceOnly 不被接受),去掉 reduceOnly 后重试一次") + retry_params.pop("reduceOnly", None) + else: + raise order = await _submit(retry_params) else: raise