如何用Python实现资产组合最优化
由bqu1vdra创建,最终由bqu1vdra 被浏览 2 用户
现代投资组合理论(MPT)是由马科维茨于1952年提出的,是现代金融7个基本理论之一。它用数学术语描述了多元化和风险管理等概念,为投资者提供了构建多元化投资组合的工具集,即假定投资者投资于多个资产,在满足给定预期回报率下,可以通过优化求解出风险最小的投资组合。所有的这些资产组合构成一条曲线(以资产组合的标准差为横轴,预期回报率为纵轴),称为前沿资产组合曲线,其中曲线的上半部分又被称为有效前沿
这个图是一个上下对称图,在图的下半部分上的每一个点,都可以在上半部分找到一个对应点,它们具有相同的风险,但有效前沿上的点具有更大的预期收益率。因此下半部分投资是没有投资者愿意持有的。
每个投资者根据自己的风险承受能力(效用函数),在有效前沿上选择自己的投资组合。
我们以最简单的两个风险资产组合为例来解释有效前沿:
$$ R_p=\omega_1R_1+(1-\omega_1)R_2
$$
这里:
组合的风险用方差来衡量:
这里的
$$ \rho_{1,2} $$
是资产1与资产2之间的相关系数。
当两个资产的相关系数为1时,上式就化简为: 当两个资产之间的相关系数为-1时,
从上式可以看出,如果两个资产完全负相关,那么等权重配置两个资产,则资产收益变为零,从而构成一个无风险的组合。此时由于方差等于零,所以它就成为图形上最左端的点。
当其中一个资产为100%时,则构成图形中上下两个点。
在这个系列中,我们将首先用4个标的的组合,先后用蒙特卡洛方法和优化算法分别演示如何求得最佳资产组合,这是比较底层的方法,当我们掌握原理之后,则可以使用第三方库来完成这项工作。
首先,假定我们的资产组合是:
600519 贵州茅台 300750 宁德时代 300059 东方财富 601398 工商银行
我们通过下面的代码获得它们近一年的收益,保存在returns dataframe中:
import arrow
import akshare as ak
import pandas as pd
import numpy as np
stocks = ["600519", "300750", "300059", "601398"]
frames = {}
now = arrow.now()
start = now.shift(years = -1)
end = now.format("YYYYMMDD")
start = start.format("YYYYMMDD")
for code in stocks:
bars = ak.stock_zh_a_hist(symbol=code,
period="daily",
start_date=start,
end_date=end,
adjust="qfq")
bars.index = pd.to_datetime(bars["日期"])
frames[code] = bars["收盘"]
df = pd.DataFrame(frames)
returns = df.pct_change()
returns.dropna(how='any', inplace=True)
returns.style.format('{:,.2%}')
接下来,我们先随机分配一个权重(这是蒙特卡洛方法的第一步),计算出它的夏普率
import numpy as np
from empyrical import sharpe_ratio
weights = np.array(np.random.random(4))
print('Random Weights:')
print(weights)
print('\nRebalance')
weights = weights/np.sum(weights)
print(weights)
weighted_returns = weights * returns
# we'll sum over all columns, so got daily portfolio's return
port_returns = weighted_returns.sum(axis=1)
cov = np.cov(port_returns.T)
port_vol = np.sqrt(np.dot(np.dot(weights, cov), weights.T))
sr = sharpe_ratio(port_returns)
print("Sharpe Ratio and Vol")
print(f"{sr:.2f} {port_vol:.2f}")
在代码中,我们先是随机生成了一个权重矩阵,然后对它进行了归一化(权重矩阵各项之和必须为1)。
一些文章会使用对数收益率。但是,在计算方差时,多数人倾向于几何方差是没有意义的(从google搜索结果看)。
我们使用了empyrical中的sharpe_ratio方法来计算夏普率,为简单起见,我们将risk_free利率设置为0。
最终,我们得到以下结果:
Random Weights:
[0.48349071 0.32903015 0.85308562 0.64038565]
Rebalance
[0.20966711 0.14268485 0.36994299 0.27770505]
Sharpe Ratio and Vol
0.72 0.01
最终我们得到了该资产组合的夏普率为0.72。一般认为,如果我们投资的是指数或者权重股,那么夏普超过1是可以接受的投资;对其它高风险权益类投资,一般要超过1.8,但很少有资产能超过3。在大富翁课程里,我们通过蒙特卡洛方法讨论了夏普率与最大回撤之间的关系,即夏普率为1时,对应的最大回撤为多少是可能出现的;夏普率为2时,对应的最大回撤为多少是可能出现的,等等。
\