问题描述
/
解决方案
报错解析
在 ptrade 量化平台进行回测或实盘交易时,出现 IndexError: index out of bounds(索引越界)报错,通常是因为你的代码尝试访问一个列表(List)、数组(Array)或 Pandas DataFrame/Series 中不存在的索引位置。例如,列表只有 3 个元素,你却尝试获取第 5 个元素(list[4])。
ptrade 中常见的触发场景
1. 历史行情数据不足(新股或停牌)
当你使用 get_history 或 get_price 获取过去 N 天的数据,并直接使用固定索引(如 df['close'][-5])时,如果该股票是新股(上市不足 5 天)或长期停牌,返回的数据行数可能小于 5,此时就会触发索引越界。
2. 盘口档位数据缺失
在 tick_data 中获取买卖盘档位数据时(如 data[security]['tick']['bid_grp'][0]),如果遇到涨跌停或流动性极差的标的,某些档位可能没有数据,直接通过索引取值会导致报错。
3. 逐笔数据为空
调用 get_individual_entrust 或 get_individual_transaction 时,如果某只股票当天没有逐笔数据,返回的列表为空,直接取 data[0] 就会报错。
解决办法与代码优化
方案一:增加长度校验(最推荐)
在访问数据索引之前,务必先检查数据的长度(len()),确保数据量满足你的计算需求。
def handle_data(context, data):
security = '600570.SS'
# 获取过去10天的收盘价
df = get_history(10, '1d', 'close', security, fq='pre', include=False)
# 校验数据长度是否足够
if df is not None and len(df) >= 10:
# 安全地获取倒数第10天的价格
past_price = df['close'][-10]
log.info("10天前的价格为: %s" % past_price)
else:
log.warning("%s 历史数据不足10天,跳过计算" % security)
方案二:过滤新股和停牌股
在 before_trading_start 中,提前将上市时间较短的新股或当前处于停牌状态的股票从股票池中剔除。
def before_trading_start(context, data):
# 过滤停牌、ST、退市股票
g.security = filter_stock_by_status(g.security, ["ST", "HALT", "DELISTING"])
# 过滤上市不足90天的新股
valid_stocks = []
stock_info = get_stock_info(g.security, field=['listed_date'])
for stock in g.security:
listed_date = stock_info.get(stock, {}).get('listed_date', '2900-01-01')
# 此处需自行实现日期相减逻辑,若上市天数 > 90 则加入 valid_stocks
# ...
方案三:使用 try...except 异常捕获
对于一些偶发的数据缺失(如 tick 档位缺失),可以使用 Python 的异常处理机制来保证策略不会因为报错而中断。
def tick_data(context, data):
security = '600570.SS'
try:
# 尝试获取买一价
bid_grp = data[security]['tick']['bid_grp']
if 1 in bid_grp:
bid_1_price = bid_grp[1][0]
log.info("买一价: %s" % bid_1_price)
except IndexError as e:
log.error("获取盘口数据索引越界: %s" % e)
except KeyError as e:
log.error("获取盘口数据键值错误: %s" % e)
总结
量化交易中,数据缺失是常态。编写 ptrade 策略时,永远不要假设 API 返回的数据长度是固定的。养成“先校验长度,再索引取值”的习惯,可以有效避免 IndexError,让你的回测和实盘更加稳健。