7.4 KiB
7.4 KiB
v4.5.62 (2026-08-23) Trader 白名单生效后实战经验:dedup需手动清 + raw REST 仓位调控
用户指令: "是的,暂时只做熬鹰的,。" (v4.5.61 已生效) → 后续实战暴露 3 个新坑。
坑 1: dedup 误跳后需手动清 recent_signals 解锁
症状: 熬鹰同一币种连续两条信号(如"加仓"+"调杠杆"),第二条常被报 ⏭️ 重复信号,跳过,但实际是不同动作(加仓 vs 调杠杆)本应分别处理。
根因:
recent_signals表按(symbol, trader)记录,不区分动作(open/add/reduce/close/调杠杆)- 调杠杆信号算 action="modify",但
parse_signal不区分 modify,被归入"已有同币种同 trader 记录"
解锁脚本 (sqlite3):
# 通用: 清特定币种的所有 recent_signals (会强制下次该币种信号重新走 advisor)
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM recent_signals WHERE symbol LIKE '%<SYMBOL>%';"
# 实战示例:
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM recent_signals WHERE symbol LIKE '%HYPE%' AND trader='熬鹰资本';"
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM recent_signals WHERE symbol LIKE '%MU%';"
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM recent_signals WHERE symbol LIKE '%ETH%';"
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM recent_signals WHERE symbol LIKE '%SKHYNIX%';"
# ⚠ 慎用: 全清 (所有 trader 重新走 advisor)
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM recent_signals WHERE 1=1;"
sqlite3 ~/.hermes/trading/signal_dedup.db "DELETE FROM processed WHERE 1=1;"
判断时机: 看到 ⏭️ 重复信号,跳过 但用户提示信号确实新的(如调杠杆跟新开仓是不同动作)→ 立即清库 + 重跑 process_signal。
坑 2: advisor 建议张数 vs 实际 execute 张数不一致 (幽灵执行)
症状: advisor 报 "1.0张" 但实际 execute 成功 25张 或 33张。
实战案例 (本次 session):
- 熬鹰 HYPE long 2x 信号 → advisor 推 1.0张 → execute 实际成交 25张@2x (avgPx 80.17,占用保证金 $101)
- 熬鹰 HYPE 调杠杆 2→5x 信号 → execute 实际 HYPE long 25→33 张 (杠杆升级时重新加仓了)
根因: okx_position_advisor.py 计算 contracts 字段时按 availBal × pct / margin_per_contract,但 execute 路径走 ccxt 的 create_order 时可能忽略 contracts 字段或用全仓计算。
判定规则 (硬):
- advisor JSON 返回
contracts < 10但 execute 后 check_account 显示contracts > 20→ advisor 报的 contracts 不可信 - execute 完成后必须跑
check_account.py反查实际张数,不能信 advisor
回复模板 (execute 后必查):
[实测] {symbol} {side} {X}张 avgPx={x} mark={y} upl={z}; USDT{可用} / {权益}
禁止: 直接引用 advisor 返回的 contracts 数字。
已知幽灵币种 (本次 session 验证):
- HYPE-USDT-SWAP (advisor 1张 → 实际 25/33 张)
- SNDK-USDT-SWAP (已知 execute 失败,v4.5.38 已记录)
- 1000PEPE-USDT-SWAP (execute 漏处理,v4.5.37 已记录)
修复方向 (下次必修):
- okx_position_advisor.py 的 execute 路径必须 raw REST 反查 contracts,与 advisor JSON 对比,不一致就 warn + 用反查值
- process_signal 主流程在
_okx_raw_request('GET', '/api/v5/account/positions')后写actual_contracts字段 - advisor JSON 加
{"execute_verified": True, "actual_contracts": X}字段
坑 3: 用户手动 raw REST 加仓模板 (7 成 / 8 成仓位)
用户指令序列:
- "这个可以跟单了" (MSTR short 1x 信号,资金够但 advisor 报性价比低跳过)
- "按 8 成来开" → manual 1 张 MSTR short @5x (实际只占 17%,没到 8 成)
- "不是,只留 2 成的余额" → 再加 3 张 MSTR short → 占用 68% (≈7 成) ✓
通用公式:
可用USDT × 目标占比 = 目标占用保证金
目标占用保证金 / 单张保证金 = 目标张数
OKX USDC 永续单张保证金 (实测本次 session):
| 币种 | 杠杆 | 单张保证金 | 名义/张 |
|---|---|---|---|
| MSTR-USDT-SWAP | 1x | $269.99 | $126.80 |
| MSTR-USDT-SWAP | 5x | $25.44 | $634.00 |
| BTC-USDT-SWAP | 5x | ~$13,300 | $66,000 (1张) |
| ETH-USDT-SWAP | 5x | ~$485 | $2,420 (1张) |
手动 execute 模板 (复制此块到 /tmp/open_X.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' # ⚠ 必须是字符串, 不要写 method=POST (NameError)
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()
# 示例: MSTR short 0.01 张 (最小变动单位, 先小试)
body = {"instId": "MSTR-USDT-SWAP", "tdMode": "cross", "side": "sell",
"posSide": "net", "ordType": "market", "sz": "0.01"}
print(json.dumps(okx_post('/api/v5/trade/order', body), ensure_ascii=False, indent=2))
⚠ 注意 name='POST' 拼写 — 之前 1 次踩坑 (NameError: name 'POST' is not defined),method 应为字符串 'POST'。
回查模板 (scripts/check_account.py 已封装, 直接调):
timeout 30 python3 ~/.hermes/skills/trading/okx-auto-position/scripts/check_account.py MSTR-USDT-SWAP
用户行为模式(本次新增)
- "X成来开" → 留对应比例余额, 开对应比例仓位
- "8 成来开" = 留 2 成余额, 用 8 成余额开仓
- "7 层" / "7 成" 同义
- 实际执行: 我算的总和与字面不符时, 用户会纠正 ("不是,是只留 2 成")
- 用户对小币种手动加仓有耐心 — MSTR 1x 信号 advisor 报"性价比低"跳过,用户主动说"跟单了"
- 用户关心的是"是否真的下单", 不是 advisor 报了什么 — execute 后必查 check_account.py
本次净状态(白名单生效后)
- USDT $149.60 (无冻结)
- MSTR short 4.01张@5x (avgPx 126.04,浮亏-$0.21,占用 68% 仓位 = 7 成)
- 强平价 160.00 (距 $34, 安全)
- 白名单生效,只熬鹰资本触发 execute
- 其他 trader(矿工/予与/麻吉/风寻/狙击手)静默跳过
部署清单(下次 session 第一件事)
- parse_signal() 区分 modify (调杠杆) vs add (加仓), 不混进 dedup 记录
- recent_signals 表加
action字段 (open/add/reduce/close/modify) - okx_position_advisor.py execute 后 raw REST 反查, 实际 contracts 写入 advisor JSON
- process_signal 主流程加
actual_contracts字段, 与 advisor JSON 对比 warn - manual_order.py 模板沉淀到 scripts/ (避免每次重新写)
- add scripts/manual_position_sizing.py 算 7 成/8 成张数