Files
big-qmt/docs/zt.md
2026-09-15 20:02:05 +08:00

137 lines
6.8 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.
# ZT 日内做 T 策略
正T先买后卖与反T先卖后买共用一套**轮次**状态机。持仓数量、可卖数量、
成本一律以券商快照为准;本地只记录"打算做什么、做到哪一步",不重算持仓。
## 启用
在账户 YAML 中设置:
```yaml
strategy: zt
signal_allow: ["dcm"] # zt 只接受 dcm
zt_open_hands: 1 # 建仓与正T买入的手数0 表示不启动策略
zt_sell_ratio: 0.5 # 反T卖出建仓数量的比例
zt_buy_fall_pct: 1.0 # 反T买回较卖出均价回落的百分比
zt_max_price: 200 # 高于此价不新开轮次
zt_t_band_pct: 1.0 # 中性带:建仓价 ±N% 内不动手
zt_max_hold_days: 5 # 单轮最长持有自然日,超期放弃
```
## 只管自己建的仓
**本策略不接管账户已有持仓。** 只有建仓腿由本策略成交、在轮次表里留下
`base_source=opened` 基准的证券才会被管理:
- 账户里其它持仓原样保留,既不写基准、也不做 T日志里以
`[ZT跳过] 未接管持仓 N 只…``[ZT汇总] … 未接管=N …` 体现;
- 建仓只能由 `dcm` 信号触发(`signal_allow`),建仓成交均价即建仓价;
- 升级时如果状态文件里还留着旧版本的"接管"记录,启动会丢弃它们
(已结束的轮次删掉,未平轮次保留到敞口处理完),保证这条规则成立。
## 两种 T 与 T+1 约束
| | 正T`LONG_T` | 反T`SHORT_T` |
| --- | --- | --- |
| 开仓腿 | 买入(低吸) | 卖出(高抛) |
| 平仓腿 | 卖出(高抛) | 买入(低吸) |
| 触发位置 | 现价 ≤ 建仓价×(1`zt_t_band_pct`%) | 现价 ≥ 建仓价×(1+`zt_t_band_pct`%) |
| 买入腿约束 | 可用资金 | — |
| 卖出腿约束 | **底仓可卖数量**`can_use_volume` | 底仓可卖数量 |
A股 T+1 决定了正T 能否当天闭环当天买入的份额当天不可卖所以正T 的平仓腿
只能卖底仓原有可用量。卖不动就自然留成隔夜持仓,次日再卖——这正是"允许隔夜"
存在的原因。
## 触发条件
- **正T 开仓**:现价低于中性带下沿,且 `DipWatch` 反弹确认(不接下跌中的飞刀)。
- **反T 开仓**:现价高于中性带上沿,且盈利网格出现回撤(`GridTrailingTracker`
`RETREAT`),不追最高点。
- **反T 平仓**:现价 ≤ 卖出均价×(1`zt_buy_fall_pct`%),且反弹确认。
- **正T 平仓**:现价 ≥ 买入均价×(1+`grid_step_pct`%)。
- 平仓腿不受中性带限制正T 开仓受大盘与资金闸门反T 开仓(减仓)不受资金限制。
## 数量
| 腿 | 计划量 | 上限 |
| --- | --- | --- |
| 建仓 / 正T 买入 | `zt_open_hands × 100` | 本轮剩余可用资金,向下取整手 |
| 正T 卖出 | 买入已成交量 | 底仓可卖量,向下取整手 |
| 反T 卖出 | `floor(建仓数量 × zt_sell_ratio / 100) × 100` | 底仓可卖量 |
| 反T 买回 | 卖出已成交量 | 本轮剩余可用资金 |
同一轮 tick 内串行处理所有证券,共享一份剩余资金,不会重复花同一笔钱。
资金买不起一手时返回 0不会强迫成交。
## 轮次与每日限额
状态机:`IDLE → OPENING开仓腿在途→ OPEN待平仓→ CLOSING平仓腿在途→ CLOSED`
- 一只证券任意时刻最多一个未平轮次。
- **每天最多一轮**:当天开过、或有任一条腿成交过,都不再开新轮。
- 允许隔夜:`OPEN` / `CLOSING` 可以跨日持有,不做尾盘强平。
- 超过 `zt_max_hold_days` 自然日仍未平仓 → 告警并把未平敞口**并回底仓数量**
`base_cost` 仍是建仓价),避免在裸敞口上继续开新轮。
## 建底仓与基准成本
- 底仓只能由 `dcm` 信号触发建仓,成交均价写入 `base_cost`
`base_source=opened`);账户已有持仓不会被接管,因此基准只有这一个来源。
- `base_cost` 不随做 T 买卖摊薄;超期放弃时未平敞口并回 `base_qty`
`base_cost` 保持不变。
## 日志
所有日志都带方括号标签,直接 grep 即可定位:
| 标签 | 内容 |
| --- | --- |
| `[ZT启动]` | 启动参数、状态文件路径、未平轮次明细、信号列表 |
| `[ZT成交]` | 逐笔成交入账(腿、数量、价格、编号、累计量、均价);被忽略的非本策略成交 |
| `[ZT状态]` | 轮次阶段流转 |
| `[ZT轮次]` | 一轮结束:结局、买卖均价、价差收益、基准、持有天数、备注 |
| `[ZT决策]` | **每只受管证券每轮一行**:现价、基准、偏离%、类型、阶段、敞口、可卖、持仓成本、最终动作或等待原因 |
| `[ZT下单]` | 实际提交的委托(数量、价格、目标价、订单号) |
| `[ZT跳过]` | 未接管的账户持仓、排除证券、行情无效 |
| `[ZT汇总]` | 本轮账户概览:持仓/管理/新委托数、总资产、可用、大盘与资金闸门、耗时 |
| `[ZT异常]` | 被捕获并降级的错误(含堆栈) |
排查常见问题:
```bash
grep '\[ZT决策\] 600000.SH' 20260915.log # 某只证券每轮为什么没动手
grep '\[ZT下单\]' 20260915.log # 今天实际报出去的委托
grep '\[ZT轮次\]' 20260915.log # 每轮的结果与价差收益
grep '\[ZT跳过\]' 20260915.log | tail -1 # 哪些账户持仓没被接管
grep '\[ZT异常\]' 20260915.log # 被降级的错误
```
## 状态文件
`{qmt_data_dir}/zt_{account_id}_rounds.json`,一只证券一条记录,整文件原子替换。
关键字段:`kind``phase``open_date``base_qty`/`base_cost`/`base_source`
两条腿各自的 `order_id`/`plan_qty`/`filled_qty`/`amount``seen_deal_ids`
`last_trade_date`
- 成交按 `order_sys_id` 幂等累计:重复同步不会重复计入,跨日重启靠
`seen_deal_ids` 记住已成交多少。
- 订单号统一 `zt-` 前缀(`zt-base-` / `zt-entry-` / `zt-exit-`。手工单、IPO 单
和其他策略单不带该前缀,一律不进入本策略轮次。
- 文件损坏时备份为 `.corrupt` 并由券商持仓重建,不阻断启动。
## 委托与容错
- 撤单只限 `zt-` 前缀,超时 300 秒;撤单不会丢轮次状态——余量会让轮次回到
`OPEN`,下一轮按新价重新判断。
- 防重以券商在途委托为唯一依据(同证券同方向有在途委托就不下单)。
- **先落盘意图再发请求**:请求未受理且无成交的轮次会被判为作废,已受理的委托
仍在途、成交照常累计,两种崩溃点都能自愈。
- 单证券异常只跳过该证券;账户快照、轮次推进、行情任一失败只跳过本轮,下轮重试。
## 迁移
旧账本 `zt_{account_id}_state.db``libs/state.py` 已删除,不再读写;旧库保留为
审计记录。不接管账户已有持仓:升级后只有本策略新建立的底仓会进入轮次,
老持仓保持不动。