3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化交易中,ETF 轮动策略因其波动小、跟踪行业板块效果好而广受欢迎。然而,在市场系统性下跌时,若不加限制,轮动策略仍会面临较大的回撤。本文将教你如何在聚宽(JoinQuant)平台上,通过限制最大持仓数量、设置单品种仓位上限以及引入大盘动能指标切换防御仓位来有效降低策略回撤。
以下是基于聚宽 API 编写的完整策略代码:
import pandas as pd
import numpy as np
from jqdata import *
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉比error级别低的log
log.set_level('order', 'error')
# 策略参数设置
g.momentum_window = 20 # 动量计算周期
g.max_hold_count = 3 # 最大持仓数量
g.single_cap = 0.3 # 单品种仓位上限 (30%)
# 候选进攻性 ETF 列表
g.etf_pool = [
'510300.XSHG', # 300ETF
'159915.XSHE', # 创业板ETF
'510500.XSHG', # 500ETF
'512880.XSHG', # 证券ETF
'512660.XSHG', # 军工ETF
'515000.XSHG', # 科技ETF
]
# 防御性标的
g.defense_security = '511010.XSHG' # 国债ETF
# 大盘风控参考标的
g.market_index = '000300.XSHG'
g.market_ma_window = 60 # 大盘均线周期
# 每月第一个交易日开盘运行调仓
run_monthly(handle_rotation, monthday=1, time='09:30', reference_security='000300.XSHG')
def handle_rotation(context):
# 1. 大盘风控判断
close_data = attribute_history(g.market_index, g.market_ma_window, '1d', ['close'])
current_market_price = close_data['close'][-1]
market_ma = close_data['close'].mean()
# 获取当前持仓
current_positions = list(context.portfolio.positions.keys())
# 如果大盘处于弱势(低于均线),切换到防御仓位
if current_market_price < market_ma:
log.info("大盘处于弱势,触发风控,切换至防御仓位。")
# 卖出所有非防御标的
for stock in current_positions:
if stock != g.defense_security:
order_target(stock, 0)
# 全仓买入防御标的
cash = context.portfolio.available_cash
if cash > 0:
order_value(g.defense_security, cash)
return
# 2. 大盘强势,执行进攻性 ETF 轮动
# 计算候选池动量(过去N天收益率)
scores = {}
for etf in g.etf_pool:
hist = attribute_history(etf, g.momentum_window + 1, '1d', ['close'])
if len(hist) > 0:
return_rate = (hist['close'][-1] - hist['close'][0]) / hist['close'][0]
scores[etf] = return_rate
# 按收益率降序排列,选出前 max_hold_count 个
sorted_etfs = sorted(scores.items(), key=lambda x: x[1], reverse=True)
target_etfs = [x[0] for x in sorted_etfs[:g.max_hold_count] if x[1] > 0] # 过滤掉收益为负的
# 3. 调仓执行
# 卖出不在目标列表中的持仓(包括防御标的)
for stock in current_positions:
if stock not in target_etfs:
order_target(stock, 0)
# 计算单品种分配资金(总资产 * 单品种上限)
total_value = context.portfolio.total_value
target_value_per_etf = total_value * g.single_cap
# 买入目标 ETF
for etf in target_etfs:
# 调整到目标价值
order_target_value(etf, target_value_per_etf)
# 剩余资金(如有)可闲置或自动配置到防御标的
remaining_cash = context.portfolio.available_cash
if remaining_cash > total_value * 0.05: # 剩余资金大于5%时买入防御标的填充
order_value(g.defense_security, remaining_cash)
set_option('use_real_price', True):order_target_value(security, value):total_value * g.single_cap,我们严格限制了单品种的资金占用比例(如 30%),即使某只行业 ETF 遭遇单日大跌,整体账户的损失也被控制在可承受范围内。attribute_history 获取沪深 300 指数的历史收盘价,并计算 60 日均线。当指数跌破均线时,策略果断放弃进攻,通过 order_target(stock, 0) 清空高风险 ETF,并全仓买入 511010.XSHG(国债 ETF)获取低风险收益,从而在熊市中大幅降低回撤。