- NEW_COIN_PICKS=2: 每次扫描后筛 2 个 (按 24h vol 排序) - NEW_COIN_POOL_MAX=6: 永久保留上限, 超限自动裁最早加入 - 30 天内新币 + 24h vol > $1M, 自动加入监控池 - 推 QQ 仅在变化时 (与 v2.1 C 方案一致) - references/: 新增 backtest-usage.md, change-driven-push.md, symbol-coverage-pitfall.md 用户原话: 新币最多保留六个, 每次扫描后筛选 Co-Authored-By: Claude <noreply@anthropic.com>
95 lines
3.7 KiB
Markdown
95 lines
3.7 KiB
Markdown
# Symbol Coverage Pitfall (2026-07-10 实战)
|
||
|
||
## 症状
|
||
|
||
Cron 推送"💤 静默: 无持仓, 无变化"或"💤 无持仓, 跳过做T",但实际账户**持有 1.45 张 SPCX**(或其他币种)。
|
||
|
||
**用户原话**: "一直在提示吗... 这个定时任务没改名称, 是币圈还是股票"。后续他从来没问过是否持仓,但 agent 看到 cron 消息也没去查实际持仓,以为没问题。
|
||
|
||
## 根因
|
||
|
||
`okx_t_monitor.py` 的 `DEFAULT_SYMBOLS` 是静态列表:
|
||
```python
|
||
DEFAULT_SYMBOLS = ['ETH', 'BTC', 'SOL', 'DOGE', 'XRP'] # 漏了 SPCX
|
||
```
|
||
|
||
`monitor()` 循环每个币种拉 OKX 持仓,**只在循环里的币种才被监控**。SPCX 不在列表里 → 永远查不到 → 被视为"无持仓"。
|
||
|
||
`SYMBOL_SPECS` 也必须包含该币种,否则 `KeyError` 直接崩。
|
||
|
||
**变种 1**: 用户开了小众币种(非主流)做T,监控不到
|
||
**变种 2**: 用户开了 OKX 交易但用 ccxt 报"unexpected type" 失败的币种
|
||
|
||
## 修复:三步
|
||
|
||
**1. 把持仓币种加进 `DEFAULT_SYMBOLS`**:
|
||
```python
|
||
DEFAULT_SYMBOLS = ['ETH', 'BTC', 'SOL', 'DOGE', 'XRP', 'SPCX'] # + 持仓币
|
||
```
|
||
|
||
**2. 把持仓币种加进 `SYMBOL_SPECS`**(避免 KeyError):
|
||
```python
|
||
SYMBOL_SPECS = {
|
||
'ETH': {'ct_val': 0.1, 'leverage': 25, 't_qty': 0.05, 'min_sz': 0.01},
|
||
...
|
||
'SPCX': {'ct_val': 1.0, 'leverage': 5, 't_qty': 0.5, 'min_sz': 0.01},
|
||
# ⚠️ t_qty 是"每次做T张数", NOT "总持仓"
|
||
}
|
||
```
|
||
|
||
**3. (推荐) 自动检测持仓币种**:
|
||
|
||
```python
|
||
def get_monitored_symbols():
|
||
"""从 OKX 实际持仓 + 预设列表合并"""
|
||
syms = set(DEFAULT_SYMBOLS)
|
||
try:
|
||
positions = ex.fetch_positions()
|
||
for p in positions:
|
||
if abs(float(p.get('contracts', 0))) > 0.001:
|
||
inst_id = p.get('instId', '') # e.g. "SPCX-USDT-SWAP"
|
||
sym = inst_id.replace('-USDT-SWAP', '')
|
||
syms.add(sym)
|
||
except Exception as e:
|
||
print(f"⚠️ 拉持仓失败: {e}")
|
||
return sorted(syms)
|
||
```
|
||
|
||
`monitor()` 第一行调用 `DEFAULT_SYMBOLS = get_monitored_symbols()`。
|
||
|
||
## 防御性编程
|
||
|
||
**新加币种时(尤其是用户/交易员信号里出现的)**:立刻同步 `DEFAULT_SYMBOLS` 和 `SYMBOL_SPECS`。否则:
|
||
- 信号来了推不到做T → 错过机会
|
||
- 平仓信号到了不被检测 → 持仓过夜
|
||
- 浮盈大幅波动不报警 → 用户不知道风险
|
||
|
||
**最稳**:用 `get_monitored_symbols()` 自动合并 + 当新币种出现时让用户填 SYMBOL_SPECS(告警一次后自动用默认 0.01 张)。
|
||
|
||
## 实测教训
|
||
|
||
**SPCX 1.45 张空 @ 149.15** 在 2026-07-10 上午被实测发现时,DEFAULT_SYMBOLS 没有,SYMBOL_SPECS 也没有,导致:
|
||
1. cron 跑 N 次,显示"💤 无持仓"
|
||
2. 实际有 SPCX 持仓但**变化检测 + 做T 触发都跳过**
|
||
3. 浮盈变化根本不被监控
|
||
4. 价格触及 buy1/buy2/sell1/sell2 也不会触发平仓
|
||
|
||
**修复后**:
|
||
- DEFAULT_SYMBOLS += ['SPCX']
|
||
- SYMBOL_SPECS['SPCX'] = {'ct_val': 1.0, 'leverage': 5, 't_qty': **0.5**(不是 1.45!), 'min_sz': 0.01}
|
||
- 下次 cron 跑 → 检测 SPCX 价格触及 149.15 ± ATR×0.7 → 自动推送"📍 价格触及"或成交
|
||
|
||
## t_qty 重要澄清
|
||
|
||
`t_qty` 是**每次做T张数**,不是总持仓大小。
|
||
- SPCX 持仓 1.45 张,t_qty = 0.5 → 每次 low/high 0.5 张,做满要 3 次
|
||
- 1.45 张仓位 + 做 T 一次就 1 张 → 仓位瞬间变化 67%,太大
|
||
|
||
**规则**:`t_qty ≤ 总仓位 × 0.5`(单笔不超过一半仓位)。
|
||
|
||
## 相关决策
|
||
|
||
- v2.1 C 方案"有变化时推"上线后,**静默覆盖了**"持仓不在列表"的 bug——之前会推"💤 无持仓"噪音,现在静默不推,bug 隐藏更深。
|
||
- **必须**每 24 小时或新币种出现时,核对 DEFAULT_SYMBOLS 是否包含全部持仓币种
|
||
- 实战:应该用 `get_monitored_symbols()` 而不是静态列表
|