diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index c93d8c6..990850b 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -1777,6 +1777,9 @@ class BinanceClient: if dual is True: retry = dict(params) retry.pop("positionSide", None) + # 关键修复:重试时必须清除之前的 timestamp 和 signature + 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: @@ -1785,6 +1788,9 @@ class BinanceClient: else: retry = dict(params) retry["positionSide"] = "LONG" if pd == "BUY" else "SHORT" + # 关键修复:重试时必须清除之前的 timestamp 和 signature + retry.pop("timestamp", None) + retry.pop("signature", None) logger.debug(f"{symbol} 重试1: 添加 positionSide={retry['positionSide']}(单向模式 -> 对冲模式)") retry_order = await self.futures_create_algo_order(retry) if retry_order: @@ -1819,9 +1825,10 @@ class BinanceClient: logger.error(f" 原因: 订单名义价值不足(至少需要 5 USDT)") elif error_code == -2022: logger.error(f" 原因: ReduceOnly 订单被拒绝(可能没有持仓或持仓方向不对)") - elif "immediately trigger" in error_msg.lower() or "would immediately trigger" in error_msg.lower(): + elif error_code == -2021 or "immediately trigger" in error_msg.lower() or "would immediately trigger" in error_msg.lower(): logger.error(f" 原因: 触发价格会导致立即触发(止损/止盈价不在正确一侧)") - logger.error(f" 建议: 检查止损/止盈价格计算是否正确") + # 关键修复:将此异常抛出,让上层调用者(如 PositionManager)决定是否立即执行市价平仓 + raise e elif "position" in error_msg.lower(): logger.error(f" 原因: 持仓相关问题(可能没有持仓或持仓方向不匹配)") diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index 25e7683..51824c5 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -1419,7 +1419,33 @@ class PositionManager: working_type="MARK_PRICE", ) except Exception as e: + # 检查是否是 -2021 (立即触发) + error_msg = str(e) + if "-2021" in error_msg or "immediately trigger" in error_msg: + logger.error(f"{symbol} ⚠️ 止损单会立即触发(-2021),视为已触发止损,立即执行市价平仓") + await self.close_position(symbol, reason='stop_loss') + return + logger.warning(f"{symbol} 检查止损触发条件时出错: {e},继续尝试挂单") + try: + sl_order = await self.client.place_trigger_close_position_order( + symbol=symbol, + position_direction=side, + trigger_type="STOP_MARKET", + stop_price=stop_loss, + current_price=current_price, + working_type="MARK_PRICE", + ) + except Exception as retry_e: + retry_msg = str(retry_e) + if "-2021" in retry_msg or "immediately trigger" in retry_msg: + logger.error(f"{symbol} ⚠️ 重试挂止损单会立即触发(-2021),立即执行市价平仓") + await self.close_position(symbol, reason='stop_loss') + return + logger.error(f"{symbol} 重试挂止损单失败: {retry_e}") + sl_order = None + else: + try: sl_order = await self.client.place_trigger_close_position_order( symbol=symbol, position_direction=side, @@ -1428,15 +1454,14 @@ class PositionManager: current_price=current_price, working_type="MARK_PRICE", ) - else: - sl_order = await self.client.place_trigger_close_position_order( - symbol=symbol, - position_direction=side, - trigger_type="STOP_MARKET", - stop_price=stop_loss, - current_price=current_price, - working_type="MARK_PRICE", - ) + except Exception as e: + error_msg = str(e) + if "-2021" in error_msg or "immediately trigger" in error_msg: + logger.error(f"{symbol} ⚠️ 止损单会立即触发(-2021),视为已触发止损,立即执行市价平仓") + await self.close_position(symbol, reason='stop_loss') + return + logger.error(f"{symbol} 挂止损单失败: {e}") + sl_order = None if sl_order: logger.info(f"{symbol} ✓ 止损单已成功挂到交易所: {sl_order.get('algoId', 'N/A')}")