Files
Hermes-Skills/okx-auto-position/references/post-execute-verification-checklist.md

158 lines
6.1 KiB
Markdown
Raw Permalink 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.
# execute 后判定成败的完整 self-check (2026-07-08)
## 触发场景
**用户原话(本次 session)**: "要是我没发现,就一直不推了吗? 重试机制呢"
**问题链路**: 熬鹰 ETH short 减仓信号 → 紧跟"已平仓提醒"信号 → process_signal dedup 误跳过 → agent 没自动平 → ETH 涨到 1795 → 用户 ETH short 浮亏扩大到 -$6.58 → 用户质问"自动平仓的retry在哪?"
## 三大failure mode必须能识别
### 1. execute 静默失败(advisor stdout 看起来 OK,实际没下单)
**症状**:
- advisor --execute 返回完整 JSON(contracts/margin/tp_price 等字段齐全)
- 但 raw REST 查持仓:**没新增任何仓**
- `frozenBal` 也没变化
**已知受害币种**(2026-07-08 实测):
- SPCX-USDT-SWAP (新开仓 long/short 都失败)
- MU-USDT-SWAP (新开仓静默失败,加仓成功)
- SKHYNIX-USDT-SWAP (新开仓失败,加仓成功)
**agent 必须做的 self-check**(在推QQ之前):
```bash
# 1. 立刻 raw REST 查持仓
curl -s -X GET "https://www.okx.com/api/v5/account/positions?instId={SYMBOL}-USDT-SWAP" \
-H "OK-ACCESS-KEY: ..." -H "OK-ACCESS-SIGN: ..." \
-H "OK-ACCESS-TIMESTAMP: ..." -H "OK-ACCESS-PASSPHRASE: ..." | jq .
# 2. 看 abs(pos) 是否对应 contracts × leverage
# 3. 看 frozenBal 变化值 = contracts × markPx / leverage
# 4. 若两者都不匹配 → 静默失败 → 立即 raw REST 手动重下
```
### 2. execute 返回 order_id 但实际 Rejected
**症状**: stdout 有 `order_id` 字段,但实际 status=Rejected。
**agent 必须做的 self-check**:
```bash
# OKX 私有 API 反查订单状态
curl -s -X GET "https://www.okx.com/api/v5/trade/order?instId={SYMBOL}-USDT-SWAP&ordId={ID}" \
-H "OK-ACCESS-KEY: ..." ... | jq '.data[0].state'
# state 值: filled / live / canceled / Rejected
```
**禁止**: 看到 stdout 有 order_id 就推"✅ 下单成功" —— 必须反查 state。
### 3. 平仓信号被 dedup 跳过(本次 session 实测)
**症状**: process_signal 返回 `⏭️ 重复信号跳过`,但实际持仓仍存在,平仓信号没触发市价平仓。
**agent 必须做的 self-check**(强化 v4.5.12 章节):
```bash
# 当 process_signal 返回 ⏭️ 重复信号跳过时:
# 1. raw REST 查同币种持仓
# 2. 若有持仓 + 信号是平仓类型 + 持仓方向与信号同方向 → 立即手动 raw REST 平仓
# 3. 不等下次信号,不等用户质问
```
**关键判断逻辑**(process_signal.py 应该自动化,但 agent 也得会手动):
```
process_signal 返回值: ⏭️ 重复信号跳过
↓ raw REST 查持仓
持仓: pos = -2.89 (short)
信号类型: 平仓(close)
信号方向: short
方向一致? ✅ 同方向 → 立即 raw REST 市价全平 reduceOnly=true
方向不一致? ⛔ 反向 → 不动,推"⏭️ 反向持仓不跟平"
无持仓? ⏭️ → 不动,推"⏭️ 无持仓可平"
```
## 三层验证 checklist (agent 每次 execute 后必跑)
### 第 1 层:raw REST 反查持仓(< 1秒)
```python
import json,time,hmac,hashlib,base64,requests
# 用 v4.5.2 提供的 okx_get 函数模板
result = okx_get('/api/v5/account/positions', {'instId': f'{symbol}-USDT-SWAP'})
for p in result.get('data', []):
pos = abs(float(p.get('pos', 0) or 0))
if pos > 0.001:
print(f"✅ 实际持仓: {symbol} {p['posSide']} {pos}张 @ {p['avgPx']}")
break
else:
print(f"⚠️ {symbol} 无持仓 - execute 可能静默失败")
```
### 第 2 层:raw REST 反查余额变化(< 1秒)
```python
result = okx_get('/api/v5/account/balance')
for d in result.get('data', [{}])[0].get('details', []):
if d['ccy'] == 'USDT':
frozen = float(d.get('frozenBal', 0))
avail = float(d.get('availBal', 0))
print(f"USDT: avail={avail:.2f} frozen={frozen:.2f}")
# 期望: frozen ≥ contracts × markPx / leverage
# 若 frozen < 期望 → 静默失败
```
### 第 3 层:订单 status 反查(若 advisor stdout 有 order_id)(< 1秒)
```python
result = okx_get('/api/v5/trade/order', {'instId': f'{symbol}-USDT-SWAP', 'ordId': order_id})
if result.get('data'):
state = result['data'][0].get('state')
if state == 'filled':
print(f"✅ 订单已成交: {order_id}")
elif state == 'live':
print(f"⏳ 订单挂单中: {order_id}")
elif state == 'Canceled':
print(f"🚫 订单已撤: {order_id}")
elif state == 'Rejected':
print(f"❌ 订单被拒: {order_id} - 查 OKX App 原因")
```
## 实战决策表
| 第 1 层 | 第 2 层 | 第 3 层 | 综合判定 | agent 动作 |
|---|---|---|---|---|
| 有持仓 | frozen ≥ 期望 | filled | ✅ 成功 | 推"已跟单 X 张" |
| 有持仓 | frozen ≥ 期望 | live | ⏳ 挂单中 | 推"⏳ 挂单中 @ price" |
| 无持仓 | frozen < 期望 | 无 order_id | ❌ 静默失败 | raw REST 手动重下 |
| 无持仓 | frozen < 期望 | Rejected | ❌ 拒单 | raw REST 重下 + 调小 size |
| 无持仓 | frozen < 期望 | Canceled | 🚫 撤单 | raw REST 重下 |
| 有持仓但反向 | - | - | ⛔ dedup 反向 | 不动,推"⏭️ 反向持仓不跟" |
| 平仓信号 + 有同向持仓 | - | - | ✅ 应平仓 | raw REST 市价全平 |
## 用户质问 → 强制改进
每次用户质问"为什么没自动处理"时,都应触发本 checklist 复盘:
1. 是哪个 failure mode 触发了?
2. 当时为什么没识别?
3. 把识别规则加进 skill 或 process_signal.py
**已经触发的质问(2026-07-08)**:
- "你分析这些没有用" → v4.5.2 章节
- "回复侧不要数据" → v4.5.3 章节
- "要是我没发现,就一直不推了吗? 重试机制呢" → **本 reference**
- "执行成功但agent说没成" → v4.5.0 + 本 reference 第 1 层
## 修复优先级
未来如果重写 process_signal.py,这 3 层验证应该作为 post-execute 钩子**内置**到脚本里,不是依赖 agent 手动跑:
```python
# 建议的 process_signal.py 流程
def process_signal(text):
... # 解析 + advisor + execute
# post-execute hook (新增)
if signal_type == 'open' or signal_type == 'add':
time.sleep(1)
verify_execution(symbol, expected_contracts, expected_margin)
```
## 一句话总结
**不要相信 stdout。要相信 raw REST 反查持仓 + 余额变化。**