4. 案例04:计算换手率因子并做行业中性化

任务说明

本案例基于日频行情数据,用成交量与流通股本计算换手率因子,再按行业分组做去均值处理,得到行业中性化后的换手率因子。核心公式:turnover = volume / float_share,中性化:turnover_neutral = turnover - industry_mean(turnover)。

环境与依赖

pip install pandas numpy

完整实现

import pandas as pd
import numpy as np

# 1. 构造最小示例数据:3只股票、2个行业、2个交易日
df = pd.DataFrame({
    "date": ["2024-01-02"] * 3 + ["2024-01-03"] * 3,
    "code": ["A", "B", "C"] * 2,
    "industry": ["银行", "银行", "科技"] * 2,
    "volume": [1.0e7, 2.0e7, 3.0e7, 1.5e7, 2.5e7, 4.0e7],   # 成交量(股)
    "float_share": [1.0e8, 2.0e8, 1.5e8, 1.0e8, 2.0e8, 1.5e8],  # 流通股本(股)
})

# 2. 计算换手率因子
df["turnover"] = df["volume"] / df["float_share"]

# 3. 按“日期 + 行业”分组去均值,实现行业中性化
df["turnover_neutral"] = df["turnover"] - df.groupby(
    ["date", "industry"]
)["turnover"].transform("mean")

print(df[["date", "code", "industry", "turnover", "turnover_neutral"]])

运行与验证

直接运行上述脚本。判定通过条件:

  • 每个 (date, industry) 分组内,turnover_neutral 的均值应约等于 0(浮点误差范围内)。
  • 同一分组内两只股票的 turnover_neutral 符号相反、绝对值相等(因为只有两只股票时去均值即对称化)。

可用一行代码验证:

print(df.groupby(["date", "industry"])["turnover_neutral"].mean())

输出应全部为 0(或接近 0 的极小值)。

关键点

  • 中性化必须按 date 分组,否则不同交易日的量纲会互相污染。
  • 用 transform("mean") 而非 mean(),可直接把组均值广播回原行,避免 merge。
  • 若某行业当日只有 1 只股票,去均值后该股票因子恒为 0,属于正常现象,需在后续使用中注意。