问题描述
解决方案
在聚宽(JoinQuant)平台上创建自定义因子,主要是在研究环境中通过继承 jqfactor.Factor 类来实现。
以下是创建自定义因子的标准流程、代码示例及详细参数说明。
创建自定义因子的步骤
- 导入模块:引入
jqfactor中的Factor类。 - 定义类:创建一个继承自
Factor的类。 - 设置属性:在类中定义
name(因子名称)、max_window(所需历史数据长度)、dependencies(依赖的基础数据)。 - 实现计算逻辑:重写
calc(self, data)方法,利用data中的数据计算并返回因子值。
完整代码示例
以下代码定义了一个简单的自定义因子:5日乖离率 (Bias5)。即当前收盘价相对于过去5日均价的偏离程度。
# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
from jqfactor import Factor, calc_factors
# 1. 定义因子类,继承自 Factor
class Bias5(Factor):
# 因子名称,必须唯一
name = 'bias5'
# 获取数据的时间窗口长度(例如计算5日均线,至少需要5天数据)
max_window = 5
# 依赖的基础数据字段,可以是行情数据('close', 'open'等)或财务数据
dependencies = ['close']
# 2. 实现计算逻辑
def calc(self, data):
"""
data 是一个字典,key 是 dependencies 中的字段名,
value 是 pandas.DataFrame (index为日期,columns为股票代码)
"""
# 获取收盘价数据 (DataFrame: 行=日期, 列=股票)
close_df = data['close']
# 计算过去5天的均值 (按列求均值,返回 Series)
ma5 = close_df.mean()
# 获取当前的收盘价 (最后一行)
current_close = close_df.iloc[-1]
# 计算乖离率: (当前价格 - 均价) / 均价
bias = (current_close - ma5) / ma5
# 返回结果必须是 pandas.Series (index为股票代码,value为因子值)
return bias
# --- 以下为测试因子计算的代码 ---
# 定义股票池
securities = ['000001.XSHE', '600000.XSHG', '000300.XSHG']
# 计算因子值
# start_date 和 end_date 是因子值的日期
factors = calc_factors(
securities=securities,
factors=[Bias5()],
start_date='2023-01-01',
end_date='2023-01-05'
)
# 打印结果
print(factors['bias5'])
关键属性与方法详解
1. 类属性
name(str): 因子的唯一标识符。max_window(int): 计算因子所需的历史数据天数。例如计算10日均线,该值至少为10。系统会自动截取过去max_window天的数据传给calc方法。dependencies(list): 依赖的数据列表。支持以下类型:- 行情数据:
'open','close','high','low','volume','money'。 - 财务数据: 如
'total_operating_revenue'(营业总收入),'net_profit'(净利润) 等。 - 行业/概念: 如
'HY001'(某行业代码)。 - 其他因子: 可以依赖聚宽因子库中的因子。
- 行情数据:
2. calc(self, data) 方法
- 输入参数
data: 一个字典 (dict)。- Key:
dependencies中定义的字符串。 - Value:
pandas.DataFrame。- Index: 时间序列(长度为
max_window,最后一行是当前计算日期)。 - Columns: 股票代码。
- Index: 时间序列(长度为
- Key:
- 返回值: 必须是一个
pandas.Series。- Index: 股票代码。
- Value: 计算出的因子值。
进阶:使用财务数据和额外数据
如果需要同时使用财务数据或指数数据,可以参考以下示例(计算市销率倒数):
class SalesToPrice(Factor):
name = 'sales_to_price'
max_window = 1
# 依赖营业收入(财务数据)和总市值(基础数据)
dependencies = ['operating_revenue', 'market_cap']
def calc(self, data):
# 获取财务数据:营业收入 (TTM或单季度,取决于具体字段定义,通常因子库默认为TTM或最新报告期)
revenue = data['operating_revenue']
# 获取市值
mcap = data['market_cap']
# 注意:data中的DataFrame包含max_window行,这里我们只取最新的一行(即当前日期)
#以此计算当天的因子值
current_revenue = revenue.iloc[-1]
current_mcap = mcap.iloc[-1]
# 计算 市销率倒数 = 营收 / 市值
return current_revenue / current_mcap
常见问题 Q&A
Q: calc 函数中可以直接获取大盘指数的数据吗?
A: 不能直接通过 dependencies 获取指数数据。如果在计算个股因子时需要用到指数(如计算Beta),需要在 calc 方法内部使用 self._get_extra_data(securities=['000300.XSHG'], fields=['close']) 来获取额外数据。
Q: max_window 设置为1时,data 中的数据是什么样的?
A: 当 max_window=1 时,data['close'] 等 DataFrame 只有一行(即当前计算日的数据)。在进行计算时,通常需要使用 .iloc[-1] 或 .mean() (结果相同) 将其转换为 Series 进行运算。
Q: 如何处理停牌股票的数据?
A: 在调用 calc_factors 时,有一个参数 skip_paused。
- 如果设为
True,停牌股票会被跳过(不计算)。 - 如果设为
False(默认),停牌股票的数据会包含在data中(通常是前复权价格),你需要自己在calc逻辑中决定如何处理(例如返回 NaN)。
Q: 因子计算结果全是 NaN 怎么办?
A: 请检查:
max_window是否足够长(例如计算60日均线但窗口只设了10)。dependencies中的财务字段在选定的时间内是否有数据(部分财务数据在财报发布前可能为空)。- 股票池是否包含未上市或已退市的股票。