🚀 AI 一键生成 ptrade 策略代码

PTrade 数据处理:get_history 接口的缺失值填充策略

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

问题描述

获取历史行情时,如果遇到停牌数据是 NaN,怎么自动用上一条数据填充?

解决方案

在 PTrade 量化交易平台中,处理历史行情数据(get_historyget_price)中的 NaN(空值)通常有两种方式:利用 API 自带参数或使用 Pandas 的填充方法。

虽然 PTrade 文档说明在停牌场景下,get_history 通常会自动使用停牌前的数据填充价格(成交量为0),但在某些特定数据缺失或分钟级回测场景下,依然可能出现 NaN

最稳健且通用的方法是利用 Pandas DataFrame 的 fillna 函数 进行向前填充(Forward Fill)。

核心解决方案

使用 Pandas 的 fillna(method='ffill') 方法。这会将上一个非空值赋给当前的 NaN 位置,非常适合处理停牌或数据缺失的情况。

策略代码示例

以下是一个完整的策略示例,展示了如何获取历史数据并清洗 NaN 值:

def initialize(context):
    # 设置股票池,这里以恒生电子为例
    g.security = '600570.SS'
    set_universe(g.security)

def handle_data(context, data):
    # 1. 获取历史行情数据
    # 获取过去 100 天的收盘价
    # 注意:PTrade 文档指出停牌通常会自动填充价格,但为了保险起见或处理其他缺失,我们手动处理
    df = get_history(100, frequency='1d', field=['close', 'volume'], security_list=g.security)
    
    # 打印处理前的数据情况(调试用)
    # log.info("处理前是否存在空值: %s" % df.isnull().values.any())
    
    # 2. 使用 Pandas 的 fillna 进行向前填充
    # method='ffill' 表示用前一条数据填充当前空值 (Forward Fill)
    # inplace=True 表示直接在原 DataFrame 上修改,不创建新对象
    df.fillna(method='ffill', inplace=True)
    
    # 3. 处理上市初期可能存在的 NaN
    # 如果数据开头就是 NaN(因为前面没有数据可供填充),可以用 0 或其他特定值填充
    df.fillna(0, inplace=True)
    
    # 打印处理后的数据
    # log.info("处理后是否存在空值: %s" % df.isnull().values.any())
    
    # 4. 基于清洗后的数据计算指标(例如计算均线)
    close_prices = df['close']
    if len(close_prices) >= 5:
        ma5 = close_prices[-5:].mean()
        log.info("5日均线价格: %.2f" % ma5)
        
    # 简单的交易逻辑示例
    current_price = data[g.security]['close']
    if current_price > ma5:
        order(g.security, 100)

详细说明

1. Pandas fillna(method='ffill')

这是处理时间序列数据中最常用的方法。

  • 原理:如果 T 时刻的数据是 NaN,它会查找 T-1 时刻的数据来填充。如果 T-1 也是 NaN,则继续向前查找 T-2,直到找到有效值为止。
  • 适用性:适用于所有通过 get_historyget_price 返回的 DataFrame 格式数据。

2. PTrade API 的 fill 参数

get_history 函数本身提供了一个 fill 参数:

  • fill='pre':用上一分钟数据填充。
  • fill='nan':用 NaN 填充(默认)。
  • 局限性:文档指出该参数仅在交易模块有效(实盘或模拟盘),且主要针对分钟级数据的某一时刻缺失。在回测模式下,建议使用 Pandas 方法以保证逻辑的一致性。

3. 关于停牌数据的特别说明

根据 PTrade 文档:

  • 价格(Open/High/Low/Close):停牌期间,系统通常会自动使用停牌前一交易日的收盘价进行填充。
  • 成交量(Volume):停牌期间成交量为 0。
  • 如果你在计算技术指标(如 MA、MACD)时遇到报错,通常是因为数据长度不足或上市初期的空值,而非中间的停牌空值。使用 df.fillna(method='ffill').fillna(0) 是一套完整的防御性编程写法。

Q&A

Q: 为什么 get_history 获取的数据会有 NaN?
A: 除了停牌,新股上市初期的日期(如果请求的时间范围早于上市日期)也会导致 NaN。此外,某些非活跃标的在分钟级别可能没有成交,导致特定分钟数据缺失。

Q: fillna(0)fillna(method='ffill') 有什么区别?
A: fillna(0) 会将所有空值变成 0,这对于价格数据(Price)是不合理的(价格突然变成0会严重扭曲均线计算)。fillna(method='ffill') 是用前值填充,保持了价格的连续性,更符合金融时间序列的逻辑。通常先用 ffill 处理中间的空缺,再用 0 处理最开始无法填充的部分。

Q: 在回测和实盘中,处理 NaN 的方式需要不同吗?
A: 建议保持一致。虽然实盘 API 提供了 fill='pre' 参数,但在代码层面统一使用 Pandas 的 fillna 可以确保你的策略在回测和实盘中表现一致,减少因环境差异导致的 Bug。