用Python寻找最优投资组合

用Python寻找最优投资组合原文地址 https www jianshu com p 2a25dfd465e9 现代投资组合理论 ModernPortfo MPT 告诉我们投资者应该分散投资来实现最小化风险最大化投资回报 大邓刚开始学习这方面知识 用了将近一天的时候才搞懂 MPT 理论的推导 顺便复习了部分高中数学知识 这样会让我们更加有新信心的去使用自己编写的代码 现在我们从

原文地址:https://www.jianshu.com/p/2a25dfd465e9

现代投资组合理论(Modern Portfolio Theory,MPT)告诉我们投资者应该分散投资来实现最小化风险最大化投资回报。大邓刚开始学习这方面知识,用了将近一天的时候才搞懂MPT理论的推导,顺便复习了部分高中数学知识,这样会让我们更加有新信心的去使用自己编写的代码。现在我们从实战开始接触理论。

一、资产组合理论导论

1.1 风险厌恶(Risk aversion)

在投资组合理论中,我们常常使用方差来刻画资产的风险。这里举个例子,方便大家理解。

假设你现在将要进行投资,有两种策略:

资产A给你带来的收益是200元,或者0元。每种情况发生的概率也是各50%

资产B给你带来的收益是400元,或者-200元(亏损)。每种情况发生的概率也是各50%

资产的数学期望收益

用Python寻找最优投资组合

两种投资策略的波动性-标准差

用Python寻找最优投资组合

如果你是风险偏好者,你可能会选择B,因为B的潜在的最大收益最大。但是MPT理论认为大多数的投资者是风险厌恶者,不喜欢玩心跳,所以更倾向于选择A。

1.2资产组合池(portfolio)

假设我们将采用分散投资,每种资产的比例为 w1、w2、w3…wn,我们知道所有投资比例之和为1,即 w1+w2+w3+…+wn=1 。假设R0、R1、R2…Rn分别代表每种资产的收益,则资产组合投资收益为

用Python寻找最优投资组合

我们预期的投资组合收益为

用Python寻找最优投资组合

1.3 相关性

在计算资产组合风险前,我们需要先回忆一下高中数学中的方差和相关性的计算方法。方差和相关性主要是刻画任意两个变量之间的线性关系。

X和Y的方差计算公式

用Python寻找最优投资组合

1.4 风险

现在我们将要计算资产组合的风险,这里使用 资产组合收益的方差 来刻画投资风险。

用Python寻找最优投资组合

本来大邓直接看到推导完的结果,但是忽略了中间过程,心里怎么也不相信。所以花了很多时间用来找推导过程的教程和视频,终于找到一份比较详细的,现在贴给大家看。我们将该公式中的加总用累加zigma符号表示,一步步的进行推导

用Python寻找最优投资组合

现在我们先看看简单的例子,如何将累加和的平方展开?

用Python寻找最优投资组合

我们再将上面的公式抽象一下

用Python寻找最优投资组合

因此,资产组合收益的方差可以表示为

用Python寻找最优投资组合

最后我们将上面的符号全部用向量(或矩阵)来表示,这样后期我们使用python写代码时候可以直接使用numpy表达。

用Python寻找最优投资组合

二、实战

2.1 加载数据

这里我参考JoinQuant中的一篇文章,其选取的股票的收益比较符合正太分布,我就直接拿来用吧。

‘000651’,格力电器   

”,贵州茅台  

”,中国平安               

‘000858’,五粮液  

”,伊利股份  

‘000333’,美的集团   

”,兴业银行  

”,交通银行  

”上汽集团  

我们使用tushare来获取股票数据,tushare的get_hist_data(stock_code, start, end)函数获取stock_code从start到end期间内的所有交易数据,返回的是dataframe类型。这里我们都是用close列的数据,即只用收盘价数据。

importtushareasts

deffetch_stock_data(stock_code, stock_name, start, end):

df = ts.get_hist_data(stock_code, start=start, end=end)#前复权

