feat(crypto-t-monitor): v2.3.0 新币自动挑选池 (PICKS=2, POOL_MAX=6)
- 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>
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
---
|
||||
name: crypto-t-monitor
|
||||
description: "OKX 币圈日内做T监控 - 多币种 + 动态 ATR + 网络重试 + 新币自动挑选,推结果到QQ。t-monitor cron 每15分钟跑。v2.3: 每次扫前2名, 池子最多保6个, 超限自动裁旧。"
|
||||
version: 2.3.0
|
||||
author: Hermes Agent
|
||||
license: MIT
|
||||
platforms: [linux, macos]
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [trading, crypto, okx, t-monitor, position, automatic, backtest, multi-coin, new-coin-scanner]
|
||||
related_skills: [okx-auto-position, okx-crypto, intraday-trading]
|
||||
scripts:
|
||||
- okx_t_monitor.py: "核心做T脚本, 多币种 + 动态 ATR + 自动重试 + 新币扫描"
|
||||
- backtest.py: "回测工具, 验证策略在历史 K 线上的表现"
|
||||
requires:
|
||||
- python3
|
||||
- OKX API 凭证 (in ~/.bashrc)
|
||||
- Clash 代理 (http://127.0.0.1:7890)
|
||||
- push_to_qq.sh
|
||||
---
|
||||
|
||||
# Crypto T-Monitor (币圈日内做T) v2.3.0
|
||||
|
||||
OKX 币圈日内做T自动监控系统。**核心定位**:**与股票做T(长桥)完全独立**,本 skill 只负责币圈。
|
||||
|
||||
## 🚦 何时使用本 skill
|
||||
|
||||
**使用场景**:
|
||||
- 用户在 OKX 持有币种(ETH/BTC/SOL/DOGE/XRP)做T
|
||||
- 想在动态 ATR 价位自动低吸/高抛
|
||||
- 验证策略历史表现(用 backtest)
|
||||
|
||||
**不要使用**:
|
||||
- 跟单交易员信号 → 用 `okx-auto-position`
|
||||
- 现货/DCA 长持 → 用 `dividend-investing` / `dca-monitor`
|
||||
- 股票做T → 用 `longbridge-t-monitor`
|
||||
|
||||
## ✨ v2.3.0 新功能 (2026-07-10): 新币自动挑选池
|
||||
|
||||
**问题**: 用户想要 **30 天内新上市的币** 自动监控,但:
|
||||
- 不全要 (太多噪音)
|
||||
- 每次扫描都刷新(非累积)
|
||||
|
||||
**解决方案** (用户原话: "新币最多保留六个, 每次扫描后筛选"):
|
||||
|
||||
| 常量 | 值 | 含义 |
|
||||
|------|---|------|
|
||||
| `NEW_COIN_PICKS` | `2` | **每次扫描后筛 X 个** (按 24h vol 排序) |
|
||||
| `NEW_COIN_POOL_MAX` | `6` | **永久保留上限** (超过自动裁最早加入) |
|
||||
| `NEW_COIN_DAYS` | `30` | 30 天内新列 |
|
||||
| `NEW_COIN_MIN_VOLUME_USDT` | `1_000_000` | 24h vol ≥ $1M (排除无人币) |
|
||||
|
||||
**实现逻辑**:
|
||||
```
|
||||
1. 拉 OKX 所有 SWAP (公共 endpoint, 不需 credentials)
|
||||
2. 筛 list_time 在 30 天内的
|
||||
3. 拉每个的 24h 成交量 (tickers 端点)
|
||||
4. 过滤 vol < $1M
|
||||
5. 按 24h vol 降序排序, 取前 NEW_COIN_PICKS=2
|
||||
6. 比对 state['_new_coin_picks'] 当前次, 变化才推 QQ
|
||||
7. 加入永久池 state['_new_coin_pool']
|
||||
8. 池子 > NEW_COIN_POOL_MAX=6 → 按 added_at 升序, 删最早的
|
||||
```
|
||||
|
||||
**QQ 推送格式**:
|
||||
```
|
||||
🆕 新币扫描 (30 天内新上市, vol 前 2):
|
||||
|
||||
📊 CAP: 24h vol $442.5M | 上线 13.6 天前
|
||||
📊 NES: 24h vol $67.0M | 上线 15.6 天前
|
||||
|
||||
💡 已自动加入监控池 (上限 6 个)
|
||||
```
|
||||
|
||||
**裁剪通知** (超限时):
|
||||
```
|
||||
🗑️ 新币池超限 (>6), 移除: ['OLDXYZ', 'ABC123']
|
||||
```
|
||||
|
||||
**代码位置**: `crypto/okx_t_monitor.py:194` (常量) + `:328` (`monitor()` 调用)
|
||||
|
||||
## ✨ v2.1.0 新功能 (2026-07-10): 变化驱动推送 (C 方案)
|
||||
|
||||
**问题**: v2.0 每次 cron 跑都推"💤 无持仓, 跳过做T",用户**嫌噪音**,问"有变化时推, 计划怎么改?"
|
||||
|
||||
**解决方案**: 实现 v2.1 推送规则 (用户拍板的 **C 方案**):
|
||||
- ❌ 之前: 每次 cron 都推 (噪音)
|
||||
- ✅ 现在: **只在有变化时推**,其他时间静默 (本地 print 但不推 QQ)
|
||||
|
||||
**推送触发条件 (4 类事件,任一触发就推)**:
|
||||
|
||||
| # | 事件 | 检测方法 | 推送格式 |
|
||||
|---|------|---------|---------|
|
||||
| 1 | **持仓变化** | 对比 `state[sym]_prev_pos` 与当前 `pos_qty`, 差异 > 0.001 张 | `🔄 持仓变化: 1.45 → 1.00 张` |
|
||||
| 2 | **价格触及关键位** | 当前价距 buy1/buy2/sell1/sell2 任一 < 0.5% | `📍 价格触及 buy2=1762 (距 0.32%)` |
|
||||
| 3 | **浮盈大幅波动** | 浮盈 ≥ 5% 且相对上次 ≥ 3% | `📈 浮盈变化: -2% → +5% (+7%)` |
|
||||
| 4 | **做T成交** | buy/sell 实际成交 (原有逻辑) | `✅ 做T自动执行 v2.1` |
|
||||
| 5 | **做T失败** | buy/sell `code != '0'` | `❌ {sym} {action} 失败: {msg}` |
|
||||
|
||||
**静默分支** (全部跳过,只本地 print):
|
||||
- 没持仓 + 无变化 → `💤 静默: 无持仓, 无变化`
|
||||
- 有持仓 + 价格距最近关键位 > 0.5% + 浮盈变化 < 3% → `💤 静默: 有持仓但无变化`
|
||||
|
||||
**详细实现** 见 `references/change-driven-push.md`。
|
||||
|
||||
## ✨ v2.0.0 新功能
|
||||
|
||||
**相比 v1.0.0**:
|
||||
1. **多币种自动** (ETH/BTC/SOL/DOGE/XRP), 不再硬编码 ETH
|
||||
2. **动态 ATR 价位** (基于 1H K线, 14期 ATR)
|
||||
3. **网络重试机制** (Clash 抽风时自动重试 2 次)
|
||||
4. **STATE_FILE 自动清理** (7 天前自动删除)
|
||||
5. **支持 limit 单** (替代 market 滑点)
|
||||
6. **回测工具** (`backtest.py`)
|
||||
|
||||
## 📦 核心组件
|
||||
|
||||
### 1. 监控脚本: `crypto/okx_t_monitor.py`
|
||||
|
||||
**位置**: `~/.hermes/scripts/crypto/okx_t_monitor.py`
|
||||
**兼容**: `~/.hermes/scripts/t_monitor.py` (symlink)
|
||||
|
||||
**核心逻辑**:
|
||||
```
|
||||
1. 加载 ~/.bashrc 的 OKX_* 凭证
|
||||
2. 对每个币种:
|
||||
a. 查 OKX 持仓
|
||||
b. 如果有持仓 → 拉 1H K线
|
||||
c. 计算 ATR(14 期)
|
||||
d. 动态算 buy1/buy2/sell1/sell2 价位 (ATR × 0.5)
|
||||
3. 检查价格是否触及 buy/sell 价位
|
||||
4. 拉余额/持仓, 成交
|
||||
5. 记录到 STATE_FILE (自动清理 7 天前)
|
||||
6. 推结果到 QQ
|
||||
```
|
||||
|
||||
### 2. 回测工具: `crypto/backtest.py`
|
||||
|
||||
### 2. 回测工具: `crypto/backtest.py`
|
||||
|
||||
**位置**: `~/.hermes/scripts/crypto/backtest.py`
|
||||
|
||||
**默认参数 (用户偏好: 默认短期做T, 2026-07-10)**:
|
||||
|
||||
| 参数 | 默认 | 说明 |
|
||||
|------|------|------|
|
||||
| `--mode` | **short** | 用户原话"默认是短期", 即 1H K 线 + 7 天窗口。要 trend 必须显式 `--mode trend` |
|
||||
| `--days` | 7 (short) / 30 (trend) | 短/中期不同的窗口 |
|
||||
| `--bar` | 1H (short) / 4H (trend) | 自适应 |
|
||||
| `--atr-multiplier` | 0.5 (short) / 1.5 (trend) | 严格说代码当前是 trend=1.5; 但实测 short 下 0.7 才是甜点 |
|
||||
|
||||
**用户实测发现**:
|
||||
- 默认 `--mode trend` 时, fail 拉数据 (4H K线 + 翻页有 bug), 当前只在 1H 跑通
|
||||
- `short` 模式下 ATR=0.7 实测胜率 81.6% (200 根 K 线回测), 优于 0.5 / 1.0 / 1.5
|
||||
- **实战 ATR=0.7 比默认 0.5 更好**, 但代码默认是 trend 给的 1.5。**用户跑 short 时需要显式 `--atr-multiplier 0.7`**
|
||||
|
||||
**用法**:
|
||||
```bash
|
||||
# 默认 (ETH, short = 1H, 7天)
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH
|
||||
|
||||
# 短期 + 实测甜点参数 (推荐)
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH --mode short --atr-multiplier 0.7
|
||||
|
||||
# 趋势 (4H, 30天, 较宽 ATR)
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py BTC --mode trend
|
||||
|
||||
# 自定义参数
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH \
|
||||
--days 14 \
|
||||
--bar 4H \
|
||||
--atr-multiplier 0.5 \
|
||||
--t-qty 0.03
|
||||
|
||||
# 输出: 买入/卖出次数, 胜率, 总盈亏, Top 5 盈利交易
|
||||
```
|
||||
|
||||
**重要数据源备注**: OKX 历史 K 线 `bar=4H` 翻页有 bug (当前 backtest.py 只能稳定拉 1H); 跑 trend 必须显式 `--days 7 + --bar 1H` 验证基础链路, 然后慢慢试 4H. 详见 backtest.py 注释.
|
||||
|
||||
### 3. cron 任务
|
||||
|
||||
| Job ID | 名称(**已重命名清晰化**) | 频率 |
|
||||
|--------|------|------|
|
||||
| `db03f9255ad0` | **币圈OKX做T** | `*/15 * * * *` (每 15 分钟) |
|
||||
| `a82a3ab0d48d` | signal-queue-retry | `*/5 * * * *` |
|
||||
|
||||
**命名教训 (2026-07-10)**: cron 名 "t-monitor" 太模糊,用户问"是币圈还是股票"。已重命名 `db03f9255ad0` 为 "币圈OKX做T"。股票侧用 `港股日内交易监控` / `美股日内交易监控` 已经清晰,**所有做T cron 一律带市场名 + 交易所** (例: `币圈OKX做T` / `港股日内交易监控` / `美股日内交易监控` / `A股...`)。**规则**: 任何新的做T cron, 名称必须显式标 "市场 + 交易所 + 动作" 三段。
|
||||
|
||||
## 🔧 配置 (`crypto/okx_t_monitor.py`)
|
||||
|
||||
### 默认币种
|
||||
```python
|
||||
DEFAULT_SYMBOLS = ['ETH', 'BTC', 'SOL', 'DOGE', 'XRP']
|
||||
```
|
||||
|
||||
### 合约规格 (v2.0.0)
|
||||
```python
|
||||
SYMBOL_SPECS = {
|
||||
'ETH': {'ct_val': 0.1, 'leverage': 25, 't_qty': 0.05},
|
||||
'BTC': {'ct_val': 0.01, 'leverage': 25, 't_qty': 0.03},
|
||||
'SOL': {'ct_val': 1.0, 'leverage': 20, 't_qty': 5.0},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### 动态价位算法 (已实测调优: ATR × 0.7)
|
||||
```python
|
||||
ATR = sum(trs[-14:]) / 14 # 1H K线, 14 期 ATR
|
||||
buy1 = price - ATR * 0.7 * 0.7 # = ATR * 0.49
|
||||
buy2 = price - ATR * 0.7 # = ATR * 0.70
|
||||
sell1 = price + ATR * 0.7 * 0.7
|
||||
sell2 = price + ATR * 0.7
|
||||
```
|
||||
|
||||
**实测调优 (2026-07-10, 200 根 K 线回测)**:
|
||||
|
||||
| atr 系数 | 交易次数/7天 | 胜率 | 总盈亏 |
|
||||
|---------|-------------|------|-------|
|
||||
| 0.5 | 62 + 62 | 79.0% | $16.36 |
|
||||
| **0.7** | 适中 | **81.6%** ⭐ | **$16.41** |
|
||||
| 1.0 | 偏少 | 78.8% | $11.54 |
|
||||
| 1.5 | 很少 | 66.7% | $4.17 |
|
||||
|
||||
**结论**: ATR × 0.7 是甜点——胜率最高且总盈亏最大。**已落地到 v2.0.0 代码默认**(修过 `0.5 → 0.7`), 不要退回 0.5。
|
||||
|
||||
**含义**: 价格距 ATR 中位 ±50% / ±100%(0.7 倍 ATR),自动调整会追市场波动。
|
||||
|
||||
## 📊 STATE_FILE
|
||||
|
||||
`~/.hermes/trading/t_state.json`:
|
||||
```json
|
||||
{
|
||||
"ETH_2026-07-10": ["buy1", "sell1"],
|
||||
"BTC_2026-07-10": ["buy2"]
|
||||
}
|
||||
```
|
||||
|
||||
**自动清理**: `cleanup_state(state, keep_days=7)`, 跨 7 天前的 entry 自动删除。
|
||||
|
||||
## 📋 推送格式
|
||||
|
||||
**成交** (推 QQ):
|
||||
```
|
||||
✅ 做T自动执行 v2.0
|
||||
|
||||
🟢低吸 ETH 0.05张 @ $1770.50
|
||||
级别: 1768.23(buy2)
|
||||
ATR: $11.20
|
||||
|
||||
📊 持仓: 4.05张 @ $1768.23
|
||||
💰 可用: $52.68
|
||||
💹 浮盈: +$2.45
|
||||
```
|
||||
|
||||
## 🚨 关键避坑 (2026-07-10 实战教训)
|
||||
|
||||
### 1. 默认是短期做T (用户偏好)
|
||||
|
||||
用户原话: "默认是短期". 所以:
|
||||
- 默认 `--mode short`(1H K线, 7 天窗口)
|
||||
- 默认 `atr_multiplier=0.7`
|
||||
- 默认单笔 t_qty 占持仓 5-10%
|
||||
- 不要默认跑 `--mode trend`(那是"等回调"思路,用户没要求)
|
||||
|
||||
### 2. 默认监控币种必须包含持仓 (Symbol Coverage Pitfall) ⚠️ 重要
|
||||
|
||||
用户曾在 OKX 持有 SPCX, 但 `DEFAULT_SYMBOLS` 没列、`SYMBOL_SPECS` 也没列 → cron 报"💤 无持仓"多次, 但实际持仓 1.45 张。**两类 pitfall**:
|
||||
- `DEFAULT_SYMBOLS` 缺 → `monitor()` 跳过该币种, 静默
|
||||
- `SYMBOL_SPECS` 缺 → 拉到持仓计算 LEVELS 时 `KeyError`
|
||||
|
||||
**修复**:
|
||||
- 静态补全: 把持仓币种同时加进两个 dict
|
||||
- **推荐用 `get_monitored_symbols()` 模式**: 启动时拉 OKX 持仓, 跟静态列表去重合并
|
||||
- **t_qty 关键定义**: 是"每次做T张数",**不是**总持仓 (SPCX 持仓 1.45 → t_qty=0.5, 不是 1.45)
|
||||
|
||||
详见 `references/symbol-coverage-pitfall.md`。
|
||||
|
||||
### 3. 实盘前必跑回测 (200 根 K 线起步)
|
||||
|
||||
```bash
|
||||
# 测试新参数
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH --days 7
|
||||
|
||||
# 要求:
|
||||
# - 胜率 ≥ 55%(预期值正)
|
||||
# - 最大回撤 ≤ 15%
|
||||
# - 交易频率适中(7天 20-50 次, 不要 > 100)
|
||||
# - 总盈亏 > 0
|
||||
|
||||
# 实战第一次跑, 必须用 0.01-0.05 张试水
|
||||
# (SPOT/合约都从最小单位开始, 2-3 天后验证策略再扩仓)
|
||||
```
|
||||
|
||||
### 3. 单向持仓 → 自动退出 (不做贪婪)
|
||||
|
||||
- 持仓触及 sell2 (ATR × 0.7 上方) 必须平, **不允许"想再涨点"**
|
||||
- 跌破 buy2 (ATR × 0.7 下方) 必须加仓? 看 30% utilization 线,不超就加, 不允许"等再跌点"
|
||||
- **全规则跟随 advisor (okx-auto-position)** 的 close-position 路径, 不自己拍脑袋决定
|
||||
|
||||
### 4. cron 失败 ≠ 没运行 (网络抽风)
|
||||
|
||||
**症状**: cron 报 `💤 无持仓,跳过做T`,但实际你持 ETH/SPCX。
|
||||
**原因**: 在 OKX `fetch_positions` 时网络超时(Clash 抽风), 抛异常被 try/except 吞掉, 误判为空仓。
|
||||
**修复**: 在 `monitor()` 函数 `fetch_positions` 失败时记 ERROR, 不要当空仓处理。
|
||||
**临时绕过**: 手动 `python3 ~/.hermes/scripts/crypto/okx_t_monitor.py` 复查。
|
||||
|
||||
### 5. 状态文件 (t_state.json) 跨日会"恢复"
|
||||
|
||||
如果某天没成交 (例如网络挂了), 当天 `traded_levels` 是空。下一天 `state_key` 变了("ETH_2026-07-11"), `traded_levels` 也默认空, 所以**已经触及的价位, 隔夜会再次触发**(如果第二天价格还在那)。
|
||||
**修复**: 如果你想"7日内一次性" 触发, 用 `keep_days=7` 删旧 state key 后重做。 v2.0.0 用的是 `cleanup_state(keep_days=7)` 自动删 7 天前的, 但**不**阻止"跨日重复触发同价位"。
|
||||
|
||||
## ⚠️ 关键限制
|
||||
|
||||
1. **有持仓才做T** (没持仓的币种跳过) — 这是个隐性前提。SPCX 这类"已有持仓"会被监听到,纯增量币种不会主动开仓。
|
||||
2. **网络依赖**: Clash 死了就完全不能跑(虽然有重试,但重试也失败就崩)
|
||||
3. **不支持止损** (OKX advisor v4.5.0 才有 SL conditional algo). 持仓被套只能手动 App 或调用 `okx-auto-position/scripts/okx_position_advisor.py --execute` 走 SL-only conditional。
|
||||
4. **atr_multiplier=0.7** 是实测甜点(不要退回 0.5,见上表)。`1.5` 太宽捕捉不到,`0.5` 交易频率过高产生大量手续费。
|
||||
5. **不要假设有亏损保护**: `--mode short` 时 81% 胜率不代表实战也 81%——滑点/拒单/网卡都还没建模。
|
||||
|
||||
## 🔄 跟其他 skill 的关系
|
||||
|
||||
| Skill | 用途 | 冲突? |
|
||||
|-------|------|------|
|
||||
| `okx-auto-position` | 信号跟单 (麻吉/熬鹰等) | ✅ 互补 |
|
||||
| `okx-crypto` | OKX 数据查询 | ✅ 配合 |
|
||||
| `intraday-trading` | 股票日内 | ❌ 独立 |
|
||||
| `longbridge-t-monitor` | 股票做T | ❌ 独立 |
|
||||
|
||||
## 🔧 故障排查
|
||||
|
||||
### Cron 失败?
|
||||
1. **检查 Clash**: `pgrep mihomo`
|
||||
2. **测连通**: `curl -s --max-time 8 -x http://127.0.0.1:7890 https://www.okx.com/api/v5/public/time`
|
||||
3. **看 cron 输出**: `ls -lt ~/.hermes/cron/output/db03f9255ad0/ | head -3`
|
||||
|
||||
### 没触发做T?
|
||||
1. **检查持仓**: `python3 ~/.hermes/scripts/crypto/okx_t_monitor.py` (dry-run 手动跑)
|
||||
2. **看价格 vs 价位**: 脚本会 print "动态价位"
|
||||
3. **手动改 LEVELS**: 不推荐 (v2.0.0 全自动)
|
||||
|
||||
## 🚀 快速使用
|
||||
|
||||
### 监控(自动, 推荐)
|
||||
```bash
|
||||
# 加 cron (已存在):
|
||||
db03f9255ad0 t-monitor */15 * * * *
|
||||
|
||||
# 手动跑一次:
|
||||
python3 ~/.hermes/scripts/crypto/okx_t_monitor.py
|
||||
```
|
||||
|
||||
### 回测(调试新策略)
|
||||
```bash
|
||||
# 测试 ETH 默认参数
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH
|
||||
|
||||
# 对比不同 ATR 倍数
|
||||
for m in 0.3 0.5 0.7 1.0; do
|
||||
echo "--- ATR × ${m} ---"
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH --atr-multiplier $m
|
||||
done
|
||||
```
|
||||
|
||||
### 修改默认币种
|
||||
编辑 `crypto/okx_t_monitor.py` 的 `DEFAULT_SYMBOLS`。
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- `references/change-driven-push.md` - **v2.1 推送策略** (持仓/价格/浮盈变化检测细节, 必读)
|
||||
- `references/backtest-usage.md` - 回测详细使用 (待写)
|
||||
- `references/level-dynamic-calculation.md` - ATR 算法详解 (待写)
|
||||
- `references/api-fallback.md` - 网络重试机制 (待写)
|
||||
|
||||
## 🔄 版本历史
|
||||
|
||||
- **v2.3.0** (2026-07-10): **新币自动挑选池** (NEW_COIN_PICKS=2, POOL_MAX=6)
|
||||
- **v2.2.0** (2026-07-10): **静默模式+持仓自动包含** (AUTO_INCLUDE_HOLDINGS, 默认主流币+持仓合并)
|
||||
- **v2.1.0** (2026-07-10): **变化驱动推送 (C 方案)**
|
||||
- 加 `find_nearest_level()` + `check_changes()` 函数
|
||||
- 推送规则: 持仓变化 / 价格触及 / 浮盈大幅波动 / 做T成交 (4 类)
|
||||
- 静默模式: 无以上变化时本地 print 不推 QQ
|
||||
- State 扩展: 加 `_prev_pos` 和 `_prev_upl_pct` 跟踪上次状态
|
||||
- 详细见 `references/change-driven-push.md`
|
||||
- **v2.0.0** (2026-07-10):
|
||||
- 多币种 (ETH/BTC/SOL/DOGE/XRP)
|
||||
- 动态 ATR 价位 (实测甜点 0.7, 已落地)
|
||||
- 网络重试
|
||||
- STATE_FILE 自动清理
|
||||
- 支持 limit 单
|
||||
- 新增 backtest.py
|
||||
- **v1.0.0** (2026-07-10): 初始版本, ETH 4 张硬编码
|
||||
@@ -0,0 +1,128 @@
|
||||
# Backtest 使用指南 (crypto-t-monitor v2.0.0)
|
||||
|
||||
## 概述
|
||||
|
||||
`backtest.py` 用 OKX 历史 K 线模拟做T策略,验证参数在历史数据上的胜率和盈亏。
|
||||
|
||||
**适用**: 验证 `atr_multiplier` / `t_qty` / `bar` 参数组合,不是高频回测引擎(单 symbol, 单次模拟)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 默认 (ETH, 短期 = 1H K线, 7 天) - 用户偏好
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH
|
||||
|
||||
# 显式指定 4H/30 天 趋势模式
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py BTC --mode trend
|
||||
|
||||
# 自定义 ATR 系数 (默认 0.7)
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH \
|
||||
--days 14 --bar 4H --atr-multiplier 0.5 --t-qty 0.03
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
|
||||
| 参数 | 默认 | 选择 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `symbol` (必填) | - | ETH/BTC/SOL/DOGE/XRP | OKX 永续合约 |
|
||||
| `--mode` | **short** (用户偏好) | short/trend | short = 1H+7天 短线;trend = 4H+30天 趋势 |
|
||||
| `--days` | mode 决定 | 1-90 | 回测窗口天数 |
|
||||
| `--bar` | mode 决定 | 1H/4H/1D | K 线周期(以 mode 默认覆盖) |
|
||||
| `--atr-multiplier` | 0.7 (实测甜点) | 0.3-2.0 | ATR 倍数,越大越保守 |
|
||||
| `--t-qty` | 0.05 | 0.01-1 | 单笔张数 |
|
||||
| `--leverage` | 25 | 5-125 | 杠杆倍数 |
|
||||
| `--ct-val` | 0.1 | 看币种 | 合约面值(代码里 SYMBOL_SPECS) |
|
||||
|
||||
## ATR 倍数选择 (实测 2026-07-10, 200根 1H K线)
|
||||
|
||||
| ATR | 交易/7天 | 胜率 | 总盈亏 |
|
||||
|-----|---------|------|-------|
|
||||
| 0.5 | 124 | 79.0% | $16.36 |
|
||||
| **0.7** | 适中 | **81.6%** ⭐ | **$16.41** |
|
||||
| 1.0 | 偏少 | 78.8% | $11.54 |
|
||||
| 1.5 | 很少 | 66.7% | $4.17 |
|
||||
|
||||
**结论**: 短期模式 ATR=0.7 是甜点(已落地 `crypto/okx_t_monitor.py` v2.0.0)。不要用 0.5(交易过度,手续费吃光)或 1.5(过保守,捕捉不到)。
|
||||
|
||||
## 输出解读
|
||||
|
||||
```
|
||||
📊 ETH 1H 回测 (7 天, mode=short)
|
||||
ATR=0.5 t_qty=0.05 lev=25x
|
||||
|
||||
📥 拉到 200 根 K 线
|
||||
|
||||
📈 回测结果:
|
||||
买入: 62 次
|
||||
卖出: 62 次
|
||||
胜率: 79.0%
|
||||
总盈亏: $16.36
|
||||
最终仓位: 0 (全平)
|
||||
```
|
||||
|
||||
**评估表**:
|
||||
|
||||
| 指标 | 达标 | 警告 |
|
||||
|------|------|------|
|
||||
| 胜率 | ≥ 60% | < 50% |
|
||||
| 总盈亏 | > 0 | < -10 USDT |
|
||||
| 交易频率(7天) | 20-50 次 | > 100 (手续费吃光) |
|
||||
| 最大回撤 | < 15% 资金 | > 25% |
|
||||
|
||||
## 参数调优示例
|
||||
|
||||
```bash
|
||||
# 测试不同 ATR 倍数
|
||||
for m in 0.3 0.5 0.7 1.0 1.5; do
|
||||
echo "=== ATR $m ==="
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py ETH --atr-multiplier $m
|
||||
done
|
||||
|
||||
# 测试不同币种找参数稳健性 (避免过拟合单个币种)
|
||||
for sym in ETH BTC SOL; do
|
||||
echo "=== $sym ==="
|
||||
python3 ~/.hermes/scripts/crypto/backtest.py $sym
|
||||
done
|
||||
|
||||
# 找到最佳参数后才落盘到 okx_t_monitor.py
|
||||
```
|
||||
|
||||
## 🛑 使用禁忌
|
||||
|
||||
- **不要过拟合**: 用 200 根 K 线找出来"最佳参数"对外样本(未来)很可能失效。**每月最多调一次参数**。
|
||||
- **不要同时改多个参数**: 1 个 → 验证 → 再改下一个
|
||||
- **不要在战斗日调参**: 周一调参, 周二之前观察,如果连续 2 单连亏 → 立即退回上次稳定参数
|
||||
|
||||
## 已知问题 + 临时绕路
|
||||
|
||||
### 1. Clash 抽风 → subprocess 20s timeout
|
||||
|
||||
**症状**: `[Command timed out after 20 seconds]`
|
||||
**绕路**:
|
||||
- 手动重试 (90% 概率下次成功)
|
||||
- SSH 跑: `ssh openclaw@vps 'python3 ~/.hermes/scripts/crypto/backtest.py ETH'`
|
||||
|
||||
### 2. 4H K 线拉不够 30 天
|
||||
|
||||
**症状**: `--mode trend --days 30 --bar 4H` 报 "❌ 没拉到数据"
|
||||
**原因**: OKX history-candles 4H 翻页逻辑当前代码有 bug
|
||||
**绕路**: 用 `--mode short --days 28 --bar 1H` (200 根 K 线)
|
||||
|
||||
### 3. 回测假设市价滑点 = 0
|
||||
|
||||
实际 4H K 线内会有 0.05-0.1% 滑点 + taker 手续费 0.05%。**真实盈利 ≈ 回测盈利 × 0.85**。**避免把回测当实盘 max**。
|
||||
|
||||
## 实战工作流
|
||||
|
||||
1. 调参前 baseline: `python3 ~/.hermes/scripts/crypto/backtest.py ETH > /tmp/baseline.txt`
|
||||
2. 改 `atr_multiplier`,观察胜率和总盈亏
|
||||
3. 找到最佳参数后,跑 BTC/SOL 验证(避免过拟合单个币种)
|
||||
4. ≥ 3 个币种一致胜率 > 60% 才推到 `okx_t_monitor.py`
|
||||
5. 实战**先用 0.01 张试水 2-3 天**,验证后再扩大规模
|
||||
|
||||
## 相关文件
|
||||
|
||||
- 脚本: `~/.hermes/scripts/crypto/backtest.py`
|
||||
- 主监控: `~/.hermes/scripts/crypto/okx_t_monitor.py`
|
||||
- ATR 算法详解: `references/level-dynamic-calculation.md` (TODO)
|
||||
- 网络重试机制: `references/api-fallback.md` (TODO)
|
||||
@@ -0,0 +1,115 @@
|
||||
# Change-Driven Push 推送策略细节 (v2.1)
|
||||
|
||||
`okx_t_monitor.py` v2.1 的核心: **只在有变化时推 QQ**,其他静默。
|
||||
|
||||
## 📋 推送触发矩阵
|
||||
|
||||
| 触发条件 | 推送条目 | 频率 |
|
||||
|----------|---------|------|
|
||||
| 持仓变化 (`abs(new_pos - old_pos) > 0.001`) | 🔄 "持仓: X → Y 张" | **每次变化** |
|
||||
| 价格触及 buy1/buy2/sell1/sell2 (距 < 0.5%) | 📍 "价格触及 buy2=Z (距 W%)" | **每次扫描** |
|
||||
| 浮盈 ≥ 5% 且变化 ≥ 3% | 📈/📉 "浮盈变化: X% → Y% (Z%)" | **变化触发** |
|
||||
| 做 T 实际成交 | ✅ 完整做T记录 (保留 v2.0 格式) | **每次成交** |
|
||||
| 做 T 失败 (API code != 0) | ❌ 失败原因 | **每次失败** |
|
||||
| 静默 (无以上 5 种) | (本地 print `💤 静默:`) | **静默** |
|
||||
|
||||
## 🔧 实现细节 (代码视角)
|
||||
|
||||
### `find_nearest_level(price, levels, traded_levels) -> str|None`
|
||||
|
||||
```python
|
||||
def find_nearest_level(price, levels, traded_levels):
|
||||
"""找价格 0.5% 内最近的关键位, 跨 4 个候选 (buy2/buy1/sell1/sell2)"""
|
||||
threshold = 0.005 # 0.5%
|
||||
nearest = None
|
||||
min_dist = float('inf')
|
||||
for name in ['buy2', 'buy1', 'sell1', 'sell2']:
|
||||
if levels.get(name) is None:
|
||||
continue
|
||||
dist = abs(price - levels[name]) / price
|
||||
if dist < threshold and dist < min_dist:
|
||||
min_dist = dist
|
||||
nearest = name
|
||||
return nearest
|
||||
```
|
||||
|
||||
**关键**: 同时检查 buy2 (距 -0.7×ATR) 和 sell1 (距 +0.49×ATR)。两个临界区都在 0.5% 内,**只汇报最近的一个**。
|
||||
|
||||
### `check_changes(sym, price, pos_qty, avg_px, upl, levels, state) -> list[str]`
|
||||
|
||||
```python
|
||||
def check_changes(sym, price, pos_qty, avg_px, upl, levels, state):
|
||||
"""返回事件 list (空 list = 无变化)"""
|
||||
events = []
|
||||
# 1. 持仓变化
|
||||
prev_pos = state.get(f'{sym}_prev_pos')
|
||||
if prev_pos is not None and abs(pos_qty - prev_pos) > 0.001:
|
||||
events.append(f'🔄 持仓变化: {prev_pos:.2f} → {pos_qty:.2f} 张')
|
||||
# 2. 价格触及
|
||||
nearest = find_nearest_level(price, levels, [])
|
||||
if nearest:
|
||||
level_price = levels[nearest]
|
||||
dist_pct = abs(price - level_price) / price * 100
|
||||
events.append(f'📍 价格触及 {nearest}={level_price:.2f} (距 {dist_pct:.2f}%)')
|
||||
# 3. 浮盈变化 (多空方向修正)
|
||||
if avg_px > 0 and pos_qty != 0:
|
||||
leverage = SYMBOL_SPECS.get(sym, {}).get('leverage', 25)
|
||||
pos_sign = 1 if pos_qty > 0 else -1
|
||||
upl_pct = (price - avg_px) / avg_px * 100 * leverage * pos_sign
|
||||
prev_upl_pct = state.get(f'{sym}_prev_upl_pct')
|
||||
if prev_upl_pct is not None and abs(upl_pct) >= 5:
|
||||
upl_diff = upl_pct - prev_upl_pct
|
||||
if abs(upl_diff) >= 3:
|
||||
emoji = '📈' if upl_diff > 0 else '📉'
|
||||
events.append(f'{emoji} 浮盈变化: {prev_upl_pct:.1f}% → {upl_pct:.1f}% ({upl_diff:+.1f}%)')
|
||||
return events
|
||||
```
|
||||
|
||||
### State 持久化
|
||||
|
||||
`state` 字典除了原有 `traded_levels` 之外,新增两类 key:
|
||||
- `{sym}_prev_pos`: 浮点数, 上次持仓张数
|
||||
- `{sym}_prev_upl_pct`: 浮点数 or None, 上次浮盈百分比
|
||||
|
||||
**重要**: **首次 cron 跑** 这些 key 不存在, 不会触发变化 (因为没"上次"可比)。**这是有意为之** — 不让首次运行就推"持仓从无 → 1.45 张"的噪音。
|
||||
|
||||
## 🚨 Pitfall
|
||||
|
||||
### 1. 浮盈方向
|
||||
**计算**:`(price - avg_px) / avg_px * 100 * leverage * pos_sign`
|
||||
|
||||
`pos_sign` 是关键 — **空头**是 `pos_qty < 0`, 价格跌时浮盈大, 所以乘 `-1` 让"价格下跌 = 浮盈增加"。
|
||||
|
||||
不乘 `pos_sign` 会把空头的 📈/📉 推反 — 价格跌了你说"📉 浮盈变小"是反的。
|
||||
|
||||
### 2. 静默不等于"系统没跑"
|
||||
- cron 触发 → `monitor()` 跑 → 无变化 → 本地 print `💤 静默: 有持仓但无变化` + **不推 QQ**
|
||||
- 系统正常, 只是没新事件
|
||||
|
||||
监控 cron 故障排查: 看本地 print 日志 (cron 输出文件 `~/.hermes/cron/output/db03f9255ad0/`)
|
||||
|
||||
### 3. 首次 cron 的"假静默"
|
||||
- 第 1 次跑: 没有 `prev_pos` 基准 → 全是"无变化" → 静默
|
||||
- 第 2 次跑起: 才有真正的变化检测
|
||||
|
||||
**这是有意为之**, 不是 bug。
|
||||
|
||||
## 🧪 验证测试
|
||||
|
||||
第一次部署改这版后, 建议:
|
||||
1. 手动 `python3 ~/.hermes/scripts/crypto/okx_t_monitor.py` 看本地输出
|
||||
2. 确认 cron 跑 5 次 (约 75 分钟) 后**没推 QQ** (静默)
|
||||
3. 触发一次手动市价调整 (App 改 1 张), 看下次 cron 跑是否推"持仓变化"
|
||||
|
||||
## 🔄 v2.1 升级步骤
|
||||
|
||||
如果你 fork 改了 v2.0 想升 v2.1:
|
||||
1. 加 `push_qq(msg)` helper (提取 subprocess 调用)
|
||||
2. 加 `find_nearest_level()` 函数
|
||||
3. 加 `check_changes()` 函数
|
||||
4. 重构 `monitor()` 分两阶段:
|
||||
- Phase 1: 收集 `syms_to_check`, 跑变化检测, 推 QQ
|
||||
- Phase 2: 只对有持仓币种做 T
|
||||
5. 静默分支合并到最后
|
||||
|
||||
参考 `crypto/okx_t_monitor.py` 的 v2.1 实现。
|
||||
@@ -0,0 +1,94 @@
|
||||
# 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()` 而不是静态列表
|
||||
Reference in New Issue
Block a user