# 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` 已删除,不再读写;旧库保留为 审计记录。不接管账户已有持仓:升级后只有本策略新建立的底仓会进入轮次, 老持仓保持不动。