Files
ritmex-bot/grid-trading.md
T
DisneyandGitHub b7ace263b1 Feat/grid (#26)
* feat(grid): add grid shift, exchange stops, and reconcile safeguards

* docs(grid): document smart-follow shift and new grid env vars
2026-07-21 15:30:45 +08:00

178 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 网格交易策略使用教程
本文介绍如何在 Ritmex Bot 中使用网格交易策略。当前版本的网格引擎围绕「每线状态机 + 开/平仓意图自治 + 断点恢复」重新设计,支持三种交易模式、四层止损防护与智能跟随移格。本文覆盖从环境配置到运行监控的完整流程,并详细说明各项机制与参数。
## 核心概念
在阅读参数前,先了解四个核心概念:
- **网格线(Level)**:策略在 `GRID_LOWER_PRICE` ~ `GRID_UPPER_PRICE` 之间按几何等比铺设 `GRID_LEVELS` 条价格线。每条线有独立的生命周期:`idle →(挂开仓单)entry_placed →(成交)holding →(挂平仓单)exit_placed →(平仓成交)idle`
- **开仓单(ENTRY)与平仓单(EXIT)**:策略自身通过订单登记表 + clientOrderId 编码(`grid-{网格版本}-E-…` / `grid-{网格版本}-X-…`)+ 价档匹配三级机制区分每笔挂单的意图,不依赖交易所回传的 reduceOnly 标志。
- **相邻线配对**:每条线的平仓目标固定为相邻线(多单在上一条线卖出、空单在下一条线买回),每格利润恒等于一格间距。
- **锚定价(Anchor)**:中性模式启动时以首笔行情价为分界线,上半区挂空、下半区挂多。锚定价持久化到磁盘,重启后沿用,避免价格漂移导致半区与已有持仓错位。
## 快速开始
1. 复制 `.env.example``.env`
```bash
cp .env.example .env
```
2. 配置交易所 API(以 Aster 为例):
```env
EXCHANGE=aster
ASTER_API_KEY=你的API密钥
ASTER_API_SECRET=你的API密钥
TRADE_SYMBOL=ASTERUSDT
```
3. 设置精度与网格参数(示例:1.50 ~ 2.50 区间、20 条网格、单笔 5 手、单侧最大 50 手):
```env
PRICE_TICK=0.0001
QTY_STEP=0.01
GRID_LOWER_PRICE=1.50
GRID_UPPER_PRICE=2.50
GRID_LEVELS=20
GRID_ORDER_SIZE=5
GRID_MAX_POSITION_SIZE=50
GRID_DIRECTION=both
GRID_STOP_LOSS_PCT=0.02
```
4. 启动:
```bash
bun install
bun run index.ts --strategy grid --exchange aster
```
或运行 `bun start` 后在菜单选择「基础网格策略」。
建议先用 dry-run 模拟运行(连接真实行情但不真正下单,验证建格方向与参数):
```bash
ritmex-bot strategy run --strategy grid --dry-run
# 或未全局安装时:bunx ritmex-bot strategy run --strategy grid --dry-run
```
## 参数总表
### 基础参数
| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `GRID_LOWER_PRICE` / `GRID_UPPER_PRICE` | 必填 | 网格上下边界(计价货币) |
| `GRID_LEVELS` | 10 | 网格线数量(≥2),几何等比分布 |
| `GRID_ORDER_SIZE` | TRADE_AMOUNT | 每条线的下单数量(标的资产) |
| `GRID_MAX_POSITION_SIZE` | orderSize×(levels1) | 单方向最大持仓(中性模式下多、空两侧分别约束) |
| `GRID_DIRECTION` | both | `long`(只做多)/ `short`(只做空)/ `both`(中性双向) |
| `GRID_REFRESH_INTERVAL_MS` | 1000 | 引擎轮询间隔,每轮最多新挂 1 笔限价单 |
| `GRID_PRICE_TICK` / `GRID_QTY_STEP` | PRICE_TICK / QTY_STEP | 价格与数量精度;交易所支持时会自动同步为交易所精度 |
### 风控参数
| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `GRID_STOP_LOSS_PCT` | 0.01 | 价格越过边界该比例后触发止损(层①),同时决定兜底止损单触发价 |
| `GRID_MAX_CLOSE_SLIPPAGE_PCT` | 0.05 | 所有市价平仓路径的滑点守卫:盘口价偏离标记价超过该比例时暂缓平仓、下轮重试 |
| `GRID_UNCOVERED_GRACE_MS` | 5000 | 覆盖审计(层②)的宽限期:持仓未被平仓单覆盖持续超过该时长才处置 |
| `GRID_EXCHANGE_STOP_ENABLED` | true | 在支持触发单的交易所(aster / binance / grvt / ondoperps)额外挂交易所侧 STOP_MARKET 兜底单(层④) |
| `GRID_AUTO_RESTART_ENABLED` | true | 止损停机后价格回到区间内自动重启网格 |
| `GRID_RESTART_TRIGGER_PCT` | 0.01 | 自动重启要求价格回到边界内该比例的缓冲区 |
### 智能移格参数
| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `GRID_SHIFT_ENABLED` | false | 开启后价格偏离锚定价超阈值时整体移格 |
| `GRID_SHIFT_TRIGGER_PCT` | 0.05 | 移格触发阈值:\|现价/锚定价 − 1\| |
| `GRID_SHIFT_CONFIRM_MS` | 3000 | 偏离需持续该时长才触发(防插针) |
| `GRID_SHIFT_RANGE_PCT` | 0.05 | 移格后新区间 = 新锚定价 × (1 ± 该比例) |
### 高级参数
| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `GRID_USE_REDUCE_ONLY` | false | 平仓单是否携带 reduceOnly。默认不带(部分交易所会拒绝与反向挂单共存的 reduce-only 限价单);策略靠意图登记自治区分开/平仓,无需此标志 |
| `GRID_RECONCILE_INTERVAL_MS` | 30000 | 支持 REST 查单的交易所的周期对账间隔 |
| `GRID_DATA_DIR` | ./data | 状态持久化目录(`grid-record.json` |
## 三种交易模式
`GRID_DIRECTION` 决定每条线的角色:
| 模式 | 开仓线 | 开仓方向 | 平仓目标 |
|---|---|---|---|
| `long` | 除最顶线外全部 | BUY | 上一条线(SELL |
| `short` | 除最底线外全部 | SELL | 下一条线(BUY |
| `both`(中性) | 锚定价下方 BUY / 上方 SELL | 按半区 | BUY→上一条线 / SELL→下一条线 |
- **long**:只在现价下方挂买单,买入成交后在相邻上方线挂卖单止盈。价格上行时逐格落袋,下行时逐格接多。
- **short**:镜像逻辑,只在现价上方挂卖单,成交后在相邻下方线买回。
- **both(中性)**:以启动时的锚定价分界。价格向上穿越上半区某条线时,会同时发生「下方多单的止盈卖出」与「该线自身的空头开仓」——两笔同价卖单并存是中性网格的正常形态。
## 挂单与仓位规则
- **每线一单**:只有 `idle` 状态的线才允许挂开仓单。线在 `holding` / `exit_placed` 期间,价格反复穿越也不会重复开仓,直到平仓单成交释放该线。
- **就近优先**:开仓单按与现价的距离排序,每轮只补挂 1 笔,逐步铺满。
- **仓位上限**:每次开仓前计算 `剩余额度 = GRID_MAX_POSITION_SIZE |同方向净仓| − 同方向在途开仓挂单量`,额度不足时跳过该线。中性模式下多空两侧分别计算。
- **平仓优先**:每轮规划先补挂缺失的平仓单,再考虑开仓单。
## 持久化与中断恢复
策略状态实时落盘到 `data/grid-record.json`schema v2,旧版 v1 文件自动迁移),内容包括:网格版本、锚定价、区间边界、每条线的状态与持仓量、每笔挂单的意图登记、移格进度、兜底止损单。
- **下单前写前日志(write-ahead)**:每笔限价单在发出前先落盘 inflight 槽位,交易所接单后立即登记订单号并再次落盘,消灭「交易所已接单、本地未记录」的崩溃窗口。
- **重启恢复**:启动时读取磁盘状态(要求配置指纹一致:方向 / 单笔数量 / 网格数 / 网格模式 / 交易对 / 交易所;**区间边界以磁盘为准**,移格后可能与 env 不同),然后执行三方对账:磁盘登记 ↔ 交易所挂单 ↔ 实际仓位。挂单按订单号 → clientOrderId → 价档三级匹配归位;无法归属的挂单中,平仓方向的收编为「孤儿平仓单」继续保护仓位,其余撤销;仓位差额归档到最近的线(每线不超过单笔数量),归不完的残余交给覆盖审计立即处置。
- **配置变更**:修改方向、网格数、单笔数量等指纹字段后重启会放弃旧状态、全新建格,并对现场执行孤儿扫描(撤掉旧挂单、按新网格归档仓位)。
- **断线重连**:支持连接事件的交易所(standx / ondoperps / binance)断连时冻结新下单,重连后用 REST 查单 + 查仓走同一套对账逻辑;支持 REST 查单的交易所另有周期对账兜底(`GRID_RECONCILE_INTERVAL_MS`)。其余交易所依赖网关自动重连 + 订单流差分判定,并有「下单后订单流长时间无反映则暂停新下单」的陈旧性守卫。
## 多重止损(四层防护)
1. **层① 价格越界**:现价 ≤ 下界×(1−stopLossPct) 或 ≥ 上界×(1+stopLossPct) 时,撤销全部挂单 → 市价平掉全部持仓(受滑点守卫保护,被拦截时下轮重试)→ 清空状态停机。开启移格时越界优先走移格,层①兜移格禁用或移格中再次越界的场景。
2. **层② 持仓覆盖审计**:每轮核对 `未覆盖仓位 = |净仓| − 活跃平仓挂单量 − 待挂平仓的线上持仓`。未覆盖持续超过 `GRID_UNCOVERED_GRACE_MS` 时:价格仍在区间内且浮亏未超限 → 在最近的可盈利线补挂平仓单;价格已出区间或浮亏超过 stopLossPct → 未覆盖部分直接市价平掉。
3. **层③ 恢复期孤儿扫描**:重启/重连对账后无法归档到任何线的残余仓位,跳过宽限期立即按层②处置;恢复完成前不开新仓。
4. **层④ 交易所侧兜底单**:在支持触发单的交易所(aster / binance / grvt / ondoperps),净多时挂 SELL STOP_MARKET @ 下界×(1stopLossPct),净空时挂 BUY STOP_MARKET @ 上界×(1+stopLossPct)。即使机器人进程死亡,交易所也会在极端行情中兜底平仓。方向变化、触发价偏移或订单消失时自动重挂,仓位归零时自动撤销。
## 智能跟随网格(移格)
开启 `GRID_SHIFT_ENABLED=true` 后,价格偏离锚定价超过 `GRID_SHIFT_TRIGGER_PCT` 且持续 `GRID_SHIFT_CONFIRM_MS`,策略执行三阶段移格:
1. **cancelling**:撤销全部挂单(含兜底止损单);
2. **closing**:市价平掉全部持仓(受滑点守卫保护);
3. **rebuilding**:以当前价为新锚定价,新区间 = 锚定价 × (1 ± `GRID_SHIFT_RANGE_PCT`),网格版本 +1,全部线重置后重新铺网。
每个阶段进度都持久化,进程在任一阶段崩溃后重启会从记录的阶段续跑。移格期间冻结开仓,层①②止损照常生效。移格会实现当前浮动盈亏——趋势行情中这意味着接受每次移格的亏损换取网格持续贴近现价,请结合波动性谨慎开启。
## 监控界面
Ink 仪表盘除价格与区间外,新增以下信息:
- **锚定价 / 网格版本**`v1` 起步,每次移格或重启重建 +1
- **移格状态**:移格进行中显示当前阶段(cancelling / closing / rebuilding);
- **止损防护行**:实时显示未覆盖仓位数量与交易所兜底止损单(方向 @ 触发价);
- **网格线表**:每条线的价格、方向(BUY / SELL / `-` 表示不开仓线)、状态(idle / entry_placed / holding / exit_placed)、是否有活跃挂单、线上持仓量。
## 常见问题
### Q: 为什么启动后不是一次性挂满所有网格单?
A: 引擎每轮最多新挂 1 笔限价单(按离现价由近到远),既控制请求频率也便于逐单登记意图。以默认 1 秒轮询计,20 条网格约 1 分钟内铺满。
### Q: 为什么同一价位出现两笔同向挂单?
A: 中性模式的正常形态:一笔是下方线的止盈平仓单,另一笔是该线自身的空头开仓单。价格穿越时两笔都成交,等于「平多 + 开空」。策略内部按意图分别登记,不会混淆。
### Q: 平仓单为什么不带 reduceOnly
A: 部分交易所会拒绝与反向挂单共存的 reduce-only 限价单。策略通过自身的意图登记区分开/平仓,不需要该标志。若你的交易所支持且希望强制,只需设 `GRID_USE_REDUCE_ONLY=true`。
### Q: 修改了参数重启后旧挂单怎么办?
A: 若改的是配置指纹字段(方向 / 网格数 / 单笔数量等),策略会全新建格并撤销所有无法归属的旧挂单;平仓方向的旧挂单会被保留为孤儿平仓单继续保护仓位。若只是重启未改参数,挂单和线状态原样恢复,不重复挂单。
### Q: 想要手动调仓怎么办?
A: 停止策略后手动操作,再启动即可——对账机制会以新的仓位/挂单为基准归档:手动加的仓归到最近的线,手动挂的平仓方向订单被收编,其余手动挂单被撤销。若想彻底重来,删除 `data/grid-record.json` 后重启。
### Q: 价格突破边界后发生了什么?
A: 依次发生:交易所侧兜底止损单先行触发(若启用且进程已死);进程存活时层①撤单并市价平仓后停机;若 `GRID_AUTO_RESTART_ENABLED=true`,价格回到边界内缓冲区后自动以当前价重新建格。开启移格时则优先整体平移网格而不是停机。
## 风险提示
- 网格策略在震荡行情中赚取格差,在单边行情中会累积逆势仓位。`GRID_MAX_POSITION_SIZE` 与 `GRID_STOP_LOSS_PCT` 是最重要的两道闸门,务必按可承受亏损设置。
- 移格功能会在每次移格时实现浮亏,等于把「区间失效」的损失分期支付,并不消除趋势风险。
- 请先用 `ritmex-bot strategy run --strategy grid --dry-run` 或小仓位验证参数与手续费结构,再逐步放大资金规模。
祝交易顺利!