文章目录
引言
还记得今年年初,A股行情火热的样子吗。我把年终奖投进了🔥热门网红基金里,然后就是绿油油的大半年😢。
最近在外网看了一篇关于股票投资组合优化的文章,于是想着可以把基金投资组合也评估一下,帮助自己复盘,优化投资组合,减少韭菜时刻😢,所以就有了这篇博文,介绍关于基金投资组合优化的一些基础做法。
ps.本文不含任何产品推荐,纯思路分享。
主要思路
投资组合
本文讨论的对象是投资者对不同基金的投资组合,暂不包含对股票、债券、房地产等其他类型资产。
积极的投资组合管理,就是通过战略性地买卖资产,以击败大盘。
现代投资组合理论(MPT)
现代投资组合理论,或也称为均值方差分析,由H. Markowitz制定。MPT的目标是在给定的风险水平下,获取最大化回报。
投资组合中的每一项资产都有自己的预期收益率和风险。通过创建多种资产组合,为预先定义的风险水平提供高回报。同样,可以有多个投资组合为预定义的预期回报提供最低风险。
波动率
价格的变化是该资产波动性(回报如何波动)的重要指标。资产回报的方差计算如下:
s 2 = ∑ i = 1 N ( x i – x ˉ ) 2 / N − 1 s^2 = \sum_{i=1}^N (x_i – \bar{x})^2 / N-1 s2=i=1∑N(xi–xˉ)2/N−1
波动率被衡量为该资产回报的标准偏差,即方差的平方根。
s = ∑ i = 1 N ( x i – x ˉ ) 2 / N − 1 s = \sqrt{ \sum_{i=1}^N (x_i – \bar{x})^2 / N-1} s=i=1∑N(xi–xˉ)2/N−1
协方差
协方差用于衡量两种资产回报之间的方向关系。
- 正协方差,意味着两种资产的回报一起移动。
- 负协方差,意味着它们反向移动。
通过配置具有负协方差的资产,可以降低投资组合中的风险和波动性。
关于协方差、样本协方差、协方差矩阵、相关系数的详解,可以看这篇博文:
https://blog.csdn.net/Bit_Coders/article/details/115897074
权重分配
每个资产类别的占比,由权重数组 w = [ w 1 , w 2 , . . . , w n ] w=[w_1,w_2,...,w_n] w=[w1,w2,...,wn] 表示。权重数组加和为1。
因此,投资组合优化的问题就是:找到最大化预期收益,同时最小化风险(标准差)的权重最佳值。
投资组合期望回报
资产的期望回报只是其资产价格百分比变化的平均值。
投资组合的总预期收益由下式给出:
E ( R p ) = w 1 E ( R 1 ) + w 2 E ( R 2 ) + . . . . . w n E ( R n ) E(R_p) = w_1E(R_1) + w_2E(R_2) + ..... w_nE(R_n) E(Rp)=w1E(R1)+w2E(R2)+.....wnE(Rn)
投资组合方差
σ
2
(
R
p
)
=
∑
i
=
1
n
∑
j
=
1
n
w
i
w
j
C
O
V
(
R
i
,
R
j
)
\sigma^2(R p) = \sum {i=1}^{n} \sum_{j=1}^{n} w_i w_j COV(R_i, R_j)
σ2(Rp)=∑i=1nj=1∑nwiwjCOV(Ri,Rj)
其中,
w
i
w_i
wi 和
w
j
w_j
wj 表示从 第1 ~ n 资产的权重,而 COV(Ri, Rj) 是由 i 和 j 表示的两个资产的协方差。
代码实践
下面我们以近几年的几款网红基金产品为例,来模拟分析一下这个投资组合。
获取基金净值的变化情况
df = pd.DataFrame()
start_date = '2018-10-22'
end_date = '2021-10-22'
fund_codes = ["005827","001714","270042"]#基金代码 005827:易方达蓝筹,001714:工银瑞信文体产业股票A,513300:纳斯达克100ETF
for fund_code in fund_codes:
tmp_data = get_fund_data(fund_code, per=49, sdate=start_date, edate=end_date)
print(f"{fund_code}:\n{tmp_data.head()}")
# 缺失值填充
tmp_data = tmp_data.fillna({"日增长率":"0%"})#tmp_data.dropna()
tmp_data = tmp_data.replace("nan","0%")
df["date"]=tmp_data["净值日期"]
df['date']=pd.to_datetime(df['date'])
df["change_"+fund_code]=tmp_data["日增长率"].apply(lambda x: x[:-1]).astype(float)
df["log_change_"+fund_code]=df["change_"+fund_code].apply(lambda x: np.log(1 + x))
df[fund_code]=tmp_data["累计净值"].astype(float)
# 增加“年”字段
df['year'] = pd.to_datetime(df['date'])
for i in range(df.shape[0]):
df['year'][i]=pd.to_datetime(df['date'])[i].year
print(f"Shape:{df.shape}")
print(df.head())
爬取到的基金数据格式如下:
005827:
净值日期 单位净值 累计净值 日增长率 申购状态 赎回状态 分红送配
0 2021-10-22 2.7102 2.7102 1.13% 限制大额申购 开放赎回 nan
1 2021-10-21 2.6798 2.6798 0.30% 限制大额申购 开放赎回 nan
2 2021-10-20 2.6718 2.6718 0.38% 限制大额申购 开放赎回 nan
3 2021-10-19 2.6617 2.6617 1.56% 限制大额申购 开放赎回 nan
4 2021-10-18 2.6209 2.6209 -3.20% 限制大额申购 开放赎回 nan
001714:
净值日期 单位净值 累计净值 日增长率 申购状态 赎回状态 分红送配
0 2021-10-22 3.5020 3.6910 0.66% 限制大额申购 开放赎回 nan
1 2021-10-21 3.4790 3.6680 -0.23% 限制大额申购 开放赎回 nan
2 2021-10-20 3.4870 3.6760 -0.66% 限制大额申购 开放赎回 nan
3 2021-10-19 3.5100 3.6990 0.54% 限制大额申购 开放赎回 nan
4 2021-10-18 3.4910 3.6800 -0.99% 限制大额申购 开放赎回 nan
270042:
净值日期 单位净值 累计净值 日增长率 申购状态 赎回状态 分红送配
0 2021-10-21 4.3667 4.6367 0.37% 开放申购 开放赎回 nan
1 2021-10-20 4.3507 4.6207 -0.51% 开放申购 开放赎回 nan
2 2021-10-19 4.3729 4.6429 0.73% 开放申购 开放赎回 nan
3 2021-10-18 4.3410 4.6110 0.89% 开放申购 开放赎回 nan
4 2021-10-15 4.3027 4.5727 0.60% 开放申购 开放赎回 nan
对列数据进行处理后:
计算基金的波动率
for code in ['005827','001714','270042']:
idxname = 'change_'+code
var_data = change_df[idxname].var()
vol = np.sqrt(var_data*250)
print(f"{code}的波动率:{vol}")
输出:
可以看出,坤坤的蓝筹在近一年的波动率是28%左右,是三支基金中最高的。
比较基金之间的相关性
投资组合优化中的常见做法是,获取收益或收益对数来计算协方差和相关性。
# 计算相关性 Correlation
cov_matrix = change_df.cov()
corr_matrix = change_df.corr()
print("\n资产相关矩阵:",corr_matrix)
可以看出坤坤的蓝筹和芳芳的文体股票相关性较高,都是大盘成长型产品。
纳斯达克100的产品与前两个产品相关性较弱,可以配置一些用于降低风险。
计算年期望收益
获取每个资产的年期望收益:
t = df.set_index('date')
ann = t.groupby(pd.Grouper(freq='Y'))[["change_005827","change_001714","change_270042"]].mean()
计算组合期望收益
假设 w = [ 0.6 , 0.3 , 0.1 ] w=[0.6,0.3,0.1] w=[0.6,0.3,0.1] 为一组资产配置权重,我们可以计算这个资产组合的期望回报:
# 年期望回报
w = [0.6,0.3,0.1]
ind_er = ann[1:].mean()
# 投资组合期望回报
port_er = (w * ind_er).sum()
print("\n组合期望回报:",port_er)
输出:
组合期望回报: 0.14724326989026063
利用有效边界进行投资组合优化
通过对权重数组 w w w 随机采样不同的数值,可以得到大量的投资组合,将每一个 w w w 对应的期望回报(纵轴)和波动率(横轴)计算出来,绘制成散点图。
portfolios.plot.scatter(x='Volatility', y='Returns', marker='o', s=10, alpha=0.4, grid=True, figsize=[10,10])
可以在图中,明显看到一个清晰的有效边界,靠近边界越近的投资组合,优化效果越好。
如果我们想要建立一个波动率最小的投资组合:
min_vol_port = portfolios.iloc[portfolios['Volatility'].idxmin()]
min_vol_port
这个组合的回报、波动率、各资产权重如下:
Returns 0.143355
Volatility 15.604691
change_005827 weight 0.067550
change_001714 weight 0.356889
change_270042 weight 0.575561
如果我们想要建立一个回报最高的投资组合:
max_ret_port = portfolios.iloc[portfolios['Returns'].idxmax()]
max_ret_port
这个组合的回报、波动率、各资产权重如下:
Returns 0.161274
Volatility 21.890702
change_005827 weight 0.019570
change_001714 weight 0.978369
change_270042 weight 0.002061
小结
本文整理了投资组合优化的一些基础概念,期望回报和波动率的计算方法,利用有效边界进行投资组合优化的基础方法。
下一篇改进思路,打算尝试其他更高效的优化方法。欢迎评论区分享你的建议!
参考文章
https://www.investopedia.com/terms/p/portfoliomanagement.asp
https://www.machinelearningplus.com/machine-learning/portfolio-optimization-python-example/
https://blog.csdn.net/u012710043/article/details/111590428