127 lines
4.8 KiB
Markdown
127 lines
4.8 KiB
Markdown
# 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 |