# PMS 个股交易方案（策略）框架 · 设计 v1.1

> 2026-08-11。这份 governs 下单口的改动，是全系统风险最高的一段。v1.1 并入用户四点拍板。
> **已定方向**：v1 做 **做T + 网格 + 跟踪止盈**（同一自动机的三种配置）；新挂策略**默认自动执行**
> （`autonomy=auto`，仍可逐策略改成「待确认」）；**挂了策略的股票从动作引擎自动提议里排除**。
> 纪律：只做加法（不改既有执行/闸门/动作引擎逻辑）、与现有引擎清晰隔离、**开发期先 shadow 验代码再切实盘**。
>
> **四点拍板（2026-08-11）**：① 网格跌破下界 = **继续持有、不再买**（停买入腿、保留已买、回升仍按已买档卖、告警）；
> ② 做T 当日次数上限 = **3 次**；③ 新挂策略默认自主档 = **直接自动执行**；④ **跟踪止盈补进 v1**。

---

## 一、目标与判收

**最终检验**：用户能给某只持仓挂一套价格触发的交易方案（做T / 网格 / 跟踪止盈），系统在 **T+1 与仓位纪律**
约束内、按方案自动（或待确认）地做买卖；全程留痕、可暂停、可看实时状态、有熔断/上限/平回兜底。

**输出级判收（实机，shadow 先行）**：
1. 做T：一笔**完整平回** —— 当日买卖数量对齐，T 仓过夜为 0；当日达 3 次后不再做；
2. 网格：一档买入 + 一档卖出各走通并落账本；跌破下界后**不再买**、已买仓位保留；
3. 跟踪止盈：价格从高点回落到设定比例时**触发一笔卖出**并落账本；
4. 任何策略动作都**过规则闸** —— 违反单股上限 / T+1 可卖 / 暂停买入 时被拦下；
5. 挂了策略的票，**不再冒自动提议**；暂停某策略后它**不再出手**；全局暂停买入 / 休假 / 一键清仓对策略同样生效。

---

## 二、现状（以代码为准）

**做T = 搭了架子、没通电**：参数全（`PMS_T0_RATIO_MAX`、`PMS_T0_PULLBACK_PCT`、`PMS_T0_RALLY_PCT`、
`PMS_T0_ROUND_TARGET`、`PMS_T0_CLOSE_TIME`、单票/全局当日T亏熔断）、授权命令（`T0_ENABLE`）、
账本全（`t0_qty/t0_ratio/t0_count_today/realized_t_profit`、T0 批次、卖出先核销 T0、日初重置、成本含T利润）、
`planner` 有 `A_T0="T0_ROUND"`；**但 `executor.run_tick` 的动作集不含 T0，无正T/反T触发逻辑**。设计标「二期、默认关」。

**网格、跟踪止盈 = 无**（跟踪止盈与既有「保垫减仓」同源但那是动作引擎里按安全垫自动跑的，非逐股用户配置）。

**执行链（可整条复用）**：`run_tick` 每分钟一跳，遍历在途 `pms_instruction` → `exec_advisor` 择时 → 切片 →
（卖）按 `avail_qty` 封顶（**T+1 在此挡住**）→ `rule_gate.check` 合规终检 → `dispatcher.dispatch`（→ws→QMT）→
子单 + 评审账本。指令来源 = 命令方案 / 提议采纳 / 信号。

---

## 三、一条铁律定了整个框架：T+1

当日买入不可当日卖出 → 「今天低买高卖同一批股」做不到 → 做T / 网格 / 跟踪止盈本质都是「在一只**底仓**上、
用 T+1 可卖的存量股做买卖」→ **同一自动机的三种配置**。`run_tick` 已按 `avail_qty` 封顶卖出，T+1 天然被挡住。

---

## 四、框架：策略层 = 一个新的「指令来源」（只做加法）

新增 `strategy_runner`，挂在**现有每分钟调度位**（与 `run_tick` / `scan_proposals` 并列）。每跳：载入 `ACTIVE`
策略 → 取该股 `day_snapshot` + 持仓（`avail_qty`/成本）→ 按类型 `evaluate()` 出决策 → 过**策略层 rails** →
触发就：`autonomy=auto` 发一张**短窗口指令**（`window_tdays=1`、`is_command=True`、`origin_type="strategy"`），
交 `run_tick` 用现有管线执行；`autonomy=confirm` 落一条提议进「等我拍板」。再更新 `state_json`。

**复用全部闸门**（单股上限/一手/T+1/冻结/黑名单/暂停买入），一道不重写。**不碰动作引擎**，唯一加法是下一条 skip。

**动作引擎唯一触点**：`action_engine.scan` 跳过「有 ACTIVE 策略」的票 —— 避免两个大脑抢同一只。命令驱动（用户手动清/减该股）不受影响。

---

## 五、数据模型（新增一张表，走 ddl 文件、非例行事务内嵌 DDL）

`pms_strategy`：`strategy_id`(唯一) / `ts_code` / `type`(T0|GRID|TRAIL) / `status`(ACTIVE|PAUSED|DONE|CANCELLED) /
`autonomy`(auto|confirm，**默认 auto**) / `params_json` / `state_json` / `created_at`/`updated_at`/`note`。
- `state_json`：做T=`{t_count_today, open_leg, day_realized}`；网格=`{filled_levels[], below_floor}`；跟踪止盈=`{high_water, armed}`。
- `pms_instruction.origin_type` 增加取值 `"strategy"`（≤8 字符，列宽兼容；注释同步）。

---

## 六、做T 规格（把已有架子接通）