df = df.close

df.name = stock_name

returndf

geli = fetch_stock_data(‘000651′,’格力电器’,’2016-05-28′,’2018-03-26′)

geli.head()

Run

date

2018-03-2648.13

2018-03-2348.88

2018-03-2249.90

2018-03-2151.70

2018-03-2052.20

Name: 格力电器,dtype:float64

现在我们将所有股票都的收盘数据都装进pandas.DataFrame中,每一列代表一只股票,每一行代表一天的收盘价

importpandasaspd

data = pd.DataFrame({‘格力电器’:fetch_stock_data(‘000651′,’格力电器’,’2016-05-28′,’2018-03-26′),

‘贵州茅台’:fetch_stock_data(”,’贵州茅台’,’2016-05-28′,’2018-03-26′),

‘中国平安’:fetch_stock_data(”,’中国平安’,’2016-05-28′,’2018-03-26′),

‘五粮液’:fetch_stock_data(‘000858′,’五粮液’,’2016-05-28′,’2018-03-26′),

‘伊利股份’:fetch_stock_data(”,’伊利股份’,’2016-05-28′,’2018-03-26′),

‘美的集团’:fetch_stock_data(‘000333′,’美的集团’,’2016-05-28′,’2018-03-26′),

‘兴业银行’:fetch_stock_data(”,’兴业银行’,’2016-05-28′,’2018-03-26′),

‘交通银行’:fetch_stock_data(”,’交通银行’,’2016-05-28′,’2018-03-26′),

‘上汽集团’:fetch_stock_data(”,’上汽集团’,’2016-05-28′,’2018-03-26′)})

data = data.dropna()

data.head()

用Python寻找最优投资组合

data.to_excel(‘stock_data.xlsx’)

我将整理好的数据保存到了 stock_data.xlsx 中,方便大家即使无法使用tushare也有数据可供分析。

importpandasaspd

data = pd.read_excel(‘stock_data.xlsx’)

data.head()

用Python寻找最优投资组合

将每个股票价格与最初始(2016年10月24日)的价格作比较,并据此得到之后的股价走势图

#将date列从newdata中踢出

date = data.pop(‘date’)

#data.iloc[0, :] 选取第一行的数据

newdata = (data/data.iloc[0, :])*100

昨天我们分享的可视化使用的pyplotz库,该库支持所有基于matplotlib的可视化库。今天我们用plotly这个动态可视化库来作图,正好复习下前面分享的plotly-express库,注意plotly-express是基于plotly

fromplotly.offlineimportinit_notebook_mode, iplot, plot

importplotly.graph_objsasgo

init_notebook_mode()

stocks = [‘格力电器’,’贵州茅台’,’中国平安’,’五粮液’,’伊利股份’,’美的集团’,’兴业银行’,’交通银行’,’上汽集团’]

deftrace(df, date, stock):

returngo.Scatter(x = date,#横坐标日期

y = df[stock],

name=stock)#纵坐标为股价与(2016年10月24日)的比值

data = [trace(newdata,date,stock)forstockinstocks]

iplot(data)

用Python寻找最优投资组合

2.2 计算不同股票的均值、协方差

每年有252个交易日,用每日收益率乘以252得到年化收益率。现在需要计算每只股票的收益率,在金融领域中我们一般使用对数收益率。这里体现了pandas的强大,df.pct_change()直接就能得到股票收益率

importnumpyasnp

log_returns = np.log(newdata.pct_change()+1)

log_returns = log_returns.dropna()

log_returns.mean()*252

Run

格力电器    0.

贵州茅台    0.

中国平安    0.

五粮液     0.

伊利股份    0.

美的集团    0.

兴业银行    0.024539

交通银行    0.068539

上汽集团    0.

dtype:float64

2.3 进行正态检验

马科维茨的投资组合理论需要满足收益率符合正态分布,scipy.stats库为我们提供了正态性测试函数

scipy.stats.normaltest 测试样本是否与正态分布不同,返回p值。

