This commit is contained in:
薇薇安 2026-01-14 21:23:31 +08:00
parent cd74e96c22
commit 1344435667
2 changed files with 75 additions and 25 deletions

View File

@ -476,7 +476,8 @@ class BinanceClient:
side: str, side: str,
quantity: float, quantity: float,
order_type: str = 'MARKET', order_type: str = 'MARKET',
price: Optional[float] = None price: Optional[float] = None,
reduce_only: bool = False
) -> Optional[Dict]: ) -> Optional[Dict]:
""" """
下单 下单
@ -528,24 +529,27 @@ class BinanceClient:
logger.warning(f" 需要增加数量或提高仓位大小") logger.warning(f" 需要增加数量或提高仓位大小")
return None 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': if order_type == 'MARKET':
order = await self.client.futures_create_order( order = await self.client.futures_create_order(**order_params)
symbol=symbol,
side=side,
type='MARKET',
quantity=adjusted_quantity
)
else: else:
if price is None: if price is None:
raise ValueError("限价单必须指定价格") raise ValueError("限价单必须指定价格")
order = await self.client.futures_create_order( order_params['timeInForce'] = 'GTC'
symbol=symbol, order_params['price'] = price
side=side, order = await self.client.futures_create_order(**order_params)
type='LIMIT',
timeInForce='GTC',
quantity=adjusted_quantity,
price=price
)
logger.info(f"下单成功: {symbol} {side} {adjusted_quantity} @ {order_type} (名义价值: {notional_value:.2f} USDT)") logger.info(f"下单成功: {symbol} {side} {adjusted_quantity} @ {order_type} (名义价值: {notional_value:.2f} USDT)")
return order return order

View File

@ -280,13 +280,24 @@ class PositionManager:
f"(持仓数量: {position_amt:.4f})" f"(持仓数量: {position_amt:.4f})"
) )
# 平仓 # 平仓(使用 reduceOnly=True 确保只减少持仓,不增加反向持仓)
order = await self.client.place_order( try:
symbol=symbol, logger.debug(f"{symbol} [平仓] 调用 place_order: {side} {quantity:.4f} @ MARKET (reduceOnly=True)")
side=side, order = await self.client.place_order(
quantity=quantity, symbol=symbol,
order_type='MARKET' 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: if order:
logger.info(f"{symbol} [平仓] ✓ 平仓订单已提交 (订单ID: {order.get('orderId', 'N/A')})") logger.info(f"{symbol} [平仓] ✓ 平仓订单已提交 (订单ID: {order.get('orderId', 'N/A')})")
@ -351,13 +362,48 @@ class PositionManager:
f"(原因: {reason})" f"(原因: {reason})"
) )
return True return True
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")
return False # 尝试获取更多诊断信息
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: except Exception as e:
logger.error(f"{symbol} [平仓] ❌ 平仓失败: {e}") logger.error(f"{symbol} [平仓] ❌ 平仓失败: {e}")
logger.error(f" 错误类型: {type(e).__name__}")
import traceback 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 return False
async def check_stop_loss_take_profit(self) -> List[str]: async def check_stop_loss_take_profit(self) -> List[str]: