🚀 AI 一键生成 joinquant 策略代码

JoinQuant 研究工具:将因子数据转换为 Alphalens 可用的格式

joinquant | 发布时间: 2025/12/19
以下内容由 EasyQuant 生成。

问题描述

如何将获取的数据格式转换为 Alphalens 所需的格式?

解决方案

要将 JoinQuant(聚宽)获取的数据转换为 Alphalens 所需的格式,核心在于将因子的 DataFrame 转换为 MultiIndex Series(多重索引序列),并准备好对应的价格数据。

Alphalens 的核心函数 get_clean_factor_and_forward_returns 需要两个主要输入:

  1. factor: 一个 MultiIndex Series,索引为 (date, asset),值为因子值。
  2. prices: 一个 DataFrame,索引为 date,列为 asset,值为收盘价。

以下是具体的操作步骤和代码示例。

核心步骤

  1. 获取因子数据:通常使用 get_factor_valuesget_fundamentals,得到的是一个 DataFrame(索引为日期,列为股票代码)。
  2. 数据重塑 (Stack):使用 Pandas 的 .stack() 方法将宽表(DataFrame)转换为长表(MultiIndex Series)。
  3. 获取价格数据:使用 get_price 获取收盘价 DataFrame。
  4. 生成 Alphalens 数据:调用 alphalens.utils.get_clean_factor_and_forward_returns

代码实现

以下代码可以在聚宽的研究环境中直接运行:

# -*- coding: utf-8 -*-
import pandas as pd
import alphalens
from jqdata import *
from jqfactor import get_factor_values

# 1. 设定参数
stock_pool = get_index_stocks('000300.XSHG')  # 股票池:沪深300
start_date = '2023-01-01'
end_date = '2023-03-01'

# 2. 获取因子数据 (以市盈率 PE_ratio 为例)
# get_factor_values 返回一个字典,key是因子名,value是DataFrame(index=date, columns=asset)
factor_data_dict = get_factor_values(
    securities=stock_pool,
    factors=['pe_ratio'],
    start_date=start_date,
    end_date=end_date
)
factor_df = factor_data_dict['pe_ratio']

# 3. 【关键步骤】转换因子格式
# Alphalens 需要 MultiIndex Series (date, asset)
# 使用 stack() 将列转为二级索引
factor_series = factor_df.stack()

# 为索引命名,有助于 Alphalens 识别(可选,但推荐)
factor_series.index.names = ['date', 'asset']

# 4. 获取价格数据
# 注意:价格数据的结束日期需要比因子结束日期晚,以便计算未来的收益率
# 这里多取 20 天的数据
price_end_date = (pd.to_datetime(end_date) + pd.Timedelta(days=30)).strftime('%Y-%m-%d')

prices_df = get_price(
    list(stock_pool), 
    start_date=start_date, 
    end_date=price_end_date, 
    fields=['close']
)['close']

# 确保价格数据的索引也是 datetime 类型,并且时区处理一致(通常聚宽返回的是 naive datetime)
prices_df.index = pd.to_datetime(prices_df.index)

# 5. 生成 Alphalens 所需的清洗后数据
# periods 定义了我们要分析持有 1天、5天、10天 的收益
factor_data_clean = alphalens.utils.get_clean_factor_and_forward_returns(
    factor=factor_series,
    prices=prices_df,
    quantiles=5,          # 分成 5 组
    periods=[1, 5, 10],   # 计算 1, 5, 10 日后的收益
    max_loss=0.35         # 允许丢弃数据的最大比例
)

# 6. 查看结果或进行绘图
print("转换后的数据前5行:")
print(factor_data_clean.head())

# 示例:生成全部分析图表(在 Notebook 中运行会显示图表)
# alphalens.tears.create_full_tear_sheet(factor_data_clean)

详细说明

1. 因子数据的转换 (.stack())

聚宽的 get_factor_values 返回的数据结构如下(DataFrame):

              000001.XSHE  000002.XSHE ...
2023-01-04    6.5          8.2
2023-01-05    6.6          8.1
...

Alphalens 需要的格式如下(MultiIndex Series):

date        asset      
2023-01-04  000001.XSHE    6.5
            000002.XSHE    8.2
2023-01-05  000001.XSHE    6.6
            000002.XSHE    8.1
...

Pandas 的 stack() 函数正是用于完成这种“宽表变长表”的转换。

2. 价格数据的日期范围

Alphalens 需要计算“未来收益率”(Forward Returns)。如果你计算的是 periods=[1, 5, 10],那么对于因子数据中的最后一天,Alphalens 需要往后查找至少 10 个交易日的价格数据来计算收益。因此,获取 prices 时,end_date 必须晚于因子的 end_date

3. 时区问题

聚宽返回的日期通常是不带时区信息(Naive Datetime)的,这通常能直接配合 Alphalens 使用。如果遇到时区报错,可以尝试统一转换为 UTC:

# 如果需要统一时区
factor_series.index = factor_series.index.set_levels(factor_series.index.levels[0].tz_localize('UTC'), level=0)
prices_df.index = prices_df.index.tz_localize('UTC')

但在大多数聚宽研究环境中,直接使用默认格式即可。


Q&A

Q: 为什么运行 get_clean_factor_and_forward_returns 时提示价格数据不足?
A: 这是因为计算未来收益率需要未来的价格。例如,要计算因子在 3月1日 的 10日预期收益,必须拥有 3月1日 之后至少 10 个交易日的价格数据。请确保 get_priceend_date 比因子的 end_date 往后延足够多的天数。

Q: 如果我的因子数据包含 NaNInf 怎么办?
A: get_clean_factor_and_forward_returns 函数内部会自动处理部分无效数据。你可以通过参数 max_loss 控制允许丢弃的数据比例(默认 35%)。如果无效数据过多,建议在传入 Alphalens 之前使用 Pandas 的 dropna()fillna() 进行预处理。

Q: 如何处理多因子?
A: Alphalens 一次只能分析一个因子。如果你有多个因子,需要对每个因子分别执行上述转换流程,或者将它们合并成一个大的 DataFrame 后,通过循环对每一列进行 stack() 和分析。