4.5 KiB
4.5 KiB
v4.5.27 静默 execute 失败模式 (2026-07-08 实测)
现象
process_signal.py 处理加仓信号时,advisor --execute 步骤因 SSL/ReadTimeout 抛异常,但 process_signal 只返回:
⚠️ advisor错误: Traceback (most recent call last)
File ".../urllib3/response.py", line 905, in _error_catcher
此时用户实际持仓无变化(无冻结余额增加、无可用USDT减少),但 process_signal 已经返回"已推送"给 QQ,QQ 上写着"已跟单 X 张"是假阳性。
真实案例(2026-07-08)
- 风寻 SKHY 加仓: advisor SSL抽风,QQ推了但实际未execute
- 熬鹰 SPCX long 新开仓:advisor SSL抽风,QQ推但实际未下单(连续2次都失败)
- 熬鹰 SKHY 空单新开仓:同上
- 熬鹰 MU 新开仓:同上
这4个都中了,用户实际未跟单,但 QQ 显示已跟单。
根因
process_signal.py调run_advisor()返回{'error': '...'}- 接着进入
format_message(rec)路径,format 不检查 error 状态 - 然后
push_to_qq()+record_signal(),没有 execute 失败回滚 - 结果:QQ 拿到"已跟单 X 张"推送,但实际持仓0张变化
二次校验硬约束(已写 SKILL.md v4.5.18)
scripts/process_signal.py 流程:
1. parse → fields
2. classify → signal_type
3. close 信号 → 走独立通道
4. 其他信号 → run_advisor() → rec
5. 若 rec.error:
❌ 当前: 直接 format + push,QQ看到假的"已跟单"
✅ 必须: 查 raw REST /api/v5/account/positions,若该币种 pos==0 或未变化,
推"⚠️ advisor 错误,建议仓位=X张,但 execute 失败,需手动"
验证execute是否真下单
# 每次 advisor --execute 后,必须反查
timeout 30 python3 -c "
import json,time,hmac,hashlib,base64,requests
def okx(p,params=None,t=15):
creds=open('/home/openclaw/.bashrc').read()
k=s=pw=None
for l in creds.split('\n'):
if l.startswith('export OKX_API_KEY='): k=l.split('=',1)[1].strip().strip('\"').strip(\"'\")
elif l.startswith('export OKX_SECRET='): s=l.split('=',1)[1].strip().strip('\"').strip(\"'\")
elif l.startswith('export OKX_PASSPHRASE='): pw=l.split('=',1)[1].strip().strip('\"').strip(\"'\")
ts=time.strftime('%Y-%m-%dT%H:%M:%S.000Z',time.gmtime())
msg=ts+'GET'+p+(json.dumps(params) if params else '')
sig=base64.b64encode(hmac.new(s.encode(),msg.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'}
px={'http':'http://127.0.0.1:7890','https':'http://127.0.0.1:7890'}
return requests.get(f'https://www.okx.com{p}',params=params or {},headers=h,proxies=px,timeout=t).json()
pos=okx('/api/v5/account/positions')
for p in pos.get('data',[]):
if float(p.get('pos','0') or 0)!=0:
print(f\"{p['instId']:25s} {p['pos']:>10s}张 avgPx={p['avgPx']} mark={p['markPx']} upl={p['upl']}\")
bal=okx('/api/v5/account/balance')
for d in bal['data'][0].get('details',[]):
if d['ccy']=='USDT':
print(f\"USDT: availBal={d['availBal']} frozenBal={d['frozenBal']} eq={d['eq']}\")
"
如果该币种 pos 没新增 + frozenBal 没增加 → execute 失败。
修复方向(待实施)
短期:在 process_signal.py 加 execute 失败兜底:
if 'error' in rec:
# advisor报错,验证一下真没execute
time.sleep(3)
actual_pos = fetch_position(symbol)
if actual_pos is None or actual_pos == existing_pos:
# 真没execute
msg = f"⚠️ {symbol} {side} advisor失败且未下单: {rec['error'][:100]}"
push_to_qq(msg)
return f"⚠️ execute失败: {rec['error'][:50]}"
长期:advisor --execute 路径加 retry + 真错误识别(SSL抽风不算 fatal,应重试一次)。
实战经验(2026-07-08)
- advisor SSL抽风时,等30-60秒再 retry 通常可恢复 — OKX API 暂时性网络问题
- 小张数(< 0.5张)信号经常 fail execute — 因为OKX最小变动单位不匹配
- 新币种(SPCX/SKHYNIX)首次 execute 经常 fail — 可能合约 metadata 未完全加载
- 失败时advisor 返回 JSON 看起来正常,但无 order_id — 这就是 v4.5.18 execute 反查硬约束的根因
v4.5.27 决策规则(可入主 SKILL.md)
- advisor 报 SSL/Timeout/Connection 错误 → 自动 retry 一次,间隔 10s
- retry 仍失败 → 推"⚠️ {symbol} execute失败,需手动"到 QQ,不推"已跟单"
- 用户看到这条 → 自己手动 retry 或 等下次信号
- 绝对禁止在 advisor 报错时推"已跟单 X 张"格式