简体中文 | English
一个面向 AI 和自动化研究流程的 A 股单因子回测引擎。输入表达式与数据配置,CLI 会完成安全编译、A 股交易约束处理、滚动检验,并输出稳定的机器可读结果。
性能摘要: 在 500 只证券 × 1,500 个交易日的固定完整单因子回测中,本项目中位耗时 1.330 s,Qlib 为 19.070 s,约快 14.34x;速度比仅在 11 项结果一致性检查全部通过后生成。详见性能证据。
本项目仅用于研究,不构成投资建议。回测结果和合成示例不能证明未来收益。
通用回测框架通常把数据整理、股票池历史、复权、涨跌停、停牌和报告口径留给使用者处理。本项目把这些容易反复出错的 A 股规则固化为可复用协议,让人或 AI 只需提交类似 WorldQuant 风格的因子表达式,不必为每个实验重写一套回测代码。
它不是因子搜索器,也不承诺发现盈利因子。v0.2 专注于把一条已有表达式快速、可复现地变成一份可信的单因子回测结果。
本项目可独立构建为 wheel。在当前目录运行:
uv sync --locked --all-groups
uv run ashare-backtest doctor --json
uv run ashare-backtest compile 'cs_rank(ts_pct_change(close,5))' --json
uv run ashare-backtest inspect-job --job examples/demo_daily/job.yaml --json
uv run ashare-backtest audit-causality \
--job examples/demo_daily/job.yaml \
'cs_rank(ts_pct_change(close,5))' \
--work-root /tmp/ashare-factor-demo \
--json
uv run ashare-backtest evaluate \
--job examples/demo_daily/job.yaml \
'cs_rank(ts_pct_change(close,5))' \
--through rolling \
--work-root /tmp/ashare-factor-demo \
--jsonCLI 每次只向标准输出写一行 JSON,适合由 Codex、Claude Code、流水线或其他程序直接调用。诊断日志写到标准错误,不会污染机器协议。
仓库自带的数据完全由程序生成,仅用于检查上市边界、ST 区间、停牌、开盘涨停和开盘跌停等执行规则,不用于展示 alpha。
- 表达式编译: 字段和算子采用白名单;拒绝未知字段、非法参数和前视引用。
- 因果审计: 独立的截断一致性检查会重新计算历史前缀;如果增加未来数据会改变 过去的因子值,命令失败并保存机器可读凭证。
- A 股时间点语义: 区分因子观察时点、股票池历史与下一开盘执行,避免使用未来成分股或未来行情。
- 历史分类插件: 可把实体、类别、生效日和失效日组成的外部分类表物化为 PIT 字段;缺失、重叠或同日多重归属会 fail closed,申万等具体数据不绑定在核心中。
- 可选组内相对算子: Python 扩展接口提供
group_demean、group_rank和group_zscore,支持按当日 PIT 分类做横截面比较;类别具有独立类型,不能被 AI 当作连续数值误用。它们目前不进入默认 CLI 算子目录。 - 双价格坐标: 因子与连续估值使用当时可构造的后复权序列;能否成交和下单价格使用未复权开盘及未复权涨跌停价。
- 复权尺度警告: 后复权价格适合收益、比率和时间序列标准化;直接价格、均价或价差用于横截面选股时,编译器会报告机器可读警告。
- 交易约束: 支持上市状态、ST、停牌、开盘涨跌停、逐股票部分成交、净额换仓、费用和只做多组合。
- 滚动检验: 输出训练段和测试段证据、Rank IC、策略与基准指标、超额指标及覆盖率。
- 可复现产物: 表达式、数据身份、任务配置和评价语义共同决定产物身份,便于缓存、审计和复跑。
- AI 友好接口:
capabilities、schema、doctor、compile、inspect-job、audit-causality和evaluate均提供版本化 JSON 协议。
inspect-job 在回测前返回引擎版本、协议、数据资产身份、股票池和执行合同身份。上层 Agent 可用
这些字段生成实验哈希并安全复用结果,而不需要导入本项目内部 Python 模块。
audit-causality 是发布或接入新算子时使用的独立检查,不会拖慢普通 evaluate。
它验证表达式执行是否依赖未来行,但不能证明上游数据供应商没有把事后修订值写进历史;
因此凭证表述为 prefix_invariance_verified,而不是“保证不存在任何未来函数”。
v0.2 包含表达式求值、数据契约、单因子分组回测、A 股执行约束和滚动证据。
以下能力刻意不放进当前版本:因子生成与搜索、多因子组合优化、实盘交易、私有行情数据和通用事件驱动订单系统。它们可以在上层调用本引擎,但不应混进单因子回测的可信计算核心。
信号在 T 日冻结,并在 T+1 开盘执行。每个持仓批次只交易现有持仓与新等权目标之间的差额:连续入选的股票直接保留;可卖差额正常卖出;停牌或跌停导致的受阻卖单保留为残余仓,但不会取消其他股票订单;随后只用实际可用现金购买可买的目标缺口。系统同时报告计划换手、实际换手、受阻买卖单、目标偏离和期末残余市值。
这里模拟的是双价格坐标下的“分红再投资总收益代理”,不是券商逐股账户撮合器。原始价格已经用于可交易性和订单坐标,但快速账户仍不记录真实股数,因此不处理 100 股整数手、每笔最低佣金、分红送转、盘口排队或逐笔冲击成本;这些能力属于后续严格账户层。
所有速度结论都来自确定性合成数据、干净源码提交和归档 JSON。只有 Python 环境一致,且因子值、每日选股、收益、Sharpe 与 Rank IC 通过预先固定的对齐检查,比较程序才会输出速度比。
v0.2 采用逐股票目标差额换仓:连续入选的股票保留,只交易目标持仓差额。Qlib 侧使用独立的同口径订单适配器;速度比较只有在因子、选股、逐日收益、换手、费用和 Rank IC 全部通过一致性门后才会生成。
共同工作负载包含 500 只证券、1,500 个交易日和一条五日价格变化表达式。两端都从持久化数据开始,执行因子计算、每日横截面选股、下一开盘换仓、双边费用、期末平仓,并产出净值、收益、回撤、换手、Rank IC 和结果文件。预热 1 次后独立测量 5 次,单进程运行。
| 引擎 | 墙钟时间中位数 | 进程峰值内存 |
|---|---|---|
ashare-factor-backtest 9eda124 |
1.330 s | 568 MiB |
Microsoft Qlib d5379c5 |
19.070 s | 1,038 MiB |
在这项固定策略完整回测中,Qlib 与本项目的墙钟时间比为 14.34x。11 项一致性检查全部通过且没有首个差异日;逐日净收益最大绝对误差为 3.04e-15,换手误差为 4.98e-12,总收益误差为 2.84e-14,Sharpe 误差为 8.38e-14,Rank IC 均值误差为 5.74e-08。
这个倍数只对应上述固定工作负载,不能外推到所有公式、数据规模和机器;共同口径也不包含整手、最低佣金、涨跌停、停牌或公司行动。合成因子是否盈利与基准无关:这里检验的是相同交易结果下的正确性和速度,不是展示 alpha。v0.1 的整批卖出再买入口径及 31.77x 历史数字仍保存在版本化证据中,但不得归因于 v0.2。
本项目自己的生产流程还额外处理 PIT 上市状态、ST、停牌、开盘涨跌停、压力费用、筛选窗口和滚动检验。相同的 500 × 1,500 数据上,一条表达式触发 5 个滚动折、90 次组合模拟和 12 次 Rank IC 计算。共享因子与成交数据读取后,完整中位耗时由 9.777 s 降至 7.256 s,提升 25.8%;进程峰值内存由 459 MiB 降至 411 MiB。
优化后的中位耗时约为:共享数据读取、因子计算和成交面板收集 4.569 s、成交矩阵最终物化 0.028 s、滚动检验 2.045 s、初筛 0.592 s。自动比较器确认新旧 workload 与完整 evidence JSON 完全相同。这里不发布 Qlib 倍数,因为两边没有完全同构的 A 股约束与滚动证据流程;它用于展示真实生产入口的一次完整调用成本。
下面的表格由已归档 JSON 自动生成。对比固定了输入值、表达式语义、有效值掩码、Python 环境、进程数和输出范围;只有数值结果对齐后才允许显示速度比。
早期微基准测量的是两套引擎从各自原生持久化存储读取数据并生成四个因子矩阵的时间,不包含成交模拟、IC、费用和滚动检验。它被保留为底层计算证据,不应与上面的完整回测结果混用。
证据状态: 可复现发布版本。
| 引擎 | 墙钟时间中位数 | 峰值内存 |
|---|---|---|
| ashare-factor-backtest-public-evaluator | 0.086 s | 372 MiB |
| microsoft-qlib-local-provider-kernels-1 | 0.903 s | 690 MiB |
在该工作负载下,Qlib 与本引擎的墙钟时间比为 10.50x。工作负载包含 500 只证券、1500 个交易日和 4 条语义对齐的表达式。输出最大绝对误差为 1.45e-05,所有有限值位置完全一致。
该结果是在同一 Python 环境中,以单进程、缓存预热方式,从各自原生存储读取数据并生成因子矩阵。它不是完整回测速度对比,也不代表其他公式、数据规模或机器仍有相同比例。引用前请阅读 BENCHMARKS.md 和已归档的 JSON 结果。
完整口径、原始 JSON 和复现命令见 BENCHMARKS.md。
代码使用 Apache-2.0 许可证。合成示例数据单独以 CC0 1.0 发布,详见 examples/DATA_LICENSE.md。