5.7 KiB
5.7 KiB
交易信号三库架构 — DB Topology (2026-08-25)
User asked "币圈持仓有平仓信号吗?" → 暴露 schema 错位:我先查了不存在的
recent_signals表,才意识到三个 DB 各司其职。
三个 DB 各管一段
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
│ TelegramForwarder │ │ signal_queue.db │ │ signal_history.db │
│ db/forward.db │───→│ .hermes/trading/ │───→│ .hermes/trading/ │
│ │ │ │ │ │
│ Tables: │ │ Tables: │ │ Tables: │
│ • chats │ │ • queue │ │ • signals │
│ • users │ │ • sqlite_sequence │ │ • confirmed_signals │
│ • forward_rules ⚠️ │ │ │ │ • position_history │
│ • replace_rules │ │ Cols: id, raw_text, │ │ • position_locks ⚠️ │
│ • media_types │ │ status, created_at, │ │ • sqlite_sequence │
│ • keywords │ │ processed_at, │ │ │
│ • push_configs │ │ result, error, │ │ │
│ • rss_* │ │ retries │ │ │
│ • rule_syncs │ │ │ │ │
└──────────────────────┘ └──────────────────────┘ └──────────────────────┘
转发规则 实时队列 历史 + 持仓锁
各表职责
1. forward.db::forward_rules — 转发规则
enable_rule字段(0/1)是 silent killer:8h+ 无信号先查这条(v4.5.43,2026-08-06 session)- 管 TG channel → 内部 queue 的路由
- 与本 skill 无直接关系,但
enable_rule=0会让 queue 不进数据
2. signal_queue.db::queue — 实时信号流(source of truth for "现在有没有信号")
status='done'+result字段 = 最新处理结果result内容:✅ 已推送 | X long 5x | 28.0张 | 性价比高/⏭️ 跳过: 性价比低/⏭️ 跳过: trader [未知] 不在白名单- 问"现在有没有平仓信号"先查这里
- 看
raw_text是否含🚨 已平仓提醒/已平仓
3. signal_history.db::signals — 历史信号落库
- 只追加,反映"曾经来过什么信号"(无论 execute 是否成功)
- 有
outcome+outcome_time字段记录执行结果 - 不是实时信号源(等 queue 处理完才写)
4. signal_history.db::position_locks — 持仓归属(source of truth for "现在持仓是谁的")
- 唯一字段:
symbol, trader, side, locked_at, reason, auto_locked - 当前持仓要查这张表(不是
signals) locked_at是 ISO 字符串(不是 timestamp!),parse 时datetime.fromisoformat()- 用户问"持仓谁的" → 先看这张
5. signal_history.db::confirmed_signals — execute 记录
- 哪条信号真正触发了下单
- v4.5.51 lock 追溯方法的核心表
常见错位与正解
| 用户问题 | ❌ 错查 | ✅ 正查 |
|---|---|---|
| "现在持仓多少?" | signals 表(只有历史) |
position_locks |
| "持仓是谁的?" | signals.trader(可能 stale) |
position_locks.trader |
| "现在有没有平仓信号?" | signals 表(等落库有延迟) |
signal_queue.db::queue (status='done') |
| "X 信号 execute 成功了吗?" | signals.outcome |
confirmed_signals |
| "TG 转发还活着吗?" | signals 表 |
forward.db::forward_rules.enable_rule |
实战速查 (一键脚本)
# 当前持仓 (5 个字段)
sqlite3 /home/openclaw/.hermes/trading/signal_history.db \
"SELECT symbol, trader, side, locked_at, reason FROM position_locks;"
# 最近 24h 平仓信号 (从 queue 实时拿)
python3 -c "
import sqlite3
conn = sqlite3.connect('/home/openclaw/.hermes/trading/signal_queue.db')
rows = conn.execute('''
SELECT created_at, raw_text, result FROM queue
WHERE status='done' AND raw_text LIKE '%已平仓%'
ORDER BY id DESC LIMIT 5
''').fetchall()
for ts, txt, res in rows: print(ts, res, txt[:80])
"
# forwarder 规则是否启用
sqlite3 /home/openclaw/TelegramForwarder/db/forward.db \
"SELECT id, source_chat, dest_chat, enable_rule FROM forward_rules;"
教训 (本次 session 2026-08-25)
recent_signals表在signal_dedup.db—signal_history.db里没有它(我第一查就报 "no such table: recent_signals")position_locks.locked_at是 ISO 字符串不是 timestamp — 不要int(timestamp/1000),用datetime.fromisoformat()signals表的timestamp字段是 ISO 字符串 — 同样不能用/1000转 unixsignal_queue.db::queue.created_at是 ISO 字符串 — 用datetime.fromisoformat()parse
跟 v4.5.51 / v4.5.56 的关系
v4.5.51 锁追溯三步 (position_locks → confirmed_signals → recent_signals) 已覆盖,但没说明为什么用三张表。本 reference 补充了 DB 拓扑(为什么三表 + 各表职责),让"三步追溯"不再像 magic incantation。
维护建议
- 任何新增"信号处理流程"的代码 → 必须先说明写入哪张表(queue / signals / confirmed_signals / position_locks)
- 任何"实时状态"查询 → 必须说明用的是 queue 还是 signals
- 新加 DB 必然更新本 reference + 顶部架构图