103 lines
3.6 KiB
Markdown
103 lines
3.6 KiB
Markdown
# v4.5.4 平仓信号 dedup 误跳 — 真实事件复现 + 用户视角教训
|
|
|
|
**时间**: 2026-07-08
|
|
**事件**: 熬鹰ETH short 减仓→平仓 信号链
|
|
**触发用户反馈**: "要是我没发现,就一直不推了吗?重试机制呢"
|
|
|
|
---
|
|
|
|
## 事件完整时间线
|
|
|
|
1. **15:00** 熬鹰 ETH short 1773张 减仓信号
|
|
- process_signal 返回 `✅ 已推送 | ETH short 5x | 0.64张 | 性价比低`
|
|
- 用户持仓: ETH short 1.85张 @5x (avgPx 1759.78, 浮亏 -$3.52)
|
|
- ⚠️ 这是"减仓信号",不是"新开仓" — 本应触发 advisor 加仓路径
|
|
|
|
2. **15:01** 熬鹰 ETH short 平仓信号 (跟单号:`🚨 已平仓提醒`, +11.23%)
|
|
- process_signal 返回 `⏭️ 重复信号,跳过`
|
|
- **❌ BUG**: 平仓信号走了2分钟窗口 dedup,没走 close 独立通道
|
|
- ETH short 1.85张 **未自动平仓**
|
|
|
|
3. **15:05** ETH 继续涨到 1795
|
|
- 用户浮亏扩大到 -$6.58
|
|
- 用户追问: "这个没推平仓信号"
|
|
|
|
4. **15:06** agent 手动重跑同一平仓信号
|
|
- process_signal 返回 `✅ 平仓处理: closed | ETH short`
|
|
- ETH short 1.85张 全平成功
|
|
- USDT 回到 $106.34
|
|
|
|
---
|
|
|
|
## 根因
|
|
|
|
`process_signal.py` 主流程顺序错误:
|
|
|
|
```python
|
|
# 错误顺序:
|
|
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)
|
|
|
|
```python
|
|
# 正确顺序:
|
|
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 的提醒
|
|
|
|
1. **不要相信 is_duplicate() 适用于所有信号类型** — 它是为 open/reduce 设计的
|
|
2. **close 信号是"必须执行"的命令**,不能和 open/reduce 共用去重窗口
|
|
3. **用户视角优先**: 平仓失败=系统坏了,不是"按规则跳过了"
|
|
4. **process_signal 返回值 ≠ 实际行为**: 返回"重复信号"不代表持仓已处理,必须查 raw REST 验证 |