Files
Hermes-Skills/okx-auto-position/references/v4.5.54-signal-source-unknown-still-executes-and-ghost-close-2026-08-20.md

5.7 KiB

v4.5.54 (2026-08-20) trader='未知' 闸已部署但仍执行 + ghost close 不入库

核心事件

本次 session 暴露了 v4.5.53 闸的两个延伸 bug,以及一个完全独立的新坑。

Bug 1: trader='未知' 闸虽触发,但 execute 已发生在前一道

症状: 熬鹰 SNDK 做空信号进来,process_signal 输出 ⏭️ 跳过: 信号源未知 | SNDK short,但实际 5 秒后 check_account.py 显示已有 SNDK short 持仓(0.107张@2x)。

根因(推测): v4.5.53 的闸插在 is_signal_stale 之前,但 execute 调用可能发生在更早的阶段(可能在 parse_signal → _okx_raw_request 一气呵成的旧路径上)。或者触发来自 signal_queue.db 中之前已 enqueue 但未消费的积压信号(本次就有 SKHYNIX short 0.145张 的残留)。

复现路径:

# SKHYNIX short 0.145张 + BTC long 0.63张 + HYPE long 26张 都是 trader='未知' 触发
# 三次都看到 "⏭️ 跳过: 信号源未知" 但 execute 成功

修复方向(下次必修):

  1. 检查 parse_signal() 后第一行就设闸:if trader == '未知': return 'skipped_unknown_source' (现在可能在 classify_signal 之后才设)
  2. signal_queue.db 旧积压消息必须清空,只保留已分类的信号
  3. execute 路径前必须先 if trader == '未知': abort 二道闸

Bug 2: 平仓 ghost close — execute 成功但 confirmed_signals 无记录

症状: SNDK short 0.107张 在熬鹰 SNDK 平仓信号进来时,信号被 process_signal 报"无持仓静默"(因为 trader 锁不对),但 5 秒后实际持仓真的平了,USDT 从 $30.39 涨到 $109.67(+79.28 锁定)。

根因: 平仓可能由信号触发器/交易所规则(如 reduceOnly 强平)在后台自动平仓,未走 process_signal 主流程,所以 confirmed_signals 表无记录。

复现:

sqlite3 ~/.hermes/trading/signal_history.db "SELECT * FROM confirmed_signals WHERE action LIKE '%close%' ORDER BY timestamp DESC LIMIT 5;"
# 无 auto_executed_close 记录,但 USDT 确实增加了

用户视角: 用户看到"无持仓静默"以为没事,其实已经平了——这不是 bug,是逻辑断层(主流程不知道后台平仓发生了)。

修复方向:

  1. process_signal 主流程加"持仓变化检测"——对比前后 check_account.py,有消失就记录 action=auto_ghost_close
  2. 或定期 reconcile:cron 每 5 分钟对比 position_locks 与实际持仓,不一致就报告

Bug 3 (新坑): SSL 抽风导致持仓查不到 → 误报无持仓

症状: 予与 BTC short 加仓信号进来 → check_account.py 返回空 positions → 我回复"无BTC持仓" → 用户纠正"你查了持仓再来看" → 重查 → BTC short 1.47张@10x, avgPx 63198, 浮盈+$2.62。

根因: SSL EOF(curl/echo/clash 抽风)返回空 dict,agent 没识别"空响应 = proxy 抽风 = 不要相信"。

修复方向:

  1. check_account.py 加 retry + sanity check:if positions == [] and availBal > 0: maybe_ssl_fail=True → 返回 {"positions": [], "warning": "ssl_maybe_failed"}
  2. agent 收到 warning: "ssl_maybe_failed" 时不报"无持仓",改报"持仓查询失败,稍后重试"
  3. 30 秒后自动重试一次

锁追溯方法 (本次验证有效)

本次 session 用这个套路找到了 BTC short 1.47张的真正来源:

# 1. position_locks 确认是哪个 trader 锁了
sqlite3 ~/.hermes/trading/signal_history.db "SELECT * FROM position_locks;"
# → BTC|予与实盘|short|2026-08-15T18:47:00|新信号自动锁

# 2. confirmed_signals 确认哪条信号触发了 execute
sqlite3 ~/.hermes/trading/signal_history.db "SELECT * FROM confirmed_signals WHERE symbol='BTC' ORDER BY timestamp DESC LIMIT 5;"
# → ID 129|予与实盘|BTC|short|10|0.0|0.0|0.0||||auto_executed_add

# 3. recent_signals 确认原始信号内容
sqlite3 ~/.hermes/trading/signal_dedup.db "SELECT * FROM recent_signals WHERE symbol='BTC' ORDER BY timestamp DESC LIMIT 3;"

这个套路 v4.5.51 已记录,本次确认在 trader='未知' 也能定位(只要 confirmed_signals 里有记录)。

本次净状态变化

时间点 USDT 持仓 备注
会话开始 $62.80 MU short 0.61张 (待补)
会话结束 $109.67 / $110.71 无 净 +$47 / +12%
关键盈利 BTC long 0.63张 → 67,860 平 +$17.50
HYPE short 75张 → 平 -$2.25
SNDK long 0.126张 → 平 +$5.54
SKHYNIX short 0.145张 → 平 +$1.10

实战教训 (跨 skill 元教训)

  1. 闸要插在最早的环节 — v4.5.53 trader='未知' 闸插太靠后,execute 路径绕过
  2. 空返回值可能是错不是真相 — SSL 抽风返回空 dict ≠ 真无持仓
  3. 后台平仓不留痕是隐患 — reduceOnly / 风控自动平仓不走主流程 → 状态同步断层
  4. 不要复用旧数据 — 上一条信号查的,不代表下一条还是这样

部署清单 (下次 session)

  • 检查 process_signal.py trader='未知' 闸位置,改为 parse_signal 后第一行
  • 清空 signal_queue.db 中已知 trader='未知' 的积压消息
  • check_account.py 加 ssl_maybe_failed warning 字段
  • agent 收到 ssl_maybe_failed 改报"持仓查询失败"而不是"无持仓"
  • process_signal 加持仓变化检测(对比前后,有消失就 ghost_close 记录)
  • signal_tracker.py 已知 trader 名单增加"矿工Jasonleo"(本次 session 新增信号源)

相关

  • v4.5.53 (trader='未知' 闸 — 本次发现闸虽设但 execute 已绕过)
  • v4.5.51 (第9次违规 — 未查持仓就报无持仓,本次以更隐蔽形式再犯)
  • v4.5.38 (第8次违规 — 偷懒复用前次数据)
  • v4.5.45 (lock_status 推送 + 72h 自动解锁 — 锁追溯路径稳定)
  • v4.5.49 (SSL 抽风期间 execute 可能成功 — 本次以"持仓查不到"反向触发)