diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index 74d3d67..cf7a7a6 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -2245,8 +2245,64 @@ class PositionManager: # 尝试从币安历史订单获取实际平仓价格 exit_price = None + realized_pnl = None + commission = None close_orders = [] try: + # 优先尝试从成交记录(Trade History)获取精确的 Realized PnL + # 这是最准确的方式,因为它包含了资金费率、手续费扣除后的实际盈亏 + try: + recent_trades = await self.client.get_recent_trades(symbol, limit=50) + + # 确定过滤时间戳 + entry_ts_ms_filter = 0 + et_obj = trade.get('entry_time') + if hasattr(et_obj, 'timestamp'): + entry_ts_ms_filter = int(et_obj.timestamp() * 1000) + elif isinstance(et_obj, (int, float)): + # 区分秒和毫秒 + entry_ts_ms_filter = int(et_obj * 1000) if et_obj < 3000000000 else int(et_obj) + elif isinstance(et_obj, str): + try: + from datetime import datetime + dt_obj = datetime.strptime(et_obj, "%Y-%m-%d %H:%M:%S") + entry_ts_ms_filter = int(dt_obj.timestamp() * 1000) + except: + pass + + if entry_ts_ms_filter > 0: + # 筛选出入场之后的成交记录 + closing_trades = [ + t for t in recent_trades + if t.get('time', 0) > entry_ts_ms_filter and float(t.get('realizedPnl', 0)) != 0 + ] + + if closing_trades: + total_pnl = 0.0 + total_comm = 0.0 + total_qty = 0.0 + total_val = 0.0 + + for t in closing_trades: + total_pnl += float(t.get('realizedPnl', 0)) + total_comm += float(t.get('commission', 0)) + qty = float(t.get('qty', 0)) + price = float(t.get('price', 0)) + total_qty += qty + total_val += qty * price + + realized_pnl = total_pnl + commission = total_comm + if total_qty > 0: + exit_price = total_val / total_qty + + logger.info( + f"{symbol} [状态同步] ✓ 从成交记录获取精确盈亏: " + f"PnL={realized_pnl} USDT, 均价={exit_price:.4f}" + ) + except Exception as trade_hist_err: + logger.warning(f"{symbol} [状态同步] 获取成交记录失败: {trade_hist_err}") + # 获取最近的平仓订单(reduceOnly=True的订单) import time end_time = int(time.time() * 1000) # 当前时间(毫秒) @@ -2412,12 +2468,24 @@ class PositionManager: ) continue - if trade.get('side') == 'BUY': - pnl = (exit_price - entry_price) * quantity - pnl_percent = ((exit_price - entry_price) / entry_price) * 100 - else: # SELL - pnl = (entry_price - exit_price) * quantity - pnl_percent = ((entry_price - exit_price) / entry_price) * 100 + # 如果已经获取到精确的 Realized PnL,直接使用 + if realized_pnl is not None: + pnl = realized_pnl + # 根据 Realized PnL 反推百分比 (PnL / 保证金) 或者 (PnL / 名义价值)? + # 这里保持与价格差计算一致的逻辑:(PriceDiff / EntryPrice) * 100 + # 如果 exit_price 是计算出来的均价,这个公式依然成立 + if trade.get('side') == 'BUY': + pnl_percent = ((exit_price - entry_price) / entry_price) * 100 + else: + pnl_percent = ((entry_price - exit_price) / entry_price) * 100 + else: + # 降级方案:使用价格差计算 + if trade.get('side') == 'BUY': + pnl = (exit_price - entry_price) * quantity + pnl_percent = ((exit_price - entry_price) / entry_price) * 100 + else: # SELL + pnl = (entry_price - exit_price) * quantity + pnl_percent = ((entry_price - exit_price) / entry_price) * 100 logger.debug( f"{symbol} [状态同步] 盈亏计算: "