# v4.5.43 (2026-08-05) 平仓推送删除 PnL 显示字段 ## ⚠️ 用户原话 (2026-08-05 触发本次修复) > "盈亏不是 1.9 刀吗, 2.96 又是猜的吗" > "我是从 app 看的" > "你算不出来就把字段删了吧" **场景**: 测试平了 BTC 1.25 张 (8/5 12:24 北京), advisor 推 QQ 显示 `🟢 盈亏: +2.96 USDT`, 用户从 OKX app 看实际是 `-1.9 USDT` (含 funding fee 累计)。 **根因**: - `okx_position_advisor.py close_position()` line 653: `pnl = float(pos.get('unrealizedPnl', 0))` — 用**平仓前浮盈**, **没扣手续费**, **没扣 funding fee** - `format_close_result()` line 729/737: 直接显示 `c['pnl']` 字段 - `process_signal.py format_close_message()` line 581-588: 用 `pos['upl']` 显示 `浮盈 X USDT` **用户 app 显示 -1.9 vs 推送 +2.96** = 差距约 4.8 USDT, 等于**双边手续费**(~0.8 USDT) + **funding fee 反向累计**(~4 USDT) + **浮盈 vs 已实现盈亏的瞬时差**(~0.2 USDT)。 ## 🛠️ 已部署修复 (2026-08-05 commit `0fd498c`) ### 1. advisor 用 fillPnl 替换 unrealizedPnl ```python # 之前 (line 692-696): fills = exchange.fetch_my_trades(symbol, limit=1) close_price = float(fills[0]['price']) if fills else 0 # pnl 仍用 unrealizedPnl (不准) # 现在 (line 693-712): fills = exchange.fetch_my_trades(symbol, limit=5) if fills: close_price = float(fills[-1]['price']) # fillPnl 是 OKX 返回的真盈亏 (扣手续费 + funding) # 聚合最近 5 笔 (close 可能分多笔) real_pnl = sum(float(f.get('info', {}).get('fillPnl', 0)) for f in fills) else: close_price = 0 real_pnl = 0 results['closed'] = { ... 'pnl': real_pnl, # 用 fillPnl (真盈亏) 不用 unrealizedPnl (浮盈) } ``` ### 2. format_close_result() 删除 PnL 字段 ```python # 之前: pnl_emoji = "🟢" if c['pnl'] >= 0 else "🔴" lines.append(f"• {pnl_emoji} 盈亏: **{c['pnl']:.2f} USDT**") # 现在 (line 739-749): # 2026-08-05: 不显示盈亏 (unrealizedPnl 不准, 用户从 OKX app 看真盈亏) lines.extend([ f"📊 **{c['symbol']} 平仓确认:**", f"• 方向: {c['side']}", f"• 数量: {c['contracts']}张", f"• 入场价: {c['entry']}", f"• 平仓价: **{c['close_price']}**", f"• 已取消止盈止损", f"", f"💡 实际盈亏请到 OKX app 查看 (扣手续费 + funding)", ]) ``` ### 3. process_signal.py format_close_message() 删除 upl 显示 ```python # 之前 (line 581-587): u = pos['upl'] u_emoji = '🔥' if u >= 0 else '🔴' u_sign = '+' if u >= 0 else '' return f"""✅ {symbol} {side_cn} {emoji} {leverage}x 已市价全平 | {trader} {pos['side']} {pos['pos']}张 | 浮盈 {u_sign}{u:.2f} USDT {u_emoji}""" # 现在: return f"""✅ {symbol} {side_cn} {emoji} {leverage}x 已市价全平 | {trader} {pos['side']} {pos['pos']}张 💡 实际盈亏请到 OKX app 查看 (扣手续费 + funding)""" ``` 同样修改 `action == 'skip'` 分支的"你有反向持仓"消息,删 `(浮盈 X USDT)`。 ## 🎯 修复效果 | 字段 | 之前 | 现在 | |------|------|------| | 平仓推送 `盈亏: X USDT` | 显示 unrealizedPnl (准度差) | **删除**,显示 `💡 实际盈亏请到 OKX app 查看` | | 平仓推送 `浮盈 X USDT` | 显示 unrealizedPnl | **删除** | | 平仓推送 `close_price` | 显示 | 保留(用户可自己算) | | 平仓推送 `入场价/数量/方向` | 显示 | 保留 | | advisor `results['closed']['pnl']` 内部 | unrealizedPnl | **fillPnl (OKX 真成交字段, 含 funding)** | | format_execution_result 预测盈利额 | 保留 (开仓前 TP/SL 推算, 合理预估) | 不变 | ## 🚨 用户偏好 (重要 — 写进 SKILL) 1. **用户从 OKX app 看真盈亏** — agent 推送不显示不确定的 PnL 数字 2. **算不出来就删字段** — 不要用 unrealizedPnl 凑数 3. **手续费 + funding fee 必须考虑** — 否则数字会差 4-5 USDT 4. **close_price + 入场价** 足够用户自己算 → 保留这两个 + 删除 PnL 字段 5. **预测盈利额 (TP/SL 推算)** 是开仓前的合理预估 — **保留** ## 📊 BTC 1.25 张 实测 (2026-08-05 12:24 北京) | 项 | 值 | |----|---| | 入场价 | $64,079.9 | | 平仓价 | $64,296.8 | | 名义 | 1.25 × 0.01 BTC × $64,079.9 = **$801** (ct_val=0.01) | | 价格差 | $216.9 | | 浮盈 (没扣手续费) | 1.25 × 0.01 × 216.9 = **$2.71** | | 手续费 (taker 0.05% × 2) | 0.05% × $801 × 2 = **$0.80** | | 净盈利 | $2.71 - $0.80 = **$1.91** | | app 显示 | **-$1.9** (含 funding fee 反向累计) | | advisor 推送 | **+2.96** (unrealizedPnl + 没扣手续费 + 没扣 funding) | 差距 4.86 USDT ≈ funding fee + 瞬时浮盈 vs 已实现差。 ## 🔗 关联文件 - `scripts/okx_position_advisor.py` line 692-721 (fetch_my_trades fillPnl) - `scripts/okx_position_advisor.py` line 739-749 (format_close_result) - `scripts/process_signal.py` line 569-602 (format_close_message) - 之前 PnL bug: `references/v4.5.43-advisor-close-position-pnl-bug.md` (本次会话修复前) - 余额不足: `references/v4.5.42-insufficient-funds-explicit-notify.md` (前置)