1. 行业轮动策略概述
行业轮动策略是量化投资领域中一种经典的中观策略,它基于宏观经济周期、行业景气度和市场行为特征,通过捕捉不同行业间的相对强弱变化来获取超额收益。这种策略的核心逻辑在于:不同行业在经济周期的不同阶段会表现出差异化的业绩和股价表现。
我在实际回测中发现,A股市场具有明显的行业轮动特征。以2019-2023年为例,消费、科技、周期等板块每年都会出现1-2次显著的轮动机会。比如2020年的医药、2021年的新能源、2022年的煤炭,都曾引领过阶段性行情。
关键提示:行业轮动策略成功的关键在于三点:准确的行业分类、有效的轮动信号、合理的持仓周期。这三者缺一不可,后续我们会详细拆解每个环节的实现方法。
2. 数据准备与Tushare配置
2.1 Tushare Pro接口初始化
首先需要配置Tushare Pro的Python环境:
import tushare as ts import pandas as pd # 替换为你的实际token pro = ts.pro_api('你的Tushare Token') # 设置缓存路径(避免重复请求) ts.set_token('你的Tushare Token')2.2 关键数据获取
行业轮动策略需要以下几类核心数据:
- 行业分类数据:
# 获取申万一级行业分类 industry = pro.index_classify(level='L1', src='SW')- 行业指数行情:
# 获取各行业指数日线数据 industry_daily = pro.index_daily(ts_code='行业代码', start_date='20200101', end_date='20231231')- 宏观经济指标:
# 获取PMI等经济指标 pmi = pro.cn_pmi(start_m='2020-01', end_m='2023-12')常见坑点:Tushare的行业指数数据存在两个常见问题:1) 部分行业指数成立时间较晚导致数据缺失 2) 行业成分股调整带来的指数计算口径变化。建议对数据做前向填充处理。
3. 行业轮动模型构建
3.1 动量-波动率综合评分模型
我开发了一个经过实战检验的行业轮动评分模型:
def industry_score(df, lookback=20): """ 计算行业综合得分 参数: df: 行业指数日线DataFrame lookback: 观察窗口(交易日) 返回: 带有score列的DataFrame """ # 动量得分(过去20日收益率) df['momentum'] = df['close'].pct_change(lookback) # 波动率得分(过去20日波动率倒数) df['volatility'] = 1 / df['close'].pct_change().rolling(lookback).std() # 标准化处理 df['mom_score'] = (df['momentum'] - df['momentum'].mean()) / df['momentum'].std() df['vol_score'] = (df['volatility'] - df['volatility'].mean()) / df['volatility'].std() # 综合得分(可调整权重) df['score'] = 0.6*df['mom_score'] + 0.4*df['vol_score'] return df3.2 行业景气度辅助指标
单纯的量价指标容易受到市场情绪干扰,我通常会加入三个基本面辅助指标:
- 行业PE分位数:
pe_history = pro.index_dailybasic(ts_code='行业代码', start_date='20100101', end_date='20231231', fields='ts_code,trade_date,pe_ttm')- 机构持仓变化:
fund_holding = pro.fund_holding(ts_code='行业代码', period='20230630')- 行业新闻情绪(需要另接NLP接口)
4. 策略回测实现
4.1 回测框架搭建
使用backtrader框架进行回测:
import backtrader as bt class IndustryRotation(bt.Strategy): params = ( ('top_n', 3), # 持仓行业数量 ('rebalance_month', 1), # 再平衡月份(1=每月) ) def __init__(self): self.industries = {} # 存储行业数据 self.signal_date = None def next(self): if self.data.datetime.date(0).month != self.p.rebalance_month: return # 计算行业得分 scores = {} for ind, data in self.industries.items(): df = pd.DataFrame({ 'close': data.close.get(size=20), 'volume': data.volume.get(size=20) }) scores[ind] = industry_score(df)['score'][-1] # 选择得分最高的top_n个行业 selected = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:self.p.top_n] # 执行调仓逻辑 self.rebalance(selected)4.2 关键参数优化
通过网格搜索确定最优参数组合:
| 参数 | 测试范围 | 最优值 | 说明 |
|---|---|---|---|
| 动量周期 | 10-60日 | 20日 | 短期动量表现最佳 |
| 持仓行业数 | 1-5个 | 3个 | 分散效果与收益的平衡点 |
| 再平衡周期 | 月/季 | 月度 | A股市场适合更高频调整 |
| 权重分配 | 动量50-80% | 60% | 兼顾趋势与稳定性 |
5. 实盘注意事项
5.1 交易成本控制
行业轮动策略的换手率较高,必须精确计算交易成本:
- ETF买卖佣金(通常0.02%-0.03%)
- 印花税(卖出0.1%)
- 冲击成本(大资金需特别注意)
建议在回测中将交易成本设置为0.15%-0.2%以反映真实情况。
5.2 行业ETF选择技巧
不同行业的ETF流动性差异很大,我的选择标准是:
- 日均成交额>5000万元
- 跟踪误差<2%
- 规模>10亿元
- 成立时间>3年
血泪教训:避免选择新成立的行业ETF,我曾因某新能源ETF流动性不足导致无法及时调仓,单月损失超5%。
6. 策略进阶方向
6.1 宏观因子增强
将宏观经济指标作为权重调整因子:
def macro_adjustment(score, macro_indicator): """ 根据宏观经济指标调整行业得分 """ if macro_indicator > 50: # 扩张期 return score * 1.2 # 放大周期行业得分 else: return score * 0.8 # 降低周期行业得分6.2 机器学习应用
使用XGBoost构建行业轮动预测模型:
from xgboost import XGBClassifier # 特征工程 features = ['momentum_20', 'volatility_20', 'pe_quantile', 'fund_inflow'] target = 'outperform' # 下月是否跑赢大盘 # 模型训练 model = XGBClassifier(n_estimators=100) model.fit(train[features], train[target])6.3 风险控制模块
必须设置最大回撤止损:
class RiskControl: def __init__(self, max_drawdown=0.15): self.max_dd = max_drawdown self.peak = 0 def update(self, current_value): self.peak = max(self.peak, current_value) drawdown = (self.peak - current_value) / self.peak if drawdown > self.max_dd: return False # 触发风控 return True7. 常见问题排查
7.1 Tushare数据问题
数据缺失:部分行业指数早期数据不存在
- 解决方案:使用
fillna(method='ffill')前向填充
- 解决方案:使用
复权不一致:不同API返回的复权方式不同
- 解决方案:统一使用
adj_factor字段自行计算
- 解决方案:统一使用
频率限制:免费版有每分钟200次的限制
- 解决方案:合理设置
time.sleep或升级VIP
- 解决方案:合理设置
7.2 策略表现不稳定
可能原因及解决方法:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 近期大幅回撤 | 市场风格突变 | 加入波动率过滤条件 |
| 年度收益差异大 | 参数过拟合 | 使用Walk-Forward优化 |
| 实盘与回测差距大 | 未考虑冲击成本 | 提高交易成本假设 |
8. 我的实战心得
经过三年实盘验证,我总结了行业轮动策略的几点关键经验:
不要过度追求换手频率:月度调仓效果往往优于周度调仓,过于频繁的交易会被成本侵蚀收益。
重视行业逻辑验证:当模型选出某个行业时,一定要查阅最近的行业研报,确认基本面支持。
保持策略多样性:建议同时运行2-3套不同参数的轮动策略,分散风险。
警惕极端市场环境:在2018年和2022年这样的单边下跌市中,行业轮动策略往往失效,此时应启动风控模块。
最后分享一个实用技巧:可以设置5%的"观察仓"机制,当新行业进入候选名单但不确定其持续性时,先建立小仓位跟踪,确认趋势后再加大配置。这个技巧帮我避免了多次假突破的损失。