Files
Hermes-Skills/okx-auto-position/references/v4.5.53-unknown-trader-gate-2026-08-18.md
T

130 lines
5.1 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.
---
name: v4.5.53-unknown-trader-gate-2026-08-18
description: "2026-08-18 SNDK 做空 0.095 张误开仓 — parse_signal fallback '未知' 没有 gate。v4.5.53 在 process_signal() 主流程加了 trader='未知' 闸。"
version: 1.0.0
type: reference
status: active
---
# v4.5.53 (2026-08-18) 信号源缺失闸 — trader='未知' 直接跳过
## 事件
**时间**: 2026-08-18
**信号原文**:
```
✅ SNDK 做空 🟥 2x 新开仓
📊 信号源: 未知 158.00 SNDK(价值$?)
📐 性价比检查
• 盈亏比: 3.0:1 ✅
• 盈利额: +21.40 USDT ✅
...
```
**实际执行**:
- 入场: $1724.76
- 仓位: **0.095 张** ⚠️ (不该开)
- TP: $1499.38
- SL: $1799.79
**用户反馈**: "这个没信号源的就不要跟单了"
## 根因分析
`parse_signal()` 在 trader 字段提取不出来时,会**硬编码** `fields['trader'] = '未知'`(参见 `process_signal.py` 第 86 行, 2026-08-07 加的注释: "实在找不到 trader 标签 — 标 '未知' (不要硬编码 'X聚合社区', 会误导)")。
但**主流程 process_signal() 没有任何 gate 去尊重这个 '未知' 标记** —— 它继续往下走:
- `is_signal_stale()` → 通过(没时间戳算新鲜)
- `classify_signal()` → 'open'
- `is_duplicate()` → 新信号
- `run_advisor()` → 返回 rec
- `execute_order()` → **真的下了 0.095 张**
**为什么有这条 fallback 设计却没 gate**:
- 2026-08-07 加 fallback 的目的是:**显示**给用户看时标 "未知",**不要硬编码 'X聚合社区'** 误导
- 当时没人想到"主流程应该拒绝执行 '未知' 来源"
- 这是一个**典型 antipattern**: "parser 加了 fallback 让字段看着像合法值,但下游没加 'reject if fallback'" — parser 兜底 ≠ 业务允许
## 改动 (v4.5.53)
**位置**: `scripts/process_signal.py::process_signal()` 在 `is_signal_stale` 之前插闸
```python
_sig_type_for_gate = classify_signal(fields)
if trader == '未知' and _sig_type_for_gate in ('open', 'add', 'reduce'):
msg = f"""⏭️ **跳过跟单: 信号源未知** ⏭️
📊 币种: {symbol} {side} {leverage}x
🚫 信号文本里没有【交易员】/👉 跟单就选 / 任何 trader 标签
❌ 不自动跟单,避免执行来路不明的开仓
💡 如果这条信号确实要跟, 请手动开仓 + 告诉我 trader 名字, 我会加到名单。
"""
push_to_qq(msg)
# 留痕: tracker outcome=skipped_unknown_source
_tracker_record(trader='未知', ..., outcome='skipped_unknown_source')
return f"⏭️ 跳过: 信号源未知 | {symbol} {side}"
```
**关键设计**:
- **只阻断 open/add/reduce** — close (平仓) 不阻断, 平仓是兜底必须执行
- **推 QQ 通知** — 用户能看到"为什么没跟", 不是静默
- **写 tracker** — outcome='skipped_unknown_source' 留痕, 可查询
- **不修改 parse_signal** — fallback '未知' 保留, 这是正确的语义("我没找到 trader, 我不知道"), 是闸拒绝执行, 不是 parser 假装找到了
## 防回归检查 (下次类似修复时跑)
```python
import sys
sys.path.insert(0, '~/.hermes/skills/trading/okx-auto-position/scripts')
from process_signal import parse_signal, classify_signal
# 测试 1: 合法结构 + trader 缺失 → 应该 skip
text = '''【币种】SNDKUSDT
【方向】做空
【杠杆】2x
【仓位大小】158
【仓位价值】$
【开仓价】1724.76
'''
fields = parse_signal(text)
assert fields['trader'] == '未知', f"fallback broken: {fields.get('trader')}"
assert classify_signal(fields) == 'open'
print('✓ parser fallback + classifier still work — gate will trigger')
```
```python
# 测试 2: 完整 process_signal() 跑一遍 (mock push_to_qq + tracker)
import process_signal
captured = []
process_signal.push_to_qq = lambda msg: (captured.append(msg), True)[1]
result = process_signal.process_signal(text)
assert result.startswith('⏭️ 跳过: 信号源未知')
assert any('跳过跟单: 信号源未知' in m for m in captured)
print('✓ gate fires correctly')
```
## 通用教训 (class-level pitfall)
**Parser fallback without gate is a silent execution hazard.**
任何"parser 提取不到字段 → fallback 到默认值"的代码,如果这个默认值会让**下游误以为是合法值继续执行**,都是这种 bug 的高发地。
检查清单:
1. **parse** 时找不到 → 返回/标记什么?
2. **业务允许**这个 fallback 值进入主流程吗?
3. 如果不允许,**gate 在哪一道**(解析后立即?分类前?执行前?)
4. fallback 时的**通知**机制是什么?(静默跳过会让用户以为没信号,显式推 "跳过了" 才对)
这次的具体教训:
- ❌ parser fallback 到 '未知' → 主流程照样执行 → 误开仓
- ✅ parser fallback 到 '未知' → 主流程识别 '未知' → 跳过 + 通知用户
## 关联
- `SKILL.md` v4.5.53 章节 — 主 skill 已升级到 4.5.53
- `references/signal-source-drift-2026-07-15.md` — trader 名单失效 (相关但不同问题):那个是"知道是哪个 trader 但名单可能错",这个是"连是哪个 trader 都不知道"
- `scripts/process_signal.py:86` — parse_signal 的 fallback 源头
- `scripts/process_signal.py` 新闸位置 — 在 is_signal_stale 之前