importscipy.statsasscs

defnormality_test(array):

print(‘Norm test p-value %14.3f’% scs.normaltest(array)[1])

forstockinstocks:

print(‘\nResults for {}’.format(stock))

print(‘-‘*32)

log_data = np.array(log_returns[stock])

normality_test(log_data)

Run

Resultsfor格力电器

——————————–

Normtestp-value          0.000

Resultsfor贵州茅台

——————————–

Normtestp-value          0.000

Resultsfor中国平安

——————————–

Normtestp-value          0.000

Resultsfor五粮液

——————————–

Normtestp-value          0.051

Resultsfor伊利股份

——————————–

Normtestp-value          0.000

Resultsfor美的集团

——————————–

Normtestp-value          0.453

Resultsfor兴业银行

——————————–

Normtestp-value          0.000

Resultsfor交通银行

——————————–

Normtestp-value          0.000

Resultsfor上汽集团

——————————–

Normtestp-value          0.000

从上面的检验中,伊利股份和兴业银行股票收益率不符合正态分布。

2.4 投资组合预期收益率、波动率

我们先随机生成一维投资组合权重向量(长度为9,与股票数量相等),因为中国股市的不允许卖空,所以投资组合权重向量中的数值必须在0到1之间。

weights = np.random.random(9)

weights /= np.sum(weights)

weights

array([0.,0.,0.,0.0,0.,

0.,0.0,0.,0.])

投资组合预期收益率等于每只股票的权重与其对应股票的年化收益率的乘积。

np.dot(weights, log_returns.mean())*252

0.01051

投资组合波动率(方差)

用Python寻找最优投资组合

np.dot(weights, np.dot(log_returns.cov()*252, weights))

0.0

投资组合收益的年化风险(标准差)

np.sqrt(np.dot(weights, np.dot(log_returns.cov()*252, weights)))

0.

2.5 随机生成大量的投资组合权重

生成1000种随机的投资组合,即权重weights的尺寸为(1000*9)。

importmatplotlib.pyplotasplt

%matplotlib inline

port_returns = []

port_variance = []

forpinrange(1000):

weights = np.random.random(9)

weights /=np.sum(weights)

port_returns.append(np.sum(log_returns.mean()*252*weights))

port_variance.append(np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()*252, weights))))

port_returns = np.array(port_returns)

port_variance = np.array(port_variance)

#无风险利率设定为3%

risk_free =0.03

plt.figure(figsize=(8,6))

plt.scatter(port_variance, port_returns, c=(port_returns-risk_free)/port_variance, marker =’o’)

plt.grid(True)

plt.xlabel(‘Expected Volatility’)

plt.ylabel(‘Expected Return’)

plt.colorbar(label =’Sharpe Ratio’)

用Python寻找最优投资组合

2.5.1 投资组合优化1—夏普率最大

建立statss函数来记录重要的投资组合统计数据(收益,方差和夏普比)。scipy.optimize可以提供给我们最小优化算法,而最大化夏普率可以转化为最小化负的夏普率。

importscipy.optimizeassco

defstats(weights):

weights = np.array(weights)

port_returns = np.sum(log_returns.mean()*weights)*252

port_variance = np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()*252,weights)))

returnnp.array([port_returns, port_variance, port_returns/port_variance])

#最小化夏普指数的负值

defmin_sharpe(weights):

return-stats(weights)[2]

#给定初始权重

x0 =9*[1./9]

#权重(某股票持仓比例)限制在0和1之间。

bnds = tuple((0,1)forxinrange(9))

#权重(股票持仓比例)的总和为1。

cons = ({‘type’:’eq’,’fun’:lambdax: np.sum(x)-1})

#优化函数调用中忽略的唯一输入是起始参数列表(对权重的初始猜测)。我们简单的使用平均分布。

opts = sco.minimize(min_sharpe,

x0,

method =’SLSQP’,

bounds = bnds,

constraints = cons)

opts

Run

