From f00b6962e2a16361b1ee168e6d41681086fd6d3f Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 5 Aug 2026 12:17:04 +0800 Subject: [PATCH] =?UTF-8?q?okx-auto-position:=20=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E4=B8=8D=E8=B6=B3=E6=98=BE=E5=BC=8F=E6=8F=90=E7=A4=BA=20+=20ex?= =?UTF-8?q?it=20code=20!=3D=200?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Bug**: 8/4 20:32 SNDK 加仓信号 done, 但 OKX 没持仓 — 用户以为是 bug **原因**: process_signal.py 余额不足时只推'pushed_add_insufficient'消息, 不标 failed signal_queue.db 标 done → 用户/agent 都以为是 bug **Fix**: 1. process_signal.py 新增 _get_usdt_free() helper (实时查 OKX USDT free) 2. 余额不足时 QQ 推送加前缀 '⚠️ 跟单失败: 余额不足 ⚠️' + USDT 余额显示 3. process_signal.py main() 加 exit code 2 (跟单失败时) → signal_queue.retry 标 failed (而非 done) 4. retry < 3 仍会重试, 但 failed 状态可区分 done (signal_queue.db 加 status='failed') **注意**: advisor 实际会给 0.056 张 SNDK (USDT 26.82 保证金), 不是 0 张 — 但用 99.7% 余额不健康 → 用户应该知道是'满仓'而非'跟单成功' --- okx-auto-position/scripts/process_signal.py | 40 +++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/okx-auto-position/scripts/process_signal.py b/okx-auto-position/scripts/process_signal.py index 7c6f903..7251233 100644 --- a/okx-auto-position/scripts/process_signal.py +++ b/okx-auto-position/scripts/process_signal.py @@ -602,6 +602,22 @@ def format_close_message(fields, close_result): # ─── 执行订单 ──────────────────────────────────────────────────────────── +def _get_usdt_free(): + """实时查 OKX USDT free (失败返回 0).""" + try: + from okx_position_advisor import load_credentials, create_exchange + creds = load_credentials() + ex = create_exchange(creds) + bal = ex.fetch_balance() + # 兼容 ccxt OKX 多账户结构 + usdt_info = bal.get('USDT', {}) if isinstance(bal, dict) else {} + free = usdt_info.get('free', 0) if isinstance(usdt_info, dict) else 0 + return float(free or 0) + except Exception as e: + print(f"[warn] _get_usdt_free err: {e}", file=__import__('sys').stderr) + return 0.0 + + def execute_order(symbol, side, leverage, rec): """执行开仓订单""" cmd = [ @@ -809,14 +825,28 @@ def process_signal(text): trader_pnl=float(fields.get('pnl', '0').replace(',', '')), raw_text=text, outcome='auto_executed_add') else: - # 余额不足/执行失败 → 推消息不执行 - msg = format_message(fields, rec, signal_type) + # 余额不足/执行失败 → 推消息不执行 (2026-08-05: 余额不足显式提示) + exec_err = (exec_result or {}).get('error', 'unknown') if exec_result else 'no result' + # 看是余额不足还是其他错 + is_insufficient = '余额不足' in str(exec_err) or 'insufficient' in str(exec_err).lower() + # 实时查 USDT free (用 okx_position_advisor helper) + usdt_free = _get_usdt_free() + if is_insufficient: + msg = format_message(fields, rec, signal_type) + msg = f"⚠️ **跟单失败: 余额不足** ⚠️\n\n{msg}\n\n💡 你 USDT ${usdt_free:.2f} 不足以开 1 张 {symbol} 3x 杠杆 (约需 ~$46k)\n" + outcome = 'pushed_add_insufficient' + else: + msg = format_message(fields, rec, signal_type) + msg = f"⚠️ **跟单失败: 执行错误** ⚠️\n\n{msg}\n\n❌ 错误: {exec_err}\n" + outcome = 'auto_executed_failed' _tracker_record(trader=trader, symbol=symbol, side=side, leverage=int(leverage) if leverage else 10, trader_size=float(fields.get('size', '0').replace(',', '')), trader_entry=float(fields.get('entry', '0').replace(',', '')), trader_pnl=float(fields.get('pnl', '0').replace(',', '')), - raw_text=text, outcome='pushed_add_insufficient') + raw_text=text, outcome=outcome) + # 2026-08-05: 在 main() 标记 status=failed (signal_queue.db) — 让 cron retry 时知道 + _exec_failed = exec_err elif signal_type == 'reduce': # 减仓信号: 锁了同方向 → 按大佬减仓比例, 自动减我们的同向持仓 try: @@ -908,6 +938,10 @@ def main(): result = process_signal(text) print(result) + # 2026-08-05: 余额不足/执行失败 → exit code != 0 → signal_queue.retry 标 failed + import sys as _sys + if '跟单失败' in str(result): + _sys.exit(2) if __name__ == '__main__': main()