问题描述
解决方案
在 JoinQuant(聚宽)的策略回测框架中,handle_data(context, data) 是核心的策略执行函数。以下是关于 data 参数的详细解释以及如何使用它计算移动平均线的说明。
1. data 参数具体是什么?
data 是一个字典形式的对象(Dictionary-like Object),它包含了当前单位时间(按天回测是前一天,按分钟回测是前一分钟)的行情数据快照。
- 键 (Key):标的代码(例如
'000001.XSHE')。 - 值 (Value):
SecurityUnitData对象。
当你使用 data['000001.XSHE'] 时,你获取的是该标的在当前时间点的 SecurityUnitData 对象。这个对象包含以下常用属性和方法:
- 基本属性:
open,close,high,low,volume,money,high_limit,low_limit,paused等。 - 内置计算方法:
mavg()(移动平均),vwap()(加权平均),stddev()(标准差)。
注意:为了提高回测速度,data 中的数据是按需获取(Lazy Loading)的。只有当你代码中明确调用 data[security] 时,系统才会去获取该标的的数据。
2. 如何使用 data 计算移动平均线?
SecurityUnitData 对象内置了一个便捷方法 mavg,可以直接用来计算移动平均线。
语法:
data[security].mavg(days, field='close')
- days:计算平均线的时间窗口长度(例如 5 表示 5日均线)。
- field:基于哪个字段计算,默认为
'close'(收盘价),也可以是'volume'(成交量)等。
3. 代码示例
下面是一个完整的策略代码示例,展示了如何在 handle_data 中使用 data 参数来获取 5日均线 和 10日均线,并打印出来。
# -*- coding: utf-8 -*-
def initialize(context):
# 定义一个全局变量, 保存要操作的股票
g.security = '000001.XSHE'
# 设置股票池
set_universe([g.security])
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
def handle_data(context, data):
security = g.security
# 1. 获取 SecurityUnitData 对象
# 注意:如果股票停牌或未上市,data[security] 可能无法获取有效数据,建议先检查
if security in data:
stock_data = data[security]
# 2. 使用 .mavg() 方法计算移动平均线
# 计算过去5天的收盘价平均值
ma5 = stock_data.mavg(5, field='close')
# 计算过去10天的收盘价平均值
ma10 = stock_data.mavg(10, field='close')
# 3. 获取当前结束时的收盘价
current_close = stock_data.close
# 打印结果
log.info("股票: %s, 当前价: %.2f, MA5: %.2f, MA10: %.2f" % (security, current_close, ma5, ma10))
# 简单的策略逻辑示例:金叉买入
if ma5 > ma10 and context.portfolio.positions[security].total_amount == 0:
order_value(security, context.portfolio.available_cash)
log.info("金叉买入")
# 死叉卖出
elif ma5 < ma10 and context.portfolio.positions[security].total_amount > 0:
order_target(security, 0)
log.info("死叉卖出")
4. 补充说明:另一种计算方式(推荐)
虽然 data[security].mavg() 很方便,但在复杂的策略中,通常建议使用 attribute_history 函数配合 pandas 或 numpy 来计算指标。这种方式更灵活,且能处理更复杂的逻辑(如计算 MACD、KDJ 等)。
使用 attribute_history 计算均线的示例:
# 获取过去5天的收盘价数据(DataFrame格式)
history_data = attribute_history(g.security, 5, '1d', ['close'])
# 计算均值
ma5 = history_data['close'].mean()
Q&A
Q: data 参数里包含当天的数据吗?
A: 不包含。在回测中,为了避免“未来函数”,handle_data 中的 data 获取的是前一个单位时间的数据。如果是按天回测,data 是昨天的收盘数据;如果是按分钟回测,data 是上一分钟的数据。如果需要当天的开盘价或实时涨跌停价,请使用 get_current_data()。
Q: data[security].mavg(5) 会包含停牌的日期吗?
A: mavg 方法会自动跳过停牌日期。如果历史交易天数不足(例如刚上市),可能会返回 nan。
Q: 为什么有时候调用 data[security] 会报错?
A: 如果该股票在当前时间点已退市、未上市,或者不在你的 set_universe(股票池)设置范围内(虽然现在 set_universe 已主要用于 history 默认参数,但保持良好的股票池设置习惯很重要),可能会导致获取不到数据。建议在使用前判断 if security in data:。