Files
quantdingerdocs/SIGNAL_EXECUTION_STANDARD_CN.md
2026-07-11 20:14:35 +00:00

261 lines
11 KiB
Markdown
Raw Permalink 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.
# QuantDinger 信号与执行标准(SSOT
**版本**1.0
**状态**:现行
**适用范围**:所有基于 `IndicatorStrategy`(指标 Python + 保存为策略)的回测与实盘
**关联实现**`BacktestService``TradingExecutor``validate_code_safety` / `verifyCode`
**开发指南**[STRATEGY_DEV_GUIDE_CN.md](./STRATEGY_DEV_GUIDE_CN.md)(教程与示例)
---
## 1. 目的
平台会同时运行**多种不同逻辑**的策略。若没有统一标准,会出现:
- 同一套 `buy`/`sell` 在不同策略里含义不同;
- 回测按「收盘 + 下一根开盘」成交,实盘按「未收盘 K + 立即平仓」执行;
- 指标内止盈止损与 `# @strategy trailingEnabled` 叠加,导致重复平仓与拒单。
本标准定义:**策略作者写什么、引擎如何解释、回测与实盘必须如何对齐**。
所有新策略 **SHOULD** 遵循;存量策略 **SHOULD** 按第 9 节迁移。
---
## 2. 术语
| 术语 | 含义 |
|------|------|
| **信号 K 线** | 产生布尔信号的那根 K 线(时间戳 = 该 bar 收盘时刻) |
| **成交 K 线** | 订单实际执行所锚定的 K 线(默认 = 信号 K 的下一根) |
| **边缘触发** | 仅在与上一根 K 相比由 false→true 时记为信号 |
| **重绘** | 未收盘 K 上条件随行情变化而反复成立/消失 |
| **退出负责人** | 唯一主导平仓逻辑的层:指标信号 **或** 引擎风控,不可并列窄规则 |
---
## 3. 策略形态选型(必须先选)
| 形态 | 适用 | 不适用 |
|------|------|--------|
| **A. 简单两路** `buy` / `sell` | 金叉/死叉、单方向或对称反转;无独立「仅平仓」语义 | 多空分离 tp/sl、状态机、同 bar 先平后开需写清 |
| **B. 专业四路** `open_long` / `close_long` / `open_short` / `close_short` | 状态机、触及止盈止损、多空分离、与回测队列一一对应 | 极简趋势(可用 A,但 B 更利于长期维护) |
| **C. ScriptStrategy** `on_bar` + `ctx` | 强依赖持仓、分批、冷却、bot 网格 | 纯历史序列可表达的指标信号 |
**平台推荐默认值**:新上架、多空或带指标内退出的策略 → **形态 B(四路)**
---
## 4. 信号输出标准(IndicatorStrategy
### 4.1 通用 MUST
1. **MUST** `df = df.copy()` 作为首行可变操作。
2. **MUST** 提供 `output` 字典(含 `name``plots``signals` 可选用于图表标记)。
3. **MUST** 执行列与 `len(df)` 一致、类型为 `bool``fillna(False).astype(bool)`)。
4. **MUST** 对执行列做**边缘触发**(见 4.3),除非策略说明中明确声明「连续持仓信号」并经产品审核。
5. **MUST NOT** 使用 `shift(-1)` 及任何未来数据引用。
6. **MUST NOT** 在单脚本内混用「形态 A 执行列」与「形态 B 执行列」作为成交依据(可同时保留 `buy`/`sell` 全 false 仅作兼容)。
### 4.2 形态 A:两路 `buy` / `sell`
| `tradeDirection` | `buy=True` 含义 | `sell=True` 含义 |
|------------------|-----------------|------------------|
| `long` | 开多 | 平多 |
| `short` | 平空 | 开空 |
| `both` | 开多;若持空则**先平空再开多** | 开空;若持多则**先平多再开空** |
**MUST NOT**`both` 下把 `buy` 理解为「仅平空」或「仅平多」。
若需**只平仓不反手**,**MUST** 使用形态 B 的 `close_*`
### 4.3 形态 B:四路(推荐标准)
| 列 | 含义 |
|----|------|
| `open_long` | 开多(或加多,若引擎配置允许) |
| `close_long` | 平多(全部或按 reduce 配置) |
| `open_short` | 开空 |
| `close_short` | 平空 |
**MUST** 满足:
- 四列均存在且为 bool。
- **SHOULD** 同 bar 优先级:`close_*` 先于 `open_*`(脚本内互斥或交给引擎「先平后开」)。
- **SHOULD NOT** 同 bar 同时 `open_long``open_short` 为 true(反手请用 `close_*` + 对侧 `open_*`,或分两根 K)。
- 使用四路时,引擎按**显式信号**处理(非 buy/sell 的 both 隐式映射)。
边缘触发模板:
```python
def edge(s: pd.Series) -> pd.Series:
s = s.fillna(False).astype(bool)
return s & ~s.shift(1).fillna(False)
df['open_long'] = edge(raw_open_long)
df['close_long'] = edge(raw_close_long)
df['open_short'] = edge(raw_open_short)
df['close_short'] = edge(raw_close_short)
```
`output['signals']` 仅用于展示;**成交只认上述执行列**。
### 4.4 `tradeDirection` 与四路的关系
| `tradeDirection` | 行为 |
|----------------|------|
| `long` | 忽略 `open_short` / `close_short`(或校验警告) |
| `short` | 忽略 `open_long` / `close_long` |
| `both` | 四路均有效;**不**再对 `buy`/`sell` 做反手映射 |
---
## 5. 退出与风控标准(解决重复平仓)
每个策略 **MUST** 在说明或注释中声明「退出负责人」之一:
| 模式 | 脚本 | `# @strategy` | 说明 |
|------|------|---------------|------|
| **指标退出** `exit_owner: indicator` | 输出 `close_*`,或两路中明确等价的退出语义 | `trailingEnabled false`;不要依赖 `stopLossPct` / `takeProfitPct` / trailing | 触及型、中轨/轨道 tp/sl;当前实现会关闭服务端价格退出 |
| **引擎退出** `exit_owner: engine` | 只输出入场,或只输出趋势反转用的结构性 `close_*` | `trailingEnabled` / `stopLossPct` / `takeProfitPct` 按需 | 固定止损止盈、追踪止损、简单趋势 |
**MUST NOT**:指标内窄 tp/sl **且** `trailingEnabled true` 窄移动止损(易造成 `server_trailing_stop` 后再发 `close_*` → 数量为 0)。
启用 trailing 时:**SHOULD** 关闭指标内同方向的 tp/sl 布尔列,或关闭 trailing。
当前后端只支持 `exit_owner: indicator``exit_owner: engine`。不要生成或上架 `exit_owner: layered`;若确实需要“指标退出 + 引擎兜底”的混合方案,必须先产品评审并明确改造执行器语义。
---
## 6. 执行契约(回测与实盘对齐)
以下配置在「保存后的策略」`trading_config` 中生效;**回测与实盘 MUST 使用同一套规范化结果**。
### 6.1 信号时刻(抗重绘)
| 项 | 标准值 | 说明 |
|----|--------|------|
| `signal_mode` | **`confirmed`** | 入场信号仅来自**上一根已收盘** K |
| `exit_signal_mode` | **`confirmed`** | 出场信号同上;与回测一致 |
| 形成中 K | **不参与下单** | 实盘可刷新最后一根 K 做展示,但不应作为默认成交依据 |
**MAY** 在产品层提供 `aggressive` 供研究;上线组合策略 **SHOULD NOT** 默认 aggressive。
### 6.2 成交时刻
| 项 | 标准值 |
|----|--------|
| 回测 `signalTiming` / 策略快照 | **`next_bar_open`**(默认) |
| 语义 | 信号 K 收盘确认 → **下一根 K 开盘价**(±滑点)成交 |
**SHOULD NOT** 在未改回测配置的情况下,实盘使用 `exit_trigger_mode=immediate` 做指标策略。
### 6.3 同 bar 多信号
| 规则 | 说明 |
|------|------|
| 优先级 | `close_*` > `reduce_*` > `open_*` > `add_*` |
| 反手 | **方案 R1(推荐)**:同 bar 只平不開,**下一根**再 `open_*`**方案 R2**:同 bar 先平后开(与历史 both 回测一致,需策略与回测均启用) |
| 每 tick | 指标模式默认每 tick 最多执行 **1** 个外部信号;反手若用 R2,引擎可在单次 `open_*` 内先平对侧 |
策略说明 **MUST** 注明采用 R1 或 R2。
### 6.4 平仓数量
| 规则 | 说明 |
|------|------|
| 数量来源 | 平仓 **MUST** 以本地持仓与交易所持仓较大者为准(sync + resolve |
| 数量为 0 | **MUST** 再 sync 一次后重试;仍为空则拒单并记日志,**MUST NOT** 静默跳过 |
---
## 7. 配置标准(`# @strategy` / `# @param`
### 7.1 `# @strategy`SHOULD 显式声明)
| Key | 类型 | 说明 |
|-----|------|------|
| `tradeDirection` | `long` \| `short` \| `both` | 与执行列一致 |
| `entryPct` | 0.011.0 | 开仓资金占比(`1` = 100% |
| `stopLossPct` / `takeProfitPct` | 0–1 | **标的涨跌幅**阈值;亚 1% 写 `0.001` 等小数 |
| `trailingEnabled` | bool | 见第 5 节 |
| `trailingStopPct` / `trailingActivationPct` | 0–1 | 追踪回撤/激活阈值(同为价格涨跌幅,**不除杠杆**) |
**MUST NOT**`@strategy` 中写 `leverage`(由产品 UI / 策略配置)。
### 7.2 推荐策略头注释块(复制模板)
```python
# --- QuantDinger execution contract (v1) ---
# signal_form: four_way # two_way | four_way
# exit_owner: indicator # indicator | engine
# flip_mode: R1 # R1=close bar then open next bar | R2=same bar flip
# tradeDirection: both
# @strategy entryPct 1
# @strategy trailingEnabled false
```
---
## 8. 校验与发布清单
### 8.1 保存 / `verifyCode` 时(引擎 SHOULD
- [ ] 执行列存在且长度正确
- [ ] 禁止不安全代码(见 `safe_exec`
- [ ] 警告:`trailingEnabled` + 高比例 `close_*`
- [ ] 警告:同 bar `open_long` & `open_short`
- [ ] 警告:连续多根同向 `open_*` 无 edge(可选启发式)
### 8.2 上线前人工清单
- [ ] 已选形态 A/B/C 并写在策略说明
- [ ] 已声明退出负责人
- [ ] `signal_mode` / `exit_signal_mode` = `confirmed`
- [ ] 回测成交时间为 next bar open,与预期一致
- [ ] 对比最近 20 笔:回测信号时间 vs 实盘日志时间偏差可解释
- [ ] 小仓位、单标的试跑 24h,无大量 `invalid amount (0.0)`
---
## 9. 存量策略迁移
| 优先级 | 特征 | 动作 |
|--------|------|------|
| P0 | `both` + `buy` 含 tp/sl + `trailingEnabled` | 关 trailing 或改四路 `close_*` |
| P1 | 触及型逻辑 + 实盘差异大 | 改 `confirmed` + 四路 + edge |
| P2 | 纯金叉死叉两路 | 可保留形态 A,补全契约注释 |
| P3 | 已是四路 | 补 edge、退出负责人、配置对齐 |
**MAY** 在策略市场标注「契约 v1 已认证」徽章,便于用户筛选。
---
## 10. 策略分级(运营可选)
| 等级 | 要求 |
|------|------|
| **L1 基础** | 通过 `verifyCode` + 沙箱 |
| **L2 对齐** | 四路或声明两路 + `confirmed` + 退出负责人明确 |
| **L3 生产** | L2 + 回测/实盘时间偏差评审 + 7 日模拟盘无异常拒单 |
---
## 11. 与实现的对照(便于研发)
| 标准条 | 代码锚点 |
|--------|----------|
| 形态 B 四路 | `TradingExecutor._execute_indicator_with_prices``BacktestService` norm_signals |
| both 两路映射 | 仅当无四路且 `buy`/`sell` 时;`_indicator_both_mode` |
| confirmed | `signal_mode` / `exit_signal_mode` 检查集 |
| 平仓重试 | `PendingOrderWorker` + `resolve_reduce_only_quantity` |
| 静态安全 | `app/utils/safe_exec.py` |
标准变更时 **MUST** 同步更新本文件版本号与 CHANGELOG。
---
## 12. 修订记录
| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2026-05 | 首版:四路推荐、执行契约、退出负责人、迁移与分级 |