# v4.5.90 (2026-09-16) 仓位上限规则细化: $200 单币 ceiling + $1000 总资产 disable + process_signal hard pre-trade check **会话**: 9 月 16 日继续 9/14 CL 98.5% bug 修复讨论, 用户最终拍板单币种仓位规则。 ## 用户最终拍板的规则 ```python # 单币种上限 = min(总资产, $200) # 首仓 (已用=0): 上限 × 70% # 加仓 (已用>0): 上限 × 100% (可追满) # 总资产 ≥ $1000: 整个信号跳过 + 推 QQ 提示 ``` **多次纠正理解**: - 第一轮: user 说 "单币最多 $200 的 70%", 我理解成"单币占总资产 70%" (MEMORY 9/10 已存) - 第二轮: 我又理解错为"单次加仓 $200" - 第三轮: user 明确"单币种的总占用上限就是 $200, 多少用多少, 百分比按这个算" ## 改动 (3 处) ### 1. config.json ```json "position_sizing": { "balance_utilization": 0.60, "single_coin_max_pct": 0.70, // 已有 "single_coin_add_pct": 1.00, // 新 "single_coin_ceiling_usdt": 200, // 新 "single_coin_total_cap_disable_usdt": 1000, // 新 (≥1000 跳过) "safety_factor": 1.07, // 新 (从代码迁出) "max_leverage": 20, "default_leverage": 10, "min_profit_usdt": 10 } ``` ### 2. okx_position_advisor.py recommend_position 替换原 75% × total_cap 公式: ```python # 2026-09-16: 单币种上限 = min(总资产, $200), 百分比按上限算 total_cap = acct_info.get('total_capital', acct_info['usdt_free']) disable_threshold = cfg('position_sizing', 'single_coin_total_cap_disable_usdt', 1000) if total_cap >= disable_threshold: return {'error': f'⚠️ 总资产 ${total_cap:.2f} ≥ ${disable_threshold}, 配置上限失效, 跳过'} # 当前同币种已用保证金 base = symbol.split('/')[0] same_coin_margin = 0.0 for p in acct_info.get('positions', []): if p['symbol'].startswith(base): same_coin_margin += abs(p['margin']) # 单币种上限 = min(总资产, $200) coin_cap = min(total_cap, cfg('position_sizing', 'single_coin_ceiling_usdt', 200)) # 首仓 vs 加仓 if same_coin_margin == 0: cap = coin_cap * cfg('position_sizing', 'single_coin_max_pct', 0.70) else: cap = coin_cap * cfg('position_sizing', 'single_coin_add_pct', 1.00) # 还可加仓 = 上限 - 已用 single_coin_avail = max(0, cap - same_coin_margin) # 同时考虑 free 余额 + 1.07 缓冲 SAFETY_FACTOR = cfg('position_sizing', 'safety_factor', 1.07) avail_margin = min(acct_info['usdt_free'] / SAFETY_FACTOR, single_coin_avail / SAFETY_FACTOR) ``` **advisor return dict 加 `single_coin_avail` 字段** (供 process_signal hard check 用): ```python return { ... 'single_coin_avail': round(single_coin_avail, 2), ... } ``` ### 3. process_signal.py hard pre-trade check (CL bug 9/14 必修) execute 前加: ```python # 2026-09-16: hard pre-trade check (CL bug 9/14 教训) # 不可信 advisor rec['contracts'] — 复核单币种上限 try: margin_to_use = float(rec.get('margin') or 0) single_coin_avail = float(rec.get('single_coin_avail') or 0) except (TypeError, ValueError): margin_to_use = 0 single_coin_avail = 0 if margin_to_use > single_coin_avail + 1.0: # 1 刀容差 push_to_qq(f"❌ 拒绝: {symbol} 单币超限 " f"(本次 ${margin_to_use:.2f} > 上限 ${single_coin_avail:.2f})") record_signal(dedup_conn, text, symbol, trader) dedup_conn.close() return f"⏭️ 单币超限跳过 | {symbol} | ${margin_to_use:.2f} > ${single_coin_avail:.2f}" ``` **`record_signal` + `dedup_conn.close()` 在跳过分支** — 信号标 done 不再来 (用户原话: "A. 拒绝执行 + 推 QQ + 信号标记 done (不会再来)")。 ## 触发场景 | 总资产 | 单币上限 | 首仓 (70%) | 加仓 (100%) | |---|---|---|---| | $50 | $50 | $35 | $50 | | $150 | $150 | $105 | $150 | | $200 | $200 | $140 | $200 | | $300 | $200 (封顶) | $140 | $200 | | $500 | $200 | $140 | $200 | | $999 | $200 | $140 | $200 | | **$1000+** | ⚠️ **跳过** | ⚠️ **跳过** | ⚠️ **跳过** | ## 验证 ``` $ cd ~/.hermes/skills/trading/okx-auto-position/scripts && python3 -c " from config_loader import get as cfg print('ceiling =', cfg('position_sizing', 'single_coin_ceiling_usdt')) # 200 print('max_pct =', cfg('position_sizing', 'single_coin_max_pct')) # 0.7 print('add_pct =', cfg('position_sizing', 'single_coin_add_pct')) # 1.0 print('disable =', cfg('position_sizing', 'single_coin_total_cap_disable_usdt')) # 1000 print('safety =', cfg('position_sizing', 'safety_factor')) # 1.07 " ``` ## 关联 - v4.5.86: 单币种上限 70% 首次配置化 (比例, 无 $200 封顶) - v4.5.87-88: CL 98.5% bug 教训, advisor `free` 字段不可信 - v4.5.89: advisor hard pre-trade check 入口 (现在 v4.5.90 落地) - v4.5.90 (本次): 完整公式 + $200 ceiling + $1000 disable + advisor return `single_coin_avail` 字段 + process_signal hard check