3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化交易中,动量策略(Trend Following)适合单边趋势行情,而反转策略(Mean Reversion)则在震荡市中表现更佳。为了在不同市场环境下获得稳健收益,我们可以构建一个自适应 ETF 动量与反转切换策略。
本指南将教你如何在聚宽(JoinQuant)平台中,通过大盘指数(如沪深300)的均线系统来识别市场大级别行情,并动态选择执行 ETF 动量模型或反转模型。
市场环境识别(大级别行情判断):
000300.XSHG)的长期均线(如 60 日均线 MA60)作为牛熊分界线。模型执行:
请将以下代码复制到聚宽策略编辑器的代码框中进行回测:
import jqdata
import numpy as np
import pandas as pd
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉比error级别低的log
log.set_level('order', 'error')
# 设定交易税费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 策略参数设置
g.market_index = '000300.XSHG' # 市场环境参考指数
g.ma_period = 60 # 判断大趋势的均线周期
# 候选 ETF 标的池(涵盖宽基、行业、商品等)
g.etf_pool = [
'510300.XSHG', # 沪深300ETF
'510500.XSHG', # 中证500ETF
'510050.XSHG', # 上证50ETF
'159915.XSHE', # 创业板ETF
'518880.XSHG', # 黄金ETF
'512880.XSHG', # 证券ETF
'512010.XSHG', # 医药ETF
'512660.XSHG' # 军工ETF
]
g.hold_num = 2 # 最大同时持仓的ETF数量
# 每周第一个交易日运行调仓
run_weekly(my_rebalance, weekday=1, time='09:30')
def my_rebalance(context):
# 1. 判断市场大级别行情环境
# 获取参考指数的历史收盘价
hist_index = attribute_history(g.market_index, g.ma_period + 5, '1d', ['close'])
ma_60 = hist_index['close'][-g.ma_period:].mean()
current_index_price = hist_index['close'][-1]
ma_60_prev = hist_index['close'][-(g.ma_period+1):-1].mean()
# 判断是否处于大级别多头动量行情:指数在MA60上方,且MA60方向向上
is_momentum_market = (current_index_price > ma_60) and (ma_60 > ma_60_prev)
# 2. 获取候选池数据并计算因子
target_list = []
if is_momentum_market:
log.info("当前市场环境:【动量牛市】 -> 激活动量模型")
# 动量模型:计算过去20日涨幅
momentum_scores = {}
for etf in g.etf_pool:
hist = attribute_history(etf, 20, '1d', ['close'])
if not hist.empty:
return_20d = (hist['close'][-1] - hist['close'][0]) / hist['close'][0]
momentum_scores[etf] = return_20d
# 按涨幅从大到小排序,取前 hold_num 名
sorted_etfs = sorted(momentum_scores.items(), key=lambda x: x[1], reverse=True)
target_list = [x[0] for x in sorted_etfs[:g.hold_num]]
else:
log.info("当前市场环境:【震荡/熊市】 -> 激活反转模型")
# 反转模型:计算过去5日跌幅(寻找超跌标的)
reversal_scores = {}
for etf in g.etf_pool:
hist = attribute_history(etf, 5, '1d', ['close'])
if not hist.empty:
return_5d = (hist['close'][-1] - hist['close'][0]) / hist['close'][0]
reversal_scores[etf] = return_5d
# 按跌幅从小到大排序(即跌得最惨的排在前面),取前 hold_num 名
sorted_etfs = sorted(reversal_scores.items(), key=lambda x: x[1], reverse=False)
target_list = [x[0] for x in sorted_etfs[:g.hold_num]]
# 3. 执行调仓交易
# 卖出不在目标持仓列表中的ETF
current_positions = list(context.portfolio.positions.keys())
for etf in current_positions:
if etf not in target_list:
order_target(etf, 0)
log.info("卖出不符合当前模型的标的: %s" % etf)
# 等权重买入目标ETF
if target_list:
target_value = context.portfolio.total_value / len(target_list)
for etf in target_list:
order_target_value(etf, target_value)
log.info("调仓/买入目标标的: %s, 目标价值: %.2f" % (etf, target_value))
# 记录当前市场状态画图
record(market_status=1 if is_momentum_market else 0)
自适应切换机制:
策略通过 is_momentum_market 变量动态感知大盘强弱。在牛市中,策略自动切换为动量模型,买入最强势的 ETF 享受趋势红利;在震荡市或熊市中,策略自动切换为反转模型,买入短期超跌的 ETF 捕捉反弹机会。
避免未来函数:
策略使用 attribute_history 获取历史数据,且调仓执行在每周一开盘时,完全基于历史已知信息,有效规避了未来函数。
真实价格模式:
在 initialize 中调用了 set_option('use_real_price', True)。对于 ETF 交易,开启真实价格模式能更准确地模拟分红、拆分对账户净值的影响,使回测结果更贴近实盘。