问题描述
为什么在模拟交易模块中使用get_history函数报错或无法获取数据?
解决方案
在 ptrade 平台中,get_history 函数在回测、交易(包含模拟交易和实盘交易)、研究模块中均是可用的。如果您在模拟交易模块中使用该函数时遇到报错或无法获取数据(返回空值)的情况,通常是由以下几个常见原因导致的:
1. 多线程并发调用冲突(最常见导致数据为空的原因)
原因分析:根据 ptrade 官方 API 文档说明,get_history 接口与 get_price 接口不支持多线程同时调用。如果您在 run_daily 或 run_interval 等定时/周期函数中,与 handle_data 等框架模块在同一时刻调用了 get_history 或 get_price 接口,会偶现获取数据为空的现象。
解决方法:错开调用时间。例如,不要将 run_daily 的执行时间设置在刚好触发 handle_data 的整分钟时刻,或者在代码逻辑中加入状态锁,避免并发请求行情数据。
2. 单只股票与多只股票的入参格式错误导致解析报错
原因分析:get_history 的返回值结构会根据 security_list 参数的类型发生变化:
- 单只股票:必须传入字符串类型(如
security_list='600570.SS')。此时返回的 DataFrame 列索引是行情字段(如 'open', 'close')。 - 多只股票:必须传入列表类型。注意:即使列表中只有一只股票(如
security_list=['600570.SS']),系统也会将其作为多股票处理。在 Python 3.11 环境下,返回的 DataFrame 会多出一列code;在 Python 3.5 环境下,可能会返回 Panel 对象或列索引为股票代码的 DataFrame。
解决方法:严格区分单只股票和多只股票的传参方式,并根据返回的数据结构(DataFrame 或 dict)正确解析数据。建议开启is_dict=True参数,返回字典格式取数速度相对较快且结构稳定。
3. 未指定 security_list 且未设置全局股票池
原因分析:当调用 get_history 时,如果 security_list=None(默认值),系统会默认获取上下文 universe 中选中的所有股票数据。如果您的策略在 initialize 中没有调用 set_universe() 设置股票池,将无法获取到数据。
解决方法:在 initialize 中使用 set_universe() 设置股票池,或者在调用 get_history 时明确传入 security_list 参数。
4. 获取了 2005 年以前的数据
原因分析:API 限制 get_history 只能获取 2005 年之后的数据。如果请求的时间范围超出此限制,可能会报错或返回空。
正确调用示例
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
# 推荐用法:明确传入单只股票字符串,并使用 is_dict=True 提高速度
his_dict = get_history(5, '1d', 'close', security_list=g.security, is_dict=True)
if his_dict and g.security in his_dict:
# 解析字典数据
close_data = his_dict[g.security]
log.info('获取到的历史收盘价数据: %s' % close_data)
else:
log.error('未获取到历史数据')
总结:在模拟交易中,请重点排查是否在 run_interval 和 handle_data 中同时请求了历史数据,并检查 security_list 的参数类型是否与您的解析逻辑匹配。