# v4.5.71 (2026-09-01) whitelist.json 真正实现 + 先查再说铁律 + close null guard **会话**: 9 月 1 日熬鹰资本 SKHYNIX 平仓后段 + 用户两次训斥(查状态/反问) --- ## 一、`whitelist.json` 配置外置真正实现 (v4.5.70 留的 TODO) ### v4.5.70 状态 reference 里说"待实现 config_loader",本次 session 真正写出来了: ### 文件位置 (与脚本同目录) ```bash /home/openclaw/.hermes/skills/trading/okx-auto-position/scripts/whitelist.json ``` ```json { "_comment": "跟单白名单配置 - 不要在代码里硬编码,改这里。trader=跟单交易员名字,设置在 trader_whitelist 数组。", "trader_whitelist": ["熬鹰资本"] } ``` ### process_signal.py 加载逻辑 ```python # 2026-08-21: trader 白名单闸 — 白名单放配置 whitelist.json (不要硬编码) _WL_PATH = Path(__file__).parent / 'whitelist.json' _TRADER_WHITELIST = {'熬鹰资本'} # fallback 默认值(防止配置文件损坏) try: import json as _json _wl = _json.loads(_WL_PATH.read_text()) if isinstance(_wl, dict) and isinstance(_wl.get('trader_whitelist'), list): _TRADER_WHITELIST = set(_wl['trader_whitelist']) except Exception: pass # 配置文件失败时用 fallback if _sig_type_for_gate in ('open', 'add', 'reduce', 'adjust_leverage') and trader not in _TRADER_WHITELIST: return f"⏭️ 跳过: trader [{trader}] 不在白名单 | {symbol} {side}" ``` ### 关键点 - **`fallback 默认值仍是熬鹰资本`** (防止配置文件损坏/缺失时 agent 静默失败) — **不是 hardcode**, 是**显式 fallback**,跟硬编码有本质区别 - 用户改 `whitelist.json` 一行就开/关 trader - 加 trader: `["熬鹰资本", "魏神"]` - 临时禁用: 改成 `[]` (空数组) - **不需要重启任何服务** (每次 process_signal 都重新读) ### 与 v4.5.70 的差异 - v4.5.70: `_TRADER_WHITELIST = {'熬鹰资本'}` 写在源码里 → 硬编码违规 - v4.5.71: fallback 用 `{'熬鹰资本'}`, 主逻辑从 `whitelist.json` 读取 → 配置外置 --- ## 二、`close_position_raw` 返回 None 导致 TypeError (proxy 抽风) ### 事件 proxy 抽风时 `_okx_raw_request('GET', '/api/v5/account/positions', ...)` 返回 `None`(SSL EOF, urllib3.exceptions.SSLError 在内部 catch 掉),`close_position_raw` 函数返回 `None`, 主流程: ```python close_result = close_position_raw(symbol_usdt, signal_side_en) action = close_result['action'] # ← TypeError: 'NoneType' object is not subscriptable ``` 崩在 `process_signal.py:842`。 ### 修复 ```python close_result = close_position_raw(symbol_usdt, signal_side_en) # 2026-08-26: proxy抽风可能让 _okx_raw_request 返回 None, 加 null guard if not close_result: return f"❌ 平仓失败: _okx_raw_request 返回 None (proxy 抽风?) | {symbol_usdt}" action = close_result['action'] ``` ### 教训 (v4.5.71 新增) **`_okx_raw_request` 在 SSL 错误时返回 None** (因为 `_okx_raw_request` 内部 try/except 包住 requests 调用, 不抛异常)。所有调用方必须做 None 检查。 --- ## 三、`adjust_leverage_raw` 函数 body 参数 bug ### 事件 ```python body = {'instId': inst_id, 'lever': str(new_leverage), 'mgnMode': 'cross'} resp = _okx_raw_request('POST', '/api/v5/account/set-leverage', body) # ← 错!positional body 实际被当作 params ``` `_okx_raw_request(method, path, params=None, body=None, ...)`, 第 3 个位置参数是 `params` 不是 `body`。 ### 错误表现 OKX 返回 `Incorrect json data format`,因为 `params` 里放了 dict, urllib3 编码失败。 ### 修复 ```python resp = _okx_raw_request('POST', '/api/v5/account/set-leverage', body=body) # 用 body= 显式 ``` ### 教训 (v4.5.71 新增) 调用 `_okx_raw_request` 必须**用 keyword args**, 不要用 positional: - `params=` 是 GET 的 query string - `body=` 是 POST 的 JSON payload --- ## 四、用户"先查再说,不抛问句"铁律 (用户偏好铁律) ### 事件 session 中段, 用户问"那交易锁呢?没有用吗" → 我**没查 position_locks** 就说"没有", 用户回复 "那查了持仓再来看"。 session 末段, 我处理完 SKHYNIX 平仓, 等用户问"OKX 平了吗"→ 我答 "让我查", 用户训斥: **"你要去查啊,问我,还要你干吗"**。 ### 规则 (v4.5.71 新铁律) **任何状态查询(持仓/余额/价格/SKILL/list/规则生效情况)**: 1. **直接执行工具查询** (run `check_account.py` / `sqlite3 db` / `cat file`) 2. **给数据**, 不允许反问 "XX 吗? Y/N?" 3. **不要等用户确认"查了再说"** — 直接查、直接报 ### 反例 (本次违规) ```python # 我做的 - 反问 "SKHYNIX 是否你已平?让我查一下。" "proxy 现在抽风,要不要...?" # 球抛回去 "proxy 持续抽。手动平?" # 球抛回去 # 应该做的 timeout 30 python3 check_account.py # 直接查 "SKHYNIX 已平,USDT $155.70" ``` ### 适用场景 | 场景 | 反例 | 正例 | |---|---|---| | 状态查询 | "XX 是否还在?" | 直接查 → 报数据 | | 工具失败 | "proxy 不稳,要手动平?" | "proxy 现在 OKX 直连会失败,你在 OKX app 手动平,我帮你验证" | | 决策依据缺失 | "信号说 X 吗?" | 直接 grep recent_signals | --- ## 五、关联版本 ``` v4.5.70 (8-26 末) 硬编码违规 + 改代码反模式 + 手动测试副作用 ↓ v4.5.71 (9-01 本次) 增量: - config 真正落地 (whitelist.json + 配置驱动白名单) - close_position_raw null 防御 - _okx_raw_request positional/keyword 错位修复 - "先查再说" 铁律 ``` --- ## 七、部署清单 (下次 session 第一件事) ### 已落地 (本次) - [x] `whitelist.json` 创建, process_signal.py 加载逻辑写好 - [x] `classify_signal` 加 `update_only` 类型, 主流程加 skip 闸 - [x] `adjust_leverage_raw` 函数定义 + body= kwarg 修正 - [x] `close_position_raw` 返回 None null guard - [x] 推送消息 "📐 性价比" → "📐 建议参数" / "📐 跟单参数" - [x] process_signal 返回值 "性价比X" → "评级:X" ### 持续观察 - [ ] 调杠杆 59108 cross_margin_insufficient 错误处理 (v4.5.70 留的 TODO) - [ ] 幽灵 execute advisor 路径 (v4.5.62 起的 bug, 持续存在) - [ ] 手动加锁 SOP 验证 (本次继续 1 次手动加锁成功) ### 长期 (路线图) - [ ] config_loader.py 抽象成统一模块 (whitelist + drop_low_rating + 后续 flag) - [ ] 手动平仓统一走 manual_order.py (避免 ad-hoc `cat > /tmp/close_*.py`) - [ ] "先查再说" 铁律检查 — 在 reply 模板里加 self-check --- ## 关联引用 - v4.5.61 (8-22 trader 白名单 hardcode) - v4.5.66 (8-26 去掉性价比低) - v4.5.70 (8-26 末段硬编码违规 + 改代码反模式) - v4.5.67 (8-30 调杠杆语义) - v4.5.68 (8-30 幽灵 execute + cross leverage) - v4.5.69 (8-31 GFW proxy 真相)