From 0fd498c2c39a0172553c966ddc0354106f1c6576 Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 5 Aug 2026 13:58:03 +0800 Subject: [PATCH] =?UTF-8?q?okx-auto-position:=20=E5=B9=B3=E4=BB=93?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=88=A0=20unrealizedPnl=20=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20(=E6=94=B9=E7=94=A8=20fillPnl/=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Bug**: 平仓推送显示 unrealizedPnl (浮盈) + 不扣手续费 **实际**: 用户从 OKX app 看真盈亏 (-1.9 vs 推送 +2.96 不一致) **Fix**: 1. okx_position_advisor.py close_position() 用 fillPnl (OKX 真成交字段) 替换 unrealizedPnl 2. format_close_result() 删 '盈亏: X USDT' 字段 3. format_close_message() 删 '浮盈' 字段 4. 平仓推送加 '💡 实际盈亏请到 OKX app 查看 (扣手续费 + funding)' 提示 **保留**: - format_execution_result() 开仓前预测盈利额 (TP/SL 推算的合理预估) - record_confirmed 表的 pnl 字段 (历史归档) 预期: 用户平仓时推送不带误导性'X USDT 浮盈', 改从 OKX app 自己看真盈亏 --- .../scripts/okx_position_advisor.py | 23 ++++++++++++++----- okx-auto-position/scripts/process_signal.py | 10 ++++---- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/okx-auto-position/scripts/okx_position_advisor.py b/okx-auto-position/scripts/okx_position_advisor.py index 6ee08c6..6a6df35 100644 --- a/okx-auto-position/scripts/okx_position_advisor.py +++ b/okx-auto-position/scripts/okx_position_advisor.py @@ -692,12 +692,21 @@ def close_position(exchange, symbol, inst_id): import time time.sleep(2) - # 5. Get close price from trades + # 5. Get REAL close PnL from fills (扣手续费后的已实现盈亏) + # fetch_my_trades 返回字段: price/fee/cost/info/fillPnl (OKX 真实成交) try: - fills = exchange.fetch_my_trades(symbol, limit=1) - close_price = float(fills[0]['price']) if fills else 0 + 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 except Exception: close_price = 0 + real_pnl = 0 results['closed'] = { 'symbol': symbol.split('/')[0] + '/USDT', @@ -705,7 +714,7 @@ def close_position(exchange, symbol, inst_id): 'contracts': contracts, 'entry': entry, 'close_price': close_price, - 'pnl': pnl, + 'pnl': real_pnl, # 用 fillPnl (真盈亏) 不用 unrealizedPnl (浮盈) } return results @@ -726,7 +735,8 @@ def format_close_result(results): c = results.get('closed') if c: - pnl_emoji = "🟢" if c['pnl'] >= 0 else "🔴" + # 2026-08-05: 不显示盈亏 (unrealizedPnl 不准, fillPnl 需要查询) + # 用户从 OKX app 自己看实际盈亏 lines.extend([ f"", f"📊 **{c['symbol']} 平仓确认:**", @@ -734,8 +744,9 @@ def format_close_result(results): f"• 数量: {c['contracts']}张", f"• 入场价: {c['entry']}", f"• 平仓价: **{c['close_price']}**", - f"• {pnl_emoji} 盈亏: **{c['pnl']:.2f} USDT**", f"• 已取消止盈止损", + f"", + f"💡 实际盈亏请到 OKX app 查看 (扣手续费 + funding)", ]) return '\n'.join(lines) diff --git a/okx-auto-position/scripts/process_signal.py b/okx-auto-position/scripts/process_signal.py index 7251233..849604c 100644 --- a/okx-auto-position/scripts/process_signal.py +++ b/okx-auto-position/scripts/process_signal.py @@ -578,17 +578,17 @@ def format_close_message(fields, close_result): if action == 'closed': pos = close_result['pos_before'] - u = pos['upl'] - u_emoji = '🔥' if u >= 0 else '🔴' - u_sign = '+' if u >= 0 else '' + # 2026-08-05: 不显示浮盈 (unrealizedPnl 不准, 用户从 OKX app 看真盈亏) return f"""✅ {symbol} {side_cn} {emoji} {leverage}x 已市价全平 | {trader} -{pos['side']} {pos['pos']}张 | 浮盈 {u_sign}{u:.2f} USDT {u_emoji}""" +{pos['side']} {pos['pos']}张 +💡 实际盈亏请到 OKX app 查看 (扣手续费 + funding)""" elif action == 'skip': pos = close_result['pos_before'] return f"""⏭️ {symbol} 平仓信号跳过 | {trader} -你有反向持仓 {pos['side']} {pos['pos']}张 @ {pos['avgPx']:.2f} (浮盈 {pos['upl']:+.2f})""" +你有反向持仓 {pos['side']} {pos['pos']}张 @ {pos['avgPx']:.2f} +💡 实际盈亏请到 OKX app 查看 (扣手续费 + funding)""" elif action == 'none': return f"""ℹ️ {symbol} {side_cn} 平仓信号 | {trader}