262 lines
13 KiB
Markdown
262 lines
13 KiB
Markdown
# v4.5.68 (2026-08-30) Phantom Execute 加剧 + Cross 模式降杠杆被拒 + 调杠杆信号 "3→4" 解读
|
|
|
|
**详细复现**: 本次 session
|
|
|
|
## 三件新事件 (本次 session 续 v4.5.66 / v4.5.67)
|
|
|
|
### 1. Phantom Execute 加剧 — 几乎每个熬鹰信号都幽灵成交
|
|
|
|
**症状**: `process_signal` 报 `⏭️ 跳过: 信号源未知 | <X> <side>` 或 `⏭️ 跳过: 性价比低 | <X> <side>`,但 5 秒后 `check_account.py` 显示实际仓位出现。
|
|
|
|
**本次复现的幽灵 execute**:
|
|
|
|
| 信号 | advisor 报 | 实际成交 |
|
|
|---|---|---|
|
|
| SKHYNIX short 2x | "跳过 信号源未知" | 0.145 张@2x ✓ |
|
|
| BTC long 5x | "跳过 信号源未知" | 0.63 张@5x ✓ |
|
|
| HYPE long 2x | "跳过 信号源未知" | 26 张@2x ✓ |
|
|
| HYPE long 2x (信号 2) | "1张 性价比一般" | 25 张@2x ✓ (vs advisor 25 张 OK, 但 signal 2 是 1 张信号) |
|
|
| TRUMP long 1x | "137张 性价比高" | **586 张@1x** ✗ (4.3x 超额) |
|
|
| SKHYNIX long 1x (去低判断后) | "0.065张 性价比低" | 0.098 张@1x ✓ |
|
|
| SKHYNIX long 2x 加仓 | "0.039张 性价比低" | **0.407 张@2x** ✗ |
|
|
|
|
**根因 (叠加 3 个)**:
|
|
|
|
1. **trader='未知' 闸没拦 execute 路径**: `process_signal()` 在 `classify_signal()` 后加了闸,但 advisor 的 execute 路径 (`okx_position_advisor.py --execute`) 是独立脚本,**直接读信号文本 + 直接调 ccxt.create_order**, 完全不经过 process_signal 主流程
|
|
2. **advisor 的 `contracts` 字段不可信**: advisor JSON 返回的 `contracts` 是基于可用 USDT ×45% / 每张保证金 计算,但实际 ccxt 下单时用了不同的 ctVal / 最小变动单位计算器
|
|
3. **"性价比低"判断在 advisor 内层**: v4.5.66 移除外层判断,但 advisor JSON 仍带 `rating_text: 性价比低` 标签, 用户看到后误以为没跟单
|
|
|
|
**实测新发现**: 即使 process_signal 主流程加了 trader='未知'闸 + 白名单闸 + 调杠杆闸,**advisor 的独立 execute 路径** 仍会成交。这是 v4.5.54 / v4.5.57 的延伸, 但 v4.5.66 没堵上。
|
|
|
|
**修复方向 (下次必修)**:
|
|
|
|
- [ ] `okx_position_advisor.py` 加 trader 闸 + trader 白名单 (跟 process_signal 同步)
|
|
- [ ] advisor execute 后**强制**调 `check_account.py` 反查实际仓位, 反查为空时**推 QQ 失败**
|
|
- [ ] advisor JSON 的 `contracts` 字段改名为 `suggested_contracts`, 加 `actual_contracts` 字段(后置填充)
|
|
- [ ] advisor 的 `rating_text: 性价比低` 字段移除 (用户已说"把性价比去掉")
|
|
|
|
**临时 workaround (本次 session 实战)**:
|
|
|
|
执行任何 advisor 后 → **强制 sleep 5s + check_account.py 反查** → 有新增就记录, 无新增就推 QQ "实际未成交"
|
|
|
|
```bash
|
|
# 实战模板
|
|
python3 process_signal.py "signal"
|
|
sleep 5
|
|
python3 check_account.py <X>-USDT-SWAP
|
|
# 对比 advisor JSON.contracts vs check_account.contracts
|
|
```
|
|
|
|
### 2. Cross 模式降杠杆被 OKX 拒绝 (Your account leverage is too low and has insufficient margins)
|
|
|
|
**症状**: SKHYNIX long 0.098 张@5x 持仓 → 熬鹰信号 `修改了杠杆 5→2` → 调 set-leverage API → OKX 返回 `code: 59108, msg: Your account leverage is too low and has insufficient margins. Please increase the leverage.`
|
|
|
|
**复现命令**:
|
|
```python
|
|
body = {'instId': 'SKHYNIX-USDT-SWAP', 'lever': '2', 'mgnMode': 'cross'}
|
|
resp = _okx_raw_request('POST', '/api/v5/account/set-leverage', body=body)
|
|
# → {"code":"59108","msg":"Your account leverage is too low and has insufficient margins..."}
|
|
```
|
|
|
|
**根因**: OKX cross 模式下, 杠杆下调会要求"按新杠杆计算所需初始保证金 ≥ 当前可用 USDT"。SKHYNIX 0.098 张@2x 需要 ≈$60 保证金, 但用户 USDT 主要压在 ETH/TRUMP 持仓上, SKHYNIX 分账户可用余额 < $60。
|
|
|
|
**OKX API 文档事实** (硬):
|
|
|
|
- 升杠杆: 总是允许 (只要新杠杆不超过币种上限)
|
|
- **降杠杆**: 必须满足 `新杠杆所需初始保证金 ≤ 当前可用 USDT + 已冻结保证金`, 否则拒
|
|
- 用户**当前持仓杠杆 ≥ 信号目标** → 降杠杆被拒
|
|
- 用户**当前持仓杠杆 < 信号目标** → 升杠杆, 正常
|
|
|
|
**修复方向**:
|
|
|
|
- [ ] `adjust_leverage_raw` 失败时区分**升 / 降**:
|
|
- 升杠杆失败 → 重试 (proxy 抽风)
|
|
- 降杠杆失败 (59108) → **不重试**, 推 QQ "OKX 拒绝降杠杆, 账户余额不足" + 触发"用户偏好"问询"要不要平仓释放 USDT 后再降"
|
|
- [ ] 文档加 pitfall: "降杠杆在 cross 模式需要 USDT 支持, 升杠杆不需要"
|
|
|
|
**实战应对 (本次 session)**:
|
|
|
|
- 用户问 "正常操作是怎么降?" → 我列了 3 路径 (加仓满足/逐仓模式/平仓-降-重开)
|
|
- 用户没让我强制平, 信号继续 (熬鹰后续还会发 modify 信号)
|
|
- 实战教训: 调杠杆信号在 cross 模式下**经常失败**, 不要默认每次都能跟
|
|
|
|
### 3. 调杠杆信号 `A→B` 解读规则 (v4.5.68 强化 v4.5.65)
|
|
|
|
**信号**: `🔧 注意,大佬修改了杠杆 5→2 【币种】: SKHYNIX-USDT|永续|2x`
|
|
|
|
**正确解读**:
|
|
- `5→2` = 当前 5x → 改成 2x (目标值 2)
|
|
- 信号文本 `永续|2x` 字段是**目标值**, 不是"现在杠杆 2x"
|
|
- `process_signal.parse_signal()` 取 `leverage` 字段 → `2`
|
|
|
|
**代码已对**:
|
|
```python
|
|
new_lev = int(fields.get('leverage') or '10')
|
|
# leverage 字段在 `【币种】: <X>|永续|<LEV>x` 取到, 取 LEV = 2
|
|
```
|
|
|
|
**用户误读防范**:
|
|
- ❌ "5→2 我手动调到 5x" (我本次 session 干过这傻事)
|
|
- ✅ 永远取 `永续|<LEV>x` 的 LEV = 信号目标值
|
|
- 验证: 信号文本里 `永续|2x` → 调 set-leverage lever=2
|
|
|
|
### 4. signal_tracker.acquire_lock 的 symbol 参数必须无后缀
|
|
|
|
**实战发现**: 用户手动 execute MSTR short 4.01 张@5x 后, 我手动跑 `acquire_lock("MSTR-USDT-SWAP", ...)`, 结果 position_locks 出现 2 条:
|
|
|
|
```
|
|
MSTR|熬鹰资本|short|...|新信号自动锁|1
|
|
MSTR-USDT-SWAP|熬鹰资本|short|...|手动加锁|0
|
|
```
|
|
|
|
**根因**: `process_signal.parse_signal()` 提取 `symbol` 字段时**不带 `-USDT-SWAP` 后缀**, 而手动锁习惯性用 instId 完整形式。
|
|
|
|
**正确**:
|
|
```python
|
|
from signal_tracker import acquire_lock
|
|
ok, msg = acquire_lock("MSTR", "熬鹰资本", "short", reason="手动加锁", auto=False)
|
|
# ✓ 无后缀
|
|
ok, msg = acquire_lock("MSTR-USDT-SWAP", "熬鹰资本", "short", ...)
|
|
# ✗ 永远锁不上
|
|
```
|
|
|
|
**验证**:
|
|
```bash
|
|
sqlite3 ~/.hermes/trading/signal_history.db "SELECT * FROM position_locks;"
|
|
# 应只见无后缀 symbol (MSTR / TRUMP / SKHYNIX / ETH / BTC)
|
|
```
|
|
|
|
**跟 v4.5.63 的关系**: v4.5.63 已记过这个坑, v4.5.68 实战再次踩到 (MSTR 锁不上 → 用户问 "交易员锁了吗, 我是转发的消息, 也要锁的")
|
|
|
|
**修复方向**:
|
|
|
|
- [ ] `acquire_lock` 函数加注释强调"symbol 必须无 -USDT-SWAP 后缀"
|
|
- [ ] 或 `acquire_lock` 内部自动剥离后缀 (defensive)
|
|
|
|
### 5. trader='未知' 闸的"幽灵 execute" vs 主流程"静默 skip" 并存
|
|
|
|
**会话时间线**:
|
|
|
|
| 时间 | 信号 | process_signal 报 | 实际成交 |
|
|
|---|---|---|---|
|
|
| T1 | SKHYNIX short 2x | "跳过 信号源未知" | 0.145 张@2x (幽灵) |
|
|
| T2 | BTC long 5x | "跳过 信号源未知" | 0.63 张@5x (幽灵) |
|
|
| T3 | HYPE long 2x (1) | "跳过 信号源未知" | 26 张@2x (幽灵) |
|
|
| T4 | HYPE long 2x (2) | "1张 性价比一般" | 25 张@2x (幽灵) |
|
|
| T5 | 白名单闸加好 | "跳过 trader [未知] 不在白名单" | (不再幽灵) |
|
|
| T6 | TRUMP long 1x | "137张 性价比高" | 586 张@1x (超额幽灵) |
|
|
| T7 | SKHYNIX long 1x | "0.065张 性价比低" (v4.5.66 后) | 0.098 张@1x |
|
|
| T8 | SKHYNIX long 2x 加仓 | "0.039张 性价比低" | 0.407 张@2x (超额幽灵) |
|
|
|
|
**关键洞察**:
|
|
|
|
- T1~T4 在白名单闸前 → 闸没生效, advisor 独立 execute 路径成交
|
|
- T5 加白名单闸后 → advisor 路径**也**没被拦住 (advisor 不读 process_signal 的闸)
|
|
- T6~T8 都是在白名单生效后 → 仍有幽灵 execute
|
|
|
|
**结论**: **process_signal 主流程闸 ≠ advisor execute 闸**, 这是两个独立路径, 都要加固。
|
|
|
|
### 6. `scripts/manual_order.py` 已有, 本次 session 实战使用
|
|
|
|
**实战模板** (本次 session 末段):
|
|
|
|
```python
|
|
# /tmp/open_mstr2.py
|
|
import json, time, hmac, hashlib, base64, requests
|
|
def okx_post(path, body, t=15):
|
|
creds = open('/home/openclaw/.bashrc').read()
|
|
k = s = pw = None
|
|
for l in creds.splitlines():
|
|
if l.startswith('export OKX_API_KEY='): k = l.split('=', 1)[1].strip().strip('"')
|
|
elif l.startswith('export OKX_SECRET='): s = l.split('=', 1)[1].strip().strip('"')
|
|
elif l.startswith('export OKX_PASSPHRASE='): pw = l.split('=', 1)[1].strip().strip('"')
|
|
ts = time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime())
|
|
method = 'POST'
|
|
body_str = json.dumps(body)
|
|
pre = ts + method + path + body_str
|
|
sig = base64.b64encode(hmac.new(s.encode(), pre.encode(), hashlib.sha256).digest()).decode()
|
|
h = {'OK-ACCESS-KEY': k, 'OK-ACCESS-SIGN': sig, 'OK-ACCESS-TIMESTAMP': ts,
|
|
'OK-ACCESS-PASSPHRASE': pw, 'Content-Type': 'application/json'}
|
|
r = requests.post('https://www.okx.com' + path, headers=h, data=body_str, timeout=t,
|
|
proxies={'http': 'http://127.0.0.1:7890', 'https': 'http://127.0.0.1:7890'})
|
|
return r.json()
|
|
|
|
# 5x MSTR short market order
|
|
body = {'instId': 'MSTR-USDT-SWAP', 'tdMode': 'cross', 'side': 'sell',
|
|
'posSide': 'net', 'ordType': 'market', 'sz': '1'}
|
|
print(okx_post('/api/v5/trade/order', body))
|
|
```
|
|
|
|
**已知陷阱 (本次 session 实战遇到)**:
|
|
|
|
1. **POST body 必须 `body=body` keyword arg** (v4.5.64 已修, 但每次新写脚本要警惕)
|
|
2. **reduceOnly 平仓**: `sz` 必须严格等于持仓张数, 否则 OKX 报 51169
|
|
3. **proxy 必须保留**: 私有 API 直连会被 OKX 拒绝
|
|
4. **acquire_lock 必须手动**: 用户偏好不改代码 (v4.5.63)
|
|
|
|
### 7. 用户偏好 (本次 session 末段新增)
|
|
|
|
- **"调杠杆失败这个不能改吗"** (用户原话, 2026-08-26) → 我列了 3 路径, 用户未选, 默认 **不强制平仓, 等下一个调杠杆信号自然解决**
|
|
- **"正常操作是怎么降"** (用户原话, 2026-08-26) → 用户在寻求知识, 不在要我执行
|
|
|
|
## 实战时间线 (本次 session)
|
|
|
|
| 时刻 | 事件 |
|
|
|---|---|
|
|
| 2026-08-26 01:00 | 熬鹰 ETH 平仓 → close_position_raw 返回 None → process_signal 崩溃 → 加 null guard |
|
|
| 2026-08-26 01:30 | 熬鹰 ETH 新开仓 → advisor 报 1.4 张 → execute 1.4 张@3x (OK) |
|
|
| 2026-08-26 02:00 | 用户问"信号只到了 4" → 我误把 ETH 调到 5x → 手动改回 4x |
|
|
| 2026-08-26 03:00 | 熬鹰 HYPE 平仓 → 手动 execute (proxy 抽风) |
|
|
| 2026-08-26 04:00 | 熬鹰 TRUMP 新开仓 → advisor 137 张 → execute **586 张@1x** (幽灵, 4.3x 超额) |
|
|
| 2026-08-26 05:00 | 熬鹰 TRUMP 调杠杆 1→2x → 自动跟 → USDT 可用恢复 $2 → $81 |
|
|
| 2026-08-26 06:00 | 熬鹰 TRUMP 平仓 → 手动 execute (proxy 抽风) |
|
|
| 2026-08-26 07:00 | 熬鹰 SKHYNIX 新开仓 1x → "性价比低" 跳过 (v4.5.66 前) |
|
|
| 2026-08-26 08:00 | 用户 "把性价比去掉, 不要了" → 移除"性价比低"判断 |
|
|
| 2026-08-26 09:00 | 熬鹰 SKHYNIX 1x → execute 0.098 张 (OK) |
|
|
| 2026-08-26 10:00 | 熬鹰 SKHYNIX 调杠杆 1→5x → execute set-leverage OK |
|
|
| 2026-08-26 11:00 | 熬鹰 SKHYNIX 调杠杆 5→2x → OKX 59108 拒绝 (cross 模式余额不足) |
|
|
| 2026-08-26 12:00 | 熬鹰 SKHYNIX 加仓 2x → advisor 0.039 → execute 0.407 张@2x (10x 超额幽灵) |
|
|
|
|
## 累计已知 execute 失败/幽灵 清单 (v4.5.68 更新)
|
|
|
|
| 币种 | 模式 | 现象 |
|
|
|---|---|---|
|
|
| SPCX-USDT-SWAP | silent fail | advisor 报"已推送", 实际无合约, 不下单 |
|
|
| 1000PEPE / PEPE-USDT-SWAP | symbol normalize | 必须 PEPE-USDT-SWAP, advisor 有路径问题 |
|
|
| MU-USDT-SWAP | 幽灵 | advisor 报 X 张, execute X+1 张 |
|
|
| XAU-USDT-SWAP | 幽灵 | advisor 报 X 张, execute X+N |
|
|
| HYPE-USDT-SWAP | 幽灵 (本次) | advisor 报 1 张, execute 25 张 |
|
|
| TRUMP-USDT-SWAP | 幽灵 (本次) | advisor 报 137 张, execute 586 张 |
|
|
| SKHYNIX-USDT-SWAP | 幽灵 (本次) | advisor 报 0.039 张, execute 0.407 张 |
|
|
| NEIRO-USDT-SWAP | silent fail | OKX 无合约 |
|
|
| ZAMA-USDT-SWAP | silent fail | OKX 无合约 |
|
|
|
|
**通用规律**: **所有合约都可能被幽灵 execute**, 没有"安全"币种。每次 execute 后**必须反查**。
|
|
|
|
## 部署清单 (下次 session 第一件事)
|
|
|
|
- [ ] `okx_position_advisor.py` 加 trader 闸 + 白名单 + trader='未知' 闸 (跟 process_signal 同步)
|
|
- [ ] advisor execute 后**强制** `check_account.py` 反查, 反查为空时推 QQ 失败
|
|
- [ ] advisor JSON 加 `actual_contracts` 字段, 由 check_account 后置填充
|
|
- [ ] `adjust_leverage_raw` 失败时区分升/降, 降杠杆 59108 推 QQ 用户问询
|
|
- [ ] `acquire_lock` 函数加注释 "symbol 必须无 -USDT-SWAP 后缀"
|
|
- [ ] 已知 silent_fail / 幽灵 execute 币种清单 (上表) 入 reference
|
|
- [ ] X/Twitter 链接处理模板入 SKILL.md (v4.5.65 已记, 复用)
|
|
|
|
## 关联版本
|
|
|
|
```
|
|
v4.5.21 加"性价比低"判断 (兜底)
|
|
↓
|
|
v4.5.37 ~ v4.5.62 沿用 + silent_order 标识
|
|
↓
|
|
v4.5.65 silent_order 完整化
|
|
↓
|
|
v4.5.66 去掉"性价比低"判断, 跟所有熬鹰信号 (用户偏好反转)
|
|
↓
|
|
v4.5.67 用户口语"调杠杆" = 加仓 (不是 OKX set_leverage)
|
|
↓
|
|
v4.5.68 幽灵 execute 加剧 + cross 模式降杠杆被拒 + 调杠杆信号 "3→4" 解读
|
|
```
|
|
|
|
每次踩坑都在 OKX 跟单这条线上, 跟其他 skill 不重叠。 |