🚀 AI 一键生成 ptrade 策略代码
立即体验

ptrade 性能调优:如何利用 get_history 的 is_dict=True 参数实现超大数据量极速读取?

ptrade | 发布时间: 2026/8/7
以下内容由 EasyQuant 生成。

问题描述

ptrade 性能调优:利用 get_history 的 is_dict=True 参数实现超大数据量极速读取
如何优化 ptrade 行情获取速度?get_history 的 is_dict 参数在读取大量股票数据时该如何使用?

解决方案

ptrade 性能调优:利用 get_history 的 is_dict=True 实现超大数据量极速读取

在 ptrade 中进行多因子选股或全市场回测时,获取历史行情数据(如 get_historyget_price)往往是策略运行的性能瓶颈。默认情况下,这些接口返回的是 pandas.DataFramepandas.Panel 对象。虽然 Pandas 对象便于数据分析,但在处理数百只甚至数千只股票的大数据量时,Pandas 对象的构建和转换会消耗大量的 CPU 时间和内存。

为了解决这一痛点,ptrade 提供了 is_dict=True 参数。通过启用该参数,API 将直接返回原生 Python 字典(OrderedDict)和 numpy.ndarray,从而绕过 Pandas 的封装开销,实现极速数据读取


一、 为什么 is_dict=True 能大幅提升速度?

  1. 避免 Pandas 封装开销:Pandas DataFrame 在构建时需要进行索引对齐、类型推导等操作,而 is_dict=True 直接返回底层的 NumPy 数组,省去了这些繁重的转换步骤。
  2. 内存占用更小:NumPy 结构化数组(Structured Array)在内存中是连续存储的,相比 DataFrame 占用更少的内存,减少了垃圾回收(GC)的压力。
  3. 更快的遍历与检索:在字典中通过 Key(股票代码)检索数据的复杂度为 $O(1)$,在大股票池下比 DataFrame 的查询效率高出数倍。

二、 get_history 开启 is_dict=True 后的数据结构

当设置 is_dict=True 时,get_history 返回一个 OrderedDict,其结构如下:

OrderedDict([
    ('股票代码', array([(时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量, 成交额, 最新价)], 
                     dtype={'names': ['datetime', 'open', 'high', 'low', 'close', 'volume', 'money', 'price'], 
                            'formats': ['i8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8']}))
])

示例数据格式:

OrderedDict([
    ('000001.SZ', array([(202309220931, 11.03, 11.08, 11.03, 11.07, 2289400.0, 25302018.0, 11.07)], 
                        dtype=[('datetime', '<i8'), ('open', '<f8'), ('close', '<f8'), ...]))
])

三、 实战代码示例

以下是一个完整的 ptrade 策略示例,展示了如何使用 is_dict=True 获取全市场(或大批量)股票的历史收盘价,并计算 5 日均线。

def initialize(context):
    # 设置测试股票池(例如沪深300成分股)
    g.security_list = get_index_stocks('000300.XBHS')
    set_universe(g.security_list)

def handle_data(context, data):
    # 1. 开启 is_dict=True 获取过去5天的日线数据
    # 此时返回的是 OrderedDict,速度极快
    history_dict = get_history(
        count=5, 
        frequency='1d', 
        field=['close'], 
        security_list=g.security_list, 
        is_dict=True
    )
    
    if history_dict is None:
        log.error("获取行情数据失败")
        return
        
    # 2. 极速遍历并计算均值
    for security in g.security_list:
        if security in history_dict:
            # 获取该股票的 numpy array
            stock_data = history_dict[security]
            
            # 提取 close 字段的所有值
            close_prices = stock_data['close']
            
            # 计算5日均价
            if len(close_prices) >= 5:
                ma5 = close_prices[-5:].mean()
                # 打印部分日志展示结果
                if security == g.security_list[0]:
                    log.info(f"{security} 的 5日均价为: {ma5:.2f}")

四、 性能调优进阶建议

除了 get_history 之外,ptrade 的其他高频/大数据量接口也支持 is_dict 参数,建议在编写高频或 Tick 级策略时统一开启:

  1. L2 逐笔委托与成交

    • get_individual_entrust(..., is_dict=True)
    • get_individual_transaction(..., is_dict=True)
    • 注意:在获取股票数很多(>200只)的 L2 逐笔数据时,强烈建议使用 is_dict=True,否则返回的 DataFrame 可能会因为转换超时而返回 None
  2. 避免多线程冲突

    • get_historyget_price 接口不支持多线程同时调用。请避免在 run_dailyrun_interval 等定时任务中,与 handle_data 框架模块在同一时刻并发调用这两个接口,否则可能会偶现获取数据为空的现象。