# v4.5.64 (2026-08-26) 调杠杆信号必须自动跟进 + raw REST 参数顺序陷阱 **本次 session 在 v4.5.63 (手动锁 + symbol 一致性 + ETH ghost close) 基础上的新教训** --- ## 教训 1: 调杠杆信号不在 advisor 的"性价比低"覆盖范围 **用户质问**: "这个怎么没有跟调杠杆?" **症状**: 熬鹰发出 `🔧 注意, 大佬修改了杠杆 3→4x` 信号, process_signal 分类为新开仓 (`'open'`), 进 advisor → advisor 看 avgPx × 当前价格 × 杠杆 → 报"1.4张 性价比低" 或 "0.01张 性价比低" → 跳过。结果: 用户的 ETH long 1.4张@3x 没自动调到 4x。 **根因**: - `classify_signal()` 没有 `adjust_leverage` 类型, 信号被默认归为 `'open'` - advisor 只计算 open/add/reduce 的仓位, 不处理 set-leverage - 白名单闸 (`'open', 'add', 'reduce'`) 也不会拦到调杠杆, 但调杠杆信号照样进 advisor → 报"性价比低" → 跳过 **修复** (已合入 `scripts/process_signal.py`): 1. **`classify_signal()` 加 `adjust_leverage` 类型识别**: ```python # 加仓信号 if '加仓' in text or '追仓' in text: return 'add' # 调杠杆信号 (2026-08-26: 必须跟, 不算性价比低 — 熬鹰调整杠杆是策略节奏) if '修改了杠杆' in text or '调整了杠杆' in text or '调杠杆' in text: return 'adjust_leverage' # 默认为新开仓 return 'open' ``` 2. **白名单闸加 `adjust_leverage`**: ```python if _sig_type_for_gate in ('open', 'add', 'reduce', 'adjust_leverage') and trader not in _TRADER_WHITELIST: return f"⏭️ 跳过: trader [{trader}] 不在白名单 | {symbol} {side}" ``` 3. **process_signal() 主流程加独立分支** (在 close 信号之后, 2分钟窗口 dedup 之前): ```python # 调杠杆信号 (2026-08-26: 熬鹰调整杠杆要跟, 不走 advisor, 直接 set-leverage) if signal_type == 'adjust_leverage': dedup_conn = init_dedup_db() if is_duplicate(dedup_conn, text, symbol, trader): dedup_conn.close() return "⏭️ 重复信号,跳过" record_signal(dedup_conn, text, symbol, trader) dedup_conn.close() symbol_usdt = fields['symbol'] new_lev = int(fields.get('leverage') or '10') lev_result = adjust_leverage_raw(symbol_usdt, new_lev) if lev_result and lev_result.get('ok'): msg = f"⚙️ **杠杆已调整** | {symbol_usdt} → {new_lev}x" push_to_qq(msg) return f"✅ 调杠杆: {symbol_usdt} → {new_lev}x" else: err = lev_result.get('error', '未知') return f"❌ 调杠杆失败: {err} | {symbol_usdt}" ``` **为什么不走 advisor?** - advisor 只算 open/add/reduce 仓位, 不算 set-leverage - 走 advisor 会被 `性价比低` 闸拦掉 - 调杠杆本质是**单参数调用** (POST /api/v5/account/set-leverage), 不需要 advisor 的仓位计算 --- ## 教训 2: `_okx_raw_request` 参数顺序陷阱 (POST body 必须 keyword arg) **症状**: 调用 `adjust_leverage_raw` 第一次报 `'❌ 调杠杆失败: Incorrect json data format'` **根因**: ```python def _okx_raw_request(method, path, params=None, body=None, timeout=15): ... ``` 签名是 `(method, path, params, body, timeout)`, 第 3 位是 `params`, 第 4 位才是 `body`。 **错误写法** (第 3 位传 body, 被当成 params): ```python resp = _okx_raw_request('POST', '/api/v5/account/set-leverage', body) # 实际上 body 被当 params={...} 传了 → OKX 服务端签名校验失败 ``` **正确写法**: ```python resp = _okx_raw_request('POST', '/api/v5/account/set-leverage', body=body) ``` **SOP (硬规则, v4.5.64 起执行)**: - 任何 `_okx_raw_request` POST 调用 → body 必须 keyword arg (`body=...`) - 这是 v4.5.63 ETH ghost close 调查时埋下的同源 bug (虽然当时没暴露, 因为 close 路径用的是 GET) - v4.5.62 手动 execute 模板 (manual_order.py) 也可能踩这个坑 → **下次 session 第一件事检查 manual_order.py 的 okx_post 函数** **验证**: ```bash # 调杠杆信号后, check_account.py 应该看到新的 lever 字段 python3 ~/.hermes/skills/trading/okx-auto-position/scripts/check_account.py # 检查 "lever" 字段 = 目标倍数 ``` --- ## 实战时间线 (本次 session) 1. 用户 ETH long 1.4张@3x 已开仓 (v4.5.63 残留) 2. 熬鹰 ETH 调杠杆 3→5x 信号进来 → process_signal 走 advisor → 报"性价比低" → **跳过** 3. 用户质问: "这个怎么没有跟调杠杆?" 4. 我手动 raw REST set-leverage 4x → USDT 占用从 $87.72 → $70.12 (降, 因为杠杆升) 5. 用户: "要 [改代码]" 6. 我加 `adjust_leverage_raw` + `adjust_leverage` 类型 + 主流程分支 7. 测试调杠杆信号 → 先报 `'❌ Incorrect json data format'` → 找到参数顺序 bug 8. 修复后: `✅ 调杠杆: ETH → 5x` (从 4x 升 5x) **最终持仓**: - ETH long 1.4张@5x (avgPx 2486.74, 浮盈+$2.45, 占用 $70.12) - USDT 可用 $87.99 / 权益 $158.10 - ETH 锁 ✅ 熬鹰资本 long (手动锁) - MSTR short 4.01张@5x (avgPx 126.04, 浮亏-$0.21, 占用 $101.12) --- ## 部署清单 (下次 session 第一件事) - [ ] `manual_order.py` 的 okx_post 函数: 确认所有 POST 都用 keyword arg `body=body`, 不能位置传 body - [ ] process_signal 加 `adjust_leverage_raw` 调用也走 dedup (已实现) - [ ] 测试: 调杠杆信号进来 → 自动 set-leverage + 推 QQ - [ ] 调杠杆失败时: 区分"无持仓可调" (要查持仓) vs "API 报错" (重试) - [ ] 白名单闸的 signal_type 集合统一抽到顶层常量 (现在散落在多处) --- ## 跨 session 索引 - v4.5.38: 实时数据查询硬规则 - v4.5.53: trader='未知' 闸 - v4.5.61: trader 白名单 (只跟熬鹰) - v4.5.62: dedup 手动清 + 手动加仓模板 - v4.5.63: 手动锁 + symbol 一致性 - **v4.5.64 (本次)**: 调杠杆信号自动跟进 + _okx_raw_request 参数顺序陷阱