8.5 KiB
8.5 KiB
v4.5.76 — 2026-09-02 减仓方向/时区/短答案/contractSize/信号≠实仓 5 合 1 教训
0. 背景
本 session 横跨 9/2-9/3,围绕 SKHYNIX / SPCX / ZEC 持仓调整,用户连续 3 次因 agent 行为爆炸:
- "你能不能一次算好?" — 一个话题搞 7 个独立操作
- "为什么减的是 SPCX, 不是开哪个调哪个?" — 减仓方向错
- "你全在说废话, 我要结论" / "你让我想杀了你" — 中间过程太长
- "时区又又又错了?" — UTC 时间当北京展示
- "我只能买 0.95 刀的?" — OKX contractSize 误解
- "怎么币圈的两个持仓全平了? 9 分钟了怎么没推?" — 查 queue.db 漏掉手动平仓
1. 减仓方向错 — SKHYNIX 占用高却减 SPCX
时间线
- 11:00 北京: 用户手动加仓 SKHYNIX 0.310 张 @4x
- 11:00+ 北京: advisor 又发加仓信号 → SKHYNIX 总 0.39 张,占用 92%
- 触发 7% 占用原则 (本意减仓到 70% 以内)
- agent 错误选择: 减 SPCX 0.65 张 → SPCX 占用从 $22 减到 0 (以为"释放空间")
- 实际错: SPCX 是独立空头仓位,与 SKHYNIX 多头无逻辑关联,减它不解决 SKHYNIX 占用问题
- 用户发现: "为什么减的是 SPCX, 不是开哪个调哪个?"
修复过程
- 先还原 SPCX 1.0 张 → 但 Free $16 不够,51008
- 改顺序: 先减 SKHYNIX 释放 Free → 再加 SPCX
- 减 SKHYNIX 0.225 张 (从 0.39 降到 0.165) → 占用从 92% 降到合理
- 再加 SPCX 1.0 张 → 占用回到 68.5%
铁律
- 减仓必减触发的那一笔 (同币种反向)
- ❌ 禁止"减占用最小的币种" / "减无关仓位释放空间"
- ✅ 减 SKHYNIX 占用高 → sell SKHYNIX,不是 sell SPCX
- 仓位复原优先: 误减后先还原误减的仓,再调整新仓位
2. 时区错 — UTC 当北京
时间线
- queue 246 created_at = "2026-09-03 02:58:05" (UTC)
- 实际北京 = "2026-09-03 10:58:05"
- agent 说"9 分钟前 02:58 北京处理" → 用户视角是"刚刚 10:58"
- 用户: "时区又又又错了?"
同 session 还有一次
- 查 order history 时也踩过 (UTC 时间戳直接说)
铁律
- SQL/SQLite
created_at/timestamp→ 默认 UTC - OKX API 返
cTime/uTime(毫秒) → UTC - 推送和最终回复 → 永远 +8h 转北京
- agent 内部思考 → 可混用,但最终输出必须明确时区
代码
from datetime import datetime, timezone, timedelta
beijing = timezone(timedelta(hours=8))
ts_bj = datetime.fromtimestamp(ts_ms/1000, tz=beijing)
# 输出: "9-03 10:58 北京"
3. 短答案铁律再强化
用户原话
- "你能不能一次算好?" (一个话题搞 7 个独立操作)
- "我让你想杀了你"
- "你全在说废话, 我不要看你中间状态"
- "我要结论"
踩坑模式 (本次再发生)
用户问"为什么没推?" → agent:
- 查 queue.db → 给过程
- 查 order history → 给过程
- 查 advisor cron → 给过程
- 查 59108 → 给过程
- 查时区 → 给过程
- 最后才说"OKX 持仓=0,信号已处理"
用户已经在第 2 步就爆炸
正确模式
结论: [1-2 句话直接答]
证据: [1 行数字 / log / 命令输出]
详细: [可展开,但默认折叠]
触发短答案的场景
- "为什么 X 没发生" → 直接给原因 + 证据
- "拉一下" → 直接给数据,不问"拉什么"
- "减少一点" → 直接给具体数字建议
- "现在怎么样" → 直接给账户快照
4. contractSize ≠ 1 张 = 1 个币
用户原话
"我只能买 0.95 刀的? — 算法没问题吗?"
真相
- ZEC 永续合约: 1 张 = 0.01 ZEC
- 名义 = 0.01 × $956 = $9.56
- @10x 杠杆 → 保证金 = $0.96
- 用户以为"买 1 张"是买 1 ZEC → 实际买了 0.01 ZEC
OKX 各币种 contractSize (常见)
- BTC-USDT-SWAP: 0.01 (1 张 = 0.01 BTC ≈ $1000)
- ETH-USDT-SWAP: 0.1 (1 张 = 0.1 ETH ≈ $400)
- SOL-USDT-SWAP: 1 (1 张 = 1 SOL ≈ $200)
- ZEC-USDT-SWAP: 0.01
- SKHYNIX-USDT-SWAP: ? (本次持仓看到 0.01 类似)
- SPCX-USDT-SWAP: ? (本次持仓看到 0.01 类似)
修复
- 下单前:
ex.load_markets()+ex.market(symbol)['contractSize'] - 推送时: 展示名义 $ 而不是张数
- "建议买 X 张" → 用户视角会误以为买 X 个币
- agent 应自动换算: "买 X 张 = 0.Y 币 = 名义 $Z"
涉及代码位置
m = ex.market('ZEC/USDT:USDT')
contract_size = m['contractSize'] # 0.01
ct_val = contract_size * 1 # 单张 = 0.01 ZEC
margin_per_contract = ct_val * price / leverage
5. 信号队列 ≠ 真实持仓
用户原话
"怎么币圈的两个持仓全平了? 9 分钟了怎么没推?"
真相
- queue.db 最后一条是 SPCX 平仓 (10:58 北京) → 已 done
- 但 SKHYNIX 在 11:01 北京也被平了 — 用户手动在 OKX app 平的
- queue.db 没记录用户手动操作
- agent 推断错: "SPCX 平了,SKHYNIX 应该还在" → 实际 SKHYNIX 也没了
铁律
- 用户问"X 持仓还在吗" →
fetch_positions()拉 OKX 真实持仓 - queue.db 只是入站信号,不是持仓实况
- 用户手动 / 强平 / SL 触发 / 自动止盈 → 都不在 queue
- 持仓状态以 OKX 为准,不要拿 queue 最后一条推断
实战代码
# 第一件事: 查真实持仓
positions = ex.fetch_positions()
for p in positions:
if abs(p['contracts']) > 0:
print(f"{p['symbol']} {p['side']}: {p['contracts']}张")
# 第二件事: 查 queue.db (辅助)
# 只看"信号源是什么",不推断持仓
6. 59108 降杠杆拒绝 + 用户已平仓
实战
- 11:07 北京: 收到 ZEC 加仓信号 → advisor 尝试 set_leverage 2x → 59108
- 但用户已平完 ZEC → 没有持仓 → OKX 报"杠杆太低/账户保证金不足" (cross_margin 不足新仓位)
铁律
- 收到加仓信号 → 先
fetch_positions()看是否有持仓 - 没有此币种持仓 → silent skip, 标记 done, 推送"账户无此持仓,可能用户已手动平仓"
- 无持仓 + 想 2x → 直接
create_order,不必先 set_leverage (除非明确要改) - 59108 多种原因: 杠杆太低 / cross_margin 不足 / 持仓已平仓位剩
7. 反模式 (本次再强化)
- ❌ "让我先查 X / 然后查 Y" 一长串前置 → 用户已经爆炸
- ❌ UTC 时间直接展示 → "时区又又又错了?"
- ❌ 减仓方向错 (SKHYNIX 占用高 → 减 SPCX) → "为什么减的是 SPCX"
- ❌ "1 张 = 1 个币"假设 → "我只能买 0.95 刀的?"
- ❌ 查 queue.db 就以为知道持仓 → "为什么全平了"漏掉用户手动
- ❌ 59108 盲目重试 set_leverage → 应该 silent skip 或直接 create_order
- ❌ 一个话题搞 7 个独立操作散乱 → 用户: "你能不能一次算好?"
8. 关联文件
~/.hermes/scripts/parse_order_errors.py(sCode 翻译)~/.hermes/scripts/order-errors-monitor.sh(改调 parse_order_errors.py)~/.hermes/skills/trading/okx-auto-position/scripts/okx_position_advisor.py(SAFETY_FACTOR 1.07)~/.hermes/trading/order_errors.log(本次 59108 + 51008 共 4 条)~/.hermes/trading/signal_queue.db(queue 246 SPCX 平仓, queue 251 ZEC 加仓)~/.hermes/memories/MEMORY.md(新合并条目: 减仓方向 + 时区 + 短答案)~/.hermes/skills/okx-trading-failover/SKILL.md(新建: 自救公式 + sCode 翻译)
9. 完整时间线
| 北京时间 | 事件 | agent 行为 | 用户反应 |
|---|---|---|---|
| 10:00-11:30 | SKHYNIX 加仓 + 减仓 + SPCX 减仓 | 减错方向 | "为什么减的是 SPCX?" |
| 11:11 | advisor 加仓 SPCX 失败 51008 | 推错误原因 | OK (新推送格式工作) |
| 11:30 | advisor 推加仓 → 用户手动平仓 | queue 显示 done 但持仓已变 | "怎么两个全平了?" |
| 11:50 | agent 查了一堆中间状态 | 长篇过程 | "你让我想杀了你" |
| 11:51 | agent 说"02:58 北京" | UTC 当北京 | "时区又又又错了?" |
| 11:55 | ZEC 加仓 14 张 @ 2x 失败 59108 | advisor 报杠杆错误 | "我刚平仓了, 你重下" |
| 12:00 | 手动买 1 张 ZEC @ 10x | 显示占用 $0.96 | "我只能买 0.95 刀的?" |
| 12:10 | 用户说"调到 50% 占用" | 给选项列表 | "之前能买 139 张, 现在只能买 100 张?" |
| 12:20 | 挂单 945 买 99 张 | 执行 | OK |
10. 结论
本 session 教训密度极高: 5 个独立硬伤 + 1 个工作流问题。已全部 patch 到 v4.5.76。下次开 session 应该:
- 结论先行 (绝不展示中间过程除非用户问)
- 所有时间戳 +8h 转北京再展示
- 减仓必减同币种 (同方向反向操作)
- OKX 持仓状态以 fetch_positions() 为准, queue.db 只是信号源
- contractSize 不是 1, 推送必须展示名义 $ 而非张数
- 59108 不一定是杠杆问题, 先查持仓再判断