--- 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 [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 [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 [min_ago]` — process_signal 返回 "❌ 推送失败" 时,自动用 OKX REST 验证实际 execute 状态 (查持仓+近 N 分钟成交), 给出"execute 成功 / 真没成" 结论。比 check_account.py 更精准 (会显示"未 execute" vs "execute 成功") - `templates/manual_order_template.py` — 已存在, 手动 raw REST 下单模板 (开/平/调杠杆 5 种)