fun: -2.04794

jac: array([1.0e-01,-4.e-05,3.e-04,7.e-01,

5.e-01,-2.e-05,3.e-01,-1.e-04,

-5.e-04])

message:’Optimization terminated successfully.’

nfev:111

nit:10

njev:10

status:0

success: True

x: array([1.0e-16,4.e-01,2.e-01,6.e-17,

5.e-17,1.e-01,8.e-17,6.e-02,

8.e-02])

最优投资组合权重向量,小数点保留3位

opts[‘x’].round(3)

array([0.,0.494,0.238,0.,0.,0.115,0.,0.069,0.085])

sharpe最大的组合3个统计数据分别为:

stats(opts[‘x’]).round(3)

array([0.539,0.197,2.728])

2.5.2 投资组合优化2——方差最小

接下来,我们通过方差最小来选出最优投资组合。

#但是我们定义一个函数对 方差进行最小化

defmin_variance(weights):

returnstats(weights)[1]

optv = sco.minimize(min_variance,

x0,

method =’SLSQP’,

bounds = bnds,

constraints = cons)

optv

Run

fun: 0.44057

jac: array([0.,0.,0.,0.,0.,

0.,0.,0.,0.])

message:’Optimization terminated successfully.’

nfev:88

nit:8

njev:8

status:0

success: True

x: array([0.00000000e+00,2.e-01,0.00000000e+00,8.0e-18,

3.0e-02,1.e-02,3.e-01,3.e-01,

5.e-02])

方差最小的最优投资组合权重向量

optv[‘x’].round(3)

array([0.,0.214,0.,0.,0.031,0.014,0.322,0.365,0.054])

得到的投资组合预期收益率、波动率和夏普指数

stats(optv[‘x’]).round(3)

array([0.206,0.126,1.634])

2.5.3 资产组合的有效边界

有效边界是由一系列既定的目标收益率下方差最小的投资组合点组成的。在最优化时采用两个约束,1.给定目标收益率,2.投资组合权重和为1。

defmin_variance(weights):

returnstatistics(weights)[1]

#在不同目标收益率水平(target_returns)循环时,最小化的一个约束条件会变化。

target_returns = np.linspace(0.0,0.5,50)

target_variance = []

fortarintarget_returns:

#给定限制条件:给定收益率、投资组合权重之和为1

cons = ({‘type’:’eq’,’fun’:lambdax:stats(x)[0]-tar},{‘type’:’eq’,’fun’:lambdax:np.sum(x)-1})

res = sco.minimize(min_variance, x0, method =’SLSQP’, bounds = bnds, constraints = cons)

target_variance.append(res[‘fun’])

target_variance = np.array(target_variance)

下面是最优化结果的展示。

叉号:构成的曲线是有效前沿(目标收益率下最优的投资组合)

红星:sharpe最大的投资组合

黄星:方差最小的投资组合

plt.figure(figsize = (8,4))

#圆点:随机生成的投资组合散布的点

plt.scatter(port_variance, port_returns, c = port_returns/port_variance,marker =’o’)

#叉号:投资组合有效边界

plt.scatter(target_variance,target_returns, c = target_returns/target_variance, marker =’x’)

#红星:标记夏普率最大的组合点

plt.plot(stats(opts[‘x’])[1], stats(opts[‘x’])[0],’r*’, markersize =15.0)

#黄星:标记方差最小投资组合点

plt.plot(stats(optv[‘x’])[1], stats(optv[‘x’])[0],’y*’, markersize =15.0)

plt.grid(True)

plt.xlabel(‘expected volatility’)

plt.ylabel(‘expected return’)

plt.colorbar(label =’Sharpe ratio’)

用Python寻找最优投资组合

从黄色五角星到红色五角星是投资最有效的组合,这一系列的点所组成的边界就叫做 投资有效边界 。这条边界的特点是同样的风险的情况下获得的收益最大,同样的收益水平风险是最小的。从这条边界也印证了风险与收益成正比,要想更高的收益率就请承担更大的风险,但如果落在投资有效边界上,性价比最高。

