问题描述
/
解决方案
问题分析
在 ptrade 平台中使用 get_history 获取 5 分钟 (5m) 数据时触发 try...except 报错,通常由以下几个原因引起:
- 接口返回
None导致类型错误 (TypeError):当网络波动、请求过于频繁或底层数据服务异常时,get_history可能会返回None。如果代码中直接对返回值进行切片或属性访问(例如df['close']),就会引发TypeError: 'NoneType' object is not subscriptable。 - 多线程并发调用冲突:官方文档明确指出,
get_history与get_price不支持多线程同时调用。如果在run_interval或run_daily的定时任务中,与handle_data同一时刻调用了该接口,会偶现获取数据为空或报错的现象。 - 返回数据结构解析错误:
get_history在查询单只股票(传入字符串)和多只股票(传入列表)时,返回的数据结构不同(单只返回 DataFrame,多只可能返回 Panel 或包含 code 列的 DataFrame)。如果解析方式与返回结构不匹配,会引发KeyError或AttributeError。 - 参数不合规:请求的
count数量过大,或者请求了上市之前的数据。
解决方案与最佳实践
为了提高策略的健壮性,除了在外围使用 try...except,还需要在内部对返回值进行严格的有效性检查。
1. 增加 None 值和空数据判断
在获取数据后,必须先判断返回值是否为 None,以及是否为空的 DataFrame。
2. 避免并发调用
确保不要在 handle_data (每分钟触发) 和 run_interval (秒级触发) 中同一时刻调用历史数据接口。可以通过设置标志位或错开时间来解决。
3. 健壮的代码示例
以下是一个获取 5m 数据并包含完整异常处理的推荐写法:
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
try:
# 尝试获取过去 10 根 5 分钟 K 线数据
hist_data = get_history(count=10, frequency='5m', field=['close', 'volume'], security_list=g.security)
# 1. 检查返回值是否为 None
if hist_data is None:
log.warning("获取 5m 数据返回 None,跳过本次处理。")
return
# 2. 检查是否为空 DataFrame
if hist_data.empty:
log.warning("获取 5m 数据为空 DataFrame,跳过本次处理。")
return
# 3. 安全地解析数据 (单只股票返回 DataFrame,索引为时间,列为 field)
if 'close' in hist_data.columns:
close_prices = hist_data['close'].values
if len(close_prices) > 0:
latest_close = close_prices[-1]
log.info(f"成功获取 5m 数据,最新收盘价: {latest_close}")
# 在此处编写你的交易逻辑
# if latest_close > xxx:
# order(g.security, 100)
else:
log.warning("close 列数据长度为 0")
else:
log.error("返回的数据中不包含 'close' 列")
except Exception as e:
# 捕获并打印详细的异常信息,便于排查问题
log.error(f"获取 5m 数据时发生异常: {e}")
调试建议
如果报错持续发生,建议在 except Exception as e: 块中打印出具体的异常类型和信息(如上例所示),这将帮助你准确定位是网络超时、数据解析错误还是参数传递问题。