Rename engine strategy surfaces

This commit is contained in:
boris
2026-04-23 22:13:14 -07:00
parent 882053e12b
commit 0b0b9333fa
35 changed files with 245 additions and 68388 deletions

253
README.md
View File

@@ -1,22 +1,20 @@
# fidc-backtest-engine
一个面向中国 A 股长周期选股策略的 Rust 回测核心骨架。这个仓库的第一版目标不是“玩具回测器”,而是提供一个可以继续演化为平台化引擎的最小可用核心,方向参考 `nautilus_trader` 的分层架构和 `rqalpha` 的中国股票规则约束
面向中国 A 股和期货策略的 Rust 回测核心。仓库目标是提供平台自有的策略 DSL、执行模型、撮合模型和结果分析能力最终由 `fidc-backtest-service` 对外提供策略运行服务
## 当前能力
- Phase 3增加预索引数据层、可配置决策/执行语义,以及更贴近聚宽微盘股脚本的 native 策略
- 日频交易日历与确定性逐日回放
- A 股日频市场快照、估值/因子快照、基准快照、候选资格标记
- 策略接口与引擎驱动,不直接模拟 `jqdata` API
- `BacktestConfig` 支持 `decision_lag_trading_days``execution_price_field(open/close/last)`
- `DailyMarketSnapshot` 支持 `day_open` / `last_price`
- Universe 选择器:按指数位置动态切换市值带,再取最小市值 Top-N
- 风险节流:基于指数均线状态切换 100% / 50% / 0% 仓位
- Broker Simulator按次日开盘价撮合支持手续费、印花税、最小佣金
- 中国 A 股规则钩子T+1、停牌、涨停不可买、跌停不可卖
- 回测输出:权益曲线、成交记录、期末持仓摘要
- 新增 `JqMicroCapStrategy`覆盖动态市值带、停运窗口、1 元股 / ST / 科创板过滤、均线过滤、止损止盈、固定频率再平衡
- `cargo run --bin bt-demo` 可直接运行仓库内置 demo 数据
- 日频、分钟、tick 级策略生命周期与确定性回放。
- A 股行情、估值、因子、基准、候选资格、涨跌停触达、停牌和 ST 标记。
- 平台策略 DSL 与 `StrategyContext` 数据 API不暴露非平台脚本语法。
- `BacktestConfig` 支持起止日期、初始资金、决策滞后、执行价格字段、基准代码。
- `DailyMarketSnapshot` 支持 `open/close/last/day_open/prev_close/upper_limit/lower_limit`
- Universe 选择器支持动态市值带、排序、Top-N、动态订阅和策略内更新。
- A 股规则钩子支持 T+1、停牌、涨停不可买、跌停不可卖、整手和最小下单量。
- Broker 支持目标权重、显式金额、目标股数、限价、VWAP/TWAP、挂单、撤单和订单查询。
- 期货账户支持多空持仓、开平仓、今昨仓、保证金、手续费、结算和到期处理。
- 报告输出支持权益曲线、成交、持仓、月度收益、风险指标、基准序列和 JSON 分析包。
- 内置 `OmniMicroCapStrategy`,覆盖动态市值带、均线过滤、止损止盈、固定频率再平衡和盘中执行近似。
## Workspace 布局
@@ -25,7 +23,6 @@
├── Cargo.toml
├── crates
│ ├── bt-demo
│ │ └── src/main.rs
│ └── fidc-core
│ └── src
│ ├── broker.rs
@@ -33,142 +30,87 @@
│ ├── cost.rs
│ ├── data.rs
│ ├── engine.rs
│ ├── events.rs
│ ├── instrument.rs
│ ├── futures.rs
│ ├── platform_expr_strategy.rs
│ ├── portfolio.rs
│ ├── rules.rs
│ ├── scheduler.rs
│ ├── strategy.rs
│ └── universe.rs
── data/demo
│ └── strategy_ai.rs
── data/demo
└── docs
```
## 核心模块概览
## 核心模块
- `calendar`: 交易日历和滚动窗口工具,负责日频迭代和均线 lookback
- `instrument`: 证券静态定义。
- `data`: 日频市场、因子、基准、候选资格数据模型与 CSV loader内部预建 symbol 级价格前缀和、按日预排序 eligible universe
- `universe`: 动态市值带 Universe Selector
- `portfolio`: 现金、持仓、FIFO lots、T+1 可卖数量、盈亏汇总
- `rules`: 中国股票规则钩子隔离停牌、涨跌停、T+1 检查
- `cost`: 佣金、印花税、最低佣金模型
- `broker`: 同时支持“目标权重再平衡”和显式 `order_target_value / order_value` 订单意图,买单按 100 股向下取整;执行价可选 `open / close / last`
- `strategy`: 引擎驱动的策略 trait 与具体策略实现
- `engine`: 确定性的逐日回测循环和结果收集
- `calendar`: 交易日历、交易日滚动和调度日期工具
- `instrument`: 证券和合约静态定义。
- `data`: 行情、因子、基准、候选资格、公司行为、盘口和期货交易参数数据模型。
- `universe`: 动态市值带和预排序候选集
- `portfolio`: 股票账户现金、持仓、可卖数量、盈亏、分红应收和资金流水
- `futures`: 期货账户、合约参数、保证金、手续费和多空持仓
- `rules`: 中国市场交易规则和风控校验
- `broker`: 股票撮合、订单簿、滑点、成交量约束、限价和显式订单执行
- `scheduler`: 日、周、月、分钟、tick 调度规则
- `platform_expr_strategy`: 平台 DSL 解析后的表达式策略执行模型
- `strategy`: 策略 trait、内置策略和运行时视图。
- `strategy_ai`: 策略 AI 手册、提示词生成和数据库字段目录合并。
- `engine`: 回测主循环、事件发布、报告和指标汇总。
## 策略实现
## 平台策略模型
示例策略 `CnSmallCapRotationStrategy` 对应一类典型的 A 股小市值轮动逻辑,并在 phase 2 里更贴近原始 jqdata 语义
策略代码不直接运行 Python 或非平台 API而是被解析为平台自有的策略 spec。执行链路是
1. 用指数点位动态计算市值带:
- `mystart = round((index_close - base_index_level) * xs + base_cap_floor)`
- `myend = mystart + cap_span`
2. 在当前市值带内,按总市值升序取 Top-N
3. 用指数短均线/长均线关系控制总仓位:
-`MA(short) < MA(long) * rsi_rate` 时降到 `trade_rate`
- 否则恢复到 `1.0`
4.`refresh_rate` 固定频率再平衡。
5. 非再平衡日也会检查止损/止盈钩子并触发退出。
6. 候选过滤纳入资格快照:
- 停牌
- ST
- 新股
- 科创板
- 1 元股
- allow_buy / allow_sell
1. 页面编辑平台 DSL。
2. spec 生成器解析变量、函数、选股、排序、风控、资金分配和显式订单。
3. 回测引擎按交易日和调度事件构造 `StrategyContext`
4. 策略返回 `StrategyDecision` 或显式订单动作
5. Broker、规则钩子和账户模型完成撮合、费用、持仓和权益更新。
6. Analyzer 输出标准化结果供服务和前端展示。
这个接口不是 `jqdata` 风格的 `before_trading_start` / `handle_data` 直接脚本 API而是
平台 DSL 支持
- 策略收到 `StrategyContext`
- 返回 `StrategyDecision`
- 引擎和 broker 负责把目标权重和退出指令变成实际成交
- `strategy("name") { ... }` 策略入口。
- `let` 自定义参数和 `fn` 自定义函数。
- `when / unless / else` 条件块。
- `selection.market_cap_band(...)` 动态市值带。
- `filter.stock_expr(...)` 任意指标、因子和组合选股。
- `ordering.rank_by(...)``ordering.rank_expr(...)` 排序。
- `allocation.buy_scale(...)` 动态买入资金比例。
- `risk.stop_loss(...)``risk.take_profit(...)` 多条件止盈止损。
- `order.*``cancel.*``update_universe(...)``subscribe(...)` 显式交易动作。
这更接近平台化引擎需要的“策略意图”和“执行语义”分离
任意数据库指标和自定义因子通过 `factor("field")``factor_value("field", lookback)``rolling_mean("field", n)``sma("close", n)` 等函数读取。未预计算的均线窗口可在回测中按已有历史数据实时计算
新增的 `JqMicroCapStrategy` 更直接对齐 `/聚宽微盘策略.py`
## 内置微盘策略
1. 指数信号使用 `benchmark_signal_symbol` 的同日 `last_price`
2. 市值带按 `round((index_level - base_index_level) * xs + base_cap_floor)` 动态计算。
3. 在预排序后的 eligible universe 上做带内截取,避免每个交易日全表扫描。
4. 叠加脚本中的盘中规则:
- 涨停开盘 / 跌停开盘
- 当前涨停 / 当前跌停
- 停牌 / ST / 名称含退 / 科创板
- 1 元股
- 个股 5/10/20 日均线过滤
5. 止损/止盈与固定 15 日再平衡同时工作。
6. 当前实现将 `run_daily(10:17/10:18)` 近似为“同日快照决策 + `last_price` 执行”,比传统 `T-1 -> T open` 更接近原脚本。
7. 执行层不再只做目标权重映射,而是支持更接近原脚本的显式订单链路:
- `order_target_value(symbol, 0)` 风格清仓
- `order_value(symbol, cash)` 风格补仓
- 止损/止盈后按剩余现金和剩余槽位补首个可买标的
- 定期调仓时先卖出池外持仓,再按固定现金分配逐笔买入
`OmniMicroCapStrategy` 是平台内置的微盘轮动策略,用于 demo、性能验证和策略迁移基线
## 与原始 jqdata 策略族的映射
如果原始逻辑大致是:
- 依据指数点位动态切换可接受市值带
- 从候选股票里选最小市值若干只
- 按均线决定是否降仓
- 周期性调仓
- 带止损/止盈
那么本仓库中的映射关系是:
- `get_fundamentals` / `valuation.market_cap` -> `DailyFactorSnapshot.market_cap_bn`
- `get_price` / `history` -> `DailyMarketSnapshot` + `BenchmarkSnapshot`
- `set_benchmark` -> `BacktestConfig.benchmark_code`
- `filter_paused` / `filter_st` / 新股过滤 -> `CandidateEligibility`
- `order_target_value` / `order_value` -> `StrategyDecision.order_intents``BrokerSimulator` 顺序解释执行
- 风险控制逻辑 -> `CnSmallCapRotationStrategy::gross_exposure`
## Phase 2 新增内容
- `DataSet::bundle_on(date)`:引入按日 snapshot bundle 视图,方便未来直接对接 FiDataCenter / FiDataScraper 预计算快照
- `DataSet::from_partitioned_dir(path)`:新增按日分区 snapshot 目录读取入口,为真实回测数据源接入打基础
- 策略诊断输出equity curve 里新增 `diagnostics` 字段,记录市值带、候选样本、退出原因等信息
- 候选资格快照扩展:补入 `is_kcb``is_one_yuan`
- 增加策略选择行为测试
## Phase 3 新增内容
- `DataSet` 新增 symbol 级价格前缀和,均线查询变为 O(1)
- `DynamicMarketCapBandSelector` 新增预排序 eligible universe + 二分带内截取
- `BrokerSimulator` 新增 `execution_price_field`
- `BacktestEngine` 新增 `decision_lag_trading_days`
- 新增 `JqMicroCapStrategy` 和对应测试
- `StrategyDecision` / `BrokerSimulator` 新增显式订单意图,开始覆盖 `order_target_value / order_value` 语义
## 当前仍保留的简化点
下面这些是刻意保留为 v1 简化,而不是遗漏:
- 只支持日频 snapshot不直接做逐笔 tick 回放。
- `JqMicroCapStrategy` 已支持同日 `last_price` 决策/执行,但这仍然是 snapshot 近似,不是盘口逐笔成交。
- 不模拟盘口排队、成交量约束和滑点模型,成交默认按开盘价完成。
- 买单按 100 股整手向下取整,卖单允许按实际持仓数量退出。
- 未处理复权、分红送转、融资融券、可转债、科创板/北交所差异规则。
- 止损止盈仍然是 snapshot 驱动,不是逐笔止损链。
这些简化都在代码结构上留了扩展位,不会阻断后续升级到更完整的执行层。
1. 使用 `benchmark_signal_symbol` 的同日决策价格计算指数信号。
2.`(index_level - base_index_level) * xs + base_cap_floor` 计算动态市值带。
3. 在预排序 eligible universe 中按市值区间截取候选。
4. 过滤停牌、ST、退市、科创板、一元股、涨停、跌停和不可买卖标记。
5. 使用个股短中长均线过滤。
6. 支持止损、止盈、定期再平衡和替补买入。
7. 默认按 10:18 附近的平台调度快照近似盘中决策,并使用 `last_price` 或配置的盘口价格执行。
## 运行方式
默认跑仓库内置 flat demo CSV
默认运行仓库 demo 数据
```bash
cargo run --bin bt-demo
```
运行更贴近聚宽微盘股脚本的策略:
运行平台内置微盘策略:
```bash
FIDC_BT_STRATEGY=jq-microcap \
FIDC_BT_STRATEGY=omni-microcap \
FIDC_BT_SIGNAL_SYMBOL=000001.SH \
cargo run --release --bin bt-demo
```
如果要接更接近真实数据面的按日分区 snapshot 目录:
接入真实分区 snapshot 目录:
```bash
FIDC_BT_DATA_LAYOUT=partitioned \
@@ -182,30 +124,13 @@ cargo run --bin bt-demo
```text
snapshots/
├── instruments.csv
├── benchmark/
│ └── YYYY/MM/*.csv
├── market/
└── YYYY/MM/*.csv
├── factors/
│ └── YYYY/MM/*.csv
└── candidates/
└── YYYY/MM/*.csv
├── benchmark/YYYY/MM/*.csv
├── market/YYYY/MM/*.csv
├── factors/YYYY/MM/*.csv
└── candidates/YYYY/MM/*.csv
```
其中
- `market/`:日级行情快照,可显式携带 `upper_limit/lower_limit/day_open/last_price`
- `factors/`:估值/因子快照,可扩展 `turnover_ratio/effective_turnover_ratio`
- `candidates/`:候选资格/过滤标记快照
- `benchmark/`:业绩基准指数快照
补充说明:
- 策略的“调仓信号指数”可以通过 `FIDC_BT_SIGNAL_SYMBOL` 单独指定,例如 `000001.SH`
- `benchmark/` 仍用于业绩基准和默认风险参考,两者现在不必强制相同
- 分区目录支持递归读取,因此可直接消费 `YYYY/MM/*.csv` 这类真实导出布局
这层接口是为后续对接 `FiDataCenter / FiDataScraper` 的预计算 snapshot 数据准备的。
运行后会生成:
运行后默认生成
- `output/demo/equity_curve.csv`
- `output/demo/trades.csv`
@@ -218,43 +143,3 @@ cargo fmt
cargo test
cargo build
```
## 为什么这个设计适合后续做快
这个版本已经按“预计算后高速回放”的思路组织:
- 因子与资格数据和市场行情解耦,适合把 `T x N` 的选股输入预先展开。
- 快照结构是列式数据库友好的固定字段模型,后续可以自然对接 ClickHouse/Parquet。
- Engine 逐日回放时只做:
- 取当天切片
- 策略计算 target weights
- broker 做持仓差量执行
- 不把查询逻辑塞进策略内部,避免回测时频繁回源数据层。
如果未来把日频因子、资格标记、可交易标记和 `day_open / last_price / high_limit / low_limit` 全部预计算到列式存储再按日期分块读入内存6 年全市场回测在分钟级是合理目标,原因是:
- 回测时不再做昂贵的 SQL join
- 因子筛选可直接消费预先物化并排序的 snapshot
- 组合调仓只关心“目标持仓”和“当前持仓”的差量
- 事件流是 append-only适合批量写出和后处理分析
- 均线查询通过 prefix sums 变成 O(1)
- 市值带选股通过预排序 universe + 二分定位变成 O(log N + K)
## 距离真实 6 年 / 5 分钟平台还差什么
当前仓库已经有“核心引擎 + 规则钩子 + 策略接口 + demo 回放”,但距离生产级目标还差:
- 真实 snapshot loader接入 FiDataCenter / FiDataScraper 的 ClickHouse / Parquet / PostgreSQL 预计算快照,而不是 demo CSV
- 分钟级执行层:把当前 `T-1 决策 / T 开盘执行` 扩展到更接近 `10:17 / 10:18` 的分钟级执行语义
- 更完整的 A 股规则:复权、分红、涨跌停细分、创业板/北交所规则、成交量约束、滑点模型
- 更高效的数据访问:按日期块和列式布局一次性加载 6 年快照,避免回测时回源拼表
- 批量参数回测:多个参数集共享预计算快照与候选池缓存
## Roadmap
- 引入更明确的事件总线和 portfolio/account ledger 分层
- 增加多 benchmark、多 universe、多个 broker model
- 支持企业行为、前后复权与现金分红
- 增加滑点、量比约束、成交量参与率
- 增加 parquet / ClickHouse 数据源与预计算管线
- 增加指标分析、分组收益、归因和 walk-forward 框架