第 14 章:高性能因子挖掘与表达式引擎¶
1. 为什么需要因子表达式?¶
在量化投研(尤其是 Alpha 因子研究)中,研究员的核心痛点往往不是“如何写代码”,而是“如何快速验证想法”。
- 传统方式:手写 20 行 Python/Pandas 代码来实现一个动量因子,处理繁琐的数据对齐、缺失值填充和窗口计算。
- 现代方式:使用一行公式
Rank(Ts_Mean(Close, 5))即可完成计算。
因子表达式引擎(Expression Engine)的出现,将研究员从底层的工程细节中解放出来,专注于因子的数学逻辑本身。
2. AKQuant 因子引擎架构¶
AKQuant 内置的 akquant.factor 模块基于 Rust 实现的 Polars 库,提供了远超 Pandas 的计算性能。
核心特性¶
- 极速计算:利用 Polars 的 Lazy API 和多线程并行计算能力。
- 防止未来函数:封装好的时序算子(如
Ts_Mean)强制执行窗口逻辑,避免用到未来数据。 - Alpha101 风格:支持 WorldQuant 风格的经典因子语法。
3. 快速上手¶
3.1 准备数据¶
因子引擎需要标准化的面板数据(Panel Data)。
import akshare as ak
import pandas as pd
from akquant.data import ParquetDataCatalog
# 初始化数据目录
catalog = ParquetDataCatalog("./data_catalog")
# 下载数据 (以平安银行和宁德时代为例)
symbols = ["sh600001", "sz300750"]
for symbol in symbols:
df = ak.stock_zh_a_daily(symbol=symbol, start_date="20230101", end_date="20230601", adjust="hfq")
df["symbol"] = symbol
df["date"] = pd.to_datetime(df["date"])
df.set_index("date", inplace=True)
catalog.write(symbol, df)
3.2 计算因子¶
from akquant.factor import FactorEngine
# 初始化引擎
engine = FactorEngine(catalog)
# 1. 计算单个动量因子
# 逻辑:过去 5 天收盘价均值的横截面排名
df = engine.run("Rank(Ts_Mean(Close, 5))")
print(df.head())
# 2. 批量计算多个因子
expressions = [
"Ts_Mean(Close, 5)", # 时序均值
"Rank(Volume)", # 截面成交量排名
"Rank(Ts_Corr(Close, Volume, 10))" # 量价相关性排名
]
df_batch = engine.run_batch(expressions)
4. 算子详解¶
4.1 时序算子 (Time-Series)¶
在时间维度上对每只股票独立计算。支持别名(如 Mean 等同于 Ts_Mean)。
| 算子 | 别名 | 说明 | 示例 |
|---|---|---|---|
Ts_Mean(X, d) |
Mean |
移动平均 | Ts_Mean(Close, 5) |
Ts_Std(X, d) |
Std |
移动标准差 | Ts_Std(Close, 20) |
Ts_Max(X, d) |
Max |
移动最大值 | Ts_Max(High, 10) |
Ts_Min(X, d) |
Min |
移动最小值 | Ts_Min(Low, 10) |
Ts_Sum(X, d) |
Sum |
移动求和 | Ts_Sum(Volume, 5) |
Delta(X, d) |
- | 差分 (今日 - d日前) | Delta(Close, 1) |
Delay(X, d) |
Ref |
滞后 (d日前的数值) | Delay(Close, 1) |
Ts_Corr(X, Y, d) |
Corr |
滚动相关系数 | Ts_Corr(Close, Volume, 20) |
Ts_Cov(X, Y, d) |
Cov |
滚动协方差 | Ts_Cov(Close, Open, 20) |
4.2 截面算子 (Cross-Sectional)¶
在同一时间点上对所有股票进行计算。
| 算子 | 说明 | 示例 |
|---|---|---|
Rank(X) |
百分比排名 (0~1) | Rank(Close) |
Scale(X) |
归一化 (Sum abs = 1) | Scale(Close) |
4.3 逻辑与数学算子¶
| 算子 | 说明 | 示例 |
|---|---|---|
If(Cond, A, B) |
条件判断 | If(Close > Open, 1, -1) |
Sign(X) |
符号函数 (1, 0, -1) | Sign(Return) |
Abs(X) |
绝对值 | Abs(Close - Open) |
Log(X) |
自然对数 | Log(Volume) |
SignedPower(X, e) |
保持符号的幂运算 | SignedPower(Return, 2) |
4.4 基础运算¶
因子表达式支持标准的数学运算符:
- 算术运算:
+,-,*,/ - 比较运算:
>,<,>=,<=,==,!=
示例:
# 收盘价相对于开盘价的涨幅
(Close - Open) / Open
# 如果收盘价大于 5 日均线,返回 1,否则返回 0
If(Close > Ts_Mean(Close, 5), 1, 0)
5. 实战:常用因子编写范例¶
为了帮助大家更好地理解如何编写因子,这里列举了几种常见的因子逻辑及其对应的表达式。
5.1 趋势类因子 (Trend)¶
逻辑:如果是上涨趋势,则做多;下跌趋势,则做空。
- 均线突破:收盘价在 20 日均线之上。
- MACD 简化版:短期均线减去长期均线。
- 新高因子:当前价格接近过去 60 天的最高价。
5.2 反转类因子 (Reversion)¶
逻辑:涨多了会跌,跌多了会涨。
- RSI 简化版:过去 6 天的涨幅(Rank化)。
- 乖离率 (Bias):收盘价偏离均线的程度(越偏离越容易回归)。
5.3 波动率类因子 (Volatility)¶
逻辑:捕捉价格的剧烈波动或平静期。
- 波动率:过去 20 天的标准差。
- 量价相关性:价格和成交量的相关性。
5.4 复杂逻辑组合¶
- 量价背离:价格创新高但成交量没有创新高。
6. 进阶:挖掘 Alpha 因子¶
通过组合上述算子,我们可以复现经典的 Alpha 因子。例如 Alpha #6 (参考 WorldQuant):
\[
-1 \times \text{Corr}(\text{Open}, \text{Volume}, 10)
\]
在 AKQuant 中对应的表达式为:
7. 课后练习¶
- 尝试使用 AKShare 下载更多股票的数据(如沪深300成分股)。
- 实现并计算一个动量反转因子:
Rank(Ts_Mean(Close, 5)) - Rank(Ts_Mean(Close, 20))。 - 思考:如果不进行数据对齐(停牌处理),直接计算时序因子会有什么风险?