Files
Hermes-Skills/okx-auto-position/SKILL.md
T

248 lines
16 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: okx-auto-position
description: 'OKX自动仓位管理+信号推送v4.5.115: classify_signal 严格模式 (只识别 加仓/减仓/新开仓/平仓/调杠杆 5 类, 其余 unknown 零token跳过) + 1% min 减仓过滤 + 4个熬鹰号白名单(资本/币安实盘/FOMO/交易信号, 同一人多平台) + close也闸(防变体号误平) + adjust_leverage_raw body=body bug fix + 蚂蚁式减仓双层过滤 + 永不用真账户测 raw REST + TG forwarder chat_id 用 event.chat_id 不能 abs(chat.id) + "推送失败 ≠ execute失败" 必查 check_account 验证 + 换频道后必须端到端验证(规则+日志+实际信号流) + token 纪律: 同类操作合并只输出最终结果。详见references/v4.5.115 ~ v4.5.4.'
---
# okx-auto-position
OKX自动仓位管理+跟单信号处理+QQ推送 (v4.5.115)
## 核心规则 (与v4.5.115同步)
### TG forwarder chat_id 提取 (line 76, v4.5.114) — **第一铁律**
- **必须用 `event.chat_id`** (完整 TG channel id `-100xxxxxxxx`), **不能用 `abs(chat.id)`**
- `event.chat.id` (Channel 对象) = 正数 `2651333064` (剥了 -100 前缀)
- `event.chat_id` (telethon 完整 id) = `-1002651333064`
- DB 存 `Chat.telegram_chat_id == '-1002651333064'` 字符串
- 用 `abs(chat.id)=2651333064` 跟 DB 字符串对比 → **永远匹配不上**, 频道切换后信号不转发, docker 日志只看到 "Got difference for channel ... updates" 0 后续处理
- Chat 查询改成 `telegram_chat_id.in_([str(chat_id), alt1, alt2])` 三种格式防御性查询, 防 chat_id 来源不一
- 修复后必须 `docker restart telegram-forwarder`
### 推送失败 ≠ execute失败 (v4.5.115, 本session铁律)
- `process_signal.py` 返回 `❌ 推送失败` **不等于** 没下成单
- `⚠️ advisor错误` (symbol 不存在等) 也**不等于** 没下成单
- **唯一验证** = 跑 `check_account.py [SYMBOL-USDT-SWAP]` 查实际持仓/账单/成交
- 实战 (2026-09-26 ONDO加仓): process_signal 报 `❌ 推送失败`,但 OKX 上 ONDO 已加仓 329 张@0.518 成功。靠 check_account 才发现已成交。
- **结论**: 看到 push_signal 不等于没成, 必查 check_account 再下结论, 不要立刻告诉用户"失败"
- **自动化验证脚本**: `scripts/verify_execution_after_push_fail.py <SYMBOL> [min_ago]` — 自动跑查持仓+近成交, 给出"execute 成功 / 真没成"结论
### 换频道端到端验证链 (v4.5.115, 本session)
当用户说"换到 @XXX 频道"或"现在用的是哪个频道"时, 必须完成**4 步验证**才能宣告切换成功:
1. **DB 配置**: `forward_rules.source_chat_id` 改了? `chats` 表里新 chat_id 加了?
2. **Forwarder 监听器**: `docker logs telegram-forwarder` 出现 `[处理规则|新消息|命中黑名单]` 日志? (只有 `Got difference for channel XXX updates` 不够, 说明 message_handler 没匹配上)
3. **真信号触达**: 频道有真实交易信号? 用 telethon `iter_messages('username', limit=10)` 验证 (容器内需 `cp session /tmp/` 解锁)
4. **执行闭环**: 新信号→pipeline→OKX execute→check_account 显示仓位变动?
**只改 db 不验证后续 = 假成功**, 等到新信号来了才发现"漏发"就晚了 (本 session ONDO 漏发就是这个原因)。
### classify_signal 严格模式 (line ~247) — ⚠️ 也漏合法"汇总里带新开仓价"的信号 (v4.5.116, 2026-09-26 实测)
- **`'平仓' in text`** → close
- **`'加仓' in text or '追仓' in text`** → add
- **`'减仓' in text`** → reduce (必须显式含"减仓"两字)
- **`'新开仓' in text or '注意,大佬开仓了' in text`** → open
- **`'修改了杠杆' / '调整了杠杆' / '调杠杆' in text`** → adjust_leverage
- 其余全部 → `unknown` (零token跳过, 不查持仓, 不调 advisor)
**Strict 模式 trade-off**: 严格模式拦截了所有"汇总播报带价格但无动作词"的信号 (例: "熬鹰当前全部持仓" 列表里刚好有 BTC 新开仓价 81471, 但 classify 拦了)。当用户问"新频道为啥没信号进来"时, 可能是严格模式漏了合法信号, 而**不是频道配置问题**。**修复方向**: 给"汇总播报"加 `update_only` 类 + 二次校验字段(若含"原仓位/开仓均价/标记价格/实际杠杆"等价格字段, 则 hint 实际开/加/减仓方向)。
### 白名单配置 (whitelist.json, 4 个熬鹰号同一人)
- 熬鹰资本
- 熬鹰币安实盘
- 熬鹰FOMO合约实盘
- 熬鹰交易信号
闸包括 open/add/reduce/close/adjust_leverage 5 类全部过白名单。
**运维原则**: 用户明确要求"换到 @XXX 频道, 其他配置不动" — 换频道 = 只改 `forward_rules.source_chat_id`, **不要碰**白名单/黑名单/关键词/transit delay。
### 1% min 减仓过滤 (蚂蚁式减仓噪音)
减仓幅度 < 1% 跳过, 即使被识别为 reduce, advisor/推送都不触发。
### 蚂蚁式减仓双层过滤
1. **第一层 (classify)**: 汇总播报/实时更新根本不进 reduce 分支
2. **第二层 (1% min)**: 即便进了 reduce, 减仓 < 1% 也跳过
### Token 纪律: 同类操作合并输出 (v4.5.115, 本session用户明确要求)
- 同一交易员短时间内发 50+ 条"🐜 蚂蚁减仓" 噪声信号 (例: 熬鹰 ZAMA 连续 50+ 条 < 1% 减仓) 时, **不要每条都 no-op + 重复 "USDT $576"** — 浪费大量 token 输出无意义结果
- **正确**: 第一条 "蚂蚁减仓已用 1% min 过滤跳过", 后续同类只输出 "无操作" 或合并到一条总览 "⚠️ 50 条蚂蚁减仓全 no-op, 已实现累计+$X"
- 用户原话 (2026-09-26): "调整一下, 蚂蚁减仓尽量减少token的消耗"
### 合约面值 ctVal — 名义/保证金计算第一铁律 (v4.5.117, 2026-09-26 重大事故)
- **任何 contracts→名义$ 换算前必查** `GET /api/v5/public/instruments` 的 `ctVal` (每张面值)
- ONDO 1张=**10** ONDO / ZEC 1张=0.01 / BTC 1张=0.01 / PEPE 1张=10000 — **不是1, 猜=事故**
- 本session按 1张=1 ONDO 算小10倍: 以为名义$198合规, 实际**$1,986超$140上限14倍**; 以为frozen $496是"显示延迟", 实际=真实保证金
- **frozenBal 异常大 ≠ 显示延迟, = 仓位超限**。先查 ctVal 重算, 再怀疑交易所
- **手动 raw REST 绕过 advisor, 也必须过单币上限**: `min(权益,$200)×70%`, 最大张数 = 上限名义/(ctVal×markPx)
- 修正顺序: 减仓到上限内 → 再调杠杆 → check_account 验证 frozen ≈ 名义/杠杆
- 详见 `references/v4.5.117-2026-09-26-ctval-contract-size-bug-and-200-cap-violation.md`
### adjust_leverage_raw 函数 (line ~523)
- 关键 fix: `_okx_raw_request('POST', '/api/v5/account/set-leverage', body=body)`, body 必须用关键字 `body=body`
- cross 模式降杠杆会被拒 (59108), 需先减仓释放保证金
### close 也闸
平仓信号不被"平仓兜底"绕过, 也要过白名单 trader 闸 (防变体号误平)。
### advisor 报量偏差 bug (SNDK/MU/XAU/SPCX)
advisor 报 1 张, 实际可能 execute 几十张 (2344 / 2544 / 286 等)。**trust actual 持仓, not advisor 报量**。
### 杠杆字段正则只匹配独立【杠杆】标签 — 信号行内|全仓|Nx必须fallback识别 (v4.5.116, 2026-09-26 本session)
**症状**: 信号原文 `【币种】:ONDOUSDT 永续 | 全仓 | 2x`, 但 parse_signal 的 leverage 正则只匹配 `【杠杆】N` 标签, 匹配不到, 默认10x。
**根因** (`process_signal.py:79/111`):
```python
'leverage': r'【杠杆】\s*[::]?\s*(\d+)', # 只匹配独立标签
```
**实战代价**: ONDO 实际 1.95x, advisor 默认 10x = 你的风险敞口是熬鹰的 5.13 倍。你满仓 ONDO 时, 12% 跌幅爆仓, 熬鹰 88% 跌幅才爆。
**修复** (2026-09-26 已 patch):
```python
'leverage': r'(?:【杠杆】\s*[::]?\s*(\d+)|(?:永续|全仓)\s*\|\s*全仓\s*\|\s*(\d+)\s*[xX]?)',
```
+ 提取逻辑改 `v = m.group(1) or m.group(2) or ''`, 优先取独立标签组, fallback 行内组。
**验证**:
```python
text = '【币种】:ONDOUSDT 永续 | 全仓 | 2x\n【方向】:做多'
parse_signal(text)['leverage'] # 应为 '2', 不是 None/默认10
```
**用户原话** (2026-09-26): "你刚才是加仓不是开仓, ONDO 一直是 2 倍, 你是不是改成 10 倍了" — 是默认 10x 的结果, 不是显式调杠杆, 但**风险敞口5x于熬鹰等于无形调了杠杆**。
**总结**: 信号解析杠杆字段必须两个 fallback — 独立 `【杠杆】N` 标签 + 行内 `|永续|全仓|Nx`。新格式信号优先用行内 fallback。
### advisor 硬编码 1000PEPE BadSymbol bug
- advisor 用 `1000PEPE-USDT-SWAP` 查 symbol, OKX 上**不存在** (那是币安合约名), 对应是 `PEPE-USDT-SWAP`
- BadSymbol 崩溃 → 整条信号失败, advisor 报 `⚠️ advisor错误`
- **手动 raw REST 时用 `PEPE-USDT-SWAP`**; advisor 代码 bug 待修
- 同类 1000SHIB/1000PEPE 等"1000x"币种都是 OKX 上没有前缀版本
### 双频道监听区分 (2026-09-24 已切换 source)
- 用户最初给错指令/切换不彻底 → 当前源要"先查再说": `forward_rules.source_chat_id` + `chats.telegram_chat_id` 双重确认
- **新源 `@shipan_jiankong`**: chats.id=4, telegram_chat_id=`-1002651333064`, 标题"币圈实盘监控 | 熬鹰 风寻" (chats.id=4)
- **旧源 `@jiankongshipan`**: chats.id=1, telegram_chat_id=`3805472665`, 标题"实盘监控"
- 切换 = UPDATE forward_rule.source_chat_id; 修 chat_id bug = `docker restart telegram-forwarder`
### 硬编码黑名单 USDT 误杀 (v4.5.115, 修复后)
- forwarder `user_handler.py` 的 `HARD_BLACKLIST_PATTERNS` 含 `r'(?i)usdt|cny|套现'` + 裸 `带单|指导|喊单|老师|VIP` → **所有信号格式都带 USDT** (BTCUSDT 永续), 误杀 100% 信号
- 修复: `r'(?i)(usdt|cny)(?!永续|usdt).{0,4}套现|套现'` 只拦"套现", `VIP|老师` 收窄为 `VIP群|付费指导`
- 症状: docker 日志 `[用户] 消息命中硬编码黑名单, 跳过转发` 但无 `[新消息|处理规则]` 后续
### cross 降杠杆 59108 标准四步 (v4.5.118, 2026-09-25 ONDO实战)
1. `set-leverage` 直调 → 59108 (预期失败)
2. `reduceOnly` 市价减仓一部分 (释放保证金)
3. 再 `set-leverage` 到目标杠杆 → code=0
4. `check_account` 验证 `lever` 字段 + frozen ≈ 名义/杠杆
不要反复裸调 set-leverage, 也不要建议用户去 app 手动 — 脚本内闭环即可。
### $200 上限口径 = 保证金 (v4.5.118, 2026-09-25 用户最终确认)
- 用户原话: "你只管保证金在限制内就行了"
- **$200 = 单币保证金上限**, 不是名义/张数口径; advisor config `single_coin_ceiling_usdt=200` 本就是此口径, 无需改
- 首仓70%=$140, 加仓可满$200; 名义上限 = $200 × 杠杆
- 验收: `check_account` 看 frozenBal (≈保证金) 是否 ≤ $200
### 信号链路断链排查顺序 (v4.5.118, 用户"信号怎么没进来"时)
1. forwarder 日志有无 `[处理规则|新消息]` (只有 Got difference 不算)
2. `signal_queue.db` 最新 id 有无入队
3. `process_signal` 输出有无 advisor错误/无法解析
4. OKX `/api/v5/trade/fills-history` 有无成交
逐级查, 不要只查一层就下结论; 若换源后 2~4 全断, 果断回切旧源 (`forward_rules.source_chat_id` 改回), 不要恋战。
### 转发时间模板 (v4.5.118)
`time_template` = `⏱转发时间: {time}` — 该时间戳是 forwarder 收到消息的时刻, 不是原信号发布时刻; 用户要求此命名 (原"信号时间"语义混淆已改)。
### 永不用真账户测 raw REST
- 测试时用 mock 或临时子账户
- proxy 抽风时手动 execute 兜底 (sleep 15-30s 后 raw REST 重试)
## 工作流
1. 用户从 TG 发来交易信号
2. `signal_queue.py enqueue '<消息原文>'`
3. cron 或 manual 调用 `process_signal.py '<消息原文>'`
4. classify → 白名单闸 → advisor → execute_order 或 close
5. tracker 记录 outcome (auto_executed / silent_no_pos / skipped_xxx)
6. **推送失败 ≠ execute失败**: QQ 推送失败时必跑 `verify_execution_after_push_fail.py` 或 `check_account.py` 确认是否已实际下成
7. **同类操作合并输出**: 蚂蚁减仓/连续加仓信号合并回复, 不要逐条 spam
## 调用入口
```bash
# 主入口 (用户发信号后)
python3 ~/.hermes/skills/trading/okx-auto-position/scripts/process_signal.py '<消息原文>'
# execute 验证 (推送失败/疑似无成交时必跑)
python3 ~/.hermes/skills/trading/okx-auto-position/scripts/check_account.py [SYMBOL-USDT-SWAP]
# 自动化验证: 推送失败 ≠ execute失败 (v4.5.115)
python3 ~/.hermes/skills/trading/okx-auto-position/scripts/verify_execution_after_push_fail.py <SYMBOL> [min_ago]
# 手动 execute (proxy 抽风后兜底, 或 advisor BadSymbol 绕过)
# 1. 先 check_account.py 查实际持仓/可用余额
# 2. raw REST 下 reduceOnly 单 (跟单信号) 或 limit 单 (调杠杆)
# 复制 templates/manual_order_template.py 到 /tmp/order_xxx.py, 修改 body 字段
# 锁管理
python3 ~/.hermes/skills/trading/okx-auto-position/scripts/signal_tracker.py
```
## 已知数据源 / 工具限制
- screener_search 的 dividend/dpseps 字段返 None (不能筛 yield)
- OKX 单次 reduce 报 "订单失败" 可能是已成交 (51400)
- cross 模式 setLeverage 降杠杆必失败 (需先减仓)
- advisor estimate 用 contractSize 误解 (ZEC 1张=0.01 ZEC, 推送必须展示名义$而非张数)
- **OKX 没有 1000PEPE** (那是币安合约名), 对应是 `PEPE-USDT-SWAP`, advisor 用 `1000PEPE-USDT-SWAP` 会 BadSymbol 崩; 手动 raw REST 用 `PEPE-USDT-SWAP`
- advisor 实际下单量 ≠ 报量 (1张 → 实际 2344/2544/286 张都可能)
## 平仓推送真实 pnl (2026-09-22)
`_fetch_close_pnl_details(symbol_usdt)` 函数从 `/api/v5/account/bills` 拿真实已实现盈亏:
1. 拉近 7 天 type=2 bills (subType=1 = 含手续费已实现, subType=2 = 单笔成交)
2. 找绝对值最大那笔 ts (subType=1 手续费绝对值<5 跳过)
3. 累加 ±30 秒内 type=2 全部 balChg = OKX app 显示的真实数
4. 填到 `format_close_message()` 推送里 "💰 实际盈亏: **+$X.XX** (OKX 实测)"
详见 `references/okx-pnl-from-bills-api.md`.
## signal_queue.py mark_done 覆盖 bug (2026-09-22)
process_signal 失败时 returncode=0 → signal_queue.py retry 看到 returncode=0 就 mark_done → 失败信号被伪装成功.
**修复**: signal_queue.py retry 检查 stdout 含 "❌"/"⏭️"/"⚠️" 时 mark_failed (而非 mark_done). 平仓失败信号会被 retry 重试 5 分钟一次.
## TG forwarder 容器内诊断模式 (v4.5.114)
- 容器内无 sqlite3 CLI → 用 `python3 -c "import sqlite3; ..."` 读 `/app/db/forward.db`
- session 被主进程锁 → `cp /app/sessions/user.session /tmp/u.session` 再用 telethon 连
- 容器内 telethon 连 TG **必带** `proxy=('socks5','127.0.0.1',7891), request_retries=1`
- 双防御: 修 `chat_id = event.chat_id` 同时改 Chat 查询 `in_([str, alt, alt])`
- **诊断 4 步法** (见上方"换频道端到端验证链")
## 参考
详见 `references/` 目录:
- v4.5.118: ONDO杠杆降级实战(59108四步) + $200=保证金口径最终确认 + 频道回切jiankongshipan + 转发时间模板
- v4.5.115: 推送失败 ≠ execute失败 + 换频道端到端验证链 + token 纪律 (本 session 实装)
- v4.5.117: ctVal 合约面值事故 — 名义算小10倍超限 + frozen之谜 + 手动单也过$200上限
- v4.5.114: TG forwarder chat_id 提取 bug + 频道切换
- v4.5.113: classify 严格模式
- v4.5.111: 1% min 减仓过滤 + 4 熬鹰号白名单
- v4.5.110: ZAMA 蚂蚁减仓双层过滤
- v4.5.103: 4 熬鹰号首次识别为同一人, 调杠杆自动跟进
- v4.5.96: advisor reduce 三种结果 (0.001 张/方向 bug/隐性失败)
- v4.5.91: advisor vs executed size divergence matrix
- v4.5.83: whitelist 4 accounts + 新格式信号识别
- v4.5.77: close 也闸修复
- v4.5.71: whitelist.json 配置化 + query-first-no-asking 铁律
- v4.5.68: phantom execute + cross leverage lower rejection
- v4.5.64: adjust leverage 信号自动跟进
- v4.5.39: silent execute fallback
- references/forwarder-hard-blacklist-usdt-blocking-2026-09-22.md — 黑名单 USDT/CNY/带单/老师 误杀修复
## 新增 scripts (v4.5.115)
- `scripts/verify_execution_after_push_fail.py <SYMBOL> [min_ago]` — process_signal 返回 "❌ 推送失败" 时,自动用 OKX REST 验证实际 execute 状态 (查持仓+近 N 分钟成交), 给出"execute 成功 / 真没成" 结论。比 check_account.py 更精准 (会显示"未 execute" vs "execute 成功")
- `templates/manual_order_template.py` — 已存在, 手动 raw REST 下单模板 (开/平/调杠杆 5 种)