From 134443566752dae12b86cdddd4f3f9ec0fc6e8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Wed, 14 Jan 2026 21:23:31 +0800 Subject: [PATCH] a --- trading_system/binance_client.py | 34 ++++++++------- trading_system/position_manager.py | 66 +++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 25 deletions(-) diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index 7d77788..b0aea6a 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -476,7 +476,8 @@ class BinanceClient: side: str, quantity: float, order_type: str = 'MARKET', - price: Optional[float] = None + price: Optional[float] = None, + reduce_only: bool = False ) -> Optional[Dict]: """ 下单 @@ -528,24 +529,27 @@ class BinanceClient: logger.warning(f" 需要增加数量或提高仓位大小") return None + # 构建订单参数 + order_params = { + 'symbol': symbol, + 'side': side, + 'type': order_type, + 'quantity': adjusted_quantity + } + + # 如果是平仓订单,添加 reduceOnly 参数 + if reduce_only: + order_params['reduceOnly'] = True + logger.debug(f"{symbol} 使用 reduceOnly=True 平仓订单") + if order_type == 'MARKET': - order = await self.client.futures_create_order( - symbol=symbol, - side=side, - type='MARKET', - quantity=adjusted_quantity - ) + order = await self.client.futures_create_order(**order_params) else: if price is None: raise ValueError("限价单必须指定价格") - order = await self.client.futures_create_order( - symbol=symbol, - side=side, - type='LIMIT', - timeInForce='GTC', - quantity=adjusted_quantity, - price=price - ) + order_params['timeInForce'] = 'GTC' + order_params['price'] = price + order = await self.client.futures_create_order(**order_params) logger.info(f"下单成功: {symbol} {side} {adjusted_quantity} @ {order_type} (名义价值: {notional_value:.2f} USDT)") return order diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index d93effe..935081e 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -280,13 +280,24 @@ class PositionManager: f"(持仓数量: {position_amt:.4f})" ) - # 平仓 - order = await self.client.place_order( - symbol=symbol, - side=side, - quantity=quantity, - order_type='MARKET' - ) + # 平仓(使用 reduceOnly=True 确保只减少持仓,不增加反向持仓) + try: + logger.debug(f"{symbol} [平仓] 调用 place_order: {side} {quantity:.4f} @ MARKET (reduceOnly=True)") + order = await self.client.place_order( + symbol=symbol, + side=side, + quantity=quantity, + order_type='MARKET', + reduce_only=True # 平仓时使用 reduceOnly=True + ) + logger.debug(f"{symbol} [平仓] place_order 返回: {order}") + except Exception as order_error: + logger.error(f"{symbol} [平仓] ❌ 下单失败: {order_error}") + logger.error(f" 下单参数: symbol={symbol}, side={side}, quantity={quantity:.4f}, order_type=MARKET") + logger.error(f" 错误类型: {type(order_error).__name__}") + import traceback + logger.error(f" 完整错误堆栈:\n{traceback.format_exc()}") + raise # 重新抛出异常,让外层捕获 if order: logger.info(f"{symbol} [平仓] ✓ 平仓订单已提交 (订单ID: {order.get('orderId', 'N/A')})") @@ -351,13 +362,48 @@ class PositionManager: f"(原因: {reason})" ) return True - - return False + else: + # place_order 返回 None,说明下单失败 + logger.error(f"{symbol} [平仓] ❌ 下单返回 None,可能的原因:") + logger.error(f" 1. 订单名义价值不足(小于最小要求)") + logger.error(f" 2. 数量精度调整后为 0 或负数") + logger.error(f" 3. 无法获取价格信息") + logger.error(f" 4. 其他下单错误(已在 place_order 中记录)") + logger.error(f" 持仓信息: {side} {quantity:.4f} @ MARKET") + + # 尝试获取更多诊断信息 + try: + symbol_info = await self.client.get_symbol_info(symbol) + ticker = await self.client.get_ticker_24h(symbol) + if ticker: + current_price = ticker['price'] + notional_value = quantity * current_price + min_notional = symbol_info.get('minNotional', 5.0) if symbol_info else 5.0 + logger.error(f" 当前价格: {current_price:.4f} USDT") + logger.error(f" 订单名义价值: {notional_value:.2f} USDT") + logger.error(f" 最小名义价值: {min_notional:.2f} USDT") + if notional_value < min_notional: + logger.error(f" ⚠ 订单名义价值不足,无法平仓") + except Exception as diag_error: + logger.warning(f" 无法获取诊断信息: {diag_error}") + + return False except Exception as e: logger.error(f"{symbol} [平仓] ❌ 平仓失败: {e}") + logger.error(f" 错误类型: {type(e).__name__}") import traceback - logger.error(f" 错误详情:\n{traceback.format_exc()}") + logger.error(f" 完整错误堆栈:\n{traceback.format_exc()}") + + # 尝试清理本地记录(即使平仓失败) + try: + await self._stop_position_monitoring(symbol) + if symbol in self.active_positions: + del self.active_positions[symbol] + logger.info(f"{symbol} [平仓] 已清理本地持仓记录") + except Exception as cleanup_error: + logger.warning(f"{symbol} [平仓] 清理本地记录时出错: {cleanup_error}") + return False async def check_stop_loss_take_profit(self) -> List[str]: