查看原文
其他

利用Python构建马科维茨有效边界

爬虫俱乐部 Stata and Python数据分析 2022-03-15

本文作者:陈丹慧,中南财经政法大学金融学院

本文编辑:杨婉清

技术总编:陈   鼎

Stata&Python云端课程来啦!

为了感谢大家长久以来的支持和信任,爬虫俱乐部为大家送福利啦!!!Stata&Python特惠课程双双上线腾讯课堂~原价2400元的Python编程培训课程,现在仅需100元,详情请查看推文《Python云端课程福利大放送!0基础也能学~》。关于Stata,爬虫俱乐部推出了系列课程,内容包括字符串函数、正则表达式、爬虫专题和文本分析,可以随心搭配,价格美丽,物超所值,更多信息可查看Stata系列推文《与春天有个约会,爬虫俱乐部重磅推出正则表达式网络课程!》《与春天有个约会,爬虫俱乐部重磅推出基本字符串函数网络课程》等。变的是价格,不变的是课程质量和答疑服务。对报名有任何疑问欢迎在公众号后台和腾讯课堂留言哦!


引言INTRODUCTIONsummer data

1952年,美国经济学家马可维茨在他的学术论文《资产选择:有效的多样化》中,首次应用资产组合报酬的均值和方差这两个数学概念,从数学上明确地定义了投资者偏好,并以数学化的方式解释投资分散化原理,系统地阐述了资产组合和选择问题,标志着现代资产组合理论(Modern Portfolio Theory,简称MPT)的开端。现代投资组合的一个基本假设是厌恶风险假设——对于同样的风险水平,理性投资者将会选择能提供最大预期收益率的组合;对于同样的预期收益率,他们将会选择风险最小的组合。而有效集就是指同时能满足预期收益率最大、风险最小投资组合的集合。本文基于马科维茨有效集理论,将利用Python构建一个有效边界。

<<<<<<<
01SUMMER DATA利用Tushare获取股票数据首先,本文选取了今年7月1日雪球网沪深证券关注人数增长Top10中的5只股票作为构建投资组合的对象,它们分别是SZ002156(通富微电)、SZ002433(太安堂)、SZ300124(汇川技术)、 SH600771(广誉远)和SH601919(中远海控)。接下来,本文利用Tushare获取这几只股票近三年的历史交易数据。Tushare是一个免费、开源的python财经数据接口包,利用Tushare我们能实现对股票数据的采集。在之前的推文中我们介绍过Tushare的安装与配置,在此不再赘述。利用Tushare Pro的daily接口,获取这五只股票的日度收盘价,代码如下:
import tushare as tsimport pandas as pdts.set_token('您的token')pro=ts.pro_api()df = pro.daily(ts_code='600771.SH,002433.SZ,300124.SZ,601919.SH,002156.SZ', start_date='20180701', end_date='20210701')df=df.pivot(index='trade_date',columns='ts_code',values='close') #重塑数据表

为了更加直观展示这五只股票,本文绘制了股价历史走势折线图,代码如下:
import matplotlib.pyplot as pltimport seaborn as snssns.set_style("whitegrid")sns.set(font='SimHei')plt.rcParams['axes.unicode_minus'] = False #正常显示负号plt=df.plot(figsize=(10,6))plt.set_xlabel('日期',fontsize=12) plt.set_ylabel('收盘价',fontsize=12) plt.set_title('股价历史走势',fontsize=18)

02SUMMER DATA构建1000个投资组合为了构建投资组合,我们首先需要将股价转化为股票收益率。本文将相邻两天股价取对数后的差作为股票收益率,代码如下:
import numpy as npreturns_day=np.log(df)-np.log(df.shift(1)) #计算日度收益率returns_day.dropna(inplace=True) #删除空值#绘制日收益率波动图plt_v=returns_day.plot(figsize=(10,6))plt_v.set_xlabel('日期',fontsize=12) # x轴标注plt_v.set_ylabel('日收益波动率',fontsize=12) # y轴标注plt_v.set_title('股票日收益率波动',fontsize=18)

考虑到股票停盘和非交易日等因素,选取250天作为年化天数,这几只股票的年化收益率如下:
returns_annual = returns_day.mean()*250 #计算年化收益率

这几只股票的协方差如下:
returns_day.cov()*250 #计算协方差

获取单只股票的期望收益率和几只股票的协方差后,就可以求得投资组合的期望收益率和标准差,本文构建投资组合的代码如下:
#随机生成1000个投资组合portfolio_r = [] portfolio_v = [] num_assets=5 #组合中的资产数for x in range(1000): #设置不同的随机种子,生成和为1的权重 np.random.seed(x) weights = np.random.random(num_assets) weights /= np.sum(weights) returns=np.sum(weights*returns_annual) #期望收益率 volatility=np.sqrt(np.dot(weights.T ,np.dot(returns_day.cov() * 250 ,weights))) #标准差 portfolio_r.append(returns) portfolio_v.append(volatility)portfolios=pd.DataFrame({'Return':portfolio_r,'Volatility':portfolio_v})最终构建的1000个投资组合风险和收益如下图所示:

03SUMMER DATA画出有效边界已知投资组合的收益与风险,我们可以画出所有可行集。但为了得到有效边界,我们还需要求解给定收益率水平下的最小标准差。利用Scipy包中的scipy.optimize.minimize我们可以在一定约束条件下求解目标函数的最小值。
import scipy.optimize as sco
#目标函数为标准差:def sd(weights): return np.sqrt(np.dot(weights.T ,np.dot(returns_day.cov() * 250 ,weights)))#初始值x0:num_assets=5np.random.seed(0)x0=np.random.random(num_assets)x0/=np.sum(x0)#目标函数输入参数(即权重)取值范围为0-1:bounds=tuple((0, 1) for x in range(num_assets))
min_risks=[]for i in portfolios['Return']: constraints=[{'type':'eq','fun':lambda x: sum(x)-1},{'type':'eq','fun': lambda x:sum(x*returns_annual)-i}] #两个约束条件:(1)权重之和为1 (2)给定收益率 outcome=sco.minimize(sd,x0=x0,constraints=constraints,bounds=bounds) #求解 min_risks.append(outcome.fun) #将最小标准差合并到列表中
min={'收益':portfolios['Return'],'最小风险':min_risks}pd.DataFrame(min)

最终绘制有效边界的代码如下:
plt_portfolios=portfolios.plot(x='Volatility',y='Return',kind='scatter',figsize=(10,6))plt_portfolios.plot(min_risks,portfolios['Return'],'rx')plt_portfolios.set_xlabel('风险',fontsize=12) plt_portfolios.set_ylabel('收益',fontsize=12) plt_portfolios.set_title('有效边界',fontsize=18)

以上就是今天的全部内容了,欢迎各位感兴趣的小伙伴点赞转发关注哦~

最后,我们为大家揭秘雪球网(https://xueqiu.com/)最新所展示的沪深证券和港股关注人数增长Top10。


对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!

往期推文推荐 

rangestat,让统计量灵活滚动起来!

听说这样做立项成功率更高哦

如何处理缺失值?这一篇搞定!

  善用dataex命令,高效沟通你我他

  用Markdown制作简历,强力助力你的求职季

大数据下的大学分数线排行榜,快来围观!

《觉醒年代》—带你回到百年前

用Stata画的三维图很奇怪怎么办?

如何随机生成满足特定数据特征的新变量?

爬取无法翻页网页——自然科学基金项目及可视化

爬取京东评论数据进行情感分类

Stata与音乐之间的酷炫连接

这些年,爬虫俱乐部走出的博士们!
         看这里,近五年各校高被引论文上榜名单!

高校经管类核心期刊发文排行榜

疯狂的科研创新加速器——Stata!

  可盐可甜,“粽”有所爱,快来pick你最爱的粽子吧!

  好玩有趣的手绘图形库——cutecharts

  爬虫实战|摩尔庄园微博话题讨论

  一季度财报出炉,哪些公司最烧钱?

  一季度财报出炉,哪些公司最赚钱?

  技能篇 | 图片合并大法

  批量空气质量数据文件合并分析

  Stata17之日期时间新功能

  Stata17之Lasso新功能

爱奇艺视频弹幕爬取之《小舍得》数据可视化利器——Matplotlib

  从第七次人口普查看中国人口变化|Stata与Python交互绘图

  200万投资者关注!!哪家公司这么牛?

关于我们 


微信公众号“Stata and Python数据分析”分享实用的Stata、Python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。



此外,欢迎大家踊跃投稿,介绍一些关于Stata和Python的数据处理和分析技巧。

投稿邮箱:statatraining@163.com投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存