3. 行业中性化:行业分类标准、行业因子暴露、行业中性化处理方法
好,咱们接着聊市场中性组合搭建中的关键一环——行业中性化。
说实话,很多新手做出来的所谓“市场中性”组合,其实只是把大盘的Beta给抹掉了。但仔细一拆,你会发现组合里全是科技股,或者全是银行股。这叫什么中性?这叫行业赌注。
真正的市场中性,不仅要做到大盘涨跌跟我没关系,还要做到——行业涨跌,也跟我没关系。这就是行业中性化的核心。
3.1 行业分类标准:你得先知道“行业”长什么样
要做行业中性化,第一步就是得有个靠谱的行业分类。你不能自己拍脑袋说“我觉得茅台和五粮液是一个行业”,得有标准。
目前全球主流的行业分类标准,主要有这么几个:
- GICS(全球行业分类标准):由MSCI和标普联合推出。分11个一级行业、24个二级行业、69个三级行业。我个人习惯用GICS,因为它更新及时,而且国际通用。
- ICB(行业分类基准):由富时罗素推出。分11个行业、20个超行业、45个行业。跟GICS有点像,但细节上有差异。
- 申万行业分类:国内用得最多的。分28个一级行业、104个二级行业。我在做A股策略时,基本都用申万分类。为什么?因为它更贴合A股的实际生态。
- 中信行业分类:也是国内常用的,分29个一级行业。跟申万各有千秋。
你可能会问:“那我该用哪个?”
我的建议是:做A股用申万,做港股或美股用GICS。我在项目中遇到过,用GICS分类去套A股,结果把一些“跨界”公司分得乱七八糟。比如某家既做养猪又做房地产的公司,在GICS里被归到“食品”,但在申万里它被归到“农林牧渔”。你说哪个更合理?
核心要点:行业分类没有绝对的对错,但你必须保持一致。今天用申万,明天用中信,你的因子暴露计算就会乱套。
3.2 行业因子暴露:你的组合到底押注了哪些行业?
有了行业分类,下一步就是计算每个股票对行业的“暴露”。说白了,就是看你的组合里,每个行业占了多少权重。
行业因子暴露的计算其实很简单:
# 假设你有一个股票组合,weights是各股票的权重
# industry_map 是股票到行业的映射
import pandas as pd
# 示例数据
stocks = ['000001.SZ', '600519.SH', '002415.SZ', '601318.SH']
weights = [0.25, 0.25, 0.25, 0.25]
industry_map = {
'000001.SZ': '银行',
'600519.SH': '食品饮料',
'002415.SZ': '电子',
'601318.SH': '非银金融'
}
# 计算行业暴露
industry_exposure = pd.Series(weights, index=stocks).groupby(industry_map).sum()
print(industry_exposure)
# 输出:
# 银行 0.25
# 食品饮料 0.25
# 电子 0.25
# 非银金融 0.25
嗯,这个例子很简单。但实际项目中,你面对的是几百只股票,行业分类可能有几十个。这时候,行业暴露就是一个向量——每个维度代表一个行业的权重。
为什么要算这个?因为你要知道:你的组合是不是在某个行业上“下重注”。如果组合里30%都是银行股,那银行板块一跌,你的组合就跟着遭殃。这还叫什么中性?
一个小技巧:我习惯把行业暴露画成柱状图。一眼就能看出哪些行业超配了,哪些低配了。视觉上比看数字直观得多。
3.3 行业中性化处理方法:怎么把行业风险“抹掉”?
好,现在我们知道组合的行业暴露了。接下来就是核心问题:怎么让组合对行业涨跌不敏感?
行业中性化的处理方法,主要有三种。我一个个说。
3.3.1 方法一:权重调整法(最直接)
说白了,就是让组合里每个行业的权重,跟基准指数(比如沪深300)的行业权重保持一致。
举个例子:如果沪深300里银行股占15%,那你的组合里银行股也占15%。这样银行板块涨了,你的组合跟基准涨得一样多,行业风险就被对冲掉了。
具体怎么做?
# 假设基准指数的行业权重
benchmark_industry_weight = {
'银行': 0.15,
'食品饮料': 0.10,
'电子': 0.08,
'非银金融': 0.12,
# ... 其他行业
}
# 你的组合原始权重
portfolio_industry_weight = {
'银行': 0.25,
'食品饮料': 0.25,
'电子': 0.25,
'非银金融': 0.25
}
# 计算需要调整的量
adjustment = {}
for industry in portfolio_industry_weight:
adjustment[industry] = benchmark_industry_weight[industry] - portfolio_industry_weight[industry]
print(adjustment)
# 输出:银行需要减0.10,食品饮料需要加0.15,等等
这个方法简单粗暴,但有个问题:它牺牲了选股的自由度。你本来可能看好银行股,但因为要中性化,你不得不减仓。这就是代价。
3.3.2 方法二:回归法(更精细)
这个方法我比较喜欢。它的思路是:把组合的收益率对行业因子做回归,然后只取残差部分。
什么意思呢?
假设组合收益率 = 行业因子贡献 + 个股选择贡献。我们通过回归,把行业因子贡献“剥离”掉,剩下的就是纯粹的个股选择收益。
import statsmodels.api as sm
import numpy as np
# 假设你有组合的日收益率序列
portfolio_returns = np.array([...]) # 你的组合收益率
industry_returns = np.array([...]) # 各行业的收益率矩阵
# 回归:组合收益率 ~ 行业收益率
X = sm.add_constant(industry_returns)
model = sm.OLS(portfolio_returns, X).fit()
# 残差就是行业中性化后的收益
neutral_returns = model.resid
我在项目中遇到过,用回归法做中性化,效果比权重调整法好。为什么?因为它更灵活。权重调整法要求你精确匹配基准,但回归法允许你“部分暴露”——只要回归系数不显著就行。
注意:回归法有个坑——多重共线性。如果两个行业高度相关(比如银行和地产),回归系数会不稳定。我建议在回归前先做一下相关性分析,或者用正则化回归(比如Lasso)。
3.3.3 方法三:优化法(最专业)
这是机构里常用的方法。它把行业中性化变成一个优化问题:在约束条件下,最小化组合的行业暴露。
具体来说:
- 目标函数:最大化预期收益,或者最小化风险
- 约束条件:每个行业的暴露为0(或者接近0)
from scipy.optimize import minimize
# 定义目标函数:最小化组合风险
def portfolio_risk(weights, cov_matrix):
return np.sqrt(weights.T @ cov_matrix @ weights)
# 约束:行业暴露为0
def industry_neutral_constraint(weights, industry_matrix):
return industry_matrix.T @ weights # 每个行业的暴露应为0
# 优化
result = minimize(
portfolio_risk,
initial_weights,
args=(cov_matrix,),
constraints={'type': 'eq', 'fun': industry_neutral_constraint, 'args': (industry_matrix,)},
bounds=[(0, 1)] * len(stocks)
)
这个方法最灵活,但计算量也最大。我一般只在做高频策略或者大资金管理时用。平时做研究,权重调整法或回归法就够了。
3.4 一张图看懂行业中性化
说了这么多,我画张图帮你理清思路。
3.5 避坑指南
最后,分享几个我踩过的坑:
- 行业分类要定期更新:公司会转型,行业会变化。我见过有人用三年前的行业分类做策略,结果某公司已经从“房地产”转型成“新能源”了,但分类还是旧的。这会导致暴露计算完全错误。
- 不要过度中性化:行业中性化不是越严格越好。如果你把每个行业的暴露都压到0,那你的选股空间会被严重压缩。我一般允许±1%的偏差。
- 注意行业轮动:行业中性化能消除行业风险,但也会让你错过行业轮动的收益。如果你看好某个行业,那就别做中性化——直接做行业轮动策略好了。
我的习惯:在做行业中性化之前,先问自己三个问题:1)我的策略是选股还是选行业?2)基准是什么?3)允许的偏差有多大?想清楚再动手。
嗯,行业中性化就聊到这儿。说白了,它就是让你的组合“不押注任何行业”,只靠选股能力赚钱。听起来简单,做起来需要细心和耐心。