# 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 内部思考 → 可混用,但**最终输出必须明确时区** ### 代码 ```python 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" ### 涉及代码位置 ```python 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 最后一条推断 ### 实战代码 ```python # 第一件事: 查真实持仓 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 不一定是杠杆问题, 先查持仓再判断**