3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在多因子选股模型中,许多因子(如估值、成长性等)往往会受到股票所属行业和自身市值大小的显著影响。为了获取纯净的超额收益(Alpha),我们需要对因子进行**中性化(Neutralization)**处理,剔除行业和市值带来的偏差。
聚宽(JoinQuant)因子库提供了非常便捷的 neutralize 函数,支持一键对 pandas.Series 或 pandas.DataFrame 格式的因子数据进行行业和市值中性化。
在聚宽中,中性化函数定义在 jqfactor 库中:
from jqfactor import neutralize
neutralize(series, how=None, date=None, axis=1, fillna=None, add_constant=False)
pd.Series 或 pd.DataFrame,待中性化的序列。若为 Series,其 index 必须为股票代码(如 '000001.XSHE')。list,中性化使用的自变量因子名称列表。默认为 ['jq_l1', 'market_cap'](即聚宽一级行业 + 总市值)。
'jq_l1'(聚宽一级)、'sw_l1'(申万一级)等。'market_cap'(总市值)、'ln_market_cap'(对数总市值)等。str,指定中性化所依赖的财务和行业数据的日期(如 '2018-05-02')。注意:请勿传入当天实时日期,因为当天财务数据尚未更新,可能返回 Nan。1。仅在 data 为 pd.DataFrame 时生效。0 表示对每列做中性化,1 表示对每行做中性化。None。支持传入行业分类(如 'jq_l1'),表示使用行业均值填充缺失值。False。以下是一个完整的在聚宽研究环境(Notebook)中运行的示例。我们首先获取沪深300成分股在某一天的原始因子值(以“市净率因子”为例),然后对其进行聚宽一级行业和对数市值的双重中性化处理。
import pandas as pd
import numpy as np
from jqdata import *
from jqfactor import neutralize, get_factor_values
# 1. 设定参数
target_date = '2023-05-10'
# 获取沪深300成分股
stocks = get_index_stocks('000300.XSHG', date=target_date)
# 2. 获取原始因子数据(以聚宽因子库中的市净率因子 book_to_price_ratio 为例)
# get_factor_values 返回一个 dict,value 是 DataFrame
raw_factor_dict = get_factor_values(
securities=stocks,
factors=['book_to_price_ratio'],
start_date=target_date,
end_date=target_date
)
# 提取出 Series 格式的因子值,index 为股票代码
raw_factor_series = raw_factor_dict['book_to_price_ratio'].loc[target_date]
print("原始因子前5行:")
print(raw_factor_series.head())
# 3. 进行行业和市值中性化处理
# 剔除聚宽一级行业(jq_l1)和对数总市值(ln_market_cap)的影响
neutralized_factor = neutralize(
raw_factor_series,
how=['jq_l1', 'ln_market_cap'],
date=target_date,
fillna='jq_l1' # 缺失值用行业均值填充
)
print("\n中性化后的因子前5行:")
print(neutralized_factor.head())
如果您是在聚宽的单因子分析框架中自定义因子,可以直接在 calc 方法中获取数据,并在计算完成后调用 neutralize 进行处理:
from jqfactor import Factor, neutralize
import numpy as np
class MyNeutralizedFactor(Factor):
name = 'my_neutralized_factor'
max_window = 1
# 依赖基础因子:营业收入、总资产
dependencies = ['total_operating_revenue', 'total_assets']
def calc(self, data):
# 1. 计算原始因子值(例如:资产周转率 = 营业收入 / 总资产)
revenue = data['total_operating_revenue']
assets = data['total_assets']
raw_factor = (revenue / assets).mean() # 转为 Series
# 2. 获取当前逻辑日期
current_date = self._current_date.strftime('%Y-%m-%d')
# 3. 对计算结果进行中性化
try:
neutral_factor = neutralize(
raw_factor,
how=['jq_l1', 'market_cap'],
date=current_date,
fillna='jq_l1'
)
return neutral_factor
except Exception as e:
# 异常处理:若中性化失败,返回原始因子值
return raw_factor
date 参数必须是当前模拟的逻辑日期(context.current_dt 或 self._current_date),绝对不能使用未来的日期。neutralize 中设置 fillna 参数进行均值填充。