问题描述
解决方案
在 JoinQuant(聚宽)平台中,获取股票过去 3 天的成交量加权平均价(VWAP)主要有两种方式:一种是直接使用 data 对象自带的便捷方法,另一种是通过获取历史行情数据手动计算。
以下是具体的实现方法和代码示例。
方法一:使用 data 对象的内置方法(推荐)
在 handle_data 函数中,data 参数(即 SecurityUnitData 对象)提供了一个直接计算 VWAP 的方法 .vwap(days)。
- 语法:
data[security].vwap(3) - 说明:计算过去 3 天(不包含当前分钟/当前天)的加权平均价。
方法二:使用 attribute_history 手动计算
如果你需要在 handle_data 之外的地方(如 before_trading_start)计算,或者需要更灵活的控制,可以使用 attribute_history 获取过去的成交额(money)和成交量(volume)进行计算。
- 公式:$\text{VWAP} = \frac{\sum(\text{成交额})}{\sum(\text{成交量})}$
- 代码逻辑:
- 获取过去 3 天的
money和volume数据。 - 将 3 天的
money求和。 - 将 3 天的
volume求和。 - 两者相除得到 VWAP。
- 获取过去 3 天的
完整策略代码示例
以下代码展示了如何在策略中同时使用这两种方法获取 VWAP:
# -*- coding: utf-8 -*-
def initialize(context):
# 设定要操作的股票,例如平安银行
g.security = '000001.XSHE'
# 设定基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 按天回测时,每天调用一次 handle_data
run_daily(handle_data, time='every_bar')
def handle_data(context, data):
security = g.security
# -------------------------------------------------------
# 方法一:使用 data 对象内置的 vwap 方法 (最简单)
# -------------------------------------------------------
# 获取过去3天的VWAP
vwap_builtin = data[security].vwap(3)
log.info("内置方法获取的3日VWAP: %.2f" % vwap_builtin)
# -------------------------------------------------------
# 方法二:使用 attribute_history 手动计算 (更通用)
# -------------------------------------------------------
# 获取过去3天的成交额(money)和成交量(volume)
# 注意:'1d'代表日频数据,skip_paused=True跳过停牌
his = attribute_history(security, 3, '1d', ['money', 'volume'], skip_paused=True)
# 计算总成交额和总成交量
total_money = his['money'].sum()
total_volume = his['volume'].sum()
# 计算 VWAP
if total_volume > 0:
vwap_manual = total_money / total_volume
else:
vwap_manual = 0
log.info("手动计算获取的3日VWAP: %.2f" % vwap_manual)
# -------------------------------------------------------
# 验证两者是否一致
# -------------------------------------------------------
# 注意:由于浮点数精度问题,可能会有微小差异
log.info("两者差值: %.6f" % (vwap_builtin - vwap_manual))
关键点说明
-
数据包含范围:
data[security].vwap(3)和attribute_history(..., 3, ...)获取的都是过去 3 个交易日的数据,不包含回测当天的实时数据。- 例如,如果在 2023-10-20 日运行策略,获取的是 10-17、10-18、10-19 这三天的数据。
-
复权影响:
- 建议在
initialize中设置set_option('use_real_price', True)。这样获取到的价格和成交量是真实发生的数据(动态复权),计算出的 VWAP 更符合实际交易逻辑。
- 建议在
-
停牌处理:
attribute_history默认skip_paused=True,会自动跳过停牌日期向前查找,确保获取的是有交易的 3 天。- 内置的
.vwap()方法也会自动处理停牌数据。
Q&A
Q: data[security].vwap(n) 包含当天的数据吗?
A: 不包含。在日级回测或分钟级回测中,该函数获取的是过去 n 天的数据。如果需要包含当天的实时 VWAP,需要获取当天的 tick 或分钟数据自行累加计算。
Q: 为什么手动计算的 VWAP 和行情软件上的均价线数值不一样?
A: 可能有两个原因:
- 复权问题:聚宽默认提供前复权数据,如果未开启
use_real_price,计算的是复权后的 VWAP。 - 时间窗口:行情软件上的均价线通常是指“当日的分时均价”(即当天的 VWAP),而上述代码计算的是“过去 N 天的历史 VWAP”。
Q: 如果过去 3 天内有停牌怎么办?
A: 聚宽的 API(如 attribute_history)通常带有 skip_paused 参数(默认为 True)。如果过去 3 个自然日内有停牌,系统会自动向前寻找最近的有效交易日,凑齐 3 个有交易数据的日子来计算。