- **触发**：正T = 距当日高点回落 ≥ `PMS_T0_PULLBACK_PCT` 且近支撑 → 买 `t_qty`(=持仓×`t_ratio`，`≤ PMS_T0_RATIO_MAX`
  即 1/3)，按 `PMS_T0_ROUND_TARGET` 价差高卖；反T = 近压力或日内涨 ≥ `PMS_T0_RALLY_PCT` 滞涨 → 卖 `avail` 的 `t_qty`，低买回。
- **rails**：**当日 ≤ 3 次**（`t_count_today`）；**`PMS_T0_CLOSE_TIME`（14:50）强制平回**（当日买卖数量对齐、绝不过夜）；
  单票 `PMS_T0_STOCK_DAY_LOSS` / 全局 `PMS_T0_GLOBAL_DAY_LOSS` 当日T亏熔断后当日禁T；须有底仓且 `avail_qty` 足。

---

## 七、网格 规格（新）

- **配置**：中枢价（手动或取当前价）、档距（% 或元）、上界/下界、每档股数或金额、最大投入额（须落在单股上限内）。
- **规则**：现价跌破某未买档 → 买 1 份（过单股上限/资金闸）；现价涨破某已买档 → 卖 1 份（从 `avail`，T+1 挡）；越上界停做。
- **跌破下界（已定）**：**继续持有、不再买** —— 停掉买入腿，保留已买的档位，若价格回升到已买档之上仍按规则卖出；
  并在页面/账本告警「跌破下界，已停止网格买入」。不清仓、不继续往下接。
- **state**：`filled_levels` + `below_floor` 标记。不强制平回（多日底仓策略）；今天买的今天卖不了（管线挡）。
- **安全**：最大投入额 = 硬上限；单股上限闸兜底。

---

## 七·B、跟踪止盈 规格（新，v1 纳入）

- **用途**：锁住已有浮盈 —— 价格创新高就抬止盈线，从高点回落到设定比例就卖出离场。**只卖不买**（纯离场保护）。
- **配置**：启动线（浮盈 ≥ X% 才开始跟踪，默认取 `PMS_CUSHION_SOLID` 一线）、回撤比例 giveback（从高点回落 ≥ Y% 触发卖）、
  卖出比例（触发时卖 `avail` 的百分之多少，默认全清）、可选硬止盈目标（浮盈 ≥ Z% 直接全清）。
- **state**：`high_water`（启动后的最高价）、`armed`。
- **规则**：每跳更新 `high_water=max(high_water, 现价)`；浮盈达启动线则 `armed=true`；已武装且现价 ≤ `high_water×(1−giveback)`
  → 卖出（从 `avail`，T+1）。命中硬止盈目标直接全清。
- **与既有「保垫减仓」的关系**：挂了跟踪止盈的票已从动作引擎排除，不会和自动保垫减仓双触发；这是该股的用户版止盈。

---

## 八、补充策略（同一自动机，v1 之后、留接口）

`evaluate()` 加一个 `type` 分支即可：**分批建仓/定投**、**区间高抛低吸**（两档简化网格）、**突破加仓**。

---

## 九、隔离与安全（重点：动的是下单口）

1. **逐股显式挂载**（opt-in），绝不自动套用；
2. 挂策略的票**从动作引擎自动提议排除**；
3. 策略动作走**命令口径**（过规则闸、不过研判闸）；
4. **每策略自主档**：默认 `auto`（直接自动执行，你的拍板）；可逐策略改 `confirm` 进「等我拍板」观察；
5. **双保险**：rails 在策略层先拦（熔断/上限/平回/当日次数/下界），规则闸再拦一道（合规）；
6. **开发期先 shadow 后实盘**：`PMS_DISPATCH_MODE=shadow` 下先验证策略只发到影子出口、不碰真 QMT，判收通过再切 live
   —— 这是验**新代码**下单对不对，不是给你的策略设门槛；
7. 全局开关对策略同样生效：暂停买入 → 策略买入被闸拦；休假 → 策略不出手；一键清仓照常。

---

## 十、UI（交易员视图，只做加法）

- 「我的持仓」每行加**挂交易方案**：选类型（做T/网格/跟踪止盈）→ 填该类型参数（带当前价/持仓量参照，不盲填）→
  选自主档（默认自动，可改待确认）；
- 显示策略**实时状态**：做T「今日 2/3 次，日内 +¥320，平回 ✓」；网格「6 档已买 3，投入 ¥180k/上限 ¥240k」；
  跟踪止盈「高点 ¥18.6，回落 3.1%，未触发」；可**暂停/恢复/撤下**；
- 策略动作在「今日在办与动向」里与普通指令一起看，标来源 = 策略。

---

## 十一、分步落地（每步你实机验，shadow 先行）

1. 建表 `pms_strategy` + `strategy_runner` 骨架 + `origin_type=strategy` + 动作引擎 skip（先不含任何策略规则，空跑通）；
2. **做T** `evaluate` + rails(含 3 次/平回/熔断) → shadow 验「一笔完整平回」；
3. **网格** `evaluate` + rails(含下界=继续持有不再买) → shadow 验「一档买 + 一档卖」；
4. **跟踪止盈** `evaluate` + rails → shadow 验「回落触发一笔卖出」；
5. UI 挂载/状态/暂停；
6. 三种各切实盘观察 → 稳定。

---

## 十二、已定（本轮四点，无遗留待决）

① 网格跌破下界 = 继续持有、不再买；② 做T 当日 ≤ 3 次；③ 新挂策略默认自主档 = 自动执行；④ 跟踪止盈纳入 v1。
开工顺序按第十一节；每步 shadow 先行、单测你实机跑。
