155 lines
7.9 KiB
Markdown
155 lines
7.9 KiB
Markdown
# 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. **用户情绪反应**
|
||
- 用户说"我对你失望/真服了" → 立即承认失败, 执行用户要的恢复命令 (回切/暂停诊断)
|
||
- 不要在用户情绪爆发后继续在错误的频道上诊断 |