🚀 AI 一键生成 joinquant 策略代码

JoinQuant 中如何让 history 函数返回字典而非 DataFrame 以提升速度?

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

问题描述

策略运行速度太慢,history 函数能不能不返回 DataFrame 直接返回数组或字典?

解决方案

是的,history 函数可以通过设置参数直接返回字典(包含 numpy.ndarray),从而避免创建 DataFrame 带来的性能开销。

在 JoinQuant API 中,pandas.DataFrame 的创建和操作相对较慢。如果您的策略需要频繁调用 history 获取数据,建议将 df 参数设置为 False

解决方法

在调用 history 函数时,添加参数 df=False

  • 默认情况 (df=True):返回 pandas.DataFrame,索引为时间,列为股票代码。
  • 优化后 (df=False):返回一个 字典 (dict)
    • Key:股票代码(str)。
    • Valuenumpy.ndarray 数组,对应请求的字段数据。

代码示例

以下代码展示了如何使用 df=False 以及如何访问返回的数据:

# -*- coding: utf-8 -*-
def handle_data(context, data):
    # 设定要获取的股票列表
    security_list = ['000001.XSHE', '000002.XSHE']
    
    # 1. 获取数据:设置 df=False
    # 获取过去5天的收盘价,返回字典格式
    h = history(5, unit='1d', field='close', security_list=security_list, df=False)
    
    # 2. 访问数据
    # h 的结构类似于:
    # {
    #   '000001.XSHE': array([10.1, 10.2, 10.1, 10.3, 10.4]), 
    #   '000002.XSHE': array([8.5, 8.6, 8.5, 8.7, 8.8])
    # }
    
    for stock in security_list:
        # 获取该股票对应的 numpy 数组
        prices = h[stock]
        
        # 获取最新一个收盘价 (数组的最后一个元素)
        current_close = prices[-1]
        
        # 计算平均值 (使用 numpy 的方法,而不是 pandas 的 .mean())
        avg_price = prices.mean()
        
        # 打印结果
        print("股票: %s, 最新价: %f, 均价: %f" % (stock, current_close, avg_price))

注意事项

  1. 方法变更:当 df=False 时,返回的是 numpy 数组,因此不能使用 pandas 的特有方法(如 .iloc, .loc, .rolling() 等)。您需要使用 Python 原生的列表切片(如 [-1])或 numpy 的计算函数(如 .mean(), .sum())。
  2. attribute_history:同样的优化也适用于 attribute_history 函数,它也支持 df=False 参数。
  3. get_bars:如果您需要获取更大量的数据或更灵活的字段,也可以考虑使用 get_bars,它默认返回 numpy 结构(当 df=False 时),通常比 history 更高效。

Q&A

Q: 为什么 DataFrame 会比 numpy 数组慢?
A: Pandas DataFrame 是建立在 Numpy 之上的高级数据结构,提供了丰富的索引和数据对齐功能。在创建 DataFrame 时,系统需要进行额外的索引构建、数据校验和内存分配,这在循环高频调用时会产生显著的累积开销。而 Numpy 数组是底层的数值矩阵,结构简单,内存连续,计算效率极高。

Q: attribute_history 函数也可以这样优化吗?
A: 是的。attribute_history(security, count, unit='1d', fields=..., df=False) 同样支持该参数。当 df=False 时,它返回一个字典,Key 是字段名(如 'open', 'close'),Value 是 Numpy 数组。

Q: 如果我必须使用 DataFrame 的某些功能(如 rolling),该怎么办?
A: 如果必须使用 DataFrame 的特定功能,建议尽量减少调用 history 的次数。例如,不要在循环内部反复获取数据,而是一次性获取所有股票的数据(history 支持传入股票列表),然后在循环外处理,或者仅在必要计算指标时才转换为 DataFrame。

Q: get_barshistory 在速度上有什么区别?
A: get_bars 是较新的 API,设计上更高效。它默认返回 numpy array (当 df=False)。对于获取大量历史数据,get_bars 通常比 history 更快,且支持获取包含当前时刻的数据 (include_now 参数)。