3.6 KiB
3.6 KiB
v4.5.4 平仓信号 dedup 误跳 — 真实事件复现 + 用户视角教训
时间: 2026-07-08 事件: 熬鹰ETH short 减仓→平仓 信号链 触发用户反馈: "要是我没发现,就一直不推了吗?重试机制呢"
事件完整时间线
-
15:00 熬鹰 ETH short 1773张 减仓信号
- process_signal 返回
✅ 已推送 | ETH short 5x | 0.64张 | 性价比低 - 用户持仓: ETH short 1.85张 @5x (avgPx 1759.78, 浮亏 -$3.52)
- ⚠️ 这是"减仓信号",不是"新开仓" — 本应触发 advisor 加仓路径
- process_signal 返回
-
15:01 熬鹰 ETH short 平仓信号 (跟单号:
🚨 已平仓提醒, +11.23%)- process_signal 返回
⏭️ 重复信号,跳过 - ❌ BUG: 平仓信号走了2分钟窗口 dedup,没走 close 独立通道
- ETH short 1.85张 未自动平仓
- process_signal 返回
-
15:05 ETH 继续涨到 1795
- 用户浮亏扩大到 -$6.58
- 用户追问: "这个没推平仓信号"
-
15:06 agent 手动重跑同一平仓信号
- process_signal 返回
✅ 平仓处理: closed | ETH short - ETH short 1.85张 全平成功
- USDT 回到 $106.34
- process_signal 返回
根因
process_signal.py 主流程顺序错误:
# 错误顺序:
dedup_conn = init_dedup_db()
if is_duplicate(dedup_conn, text, symbol, trader): # ← close 信号在这里被误跳
return "⏭️ 重复信号,跳过"
signal_type = classify_signal(fields)
if signal_type == 'close':
# 平仓逻辑,永远到不了这里
...
is_duplicate() 的2分钟窗口把"减仓+平仓"两个完全不同语义的信号合并去重了。
修复 (v4.5.4)
# 正确顺序:
signal_type = classify_signal(fields) # ← 先分类
if signal_type == 'close':
dedup_conn = init_dedup_db()
msg_hash = hashlib.md5(text.encode()).hexdigest()
# close 信号只看 raw_text hash 唯一性,不看2分钟窗口
if dedup_conn.execute("SELECT 1 FROM processed WHERE msg_hash = ?", (msg_hash,)).fetchone():
return "⏭️ 平仓信号完全重复跳过"
# 走平仓独立路径
close_result = close_position_raw(symbol_usdt, signal_side_en)
...
# 其他信号 (open/reduce) 才走2分钟窗口 dedup
dedup_conn = init_dedup_db()
if is_duplicate(dedup_conn, text, symbol, trader):
return "⏭️ 重复信号,跳过"
关键设计原则:
is_duplicate()永远不应用于 close 信号- close 信号 dedup 只能基于 raw_text hash (因为 text 内含最终收益额+标记价,天然唯一)
- 平仓动作必须发生 — 用户可能不会逐条核对内部状态
用户视角的关键反馈 (2026-07-08)
- 用户不会逐条核对 process_signal 返回值——他只看 QQ 有没有收到平仓结果
- 一旦他认为"应该平但没平",他不会去查 process_signal 内部状态,而是怀疑系统坏了
- 必须实现重试机制: 当平仓信号 dedup 命中时,不能简单 skip,必须至少推一条"⚠️ 平仓信号疑似跳过,请人工确认持仓"到 QQ
实测结果
修复后再次收到 ETH short 平仓信号 → 走独立通道 → 自动平仓成功 ✅
推送 git commit: v4.5.4: 平仓信号 dedup 误跳 bug 修复 — close 信号走独立通道 (2026-07-08 实测)
给未来 session 的提醒
- 不要相信 is_duplicate() 适用于所有信号类型 — 它是为 open/reduce 设计的
- close 信号是"必须执行"的命令,不能和 open/reduce 共用去重窗口
- 用户视角优先: 平仓失败=系统坏了,不是"按规则跳过了"
- process_signal 返回值 ≠ 实际行为: 返回"重复信号"不代表持仓已处理,必须查 raw REST 验证