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

5.1 KiB
Raw Blame History

name, description, version, type, status
name description version type status
v4.5.53-unknown-trader-gate-2026-08-18 2026-08-18 SNDK 做空 0.095 张误开仓 — parse_signal fallback '未知' 没有 gate。v4.5.53 在 process_signal() 主流程加了 trader='未知' 闸。 1.0.0 reference 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 之前插闸

_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 假装找到了

防回归检查 (下次类似修复时跑)

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')
# 测试 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 之前