🚀 AI 一键生成 ptrade 策略代码

ptrade 平台调用 get_fundamentals 返回 NaN 怎么办?

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

问题描述

get_fundamentals获取无数据返回

get_fundamentals(g.stock_list, 'profit_ability', 'roic', context.previous_date)返回nan。

解决方案

在 ptrade 量化平台中,调用 get_fundamentals 获取财务数据时返回 NaN,通常是由以下几个原因导致的。针对您使用的代码 get_fundamentals(g.stock_list, 'profit_ability', 'roic', context.previous_date),我们可以从以下几个方面进行排查和优化:

1. 传入的日期(date)为非交易日

原因分析:根据 ptrade 官方 API 文档,在回测和交易环境中,如果 date 参数传入的是非交易日(例如周末或法定节假日),接口将直接返回 NaN。虽然 context.previous_date 表示前一天,但如果今天是周一,context.previous_date 就是周日(非交易日),从而导致获取不到数据。

解决方法:使用 get_trading_day(-1) 来获取严格意义上的上一个交易日,而不是自然日的前一天。

2. 触发了 API 的流控限制或网络拥堵

原因分析get_fundamentals 是通过 HTTP 在线获取数据的。官方文档明确指出,该接口有流量限制:每秒不得调用超过100次,单次最大调用量是500条数据(一条数据 = 一个股票 + 一个表的一个字段)。如果您的 g.stock_list 包含大量股票,或者在短时间内频繁调用,可能会因为触发流控或网络拥堵而导致应答失败,返回空值或 NaN

解决方法:对长列表进行分批查询,并在代码中加入 time.sleep() 以及异常重试机制。

3. 股票代码格式不正确或确实无数据

原因分析

  • 确保 g.stock_list 中的股票代码带有正确的后缀(如 '600570.SS''000001.SZ')。
  • 某些新上市的股票,或者在指定日期尚未发布相关财务报表的股票,其对应的财务字段本身就是缺失的,系统会用 NaN 填充。

优化后的代码示例

为了解决上述问题,建议对您的代码进行如下改造,加入交易日判断分批获取重试机制

import time
import pandas as pd

def get_financial_data_safe(stock_list, table, fields, retries=3):
    # 1. 获取上一个有效的交易日,避免传入周末或节假日
    # get_trading_day(-1) 返回的是 datetime.date 对象,符合 get_fundamentals 的要求
    last_trade_date = get_trading_day(-1)
    
    # 2. 为了防止单次请求超过 500 条数据的限制,对股票列表进行分批(假设每次查100只)
    batch_size = 100
    result_df = pd.DataFrame()
    
    for i in range(0, len(stock_list), batch_size):
        batch_stocks = stock_list[i:i+batch_size]
        
        # 3. 加入重试机制,应对网络拥堵
        for attempt in range(retries):
            try:
                # 调用接口获取数据
                df = get_fundamentals(
                    security=batch_stocks, 
                    table=table, 
                    fields=fields, 
                    date=last_trade_date
                )
                
                if df is not None and not df.empty:
                    result_df = pd.concat([result_df, df])
                    break  # 成功获取则跳出重试循环
                else:
                    log.warning(f"第 {attempt+1} 次获取为空,正在重试...")
                    time.sleep(1)
            except Exception as e:
                log.error(f"获取财务数据发生异常: {e}")
                time.sleep(1)
                
        # 批次之间稍微休眠,防止触发每秒100次的流控
        time.sleep(0.5)
        
    return result_df

# 在 handle_data 或 before_trading_start 中调用:
# roic_data = get_financial_data_safe(g.stock_list, 'profit_ability', 'roic')
# log.info(roic_data)

总结建议

  1. 永远使用 get_trading_day(-1) 替代 context.previous_date 作为财务数据的查询日期。
  2. 注意数据清洗:即使成功获取到数据,部分股票仍可能因为未披露财报而存在 NaN,在使用数据前建议使用 df.dropna()df.fillna() 进行数据清洗。
  3. 注意未来函数:在研究或交易环境中,如果不传入 date 参数,默认会获取当天的最新数据;在回测中,为了避免未来函数,强烈建议显式传入上一个交易日的日期。