问题描述
/
解决方案
问题原因分析
在 ptrade 量化平台中使用 get_fundamentals 获取财务数据时,如果遇到数据为空或报错“获取GTN数据为空!”,通常是由以下几个原因导致的:
- 网络拥堵或请求超时:
get_fundamentals接口底层为 HTTP 在线获取,在交易时段网络拥堵时,极易出现应答失败或返回空数据的情况。 - 触发了 API 流量限制(流控):官方文档明确指出,该接口有严格的流量限制:每秒不得调用超过100次,单次最大调用量是500条数据(一条数据 = 一个股票 + 一个表 + 一个字段)。如果循环调用过快或单次请求数据量过大,会被服务器拒绝。
- 参数组合冲突:
date字段与start_year/end_year不能同时输入。如果同时传入,会导致查询逻辑混乱,返回空值。 - 数据尚未发布(未来函数规避):如果在盘中时间获取当天的财务数据,由于数据尚未更新,可能会返回 NaN。建议在获取最新数据时,将
date参数设置为上一个交易日。
解决方案与优化建议
针对上述原因,可以通过在策略代码中增加保护机制和限流控制来彻底解决此问题。
1. 增加异常重试机制
由于网络原因导致的偶发性获取失败,可以通过编写一个带有重试机制的封装函数来解决。如果返回为空,则等待短暂时间后重试。
2. 加入休眠 (Sleep) 规避限流
在进行多股、多字段或多时间段的批量查询时,务必在两次调用之间加入 time.sleep(),防止触发每秒 100 次的流控限制。
3. 检查参数规范
确保查询模式单一:要么使用 date 按日期查询,要么使用 start_year 和 end_year 按年份查询。
优化后的代码示例
以下是一个封装好的、带有重试机制和防流控的财务数据获取函数示例:
import time
def get_fundamentals_safe(security, table, fields=None, date=None, max_retries=3):
"""
安全获取财务数据,包含重试机制和防流控休眠
"""
for attempt in range(max_retries):
try:
# 调用官方接口
data = get_fundamentals(security, table, fields=fields, date=date)
# 检查数据是否为空
if data is not None and not data.empty:
return data
else:
log.warning(f"第 {attempt + 1} 次获取 {security} 的 {table} 数据为空,准备重试...")
except Exception as e:
log.error(f"第 {attempt + 1} 次获取财务数据发生异常: {e}")
# 触发流控或网络异常时,休眠后重试 (递增休眠时间)
time.sleep(1 + attempt)
log.error(f"已达到最大重试次数 {max_retries},获取 {security} 财务数据失败!")
return None
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def before_trading_start(context, data):
# 建议获取前一交易日的数据,避免当天数据未更新
pre_date = get_trading_day(-1).strftime('%Y%m%d')
# 使用安全封装函数获取资产负债表数据
funda_data = get_fundamentals_safe(g.security, 'balance_statement', fields='total_assets', date=pre_date)
if funda_data is not None:
log.info("成功获取财务数据:\n%s" % funda_data)
else:
log.error("未能获取到财务数据,请检查网络或参数。")
def handle_data(context, data):
pass
总结
在 ptrade 中调用 HTTP 类的在线数据接口(如 get_fundamentals)时,**“防御性编程”**是必不可少的。通过加入 try-except 异常捕获、time.sleep() 延时以及多次重试逻辑,可以有效避免因“获取GTN数据为空”导致的策略中断。