Files
Hermes-Skills/okx-auto-position/references/v4.5.116-2026-09-26-leverage-parse-bug-and-channel-revert-flow.md
T

155 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# v4.5.116 — Leverage 字段正则 fallback + 频道切换 4 步验证 + 用户情绪识别 (2026-09-26)
## 1. 杠杆字段解析 bug
**症状**: 信号原文 `【币种】:ONDOUSDT 永续 | 全仓 | 2x` 进 `process_signal.py`, advisor 默认报 10x leverage, 实际信号是 2x。
**根因** (`process_signal.py:79`):
```python
extractors = {
'leverage': r'【杠杆】\s*[::]?\s*(\d+)', # 只匹配独立【杠杆】标签
}
```
信号里杠杆在币种标签内 (`ONDOUSDT 永续 | 全仓 | 2x`), 没有独立 `【杠杆】` 标签, 正则匹配失败, 默认 10x。
**代价**: 你的仓位杠杆 = advisor 报量 × 默认 10x。如果熬鹰实际 1.95x, 你的风险敞口是他 5.13 倍。满仓时 12% 跌幅爆, 熬鹰 88% 跌幅才爆。
**修复** (已 patch):
```python
extractors = {
# 独立【杠杆】标签 OR 行内|全仓|Nx 两种 fallback
'leverage': r'(?:【杠杆】\s*[::]?\s*(\d+)|(?:永续|全仓)\s*\|\s*全仓\s*\|\s*(\d+)\s*[xX]?)',
}
# 提取时优先取 group(1), fallback group(2)
for key, pattern in extractors.items():
m = re.search(pattern, text)
if m:
v = m.group(1) or m.group(2) or ''
if v:
fields[key] = v.replace(',', '') if key != 'unit' else v
```
**测试用例**:
```python
# 旧格式 (有【杠杆】N)
text1 = '''【币种】BTCUSDT|永续|10x
【方向】做多
【杠杆】5
【仓位】1000'''
assert parse_signal(text1)['leverage'] == '5' # ✓ group(1)
# 新格式 (币种标签内|全仓|2x, 无独立【杠杆】)
text2 = '''【币种】:ONDOUSDT 永续 | 全仓 | 2x
【方向】:做多 🟩'''
assert parse_signal(text2)['leverage'] == '2' # ✓ group(2)
# 旧格式混合 (标签+行内)
text3 = '''【币种】BTCUSDT 永续 | 全仓 | 3x
【方向】做多
【杠杆】3'''
assert parse_signal(text3)['leverage'] == '3' # group(1) 优先
```
**触发场景**: 任何"币种标签内|永续|全仓|Nx"格式信号 — 常见于 2026-08 后的新版熬鹰币安实盘/熬鹰FOMO合约实盘 模板。
**用户原话** (2026-09-26): "ONDO 一直是 2 倍, 你是不是改成 10 倍了" — 是默认 10x 的结果, 不是显式调杠杆。但效果等价于"无形调了杠杆"。
---
## 2. 频道切换 4 步端到端验证链 — 用户情绪信号
**用户原话** (按情绪递进):
1. "需要把监听的频道更新一下" — 中性
2. "换到新频道, 其他的配置不动" — 中性
3. "现在用的是哪个频道" — 中性
4. "C, 是一个群吗, 还是之前配置过 但启用的不对" — 轻微疑惑
5. "现在交易信号都没转发了吗" — 轻微失落
6. "那现在查信号为什么没进来啊, 转发器在正常工作的? 我对你十分失望" — **明确失望**
7. "现在把监听频道改回到 https://t.me/jiankongshipan" — 明确放弃新频道, 回切
**关键教训**: 用户说"我对你十分失望"时, **不要继续诊断新频道**, 立即承认失败并执行"回切到旧频道"操作。Agent 不能无限制地诊断/优化 — 用户给的是"立即恢复"的命令。
**反向验证 (anti-pattern)**: Agent 在用户失望后继续问"确认是新频道吗? 那查一下 OKX 实际是不是有信号流入?" — 这是继续在错误的频道上诊断, **不解决用户痛点**。
**正解**: 用户说失望时, 立即回切并确认 — "已切回 jiankongshipan, 当前 source=1, 查 forwarder logs 看到 NewMessage 事件正常触发, 等下一条信号验证"。
---
## 3. 频道切换"伪成功"陷阱 — 用户没说"换好了",就还在诊断
**症状**: Agent 把 `forward_rules.source_chat_id` 改成新频道, `docker restart` 转发器, 然后告诉用户"已切换"。但实际上:
1. forwarder 的 chat_id 提取还是用 `abs(chat.id)` — TG channel 是 `-100xxx`, abs 剥成 `xxx`, 跟 DB 存的 `-100xxx` 字符串匹配不上
2. user_client 虽然订阅了 channel (`Got difference for channel XXX updates`), 但 `NewMessage` 事件不触发
3. 用户发了一条"汇总播报"试探, 没看到转发
4. 用户下一句:"现在交易信号都没转发了吗"
**正解 — 4 步验证** (任何一步不通过, 都不能宣告成功):
1. DB 配置: `forward_rules.source_chat_id` 改到新 chats.id, forwarder 重启
2. **看 forwarder logs 出现 `[处理规则|新消息|命中黑名单]` 日志** — 仅有 `Got difference for channel ... updates` 不够, 说明 message_handler 没匹配上 (chat_id 提取 bug)
3. **真信号触达**: 用 telethon `iter_messages('username', limit=10)` 验证 (容器内需 `cp session /tmp/` 解锁)
4. **执行闭环**: 用户转发一条真实信号到新频道, 看 QQ 推送 + OKX execute + check_account 仓位变动
**只改 db 不验证后续 = 假成功**, 等到新信号来了才发现"漏发"就晚了 (本 session ONDO 漏发就是这个原因)。
---
## 4. token 纪律补充: 蚂蚁式减仓双层过滤 + 用户情绪触发合并输出
用户原话 (按情绪递进):
1. "调整一下, 只有加仓, 减仓, 开仓, 平仓这些字段的消息才处理" — 主动优化
2. "蚂蚁减仓尽量减少token的消耗" — 明确 token 关注
3. "我真服了" — 失望 (蚂蚁减仓 spam 不止, signal 也没进来)
**结论**: § 65 已部署 classify 严格模式 + 1% min 减仓过滤 + 同类输出合并, 2026-09-26 实测生效。本 session 蚂蚁减仓从 50+ 条 spam 收敛到"蚂蚁减仓no-op(0.X%<1%); USDT $576" 重复 1 行。但**用户信号断了**(forwarder chat_id bug), 这才是 1+2 实际 loss of progress。
**执行优先级**: token 优化只是减少噪音, 不解决"信号没进来"的核心问题。Agent 应该在用户说"信号没来"时优先诊断 forwarder 链路, 而不是继续优化 process_signal。
---
## 5. forwarder 模板名 disambiguation
**用户原话** (2026-09-26): "转发器转发内容时, 你再加一条转发时间"
**意图**: 让转发消息能区分"原信号时间"vs"转发动作发生时间"。
**当前状态**:
- `forward_rules.time_template` 默认 `⏱信号时间: {time}` — 但代码层 `{time}` 实际是 hook 接收时刻 (转发时), 不是原信号时间
- `forward_rules.is_original_time` 控制是否附加这条时间戳
**修复** (用户选项 A 已执行 2026-09-26):
- `time_template` 改名 `⏱转发时间: {time}` (语义准确)
- 用户接受 A 方案 (简洁), 不加额外"原信号时间"行
**未做**: 加`forward_time_template`双时间字段 (方案 B) — 需要改 forwarder 代码层, 改动大, 用户选择不改。
---
## 6. 调试顺序参考
当用户说"信号没来/没处理/没转发"时, 按这个顺序查:
1. **forwarder logs** (`docker logs telegram-forwarder --since 24h`)
- 有 `[处理规则|新消息]` 日志? → step 2
- 只有 `Got difference for channel ... updates`? → **chat_id 提取 bug** (event.chat_id vs abs(chat.id))
- 有 `[黑名单]` 日志? → 硬编码黑名单误杀 (USDT/老师/带单)
- 完全没有消息日志? → **user client 没真正 join channel** 或 **forwarder 完全停摆**
2. **DB 配置** (`docker exec telegram-forwarder python3 sqlite3 ...`)
- `forward_rules.source_chat_id` 是不是用户说的新频道?
- `chats.telegram_chat_id` 是不是 `-100xxxxxxxx` 格式 (负数 + 100 前缀)?
- `forward_rules.enable_rule` 是不是 1?
3. **真信号触达** (telethon iter_messages)
- 频道是不是真有最近 24h 信号? 是不是被管理员删了?
- 信号的字段格式是新版(行内|全仓|Nx)还是旧版(独立【杠杆】N)?
4. **process_signal 链**
- classify 是不是 unknown? → 检查信号格式是否太严格
- 白名单闸是不是拦了? → `forward_rules` 的 trader 白名单是不是过期
- advisor 是不是 BadSymbol? → 1000xxx 币种 OKX 上不存在
- 推送是不是失败? → **推送失败 ≠ execute 失败**, 必查 check_account
5. **用户情绪反应**
- 用户说"我对你失望/真服了" → 立即承认失败, 执行用户要的恢复命令 (回切/暂停诊断)
- 不要在用户情绪爆发后继续在错误的频道上诊断