跳转至

因子表达式引擎指南

本页定位为“查表 + 排障”,用于快速回答三个问题:

  1. 表达式怎么写才符合语义?
  2. 算子有哪些、参数怎么填?
  3. 报错或结果异常时先查什么?

如果你想系统学习从想法到落地的完整路径,可以再看 第 14 章:高性能因子挖掘与表达式引擎

1. 为什么需要因子表达式

在因子研究中,核心瓶颈通常不是“不会写代码”,而是“想法验证速度太慢”。使用表达式引擎的主要价值有三点:

  1. 把研究目标从工程细节中解耦,只关注因子数学结构。
  2. 把重复的分组、窗口、对齐逻辑交给引擎,减少手写错误。
  3. 统一因子定义格式,便于复现、对比和批量迭代。

典型对比:

  • 传统方式:每个因子都手写 DataFrame 逻辑,代码冗长且难统一。
  • 表达式方式:例如 Rank(Ts_Mean(Close, 10)),可直接进入验证和迭代。

2. AKQuant 的因子表达式特色

  1. 高性能执行:底层基于 Rust + Polars,利用 Lazy 执行与并行计算。
  2. 分区语义清晰:明确区分 TS/CS/EL,跨分区嵌套自动拆步执行。
  3. 工程化可调试:复杂表达式可先内层后外层验证,定位问题更直接。
  4. 批量计算友好run_batch 适合统一样本池下的多因子并行评估。
  5. 时区与数据规范明确:默认 Asia/Shanghai,非 A 股场景可显式设置。

3. 最小使用模板

from akquant.factor import FactorEngine

engine = FactorEngine(catalog)
df = engine.run("Rank(Ts_Mean(Close, 10))")
df_batch = engine.run_batch(
    [
        "Ts_Mean(Close, 5)",
        "Rank(Volume)",
        "If(Close > Open, 1, 0)",
    ]
)

最小执行顺序建议:

  1. 准备 catalog 并保证数据可读。
  2. run 一个单表达式验证数据链路。
  3. run_batch 做多因子并行计算。

输入数据建议至少包含:

  • symbol
  • date
  • open, high, low, close, volume(按策略实际需求)

返回结果约定:

  • run(expr):返回 date, symbol, factor_value 三列核心结果。
  • run_batch(exprs):返回 date, symbol 加多列因子值宽表。

时区约定:

  • 默认 Asia/Shanghai
  • 非 A 股场景请显式设置 timezone,并对时间列显式 tz_localize

4. 语法规则速览

4.1 变量与常量

  • 列名不区分大小写:Closeclose 等价。
  • 数值常量可直接写:10.5
  • 变量名必须能映射到真实列;如数据是 ClosePrice,写 Close 会失败。

4.2 运算符

  • 算术运算:+, -, *, /
  • 比较运算:>, <, >=, <=, ==, !=
  • 逻辑组合:可在条件中使用 &, |

示例:

If((Close > Open) & (Volume > Ts_Mean(Volume, 20)), 1, 0)

4.3 三类分区语义

  • TS(时序):按 symbol 分组滚动。
  • CS(截面):按 date 分组横截面。
  • EL(元素级):逐元素变换,不引入窗口。

跨分区嵌套(如 Rank(Ts_Mean(...)))会被拆步执行并物化中间结果。

5. 算子速查

5.1 时序算子 (TS)

算子 别名 说明 示例
Ts_Mean(X, d) Mean 过去 d 期移动平均 Ts_Mean(Close, 5)
Ts_Std(X, d) Std 过去 d 期移动标准差 Ts_Std(Close, 20)
Ts_Max(X, d) Max 过去 d 期最大值 Ts_Max(High, 10)
Ts_Min(X, d) Min 过去 d 期最小值 Ts_Min(Low, 10)
Ts_Sum(X, d) Sum 过去 d 期求和 Ts_Sum(Volume, 5)
Ts_ArgMax(X, d) ArgMax 过去 d 期最大值距今天数 Ts_ArgMax(Close, 5)
Ts_ArgMin(X, d) ArgMin 过去 d 期最小值距今天数 Ts_ArgMin(Close, 5)
Ts_Rank(X, d) - 当前值在过去 d 期分位排名 Ts_Rank(Close, 5)
Delta(X, d) - X(t) - X(t-d) Delta(Close, 1)
Delay(X, d) Ref 滞后 d 期数值 Delay(Close, 1)
Ts_Corr(X, Y, d) Corr 过去 d 期相关系数 Ts_Corr(Close, Volume, 20)
Ts_Cov(X, Y, d) Cov 过去 d 期协方差 Ts_Cov(Close, Open, 20)

5.2 截面算子 (CS)

算子 说明 示例
Rank(X) 同日横截面百分比排名(0~1) Rank(Close)
Scale(X) 同日归一化,sum(abs(X)) = 1 Scale(Close)

5.3 逻辑与数学算子 (EL)

算子 说明 示例
If(Cond, A, B) 条件判断 If(Close > Open, 1, -1)
Sign(X) 符号函数(1, 0, -1) Sign(Close - Open)
Abs(X) 绝对值 Abs(Close - Open)
Log(X) 自然对数 Log(Volume)
SignedPower(X, e) 保持符号的幂运算 SignedPower(Close, 2)

6. 排障手册(按优先级)

6.1 结果全是 NaN

优先检查:

  1. d 是否大于可用历史长度(Warmup 不足)。
  2. 原始列是否有大量 NaN。
  3. 列名是否真实可映射。

6.2 嵌套表达式明显变慢

常见原因是跨分区嵌套触发拆步物化。处理方式:

  1. 先单独运行内层表达式。
  2. 确认内层结果合理后再加外层。
  3. 批量场景再考虑 run_batch

6.3 窗口语义与预期不一致

若数据有停牌/缺失日期,滚动窗口按行推进,可能偏离“自然日”理解。建议先做交易日对齐。

6.4 列名看着对却报错

引擎会做大小写归一,但不会猜测别名。ClosePriceClose 不是同一列。

6.5 同策略跨市场结果漂移

先检查时区与本地化:

  1. 默认时区为 Asia/Shanghai
  2. 非 A 股必须显式设置 timezone
  3. 时间列需要显式 tz_localize

更多时区细节见 时区处理指南

7. 性能建议

  1. run 调通,再 run_batch 扩展。
  2. 减少不必要的深层嵌套,优先可解释的组合结构。
  3. 使用最小必要列,降低 IO 与内存占用。
  4. 对停牌和缺失日期提前清洗,减少窗口偏差导致的反复调试。

8. 教程迁移说明

当前你可能在教程页和指南页都能看到因子表达式内容。为了避免依赖单一入口,本指南保持独立可读:

  1. 教程侧重学习路径与案例。
  2. 本页侧重速查、规范与排障。
  3. 即使教程后续迁移位置,本页仍可直接作为日常开发参考。

9. FAQ

Q: 支持分钟线吗? A: 支持。date 包含时间戳即可;d=60 表示过去 60 根 bar。

Q: 为什么同一表达式在不同数据源结果不同? A: 通常不是算子问题,而是数据对齐、复权、缺失值处理与时区设置差异。

Q: 什么时候优先用 run_batch A: 同样本池、同时间段、多因子并行评估时优先;单表达式调试时优先 run