财务数据调用失败
财务接口(如get_fundamentals)依赖在线调用,瞬时流量过大易失败。
问题描述
解决方案
问题原因分析
在 ptrade 量化平台中,调用 get_fundamentals 接口获取财务数据时,如果遇到调用失败或返回空值(None/空DataFrame),通常是由以下两个原因引起的:
- 网络拥堵与在线获取机制:
get_fundamentals接口底层是通过 HTTP 在线获取数据的。在盘中或回测的密集计算期,网络拥堵可能导致请求超时或应答失败。 - 严格的流量限制(流控):官方文档明确指出,该接口有严格的流量限制:每秒不得调用超过100次,单次最大调用量是500条数据(一条数据定义为一个股票对应一个表的一个字段)。如果策略中存在多股、多字段的循环查询,极易触发流控机制导致获取失败。
解决方案
为了保证策略的健壮性,必须在代码中加入保护机制:
- 加入时间间隔(Sleep):在连续调用财务接口之间,使用
time.sleep()强制暂停,避免触发每秒调用次数限制。 - 增加异常重试机制(Retry):封装一个带有重试逻辑的函数,当返回结果为空或发生异常时,等待片刻后重新发起请求。
最佳实践代码示例
以下是一个封装好的、带有重试机制和防流控延时的财务数据获取函数示例:
import time
import pandas as pd
def get_fundamentals_with_retry(security, table, fields=None, date=None, max_retries=3, sleep_time=1):
'''
带有重试机制的财务数据获取函数
:param security: 股票代码或列表
:param table: 财务表名
:param fields: 字段名
:param date: 查询日期
:param max_retries: 最大重试次数
:param sleep_time: 每次重试前的等待时间(秒)
:return: DataFrame 或 None
'''
for attempt in range(max_retries):
try:
# 调用官方接口
df = get_fundamentals(security, table, fields=fields, date=date)
# 检查返回值是否有效(非空且包含数据)
if df is not None and not df.empty:
return df
else:
log.warning(f'第 {attempt + 1} 次获取财务数据为空,等待重试...')
except Exception as e:
log.error(f'第 {attempt + 1} 次获取财务数据发生异常: {e}')
# 触发重试前等待,防止流控
time.sleep(sleep_time)
log.error('达到最大重试次数,获取财务数据失败!')
return None
def initialize(context):
g.security = ['600570.SS', '000001.SZ']
set_universe(g.security)
def before_trading_start(context, data):
# 使用封装好的函数获取数据
# 假设我们需要获取资产负债表中的总资产
funda_data = get_fundamentals_with_retry(
security=g.security,
table='balance_statement',
fields='total_assets'
)
if funda_data is not None:
log.info('成功获取财务数据:')
log.info(funda_data)
else:
log.error('盘前获取财务数据失败,请检查网络或策略逻辑。')
def handle_data(context, data):
pass
注意事项
- 避免在
handle_data中高频调用:handle_data在分钟或 Tick 级别会频繁触发,强烈建议将财务数据的获取逻辑放在before_trading_start(盘前)或使用run_daily定时获取,并将结果缓存到全局变量g中供盘中调用。 - 批量获取优于循环单只获取:尽量将多只股票代码组成
list一次性传入get_fundamentals,而不是使用for循环单只获取,这样可以大幅减少接口调用次数,降低触发流控的风险(但需注意单次500条数据的上限)。