🚀 AI 一键生成 ptrade 策略代码

ptrade 策略回测报错:get_fundamentals 获取 pe_ttm 返回 NaN 怎么办?

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

问题描述

get_fundamentals的date参数 非交易日的值为空?

回测的时候报错“UnboundLocalError: local variable 'int_LabelPettm' referenced before assignment”。 其中'int_LabelPettm'是我自定义的变量,用于存储对滚动市盈率的判断分类结果。

同样的代码,平时不论是交易模式还是回测模式都正常,怎么今天突然就歇菜了?经反复排查,发现是get_fundamentals返回了空值的缘故。

对应代码:

df_valuation = get_fundamentals(security, 'valuation', date = None, fields = ['pe_ttm'])#获取当前的市盈率,返回DataFrame数据
int_pettm = df_valuation.loc[security,'pe_ttm']#读取出数值
if int_pettm > 35 or int_pettm <= 0:
print(security,'PE_TTM=',int_pettm,',大于35或小于等于0,剔除')
int_LabelPettm = 3
AI写代码
python
运行
返回结果:

--> df_valuation =
trading_day pe_ttm total_value
secu_code
300437.SZ NaN NaN NaN

解决方案

问题分析

在 ptrade 平台中,您遇到的 UnboundLocalError 是因为 get_fundamentals 返回了 NaN(空值),导致您的 if 条件判断未能覆盖所有情况,从而使得 int_LabelPettm 变量未被赋值就被引用。

导致 get_fundamentals 返回 NaN 的根本原因在于 valuation(估值数据表)的特殊机制

官方文档说明

根据 ptrade API 文档中关于 valuation 估值数据的说明:

关于 date 字段的说明

  • 场景一:date 字段不入参(即 date=None。回测中默认是获取 context.blotter.current_dt 交易日收盘后更新的数据,因此会产生未来函数,交易和研究会返回当日数据,若在盘中时间由于数据未更新将返回字段为 NAN 的数据,因此建议获取最新数据的场景都使用 date 参数入参上一个交易日日期
  • 场景二:date 字段入参日期。回测和交易中若 date 为非交易日,将返回字段为 NAN 的数据;研究中若 date 为非交易日,将返回往前最近一个交易日的数据。

因此,当您在非交易日运行,或者在数据尚未更新的时间点运行,且 date=None 时,系统就会返回 NaN

解决方案

为了保证策略的健壮性,建议采取以下两步进行优化:

1. 显式传入上一个交易日的日期

不要使用 date=None,而是使用 get_trading_day(-1) 获取上一个确定的交易日,并将其格式化后传入 date 参数。

2. 增加对 NaN 值的异常处理

在读取出数值后,先判断其是否为 NaN,如果是,则赋予一个默认值或直接跳过该标的。

优化后的代码示例

import pandas as pd

def handle_data(context, data):
    security = '300437.SZ'
    
    # 1. 获取上一个交易日,格式化为 YYYYMMDD
    pre_date = get_trading_day(-1).strftime('%Y%m%d')
    
    # 2. 传入确定的交易日日期
    df_valuation = get_fundamentals(security, 'valuation', date=pre_date, fields=['pe_ttm'])
    
    if df_valuation is not None and not df_valuation.empty:
        int_pettm = df_valuation.loc[security, 'pe_ttm']
        
        # 3. 增加对 NaN 的判断
        if pd.isna(int_pettm):
            print(f"{security} PE_TTM 数据为空 (NaN),跳过处理")
            int_LabelPettm = -1 # 赋予一个默认的异常标识
        else:
            if int_pettm > 35 or int_pettm <= 0:
                print(f"{security} PE_TTM={int_pettm},大于35或小于等于0,剔除")
                int_LabelPettm = 3
            else:
                print(f"{security} PE_TTM={int_pettm},符合要求")
                int_LabelPettm = 1 # 正常情况的赋值
                
        # 后续使用 int_LabelPettm 的逻辑...
        print(f"最终分类标签: {int_LabelPettm}")
    else:
        print(f"未能获取到 {security} 的估值数据")

总结

  • 凡是调用 valuation 表,强烈建议 date 参数传入 get_trading_day(-1)
  • 在量化策略中,从 DataFrame 中提取数据后,务必养成使用 pd.isna()math.isnan() 检查空值的习惯,防止因数据源缺失导致策略崩溃。