上传文件至「/」

This commit is contained in:
2026-07-11 20:14:35 +00:00
parent 0c28e0ad97
commit 2258bd8973
5 changed files with 4540 additions and 0 deletions
+260
View File
@@ -0,0 +1,260 @@
# 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 | 首版:四路推荐、执行契约、退出负责人、迁移与分级 |
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,696 @@
# ScriptStrategy 复杂策略运行时改造实施方案
## 1. 目标
让脚本策略从“按 K 线生成买卖信号”升级为“可承载复杂状态机和算法执行”的运行时,优先支持以下用户场景:
- 多层分仓,例如 5 个大分仓,每层 3 个子单。
- 层内/层间价格间距可调。
- 每个子单按马丁倍数或自定义序列放大。
- 按实际成交均价止盈,而不是按脚本计划价止盈。
- 只做多、只做空、多空双向 basket 独立运行。
- 合约场景支持按杠杆后的名义价值换算下单量。
- 后端重启、网络失败、部分成交、拒单后不重复补仓。
核心判断:现在的脚本 API 已经有基础,真正要补的是可信状态源、订单生命周期、恢复和风控。先把运行时地基打牢,再开放更复杂模板。
## 2. 当前代码基础
现有链路已经可复用:
- `app/services/strategy_script_runtime.py`
- `StrategyScriptContext` 已支持 `open_long/add_long/open_short/add_short/close_long/close_short`
- `ScriptPosition` 已有 long/short 独立腿,并保留旧版 net position 兼容视图。
- `app/services/trading_executor.py`
- 脚本产生 `ctx._orders` 后转成执行信号。
- `_enqueue_pending_order()` 写入 `pending_orders`
- `_hydrate_script_ctx_from_positions()` 会从 `qd_strategy_positions` 恢复持仓视图。
- `app/services/pending_order_worker.py`
- `PendingOrderWorker` 拉取 `pending_orders`,执行 live/signal 模式派单。
- 已有 live order context、client order id、成交回填等基础。
- `app/services/pending_orders/fill_records.py`
- `persist_strategy_fill()` 按成交更新 `qd_strategy_trades``qd_strategy_positions`
- `app/services/live_trading/records.py`
- `apply_fill_to_local_position()` 已经按成交更新均价和部分减仓。
- `migrations/init.sql`
- 已有 `pending_orders``qd_strategy_positions``qd_strategy_trades``qd_grid_resting_orders` 等基础表。
现有不足:
- `pending_orders` 更像队列表,不是完整 order intent ledger。
- `script_runtime_state` 存在 `trading_config` JSON 里,适合轻量参数,不适合作为复杂策略状态可信源。
- 缺少 `strategy_run_id`、代码快照、参数快照和运行 epoch。
- 缺少 basket / child order / fill / recovery event 的标准模型。
- 多空 position API 已具备雏形,但 basket 层还没独立。
- 订单幂等当前主要靠 `(strategy_id, symbol, signal_type, signal_ts)`,不够表达层级分仓的 `layer/order/action`
- 回测还没有完全复用 live 的 order intent、fill、fee、slippage 语义。
## 3. 总体架构
建议增加一层“策略运行时内核”,位于脚本和下单队列之间:
```text
ScriptStrategy
-> StrategyRuntimeContext
-> BasketRuntime / RuntimeStateStore
-> OrderIntentService
-> ExecutionScheduler
-> PendingOrderWorker / LiveTradingClient
-> FillLedger / PositionLedger
-> RecoveryService / RiskGuard
```
原则:
- 脚本只表达意图和状态机,不直接操作数据库和交易所。
- 数据库是恢复可信源,内存只做当前循环缓存。
- 所有真实下单先落 `order_intent`,再提交交易所。
- basket 均价、层级、TP、风险状态由实际 fill 驱动。
- live、paper、backtest 尽量复用同一套 order intent 和 fill 语义。
## 4. 数据库改造
新增表建议:
```sql
strategy_runs
strategy_runtime_state
strategy_baskets
strategy_basket_orders
strategy_order_intents
strategy_order_fills
strategy_runtime_events
strategy_runtime_locks
```
### 4.1 strategy_runs
记录每一次启动,不再只靠 `strategy_id` 表示运行实例。
关键字段:
- `id`
- `strategy_id`
- `user_id`
- `source_version_id`
- `code_hash`
- `parameter_snapshot_json`
- `exchange_id`
- `credential_id`
- `symbol`
- `market_type`
- `position_mode`
- `runtime_status`: `running/recovering/paused/needs_review/stopping/stopped/failed`
- `runtime_epoch`
- `started_at`
- `stopped_at`
- `stop_reason`
### 4.2 strategy_runtime_state
替代把复杂状态塞进 `trading_config.script_runtime_state`
关键字段:
- `strategy_run_id`
- `strategy_id`
- `state_key`
- `state_json`
- `version`
- `updated_at`
用途:
- 保存轻量脚本状态:冷却计数、上次触发价、用户自定义变量。
- 由运行时托管 `ctx.state.get/set/flush()`
- 不保存成交和订单真相。
### 4.3 strategy_baskets
复杂分仓策略的核心状态。
关键字段:
- `basket_id`
- `strategy_run_id`
- `strategy_id`
- `symbol`
- `side`: `long/short`
- `status`: `idle/opening/active/closing/closed/failed/needs_review`
- `current_layer`
- `current_order_in_layer`
- `total_qty`
- `total_notional`
- `avg_entry_price`
- `next_entry_trigger`
- `take_profit_price`
- `max_layer`
- `max_orders_per_layer`
- `risk_state_json`
- `created_at`
- `updated_at`
### 4.4 strategy_basket_orders
记录每个子单在 basket 内的归属。
关键字段:
- `basket_order_id`
- `basket_id`
- `side`
- `layer_index`
- `order_index`
- `action`: `open/add/reduce/close`
- `planned_price`
- `planned_qty`
- `planned_notional`
- `status`: `planned/intent_created/submitted/accepted/partially_filled/filled/rejected/cancelled/expired/unknown`
- `order_intent_id`
- `exchange_order_id`
- `client_order_id`
- `filled_qty`
- `avg_fill_price`
- `fee`
- `error`
唯一约束:
```text
strategy_run_id + basket_id + side + layer_index + order_index + action
```
### 4.5 strategy_order_intents
统一订单意图。后续 TWAP、BestLimit、Iceberg 都从这里开始。
关键字段:
- `order_intent_id`
- `strategy_run_id`
- `strategy_id`
- `basket_id`
- `basket_order_id`
- `idempotency_key`
- `symbol`
- `market_type`
- `side`
- `position_side`
- `reduce_only`
- `order_type`
- `quantity`
- `notional`
- `limit_price`
- `execution_algo`: `market/limit/best_limit/twap/stop/iceberg`
- `status`
- `client_order_id`
- `exchange_order_id`
- `payload_json`
- `created_at`
- `updated_at`
### 4.6 strategy_order_fills
成交流水是均价、TP 和审计的真实来源。
关键字段:
- `fill_id`
- `order_intent_id`
- `basket_id`
- `exchange_order_id`
- `exchange_fill_id`
- `side`
- `position_side`
- `price`
- `quantity`
- `notional`
- `fee`
- `fee_ccy`
- `filled_at`
- `raw_json`
唯一约束:
```text
exchange_id + exchange_fill_id
```
没有交易所 fill id 的场景,用 `order_intent_id + price + quantity + filled_at` 做近似去重。
## 5. 运行时 API 改造
保留现有 `ctx.open_long()` 等 API,同时新增更适合复杂策略的托管接口。
### 5.1 ctx.state
```python
ctx.state.get("cooldown_bars", 0)
ctx.state.set("cooldown_bars", 3)
ctx.state.flush()
```
用途:
- 轻量脚本变量。
- 自动绑定 `strategy_run_id`
- 后端定期或关键动作前 checkpoint。
### 5.2 ctx.basket
```python
long_basket = ctx.basket("long")
if long_basket.is_idle():
long_basket.open_child_order(layer=1, order=1, notional=100)
if long_basket.should_add(current_price):
long_basket.open_child_order(layer=2, order=1, notional=200)
if long_basket.should_take_profit(current_price):
long_basket.close_all(reason="avg_take_profit")
```
运行时负责:
- 检查幂等键。
- 创建 `strategy_basket_orders`
- 创建 `strategy_order_intents`
- 将 intent 推进到 `pending_orders` 或算法调度器。
- 成交后刷新 basket 均价、TP、层级和风险状态。
### 5.3 ctx.long_position / ctx.short_position
`ctx.position` 保持兼容,新增更明确接口:
```python
ctx.long_position.size
ctx.long_position.avg_entry
ctx.short_position.size
ctx.short_position.avg_entry
```
多空双开时,脚本不能再依赖单一 net position 判断。
## 6. LayeredMartingaleBasket 官方模板
先内置一个官方模板,不先开放用户自由组合所有底层能力。
参数:
```text
symbol
direction: long | short | both
base_order_value
leverage
layers = 5
orders_per_layer = 3
martingale_multiplier = 2.0
intra_spacing_pct
inter_spacing_pct
take_profit_pct
max_total_notional
max_margin_pct
hard_stop_pct
cooldown_bars
restart_after_take_profit
```
运行逻辑:
```text
idle:
创建第 1 层第 1 子单
active:
如果价格逆向达到层内/层间触发价,创建下一个子单
如果实际成交均价达到 TPclose basket
如果达到最大层数,只等 TP 或风险退出
如果触发 hard stop / margin risk,停止补仓并按配置减仓或平仓
```
第一版限制:
- `direction=long``direction=short` 先稳定上线。
- `direction=both` 内部拆成 `long basket``short basket`,要求交易所能力矩阵确认 hedge mode。
- 不支持无限马丁,必须配置最大名义价值或最大保证金占用。
## 7. 订单生命周期改造
统一状态:
```text
intent_created
submitted
accepted
partially_filled
filled
rejected
cancelled
expired
unknown
reconciled
```
现有 `pending_orders.status` 可以继续承载队列阶段,但不要作为专业订单状态的唯一来源。
推荐落地方式:
1. `OrderIntentService.create_intent()` 先写 `strategy_order_intents`
2. 根据 `execution_algo`
- `market/limit`:直接桥接到 `pending_orders`
- `twap/best_limit`:交给 `ExecutionScheduler` 拆 child order。
3. `PendingOrderWorker` 执行后回写 intent 状态和 fill。
4. `persist_strategy_fill()` 同步升级:除写 `qd_strategy_trades/positions` 外,也写 `strategy_order_fills` 并刷新 basket。
## 8. 幂等和单写入者
幂等键格式:
```text
strategy_run_id:basket_id:side:L{layer_index}:O{order_index}:{action}
```
策略运行锁:
```text
strategy_id + account_id/credential_id + symbol + side
```
机制:
- 启动策略时创建 `strategy_runs`,拿到 `runtime_epoch`
- 每个运行线程写状态和订单时必须带 `runtime_epoch`
- 新线程抢锁成功后,旧线程即使还活着,也因为 epoch 不匹配不能继续写库。
- 单机可先用数据库行锁;多实例部署再接 Redis lock + DB fencing token。
## 9. 重启恢复流程
启动或进程崩溃后恢复时:
1. 将 run 标记为 `recovering`
2. 读取 `strategy_runs``strategy_runtime_state``strategy_baskets`、未完成 `strategy_order_intents`
3. 拉取交易所当前持仓、未成交订单、近期成交。
4. 用交易所事实修正本地:
- open order 状态。
- filled quantity。
- avg fill price。
- basket avg entry。
- pending TP/close 状态。
5. 对没有 `exchange_order_id` 的 intent 做幂等判断:
- 确认未提交才允许重试。
- 状态未知则进入 `needs_review`
6. 重建 `ctx.state``ctx.basket``ctx.long_position/short_position`
7.`recovery_completed` 事件。
8. 切回 `running`
恢复优先级:
```text
交易所事实 > strategy_order_fills/order_intents > basket checkpoint > 内存状态
```
## 10. 风控改造
新增 `StrategyRuntimeRiskGuard`,在创建 intent 前检查:
- 最大层数。
- 最大子单数。
- 最大名义价值。
- 最大保证金占用。
- 最大账户权益占比。
- 最大浮亏。
- 距离强平价格最小安全距离。
- 单策略最大错误次数。
- 单交易所/全局 kill switch。
触发后写事件:
```text
risk_guard_triggered
```
并进入以下之一:
- `paused`: 暂停新增开仓。
- `needs_review`: 状态不确定,需要人工确认。
- `stopping`: 自动减仓或平仓中。
- `failed`: 无法安全处理。
## 11. 算法交易第一版
新增目录:
```text
app/services/algo_trading/
order_intent.py
scheduler.py
child_order.py
execution_algorithms/
twap.py
best_limit.py
stop.py
order_state.py
reconciliation.py
risk.py
```
P0 支持:
- `MarketIntent`: 现有 market order 的标准化入口。
- `LimitIntent`: 限价单标准化入口。
- `BestLimit`: 使用 best bid/ask 挂单,超时撤单重挂。
- `TWAP`: 按时间切片拆成多个 child order。
- `Stop/StopLimit`: 交易所支持则原生,不支持则本地触发。
P1 再做:
- Iceberg。
- Sniper。
- 更细的 order book 驱动。
## 12. 交易所能力矩阵
现有 `app/services/live_trading/capabilities.py` 只有市场类型能力,需要扩展为:
```text
supports_hedge_mode
supports_reduce_only
supports_post_only
supports_stop_order
supports_iceberg
supports_client_order_id
supports_order_query_by_client_id
supports_fills_query
min_notional
min_quantity
price_tick
quantity_step
rate_limit
```
策略启动前做 preflight
- 交易所是否支持该 market type。
- 是否支持 hedge mode。
- API key 是否有交易、订单查询、成交查询权限。
- 合约杠杆和保证金模式是否可配置。
- symbol 精度和最小下单量是否满足模板参数。
失败时不启动策略,给用户明确错误。
## 13. 回测一致性
复杂策略不能只靠布尔信号回测。建议新增运行时回测模式:
```text
ScriptStrategy -> RuntimeContext(backtest) -> OrderIntentService(backtest) -> SimulatedFillEngine -> BasketRuntime
```
模拟能力:
- 最小下单量。
- 数量步进。
- 价格 tick。
- 手续费。
- 滑点。
- 部分成交。
- 下根 K 成交 / 当前 tick 成交差异。
- 子单级成交记录。
验收目标:
- 同一份 `LayeredMartingaleBasket` 模板在 backtest/paper/live 中的子单路径一致。
- 回测报告能展示每层、每个子单、均价、TP、费用和滑点。
## 14. 前端需要配合的能力
第一版 UI 不要让用户直接编辑底层 runtime 表,而是提供模板化表单:
- 方向:只做多 / 只做空 / 多空双向。
- 分仓层数。
- 每层子单数。
- 层内间距。
- 层间间距。
- 马丁倍数或自定义序列。
- 基础下单金额。
- 杠杆。
- 均价止盈。
- 最大名义价值。
- 最大保证金占用。
- 硬止损。
- 启动前预估最大风险。
策略详情页增加:
- 当前 run id。
- 当前 basket 状态。
- 子单列表。
- 未完成订单。
- 最近成交。
- 恢复事件。
- 风控状态。
- `needs_review` 人工处理面板。
## 15. 分期落地
### Phase 0:补齐可追踪运行身份
目标:先让每次运行可追溯。
任务:
- 新增 `strategy_runs`
- 启动策略时生成 `strategy_run_id`
- 保存代码 hash、参数快照、交易所配置摘要。
- `pending_orders.payload_json` 增加 `strategy_run_id`
- `qd_strategy_trades``qd_strategy_positions` 增加 `strategy_run_id` 可选字段。
验收:
- 任意一笔订单能追到哪次运行、哪版代码、哪组参数。
### Phase 1Basket runtime MVP
目标:支持单向 `LayeredMartingaleBasket` 稳定运行。
任务:
- 新增 basket 表、basket order 表、runtime event 表。
- 实现 `ctx.state``ctx.basket(side)`
- 实现 `BasketRuntime.open_child_order/close_all/checkpoint`
- 实现幂等键和 DB 级唯一约束。
- 官方模板先支持 `long``short`
验收:
- 5 层、每层 3 单能按配置触发。
- 重启后不会重复开同一个 layer/order。
- 均价止盈基于实际成交均价。
### Phase 2Order intent 与成交驱动
目标:把 `pending_orders` 从唯一状态源降级为执行队列。
任务:
- 新增 `strategy_order_intents``strategy_order_fills`
- `TradingExecutor._enqueue_pending_order()` 前置创建 intent。
- `PendingOrderWorker` 执行后回写 intent 和 fill。
- `persist_strategy_fill()` 刷新 basket 均价、TP 和状态。
- 部分成交不再误判为完整开仓。
验收:
- 部分成交后 basket 数量、均价、TP 正确。
- 拒单不修改 basket 为已开仓。
- 同一幂等键不会重复提交。
### Phase 3:恢复与 needs_review
目标:重启、网络失败、未知订单状态可控。
任务:
- 实现 `RecoveryService`
- 启动策略前自动恢复 active run。
- 未知状态进入 `needs_review`
- UI 提供同步交易所状态、继续观察、关闭 basket、强制停止。
验收:
- 发单后模拟进程崩溃,恢复后不重复下单。
- 交易所和本地不一致时不会继续补仓。
### Phase 4:多空双 basket
目标:安全开放 `direction=both`
任务:
- `ctx.long_position/short_position` 正式化。
- `ctx.basket("long")``ctx.basket("short")` 独立持久化。
- preflight 检查交易所 hedge mode。
- 单写入锁按 `strategy_id + credential_id + symbol + side` 切分。
验收:
- long basket 和 short basket 可同时存在,互不覆盖均价和层级。
- 单向交易所不允许启动 both 模式。
### Phase 5:基础 AlgoTrading
目标:把复杂策略的“如何成交”从策略逻辑里抽出来。
任务:
- 实现 `BestLimit`
- 实现 `TWAP`
- 实现 `Stop/StopLimit`
- 子单调度器支持撤单、重挂、超时和最大滑点。
验收:
- 同一个 basket 子单可选择 market、best_limit、twap 执行。
- 执行报告展示计划成交和实际成交差异。
## 16. 测试清单
必须新增的测试:
- `test_strategy_run_identity.py`
- `test_basket_runtime_state.py`
- `test_basket_order_idempotency.py`
- `test_basket_partial_fill_avg_price.py`
- `test_basket_rejected_order_state.py`
- `test_basket_restart_recovery.py`
- `test_basket_long_short_independent.py`
- `test_order_intent_lifecycle.py`
- `test_algo_twap_scheduler.py`
- `test_algo_best_limit.py`
- `test_exchange_capability_preflight.py`
- `test_backtest_live_basket_consistency.py`
重点场景:
- 同一根 K 线重复触发,不重复开同一子单。
- 写库成功但交易所提交超时,恢复时不盲目重发。
- 部分成交后按成交数量更新均价。
- 拒单后 basket order 为 rejected,不增加层级。
- 交易所最小下单量不足,策略进入 `needs_review` 或拒绝启动。
- 多空双开时 long/short basket 独立恢复。
## 17. 最小可交付版本
建议最小版本不要一口气做完整算法交易平台,先交付:
- `strategy_run_id`
- `ctx.state`
- `ctx.basket("long"|"short")`
- `strategy_baskets` / `strategy_basket_orders`
- order intent 幂等键。
- fill 驱动 basket 均价。
- `LayeredMartingaleBasket` 单向模板。
- 重启后不重复下单。
这一步完成后,已经可以覆盖用户最核心的“多层分仓 + 马丁 + 均价止盈 + 可恢复”诉求。随后再扩展多空双向和 TWAP/BestLimit,会稳很多。
+724
View File
@@ -0,0 +1,724 @@
# QuantDinger 策略运行时与算法交易升级规划
**状态**:规划建议
**适用范围**ScriptStrategy、实盘策略运行时、订单执行、算法交易执行器
**背景**:用户开始提出更复杂的实盘策略需求,例如 5 层分仓、每层 3 个马丁子单、均价止盈、多空模式和自定义杠杆。QuantDinger 需要从“能跑策略”升级为“可靠承载复杂策略和算法执行”的量化交易基础设施。
---
## 1. 结论
当前 ScriptStrategy 基座可以支持一类复杂策略:
- 有状态的分批开仓。
- 运行时参数化。
- 多次加仓、均价止盈。
- 只做多或只做空。
- K 线/实时 tick 循环驱动。
- 回测与实盘复用同一份脚本逻辑。
但对于专业级“阶梯分仓马丁 / basket martingale / layered DCA”这类策略,当前系统还缺少一些基础设施级边界:
- 独立 basket 状态持久化。
- 多空双向 basket 的独立状态。
- 重启恢复与成交回放。
- 部分成交、撤单、拒单后的确定性状态机。
- 实盘与回测在逐笔补仓、均价、手续费、滑点上的一致性校验。
- 策略级最大风险预算、爆仓距离、保证金占用和 kill switch。
因此:
- **只做多 / 只做空版本**:当前基座可以写出来,适合先落地。
- **多空双开版本**:建议先补强 hedge-mode 状态模型,不建议直接用单一 `ctx.position` 硬写。
- **专业级可售卖模板**:需要配套 basket runtime、订单生命周期和恢复机制后再推广。
---
## 2. 用户需求是否能由脚本策略表达
用户需求:
```text
5 个大分仓
每个分仓 3 个开单
单内开仓间距可调
每个子单按马丁倍数放大
均价止盈
前一个分仓没有盈利才开下一个分仓
交易品种自定义
只做多 / 只做空 / 多空双开
基础仓位是首单金额
合约按杠杆后的名义价值计算
马丁倍数可自定义
均价止盈可自定义
```
### 2.1 当前可直接表达的部分
ScriptStrategy 已经具备这些能力:
| 需求 | 当前支持情况 | 说明 |
| --- | --- | --- |
| 自定义交易品种 | 支持 | 由策略创建参数和运行配置选择 symbol |
| 参数可调 | 支持 | 使用 `ctx.param(...)` |
| 只做多 | 支持 | `ctx.open_long` / `ctx.add_long` / `ctx.close_position` |
| 只做空 | 支持 | `ctx.open_short` / `ctx.add_short` / `ctx.close_position` |
| 分批加仓 | 支持 | 脚本维护层级和触发价 |
| 马丁倍数 | 支持 | 通过脚本计算每次下单数量 |
| 均价止盈 | 支持 | 脚本维护或读取均价后触发平仓 |
| K 线或 tick 循环 | 支持 | 运行时按 bar/tick 调用脚本 |
| 回测 | 支持 | 可用脚本回测面板验证 |
### 2.2 当前不建议硬写的部分
| 需求 | 风险点 | 建议 |
| --- | --- | --- |
| 多空双开 | 需要 long basket 和 short basket 独立状态;交易所也必须是 hedge mode | 第一版拆成两个策略实例,后续补 `ctx.long_position` / `ctx.short_position` |
| 重启后继续运行 | 内存变量可能丢失,导致重复开单或错误止盈 | 必须有 basket 状态持久化和成交回放 |
| 部分成交 | 均价和层级不能只按“已发单”计算 | 必须按实际成交回填 |
| 拒单 / 超最小下单量 | 状态机可能误以为已开仓 | 下单确认必须驱动状态迁移 |
| 合约杠杆名义价值 | 不同交易所单位、面值、张数规则不同 | 统一 order sizing 层 |
| 爆仓/保证金风险 | 马丁连续补仓容易快速提高保证金占用 | 增加策略级风险预算和强制停止 |
---
## 3. 建议的脚本策略模型
这个用户需求应该抽象成 `LayeredMartingaleBasket`,不是普通网格,也不是简单 DCA。
### 3.1 参数结构
```text
symbol
direction: long | short | both
base_order_value
leverage
layers = 5
orders_per_layer = 3
martingale_multiplier = 2.0
intra_spacing_pct = [0.5, 0.8]
inter_spacing_pct = [1.2, 1.5, 1.8, 2.2]
take_profit_pct = 2.0
max_total_margin_pct
max_notional_pct
hard_stop_pct
cooldown_bars
restart_after_take_profit = true
```
### 3.2 状态结构
```text
basket_id
side
status: idle | opening | active | closing | closed | failed
current_layer
current_order_in_layer
filled_orders
total_qty
total_notional
avg_entry_price
next_entry_trigger
take_profit_price
last_signal_ts
last_order_id
error_count
```
### 3.3 执行流程
```text
if basket is idle:
open layer 1 order 1
if price moves adverse by intra/inter spacing:
open next child order
if weighted average reaches take-profit:
close basket
reset state
if max layer/order reached:
stop adding
wait for TP or trigger risk exit
if hard risk limit reached:
close basket or stop strategy
```
---
## 4. ScriptStrategy 基座需要补齐的边界
### 4.1 Basket state persistence
复杂策略不能只依赖脚本内存变量。建议新增 basket 状态表或 runtime state 标准:
```text
qd_strategy_baskets
qd_strategy_basket_orders
```
核心能力:
- 每个 basket 有唯一 ID。
- 每个子单有独立状态。
- 状态由成交事件驱动,而不是由“发单成功”驱动。
- 后端重启后可以恢复当前层级、均价和未完成订单。
#### 4.1.1 脚本线程与持久化边界
脚本策略通常跑在线程或任务循环里,但线程内变量只能作为运行期缓存,不能作为真实状态来源。建议把策略状态拆成三层:
| 层级 | 用途 | 建议存储 | 是否可信 |
| --- | --- | --- | --- |
| 线程内存 | 当前循环临时计算、减少查询 | Python object | 不可信,重启即丢 |
| Redis / cache | 分布式锁、短期心跳、运行中标记、限频 | Redis,可选 | 半可信,可重建 |
| 数据库 | basket、订单意图、成交、风险状态、恢复检查点 | PostgreSQL / SQLite / MySQL | 可信状态源 |
原则是:脚本可以读写 `ctx.state`,但 `ctx.state` 背后必须由运行时托管并定期落库;策略代码不应该直接操作数据库连接,也不应该自己决定恢复逻辑。
建议提供运行时接口:
```python
ctx.state.get("current_layer", 0)
ctx.state.set("current_layer", 2)
ctx.state.flush()
ctx.basket("long").open_child_order(...)
ctx.basket("long").checkpoint()
```
其中:
- `ctx.state` 保存轻量策略状态,例如当前层级、最近触发价格、冷却计数。
- `ctx.basket` 保存交易相关状态,例如子单、成交、均价、止盈价、未完成订单。
- `flush()` 由运行时批量落库,也可以在发单前后强制 checkpoint。
- 真实下单前必须先写入 `order_intent`,拿到幂等键,再提交交易所订单。
#### 4.1.2 数据库与 Redis 的分工
数据库是恢复源,Redis 只做加速和协调:
- 数据库负责:策略实例、basket、子订单、订单意图、交易所订单 ID、成交回报、风险状态、最后 checkpoint。
- Redis 负责:策略运行锁、线程心跳、短期去重键、任务队列、行情订阅状态。
- 如果没有 Redis,单机版本也能工作,只是不能很好地做多进程调度和快速故障切换。
- 如果 Redis 数据丢失,不应该影响真实持仓恢复;最多影响 UI 的“运行中”即时状态。
推荐表结构方向:
```text
strategy_runtime_state
strategy_baskets
strategy_basket_orders
strategy_order_intents
strategy_order_fills
strategy_recovery_events
```
#### 4.1.3 重启与容灾流程
后端重启、线程崩溃或容器迁移后,不应该直接从脚本第一行重新开始发单。恢复流程应由运行时统一执行:
1. 标记策略实例为 `recovering`,禁止脚本继续发新单。
2. 读取数据库中的最后 checkpoint、basket、未完成 order intent。
3. 拉交易所当前持仓、未成交订单、最近成交。
4. 用交易所事实修正本地状态:成交数量、均价、未完成订单、已关闭订单。
5. 对没有交易所订单 ID 的 intent 做幂等判定:确认未提交才允许重试。
6. 重建 `ctx.state``ctx.basket`,恢复到线程内存。
7. 写入 recovery event,标记为 `running`
8. 下一轮策略循环只允许基于恢复后的状态继续运行。
关键点是:恢复优先相信交易所事实,其次相信数据库 checkpoint,最后才相信脚本内存。
#### 4.1.4 防重复下单机制
复杂马丁策略最怕重启后重复补仓。每次下单必须有稳定幂等键:
```text
strategy_id + basket_id + side + layer_index + order_index + action
```
例如:
```text
strategy-12:basket-20260629-long:L2:O3:open
```
运行时提交订单前先创建 `order_intent`
- 如果同一幂等键已有 `submitted / accepted / partially_filled / filled`,禁止再次提交。
- 如果是 `rejected / expired`,根据策略配置决定是否重试。
- 如果是 `unknown`,必须先向交易所对账,不允许盲目重发。
这样即使线程在“写库成功、发单超时、交易所实际已接收”的中间状态崩溃,也可以通过交易所订单查询恢复,而不是重复开单。
### 4.2 Position model upgrade
当前脚本更适合单方向持仓。后续建议提供清晰接口:
```python
ctx.position
ctx.long_position
ctx.short_position
ctx.basket(side="long")
ctx.basket(side="short")
```
这样多空双开不会挤在一个 `ctx.position` 语义里。
### 4.3 Order lifecycle standard
复杂策略必须清楚区分:
- intent created
- order submitted
- exchange accepted
- partially filled
- filled
- rejected
- cancelled
- expired
- reconciled
状态迁移必须幂等,避免重启后重复下单。
### 4.4 Fill-driven average price
均价止盈必须基于实际成交:
- 不能只按脚本计划价格。
- 不能只按信号价格。
- 必须考虑部分成交、手续费、合约面值和滑点。
### 4.5 Restart recovery
策略恢复时应执行:
1. 读取本地 basket 状态。
2. 拉交易所持仓和未成交订单。
3. 对账本地订单与交易所订单。
4. 重建均价、层级和风险状态。
5. 再允许继续发新单。
这一节是恢复行为摘要,详细线程、数据库、Redis 与幂等设计见 `4.1.1``4.1.4`
### 4.6 Risk guard
马丁类策略必须内置硬风险边界:
- 最大层数。
- 最大子单数。
- 最大名义价值。
- 最大保证金占用。
- 最大账户权益占比。
- 最大连续亏损次数。
- 最大浮亏。
- 距离爆仓价最小安全距离。
- 交易所错误过多自动停止。
### 4.7 Backtest/live consistency
复杂加仓策略需要增强回测:
- 支持逐层成交记录。
- 支持手续费和滑点模型。
- 支持最小下单量和价格步进。
- 支持合约张数换算。
- 支持“下根 K 成交”和“tick 触发”的差异报告。
- 支持实盘偏差报告:计划成交 vs 实际成交。
### 4.8 Strategy run identity
每一次策略启动都必须有独立 `strategy_run_id`。不要只用 `strategy_id` 表示一次运行,因为同一策略可能多次启动、暂停、恢复、修改参数。
建议记录:
```text
strategy_id
strategy_run_id
source_version_id
parameter_snapshot
account_id
exchange
symbol
market_type
position_mode
started_at
stopped_at
stop_reason
runtime_status
```
这样可以回答:
- 这笔订单属于哪一次运行。
- 当时使用的是哪一版脚本代码。
- 当时参数是什么。
- 是正常停止、用户停止、风控停止,还是异常崩溃后恢复。
### 4.9 Single writer and lock model
同一个策略实例同一时间只能有一个运行时写状态和发单。否则多线程、多进程或容器重启时容易重复补仓。
建议:
-`strategy_id + account_id + symbol + side` 作为运行锁范围。
- 单机版可以用数据库锁。
- 多实例部署建议用 Redis lock + 数据库 fencing token。
- 每次写入订单状态时检查 `runtime_epoch``fencing_token`,旧线程失去锁后不能继续写库。
- UI 上的“启动策略”如果发现已有活动 run,应提示用户恢复、接管或强制停止。
### 4.10 Event ledger
除了保存当前状态,还应该保存事件流水。当前状态用于快速恢复,事件流水用于审计和重放。
建议事件类型:
```text
strategy_started
signal_generated
order_intent_created
order_submitted
order_accepted
order_partially_filled
order_filled
order_rejected
order_cancelled
basket_checkpointed
risk_guard_triggered
recovery_started
recovery_completed
strategy_stopped
manual_override
```
有了 event ledger,后续才能做:
- 策略事故复盘。
- 回测与实盘偏差报告。
- 用户投诉时还原执行过程。
- 版本升级后的兼容性检查。
### 4.11 Code and parameter snapshot
实盘运行不能只引用“当前脚本代码”。用户可能在策略运行中修改脚本,如果没有快照,会出现无法复现的问题。
建议:
- 每次启动实盘时固定 `source_version_id`
- 保存代码 hash、参数快照、运行配置、交易账户、交易所模式。
- 修改代码后不影响正在运行的 run,除非用户明确点击“应用并重启”。
- 回测记录、实盘记录和市场模板都引用同一套版本快照。
### 4.12 Manual intervention and degraded mode
恢复失败、交易所状态不一致或订单状态未知时,不应该让策略继续自动补仓。
建议增加状态:
```text
running
recovering
paused
needs_review
stopping
stopped
failed
```
进入 `needs_review` 时:
- 禁止发新开仓单。
- 允许只减仓或撤单。
- UI 显示差异:本地 basket、交易所持仓、未成交订单。
- 用户可以选择:同步交易所状态、关闭 basket、继续观察、强制停止。
---
## 5. 算法交易能力缺口
目前 QuantDinger 已有基础下单与策略运行能力,但还不是完整 AlgoTrading 执行平台。
### 5.1 当前已有能力
- 市价单。
- 限价单。
- 基础取消订单。
- 策略信号触发下单。
- 止损、止盈、追踪止损等策略级风控。
- 网格 resting limit orders 的部分执行基础。
- 多交易所适配框架。
### 5.2 需要补齐的算法交易模块
建议新增独立域:
```text
app/services/algo_trading/
order_intent.py
scheduler.py
child_order.py
execution_algorithms/
twap.py
iceberg.py
best_limit.py
sniper.py
stop.py
order_state.py
reconciliation.py
risk.py
```
### 5.3 第一阶段建议实现
| 算法 | 优先级 | 原因 |
| --- | --- | --- |
| TWAP | P0 | 最容易解释,最适合大额分批成交 |
| BestLimit | P0 | 基于盘口最优价挂单,适合低滑点执行 |
| Stop / StopLimit | P0 | 用户理解成本低,交易刚需 |
| Iceberg | P1 | 大单隐藏,依赖交易所支持或本地拆单 |
| Sniper | P1 | 需要盘口、成交量、触发条件和撤单速度 |
| VWAP / POV | P2 | 需要可靠成交量曲线和市场深度数据 |
---
## 6. 算法交易必须补齐的边界
### 6.1 Unified order intent
所有策略和手动交易都应先生成统一订单意图:
```text
side
symbol
market_type
position_side
reduce_only
notional
quantity
limit_price
time_in_force
execution_algo
risk_budget
client_order_id
strategy_id
basket_id
```
### 6.2 Child order scheduler
TWAP/Iceberg/Sniper 都需要子单调度:
- 分片数量。
- 分片间隔。
- 每片最大数量。
- 撤单重挂。
- 超时处理。
- 最大滑点。
- 成交不足补单。
### 6.3 Market microstructure data
算法交易不能只靠 K 线。至少需要:
- best bid/ask。
- order book top levels。
- recent trades。
- spread。
- depth。
- volatility。
- exchange rate limit。
### 6.4 Reconciliation
执行器必须定期对账:
- 本地订单状态。
- 交易所订单状态。
- 实际成交。
- 当前持仓。
- 手续费。
- 平均成交价。
### 6.5 Kill switch
算法交易需要全局和策略级开关:
- 全局暂停发单。
- 单策略暂停。
- 单交易所暂停。
- 最大错误次数自动停止。
- 最大滑点自动停止。
- 仓位异常自动停止。
- API key 异常自动停止。
### 6.6 Observability
需要能回答:
- 为什么下了这笔单?
- 计划成交多少?
- 实际成交多少?
- 滑点多少?
- 哪个子单失败?
- 是策略原因、交易所原因还是风控原因?
建议新增:
```text
algo_order_logs
algo_child_order_logs
execution_trace_id
strategy_run_id
```
### 6.7 Exchange capability matrix
算法交易不能假设每个交易所能力一致。需要维护交易所能力矩阵:
```text
exchange
market_type
supports_hedge_mode
supports_reduce_only
supports_post_only
supports_stop_order
supports_iceberg
supports_client_order_id
min_notional
min_quantity
price_tick
quantity_step
rate_limit
order_book_depth
```
运行时根据能力矩阵决定:
- 能否启动某个策略。
- 是否需要本地模拟 stop / iceberg。
- 下单数量和价格如何 round。
- 策略模板是否适合某个交易所。
### 6.8 Account, permission, and secret boundary
算法交易会放大账户风险,必须把账户权限纳入运行前检查:
- API key 是否具备交易权限。
- 是否禁止提现权限。
- 是否支持读取订单和成交历史。
- 是否配置 IP 白名单。
- 是否允许合约交易。
- 是否设置账户级最大风险预算。
策略启动前应做 preflight check,失败时明确告诉用户缺哪个权限或配置,而不是启动后才报错。
### 6.9 Test and certification suite
如果要把 QuantDinger 做成基础设施,需要有策略运行时验收测试:
- 重启恢复测试:发单中途杀进程,恢复后不重复下单。
- 部分成交测试:均价和 TP 按真实成交更新。
- 拒单测试:最小下单量、余额不足、API 错误后不误改 basket。
- 断网测试:状态进入 `needs_review`,不继续补仓。
- 多空 hedge 测试:long basket 与 short basket 独立。
- 回测/实盘一致性测试:同一信号路径能对齐计划成交点。
- 交易所精度测试:价格 tick、数量 step、最小名义金额都正确处理。
---
## 7. 产品分期路线
### Phase 1ScriptStrategy 专业化
目标:让复杂状态机策略可稳定运行。
- Basket runtime state。
- 多空独立 position/basket 接口。
- 成交驱动均价。
- 重启恢复。
- 策略运行 ID、代码版本快照和参数快照。
- 事件流水和恢复审计。
- 单写入者锁,避免重复运行。
- 复杂策略回测报告。
- Layered Martingale Basket 官方模板。
### Phase 2:基础 AlgoTrading
目标:让用户可以选择执行算法,而不只是市价/限价。
- Unified order intent。
- TWAP。
- BestLimit。
- Stop / StopLimit。
- 子单状态表。
- 执行日志和偏差分析。
- 交易所能力矩阵。
- 账户权限 preflight check。
### Phase 3:高级执行
目标:降低大额交易滑点,支持专业交易执行。
- Iceberg。
- Sniper。
- VWAP。
- POV。
- 盘口深度驱动。
- 智能撤单重挂。
### Phase 4:基础设施化
目标:QuantDinger 成为策略、执行、风控、监控一体化基础设施。
- 统一策略运行 ID。
- 全链路 execution trace。
- 交易所能力矩阵。
- 多账户组合执行。
- 回测/模拟盘/实盘一致性报告。
- 策略市场模板准入审核。
- 风险沙盒和资金预算模拟器。
- 运行时验收测试套件。
---
## 8. 推荐落地顺序
最推荐的实际落地顺序:
1. 先做 `LayeredMartingaleBasket` 官方脚本模板,只支持 `long` / `short`
2. 增加 `strategy_run_id`、代码快照、参数快照,保证可追溯。
3. 增加 basket 状态持久化和事件流水,解决重启恢复。
4. 增加单写入者锁和幂等下单,解决重复运行和重复补仓。
5. 增加成交驱动均价,解决部分成交和真实 TP。
6. 增加 `long_basket` / `short_basket`,再开放多空双开。
7. 增加交易所能力矩阵和启动前 preflight check。
8. 增加 TWAP / BestLimit,作为算法交易第一版。
9. 再做 Iceberg / Sniper。
这样既能尽快满足用户需求,又不会把复杂风险压到脚本作者身上。
---
## 9. 对外表述建议
当前阶段建议谨慎表述:
```text
QuantDinger supports stateful ScriptStrategy workflows for scale-in, DCA,
martingale-style baskets, average-cost exits, backtesting, and live execution.
Advanced multi-leg basket persistence, hedge-mode basket accounting, and
algorithmic execution orders such as TWAP, Iceberg, Sniper, and BestLimit are
planned infrastructure upgrades.
```
中文:
```text
QuantDinger 当前支持有状态脚本策略,可实现分批加仓、DCA、马丁篮子、均价止盈、
回测和实盘执行。多腿篮子持久化、多空独立篮子核算,以及 TWAP、Iceberg、
Sniper、BestLimit 等算法订单执行能力,将作为后续基础设施升级重点。
```
不要过早宣传“完整算法交易平台”,应先宣传“可扩展的策略运行时 + 正在建设中的算法执行基础设施”。