# 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.01–1.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 | 首版:四路推荐、执行契约、退出负责人、迁移与分级 |