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

725 lines
21 KiB
Markdown
Raw 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 策略运行时与算法交易升级规划
**状态**:规划建议
**适用范围**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 等算法订单执行能力,将作为后续基础设施升级重点。
```
不要过早宣传“完整算法交易平台”,应先宣传“可扩展的策略运行时 + 正在建设中的算法执行基础设施”。