🚀 AI 一键生成 joinquant 策略代码

JoinQuant 高效回测:使用 calc_factors 批量计算因子数据

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

问题描述

如何在策略代码中一次性计算一段时间的因子值?

解决方案

在聚宽(JoinQuant)策略代码中,若需要一次性计算一段时间内的因子值,可以使用 jqfactor 库提供的 calc_factors 函数。

这通常涉及以下三个步骤:

  1. 导入模块:引入 Factor 类和 calc_factors 函数。
  2. 定义因子:创建一个继承自 Factor 的类,设置因子的名称、数据窗口大小(max_window)、依赖数据(dependencies)以及具体的计算逻辑(calc 方法)。
  3. 调用计算:在策略函数(如 initializehandle_data)中调用 calc_factors,传入标的列表、因子实例以及起止时间。

代码实现

以下是一个完整的策略代码示例。该示例定义了一个简单的“5日均价”因子,并在 initialize 函数中一次性计算了指定股票在一段时间内的因子值。

# -*- coding: utf-8 -*-
from jqdata import *
from jqfactor import Factor, calc_factors
import numpy as np
import pandas as pd

# 第一步:定义因子类
class MeanPrice5(Factor):
    # 设置因子名称,计算结果的字典key将使用此名称
    name = 'mean_price_5'
    
    # 设置获取数据的时间窗口长度(例如计算5日均值,需要过去5天的数据)
    max_window = 5
    
    # 设置依赖的数据字段,这里依赖收盘价
    dependencies = ['close']
    
    # 计算因子的函数
    # data 是一个字典,key是依赖的字段名,value是DataFrame(index为日期,columns为股票代码)
    def calc(self, data):
        # 获取收盘价数据
        close = data['close']
        # 计算过去5天的均值
        # 注意:close是一个 (max_window x 股票数) 的DataFrame
        return close.mean()

def initialize(context):
    # 设定基准
    set_benchmark('000300.XSHG')
    # 开开启真实价格
    set_option('use_real_price', True)
    
    # 第二步:准备计算参数
    # 设定要计算的股票列表
    securities = ['000001.XSHE', '000002.XSHE', '600000.XSHG']
    
    # 设定计算的时间段
    # 注意:在回测中,end_date 不应超过 context.current_dt,避免未来函数
    start_date = '2023-01-01'
    end_date = '2023-01-15'
    
    # 第三步:调用 calc_factors 进行批量计算
    # 参数说明:
    # securities: 股票池
    # factors: 因子实例列表,这里实例化了上面定义的 MeanPrice5
    # start_date, end_date: 计算区间
    print("开始计算因子...")
    
    factors_result = calc_factors(
        securities=securities,
        factors=[MeanPrice5()],
        start_date=start_date,
        end_date=end_date,
        use_real_price=True, # 使用真实价格(复权后)
        skip_paused=False    # 是否跳过停牌
    )
    
    # 第四步:获取和使用结果
    # calc_factors 返回一个字典,key是因子名称,value是DataFrame
    factor_df = factors_result['mean_price_5']
    
    print("因子计算完成,结果如下:")
    print(factor_df)
    
    # 示例:打印 000001.XSHE 在这段时间内的因子值
    if '000001.XSHE' in factor_df.columns:
        print("\n平安银行(000001.XSHE)的5日均价因子值:")
        print(factor_df['000001.XSHE'])

def handle_data(context, data):
    pass

关键点说明

  1. calc_factors 函数

    • 这是核心API。它返回一个字典,键(Key)是你在因子类中定义的 name,值(Value)是一个 pandas.DataFrame
    • 返回的 DataFrame 中,Index(行索引)是日期,Columns(列索引)是股票代码
  2. Factor 类定义

    • max_window:非常重要。它决定了 calc 方法中 data 参数包含的历史数据长度。例如计算5日均线,max_window 必须至少为 5。
    • dependencies:定义需要哪些基础数据(如 close, open, volume, money 等,也可以是财务数据字段)。
    • calc 方法:接收的 data 参数包含了 max_window 长度的历史数据。你需要在这里编写逻辑,返回一个 Series(索引为股票代码,值为因子值)。calc_factors 会自动按天滚动调用这个方法来生成最终的时间序列 DataFrame。
  3. 注意事项

    • 未来函数:在回测环境中使用时,请确保 end_date 不要超过当前回测时间 context.current_dt,否则可能引入未来数据。
    • 性能calc_factors 适合批量计算。如果只是在 handle_data 中需要当天的因子值,直接使用 data 获取历史数据计算可能更轻量;但如果需要历史序列分析,calc_factors 是最佳选择。

Q&A

Q: calc_factors 返回的数据结构是什么样的?
A: 它返回一个字典(dict)。字典的 Key 是因子类中定义的 name 属性值,Value 是一个 pandas DataFrame。该 DataFrame 的行索引(Index)是日期,列索引(Columns)是股票代码,单元格内的值是对应的因子值。

Q: 在 calc 方法中可以使用财务数据吗?
A: 可以。在 dependencies 列表中添加财务字段名称即可(例如 total_operating_revenue)。系统会自动匹配对应日期可获取的最新财报数据(Point-in-time),避免未来函数。

Q: max_window 设置为 1 会发生什么?
A: 如果 max_window=1calc 方法中接收到的 data 将只包含当天的 1 行数据。此时在 calc 内部进行计算时(如求均值),通常需要先将 DataFrame 转换为 Series 或直接取值。

Q: 可以在 handle_data 中每天调用 calc_factors 吗?
A: 技术上可以,但不推荐。calc_factors 设计用于批量计算一段时间的数据,开销较大。如果在 handle_data(按天或按分钟运行)中调用,建议只计算当前时间点的数据,或者直接使用 attribute_history 获取数据后手动计算,效率会更高。