问题描述
刚开始学量化,模仿别人做均线策略的时候,用聚宽回测,但收益显示为0。是我的代码出现了什么问题吗?求大神帮助!
我的策略思路是当均线MA13-MA60的值大于MA60*偏离度时,就买入ETF。
但看了一下交易记录,也没有任何交易。苦恼中
解决方案
你好!在量化交易的起步阶段,遇到回测收益为0、没有任何交易记录是非常常见的现象。这通常意味着策略的买入条件在整个回测期间从未被触发,或者代码在获取数据/下单时存在逻辑漏洞。
针对你的“MA13与MA60偏离度”策略,以下是几个最常见的排查点,并在文末为你提供了一份可以直接运行的完整源码。
🔍 常见原因排查清单
- 标的代码(ETF)后缀错误
在聚宽中,标的代码必须带有市场后缀。例如,沪深300ETF的代码是510300.XSHG(上交所),而不是单纯的510300。如果代码写错,order函数会静默失败或报错,导致无交易。 - 历史数据获取长度不足
你要计算 MA60,就必须在attribute_history或history函数中,将获取的天数(count)设置为至少 60。如果只获取了 13 天的数据去求 MA60,计算出的均线是错误的,会导致逻辑判断失效。 - 偏离度阈值设置过高
你的条件是MA13 - MA60 > MA60 * 偏离度。如果你的偏离度设置成了5(代表500%)而不是0.05(代表5%),那么这个条件在现实中几乎永远不可能成立,自然就不会有任何买入操作。 - 没有处理卖出逻辑
如果只写了买入条件,没有写卖出条件,或者卖出条件写错了,资金买完一次后就被占用,后续也不会再有交易记录(虽然这通常会有一笔买入,但如果连买入都没有,请重点检查前三点)。
💻 完整的 ETF 均线偏离度策略源码
为了帮你快速跑通策略,我为你编写了一份标准的、基于沪深300ETF(510300.XSHG)的均线偏离度策略代码。你可以直接复制到聚宽的策略编辑页面进行回测:
# 导入聚宽函数库
import jqdata
def initialize(context):
# 1. 设定要交易的标的:沪深300ETF
g.security = '510300.XSHG'
# 2. 设定沪深300指数作为基准
set_benchmark('000300.XSHG')
# 3. 开启动态复权模式(真实价格),强烈建议开启
set_option('use_real_price', True)
# 4. 设定偏离度阈值,例如 0.02 表示 2%
g.deviation_rate = 0.02
# 5. 过滤掉order系列API产生的比info级别低的log,保持日志清爽
log.set_level('order', 'info')
# 每个单位时间(按天回测则每天调用一次)调用一次
def handle_data(context, data):
security = g.security
# 获取股票过去60天的收盘价数据
# 注意:这里 count 必须填 60,否则无法准确计算 MA60
close_data = attribute_history(security, 60, '1d', ['close'])
# 容错处理:如果获取的数据不足60天,则跳过本次循环
if len(close_data) < 60:
return
# 计算 MA13 和 MA60
# 取最后13天的收盘价算平均值
MA13 = close_data['close'][-13:].mean()
# 取全部60天的收盘价算平均值
MA60 = close_data['close'].mean()
# 取得当前的可用现金
cash = context.portfolio.available_cash
# 取得当前该标的的持仓量(可卖出的数量)
current_position = context.portfolio.positions[security].closeable_amount
# 核心策略逻辑:
# 买入条件:MA13 - MA60 的值大于 MA60 * 偏离度
if (MA13 - MA60) > (MA60 * g.deviation_rate):
# 并且账户有可用资金
if cash > 0:
# 用所有可用资金买入
order_value(security, cash)
# 打印日志,方便在回测结果中查看为什么买入
log.info("【买入】MA13: %.2f, MA60: %.2f, 满足偏离度条件" % (MA13, MA60))
# 卖出条件:当 MA13 跌破 MA60 时(死叉),清仓止盈/止损
elif MA13 < MA60:
# 并且当前持有该标的
if current_position > 0:
# 目标持仓设为0,即全部卖出
order_target(security, 0)
# 打印日志
log.info("【卖出】MA13: %.2f 跌破 MA60: %.2f, 清仓" % (MA13, MA60))
💡 新手调试小技巧
如果你以后再遇到“不交易”的情况,最有效的排查方法是多用 log.info() 打印变量。例如,在 if 判断之前加上一句:
log.info("当前MA13: %s, 当前MA60: %s, 目标阈值: %s" % (MA13, MA60, MA60 * g.deviation_rate))
这样在回测日志中,你就能清楚地看到每天计算出来的均线数值是多少,为什么没有满足你的 if 条件,从而快速定位是公式写错了,还是参数设置得太苛刻了。祝你量化学习顺利!