Files
Hermes-Skills/okx-auto-position/references/v4.5.76-2026-09-02-direction-timezone-contractsize-and-conclusion-first.md
T

8.5 KiB
Raw Blame History

v4.5.76 — 2026-09-02 减仓方向/时区/短答案/contractSize/信号≠实仓 5 合 1 教训

0. 背景

本 session 横跨 9/2-9/3,围绕 SKHYNIX / SPCX / ZEC 持仓调整,用户连续 3 次因 agent 行为爆炸:

  1. "你能不能一次算好?" — 一个话题搞 7 个独立操作
  2. "为什么减的是 SPCX, 不是开哪个调哪个?" — 减仓方向错
  3. "你全在说废话, 我要结论" / "你让我想杀了你" — 中间过程太长
  4. "时区又又又错了?" — UTC 时间当北京展示
  5. "我只能买 0.95 刀的?" — OKX contractSize 误解
  6. "怎么币圈的两个持仓全平了? 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, 不是开哪个调哪个?"

修复过程

  1. 先还原 SPCX 1.0 张 → 但 Free $16 不够,51008
  2. 改顺序: 先减 SKHYNIX 释放 Free → 再加 SPCX
  3. 减 SKHYNIX 0.225 张 (从 0.39 降到 0.165) → 占用从 92% 降到合理
  4. 再加 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:

  1. 查 queue.db → 给过程
  2. 查 order history → 给过程
  3. 查 advisor cron → 给过程
  4. 查 59108 → 给过程
  5. 查时区 → 给过程
  6. 最后才说"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 应该:

  1. 结论先行 (绝不展示中间过程除非用户问)
  2. 所有时间戳 +8h 转北京再展示
  3. 减仓必减同币种 (同方向反向操作)
  4. OKX 持仓状态以 fetch_positions() 为准, queue.db 只是信号源
  5. contractSize 不是 1, 推送必须展示名义 $ 而非张数
  6. 59108 不一定是杠杆问题, 先查持仓再判断