问题描述
请问为什么我看广场上大部分策略都是用的get_price或者attribute_history,为什么很少用get_bars的,一直没搞明白。是运行的速度问题吗? 有什么区别或者注意点吗?求教
解决方案
在 JoinQuant(聚宽)平台上,获取历史行情数据是最基础也是最频繁的操作。你观察到的现象非常准确:广场上的开源策略确实绝大多数都在使用 get_price 或 attribute_history,而较少使用 get_bars。这并非单纯因为速度问题,而是由历史习惯、停牌处理机制、返回值格式以及适用场景等多方面因素决定的。
下面我们来深度剖析这三个函数的区别和注意点:
1. 三大函数的核心区别
attribute_history(回测/模拟专用)
- 定位:专门用于在
handle_data等周期运行函数中获取单个标的的过去 N 个周期的历史数据。 - 防未来函数:它严格不包含当前周期的数据(例如按天回测时,拿不到当天的收盘价),这能有效防止新手引入未来函数。
- 停牌处理:默认
skip_paused=True(跳过停牌日)。 - 返回值:默认返回 Pandas DataFrame。
get_price(全局通用)
- 定位:最通用的历史数据获取接口,支持单个或多个标的,可以在研究环境和回测环境中使用。
- 停牌处理:默认
skip_paused=False,即不跳过停牌日,停牌期间的数据会用停牌前最后一个交易日的数据进行填充。这在处理多只股票的截面数据时非常关键,能保证所有股票的时间轴(Index)是对齐的。 - 返回值:默认返回 Pandas DataFrame(多标的时建议设置
panel=False返回等效的 DataFrame)。
get_bars(偏底层、高性能)
- 定位:获取各种时间周期的 bar 数据,支持标准和非标准 bar,且支持获取当前未结束的 bar 数据(通过
include_now=True)。 - 停牌处理:没有跳过停牌选项。它获取的数据完全不包含停牌日。如果请求过去 5 个 bar,而该股票最近停牌了 2 天,它会一直往前找,直到凑齐 5 个实际交易的 bar(如果总数不够则返回实际个数,不填充)。
- 返回值:默认返回
numpy.ndarray(也可以设置df=True返回 DataFrame)。
2. 为什么大家很少用 get_bars?
主要有以下几个原因:
原因一:停牌处理机制导致的数据对齐问题(最核心原因)
在量化选股(多标的)策略中,我们通常需要获取一个股票池在同一时间段的数据。如果使用 get_price,停牌的股票会被前值填充,返回的 DataFrame 形状是规整的(例如 100只股票 * 5天)。
但如果使用 get_bars,由于它不填充停牌数据,导致不同股票返回的数据时间轴可能完全不一致。比如 A 股票返回的是过去 5 天的数据,B 股票因为停牌,返回的可能是过去 7 天中交易的 5 天的数据。这给后续的矩阵运算(如 Pandas 的截面计算)带来了极大的麻烦。
原因二:历史习惯与教程引导
get_price 和 attribute_history 是聚宽平台最早提供的一批 API,官方的早期教程、示例代码以及社区里积累的经典策略(如双均线、小市值等)几乎全部基于这两个函数。后来的用户在学习和复制策略时,自然就沿用了下来。
原因三:数据格式偏好
get_bars 默认返回 numpy.ndarray。虽然 Numpy 数组在计算速度上远超 Pandas DataFrame,但对于大部分非高频的日频/分钟频策略来说,Pandas 提供的 mean(), shift(), rolling() 等内置方法太方便了。为了开发效率,大家更愿意牺牲一点点性能去使用返回 DataFrame 的 get_price。
3. 运行速度对比
如果是追求极致速度,get_bars(返回 numpy 数组)是最快的。
get_price和attribute_history在底层需要将数据组装成 Pandas DataFrame,这个过程在频繁调用时(例如在分钟级回测的handle_data中每次都调用)会产生较大的性能开销。- 如果你在跑分钟级甚至 Tick 级的策略,且对回测速度要求极高,强烈建议改用
get_bars并直接处理 numpy 数组。
4. 总结与使用建议
| 函数 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
attribute_history |
回测中获取单只股票的历史指标(如计算均线)。 | 防未来函数,调用简单。 | 只能查单只股票,速度一般。 |
get_price |
研究环境数据分析、回测中获取多只股票的截面数据。 | 支持停牌填充,数据对齐完美,返回 DataFrame 易处理。 | 频繁调用时 DataFrame 组装耗时较长。 |
get_bars |
高频策略、需要获取当前 Bar 快照、对运行速度要求极高的场景。 | 速度极快,支持 include_now。 |
停牌不对齐,处理 numpy 数组门槛稍高。 |
最终建议:
- 新手/日频策略/多股截面策略:无脑使用
get_price(多标的)或attribute_history(单标的),开发效率最高,坑最少。 - 老手/高频策略/需要当前快照:使用
get_bars,享受 Numpy 带来的性能飞跃,但要自己写代码处理好停牌和数据对齐的问题。