参考文章

陈小米.正态性检验和蒙特卡洛完成投资组合优化. http://t.cn/EJSdrgG

定立在简书.最优风险资产组合-Python笔记. https://www.jianshu.com/p/0363bc4fdad4

王小川.《Python与量化投资:从基础到实战》

Introduction to Financial Python-Modern Portfolio Theory http://t.cn/EJSeiPo

转载来自:金融量化

推荐阅读

1.海龟交易法则策略,多读几遍少走10年路

2.一个量化策略师的自白(好文强烈推荐)

3.网格交易法,一个不容易亏钱的投资策略(附源码)

4.市面上经典的量化交易策略都在这里了!(源码)

5.期货/股票数据大全查询(历史/实时/Tick/财务等)

6.量化交易领域最重要的10本参考书推荐!

7.配对交易—这个股票策略曾年赚5000万美元

8.被动与主动的完美结合:指数增强策略的魅力

9.学了那么多技术指标为什么还不赚钱?从量化角度告诉你

10.最科学的仓位管理利器-凯利公式,从方法上胜过99%散户

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202587.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午11:47
下一篇 2026年3月19日 下午11:47


相关推荐

  • java 配置环境变量[通俗易懂]

    java 配置环境变量[通俗易懂]1.情景展示虽然,我们在实际开发过程中,无论是通过idea、eclipse、myeclipse来完成java项目的开发,通过这些工具来帮助我们实现由java文件编译成class文件,但是,一旦脱离了

    2022年7月3日
    24
  • hadoop学习视频

    hadoop学习视频杨尚川的视频 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp http www tudou com plcover EvJCo2zl9hQ 酷 6 视频 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp http v ku6 com show 8PkgqGcarHKn pUw html nr 1 优酷 hadoop 专辑 nbsp nbsp nbsp nbsp nbsp http www youku com playlist show

    2026年3月17日
    3
  • CNN 卷积神经网络结构

    CNN 卷积神经网络结构CNNcnn每一层会输出多个featuremap,每个FeatureMap通过一种卷积滤波器提取输入的一种特征,每个featuremap由多个神经元组成,假如某个featuremap的shape是m*n,则该featuremap有m*n个神经元。对于卷积层会有kernel,记录上一层的featuremap与当前层的卷积核的权重,因此kernel的shape为(上一层feature

    2022年6月23日
    32
  • Eclipse将Maven项目打成jar包[通俗易懂]

    Eclipse将Maven项目打成jar包[通俗易懂]利用Eclipse将项目打包成jar,放入服务器执行。1:在eclipse中选中项目,右键,RunAs,RunConfigurations,输入package,然后点击run执行。2:在eclipse控制台会显示打jar的日志信息,当看到BUILDSUCCESS,代表打包成功。3:将jar包发布到服务器首先将middleware-0.0.1-SNAPSHOT.jar包上传到服务器任意目录,然后查看改jar包是否正在执行。ps-ef|grepjava#查询java进程如果存在,

    2022年6月21日
    136
  • 智谱AI获杭州国资10亿融资,下一代GLM模型即将发布

    智谱AI获杭州国资10亿融资,下一代GLM模型即将发布

    2026年3月12日
    2
  • matlab毕业设计题目_matlab毕业设计论文带有程序

    matlab毕业设计题目_matlab毕业设计论文带有程序毕业设计(论文)`题目:院系机械工程系专业班级学生姓名指导教师二○一年六月Matlab的转子故障振动信号分析摘要随着机械行业的日益发展,转子等旋转机械的故障日渐趋多,转子的故障诊断技术受到越来越多的重视,并在世界范围内取得了长足的进步。作为大型机器中不可或缺的部件,有着举足轻重的作用,但,,,,。对发电机及其转子进行状态监测和信号分析,,转子故障类型主要有四种:转子不平衡、、转子…

    2022年10月15日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号