因子模块
betalens.factor 集中封装了从可交易池筛选到分组打分、权重生成的常用步骤,支持单因子、双因子和多因子分组策略。
获取可交易池
from betalens.factor.factor import get_tradable_pool
from betalens.datafeed import get_absolute_trade_days
rebalance_days = get_absolute_trade_days("2022-01-01", "2022-12-31", "M")
date_ranges, code_ranges = get_tradable_pool(rebalance_days)
逻辑要点:
对每个调仓日调用
betalens.datafeed.Datafeed,过滤交易状态value == 1的证券
批量预查询因子数据
from betalens.factor.factor import pre_query_characteristic_data
pre_queried_data = pre_query_characteristic_data(
date_list=rebalance_days,
metric="股息率(报告期)",
time_tolerance=24*2*365, # 时间容差(小时)
table_name="fundamental_data",
date_ranges=date_ranges, # 可选:复用可交易池
code_ranges=code_ranges
)
返回的 DataFrame 包含:
input_ts: 输入时间戳(调仓日期)code: 股票代码{metric}: 因子值列datetime: 匹配到的数据时间戳diff_hours: 时间差(小时)name: 股票名称
因子预处理与行业中性化
在分组打标签之前,建议先用 preprocess_factor 做一键预处理:逐截面(按 input_ts)
依次执行 去空值 → 去极值 → 标准化 → 中性化。
from betalens.factor.preprocessing import preprocess_factor
cleaned = preprocess_factor(
pre_queried_data,
metric="ROE",
winsorize_method="mad", # 去极值
standardize_method="zscore", # 标准化
industry_scheme="申万一级行业", # 自动查 industry 表做行业中性化
)
行业中性化有两种标签来源:
industry_scheme``(推荐):自动逐期调用 :func:`betalens.datafeed.query_industry` 从 ``industry表取 point-in-time 行业(datetime≤调仓日的最近一条,天然防前视), 无需事先把行业列 merge 进数据。不带版本后缀(如"申万一级行业")时自动落到查询日生效的版本。industry_col:使用调用方预先 merge 进pre_queried_data的行业列(旧行为)。
市值中性化仍由 log_mktcap_col 手动提供(先用 pre_query_characteristic_data 查”市值”再取 log)。
自动诊断打印:传入 industry_scheme 且 ``verbose=True``(默认)时,会打印三类统计,
便于判断中性化是否可靠:
行业分布:各行业占比、平均每期成分股数、行业总数
缺失情况:行业标签缺失率、因子值缺失率、按期最低/最高覆盖率
面板平衡:每期股票数与有效行业数的 min/median/max,行业数过少(<3)时告警
随后打印 中性化执行摘要:成功/跳过期数、平均回归 R²(行业+市值对因子的解释度)、 平均行业哑变量数与有效样本数。某期行业全缺失或样本不足(< 哑变量数+5)时会被跳过且不报错。
若只想单独取面板行业标签(如做行业内分析),可直接用 query_industry_panel:
from betalens.factor.preprocessing import query_industry_panel
ind_panel = query_industry_panel(pre_queried_data, scheme="申万一级行业")
ind_panel.xs(ts) # 取某期 code -> 行业名
单因子分组
from betalens.factor.factor import single_factor
labeled_pool = single_characteristic(
pre_queried_data=pre_queried_data,
metric="ROE",
quantiles={"ROE": 10}
)
特点:
支持自定义 ``quantiles``(整数代表等分桶)
自动 groupby
input_ts并添加metric_label列以
input_ts和code为 MultiIndex,便于后续透视
生成单因子权重
from betalens.factor.factor import get_single_factor_weight
# 经典多空模式
params = {
"factor_key": "ROE",
"mode": "classic-long-short",
}
weights = get_single_factor_weight(labeled_pool, params)
# 自定义模式
params = {
"factor_key": "ROE",
"mode": "freeplay",
"long": [9],
"short": [0],
"group_weights": { # 可选:组间权重
"long": {9: 2, 8: 1},
"short": {0: 2, 1: 1}
},
"intra_group_allocation": { # 可选:组内分配方式
"long": {9: {"method": "factor_value", "metric": "ROE", "order": "desc"}},
"short": {0: {"method": "equal"}}
}
}
weights = get_single_factor_weight(labeled_pool, params)
weights["cash"] = 0
模式说明:
classic-long-short:自动选择最高/最低标签freeplay:显式指定long与short标签列表,支持组间权重和组内分配
双因子分组(Double Sort)
双重排序用于同时考虑两个因子对投资组合的影响,分析因子间交互作用。
两种排序方法:
独立排序(Independent Sort): - 对所有股票分别按两个因子独立分组 - 取两个标签的交集形成N×M个组合 - 适用场景:因子之间相关性较低时
条件排序(Dependent Sort): - 先按主因子分组,然后在每个主因子组内按次因子分组 - 形成N×M个投资组合,每组股票数量相对均匀 - 适用场景:因子相关性较高,或需要控制某个因子影响时
from betalens.factor.factor import double_factor, describe_double_labeled_pool
labeled_pool = double_characteristic(
pre_queried_data1=data1,
pre_queried_data2=data2,
metric1="市值",
metric2="账面市值比",
quantiles1={"市值": 5},
quantiles2={"账面市值比": 5},
sort_method='dependent' # 或 'independent'
)
# 查看分组统计
count_pivot, mean_pivot1, mean_pivot2 = describe_double_labeled_pool(labeled_pool)
生成双因子权重
from betalens.factor.factor import get_double_factor_weight
weights = get_double_factor_weight(
labeled_pool,
params={
"factor_key1": "市值",
"factor_key2": "账面市值比",
"mode": "classic-long-short", # 自动做多(max,max),做空(min,min)
}
)
# 或自定义组合
weights = get_double_factor_weight(
labeled_pool,
params={
"factor_key1": "市值",
"factor_key2": "账面市值比",
"mode": "freeplay",
"long_combinations": [(0, 4), (1, 4)],
"short_combinations": [(4, 0), (4, 1)],
}
)
多因子分组(Multi-Factor Sort)
支持递归的独立排序和条件排序混合。
from betalens.factor.factor import multi_factor, describe_multi_labeled_pool
factors = [
{'name': '市值', 'quantiles': 5, 'method': 'dependent'},
{'name': '账面市值比', 'quantiles': 5, 'method': 'dependent'},
{'name': '动量', 'quantiles': 3, 'method': 'independent'},
]
labeled_pool = multi_characteristic(
pre_queried_data_list=[data1, data2, data3],
factors=factors
)
# 查看分组统计
stats = describe_multi_labeled_pool(labeled_pool, max_display_dims=2)
生成多因子权重
from betalens.factor.factor import get_multi_factor_weight
weights = get_multi_factor_weight(
labeled_pool,
params={
"mode": "classic-long-short", # 所有因子最高组 vs 所有因子最低组
}
)
# 或自定义组合
weights = get_multi_factor_weight(
labeled_pool,
params={
"mode": "freeplay",
"long_combinations": [(0, 4, 2), (1, 4, 2)],
"short_combinations": [(4, 0, 0)],
}
)
描述性统计
from betalens.factor.factor import (
describe_labeled_pool,
describe_double_labeled_pool,
describe_multi_labeled_pool
)
# 单因子
summary = describe_labeled_pool(labeled_pool)
# 双因子
count_pivot, mean_pivot1, mean_pivot2 = describe_double_labeled_pool(labeled_pool)
# 多因子
stats = describe_multi_labeled_pool(labeled_pool)
输出同时包含 count 与 mean 透视结果,可快速检查分组是否均衡。
实践提示
若指标存在极端值,建议在调用分组函数之前进行 winsor/标准化处理。
get_tradable_pool默认查询fundamental_data表,可酌情改写以适配自建数据库。复用可交易池:当查询多个因子时,先调用一次
get_tradable_pool,然后传入date_ranges和code_ranges复用。对于
freeplay模式,可通过group_weights和intra_group_allocation实现更精细的权重控制。
更多函数级文档见 Factor API。