最优投资组合选择SAS实现.docx
《最优投资组合选择SAS实现.docx》由会员分享,可在线阅读,更多相关《最优投资组合选择SAS实现.docx(31页珍藏版)》请在冰豆网上搜索。
最优投资组合选择SAS实现
最优投资组合选择——SAS实现
1、分享一些感觉
当初,在我翻看《金融计算与建模》这本书的时候,我也感觉:
哇,会很难懂吧!
yes,有这种感觉应该正常,因为书中的有些细节确实不是那么好理解,但这不影响我们有选择性地加以应用。
整本书的大部内容都突出了“计算”二字——各种收益率计算、各种指数计算、各种风险价值(价格或指标)计算、VaR计算、利率计算等等。
这些计算搞得我很“蒙蔽”,因为,当我在阅读程序语句时总是搞不明白,这些计算对应的是哪个数据集、哪个字段。
现在,用一种轻松的感觉挑选着翻看其中某些章节的内容,顿时发现“山重水复疑无路,柳暗花明又一村”了,原来当初是“不识庐山真面目,只缘生在此山中”啊,好吧,接下来,我就股票/证券领域中的投资组合理论来介绍一下我是如何柳暗花明的。
参看书籍是朱世武的《金融计算与建模》,数据集来自锐思数据库。
2、一句话的阳光
在SAS中进行最优投资组合选择需要:
计算股票期望收益率——
计算风险度量指标——
/
优化求解组合权重——weight
Yes,就是这三句话。
前两句没什么好说的,第三句由于是规划问题,所以就要考虑到优化建模的一系列问题,比如,灵敏度分析、整型规划、变量限制条件,等等。
投资组合就这些内容吧,分解一下就soeasy吧。
3、各个击破
在对上述三个步骤进行各个击破前,让我们来熟悉一下,我们所要使用的数据集,以及数据集中的字段吧————这是一个十分十分重要的觉悟性认识!
需要字段:
8只股票包括代码名、1995-2005年A股市场月持有收益率、3只股票月持有收益率。
由于这三个字段来自不同方的数据集,所以需要进行整合。
为什么选择这8只股票?
这就是我们最初选股的问题了,而不是投资组合问题。
数据说明:
resdat是自建的存储在SAS系统逻辑库下的库名,类似Work。
monret是个股月持有期收益率数据集;monretm是市场持有期收益率数据集。
(这里,我门不关心这两个收益率是如何得来的)
Ø数据准备阶段,程序见下:
创建8只股票的代码收益率
dataStk8;
inputstkcd$6.;
cards;
000002
000007
000011
000016
600601
600604
600651
600653
;run;
按8只股票名合并数据,回忆一下merge函数,学习samp变量作用哟
datareturn;
mergeresdat.monretstk8(in=samp);
bystkcd;
ifsamp;
year=year(date);
month=month(date);
if1995<=year<=2005;
keepstkcddateyearmonthmonret;
提取1995-2005年A股市场月持有期收益率
datamonretm;
setresdat.monretm;
year=year(date);
month=month(date);
If1995<=year<=2005andExchflg='0'andMktflg='A';
keepdateyearmonthMretmc;
procsortdata=return;
byyearmonth;
合并市场月收益率数据集和8只股票月收益率
datareturn;
mergereturnmonretm;
byyearmonth;
procsortdata=return;
bystkcdyearmonth;
run;
Ø数据计算阶段,程序见下:
计算期望收益,没什么好解释的,复习一下output和where
procmeansdata=returnnoprint;
bystkcd;
varmonret;
outputout=m_out;
datam_out1a;
setm_out;
where_stat_='MEAN';
keepstkcdmonret;
run;
计算风险度量指标
常用的风险度量指标有股票收益标准差
和资本资产定价模型(CAPM)的
。
计算
注意,_stat_=“大写”(看看m_out数据集就知道了),SAS不分函数大小写,但是变量名(有些时候也宽容地认为不分大小写的)和值分大小写。
datam_out1b;
setm_out;
where_stat_='STD';
keepstkcdmonret;
renamemonret=std;
labelmonret='月收益率标准差';
run;
计算
根据CAPM模型,资产i的期望收益和市场收益之间的关系为:
,设投资组合权重为
,投资组合p的参数为:
,
,(在这里要理解一下N和p的关系,N可以理解为股票的个数,p可以理解为选出的组合,p≤N,M就不难理解了,表示市场总体)定义总风险为收益的标准差,则资产i收益的方差为:
,投资组合p收益的方差为:
,
相当于单个股票的收益方法差,
写成这样有一个隐含的假设,即各只股票的收益不相关(独立),既然这样,当投资组合相当分散时,
会趋近于0,收益方差近似为:
。
其实,在我们的数据分析中,就是搞了一个线性回归(由于是时间序列数据,所以做了一个dw自相关检验),来看下程序吧:
procregdata=returnoutest=capmest11;
bystkcd;
modelmonret=Mretmc/dw;
quit;/*换成run也可以,这就是SAS的包容性所在,交互环境问题*/
/*我查看了一下常数项不显著,反正它没什么解释性意义,去掉常数项重新拟合模型,这里保持原文,不做修改*/
/*procregdata=returnoutest=capmest11;*/
/*bystkcd;*/
/*modelmonret=Mretmc/dwnoint;*/
/*run;*/
优化求解组合权重——无限制权重
对期望收益进行组合后的最大化求解,选择
为风险
建立优化求解的数据格式,这种实现整理好优化建模所需数据集格式的方式真值得学习(只要足够认真,就能发现书中的错误,改正之便是一种超越,走进书还要跳出书)
dataweight1;
input_id_:
$10.r000002r000007r000011r000016r600601r600604r600651r600653_type_$_rhs_;
cards;
exp_return0.02470.01270.01240.0080.02160.00680.02630.0144max.
beta1.11850018911.34701230111.31857492331.02606541291.35094999650.90389584431.25591093351.2961143173eq1.2
sum_wts1.01.01.01.01.01.01.01.0eq1.0
available11111111upperbd.
available00000000lowerbd.
;run;
优化求解权重
proclpdata=weight1primalout=lp_out1;
title1'最优投资组合权重';
run;
quit;
优化求解组合权重——增加限制权重条件
将权重设置为0.05~0.3333,这样做的意义何在呢?
确保投资组合的分散性
dataweight2;
input_id_:
$10.r000002r000007r000011r000016r600601r600604r600651r600653_type_$_rhs_;
cards;
exp_return0.02470.01270.01240.0080.02160.00680.02630.0144max.
beta1.11850018911.34701230111.31857492331.02606541291.35094999650.90389584431.25591093351.2961143173eq1.2
sum_wts1.01.01.01.01.01.01.01.0eq1.0
available.3333.3333.3333.3333.3333.3333.3333.3333upperbd.
available.05.05.05.05.05.05.05.05lowerbd.
;
run;
proclpdata=weight2primalout=lp_out2;
title2'多约束的投资组合权重';
run;
quit;
灵敏度分析——以weight2为例
选项rangeprice是规定输出价格系数范围的分析,rangehs是规定输出优化求解中右侧变化的分析。
proclpdata=weight2primalin=lp_out2rangepricerangerhs;
title2'灵敏度分析';
run;
quit;
当限定组合的最高风险水平时
设定投资组合风险小于等于1.2,这样做事为了放宽风险的下限变化区域,在一个宽松的环境中求解目标函数,当出现更大的收益和更小的风险时,说明这种投资组合更优越。
dataweight3;
setweight2;
if_id_='beta'then_type_='le';
run;
proclpdata=weight3primalout=lp_out3;
run;
quit;
计算投资金额,很简单的程序,没什么可解释的
datalp_out3a;
setlp_out3;
if_n_>8thendelete;
amount=_value_*100000;
rename_var_=asset;
procprintdata=lp_out3a;
varassetamount;
title'线性规划';
title2'在每种资产上的投资金额';
run;
整数规划
创建只股票2005年12月30日的收盘价数据集
dataprice;
mergeresdat.qttndiststk8(in=samp);
bystkcd;
ifsampanddate='30dec2005'd;
keepstkcdclpr;
run;
规划求解
收盘价乘以100作为每手价格,限定投资总额小于等于100000,每只股票的手数设定为5~50手,每只股票的风险与购买手数的乘积之和小于200。
dataweight4;
input_id_:
$10.r000002r000007r000011r000016r600601r600604r600651r600653_type_$_rhs_;
cards;
exp_return0.02470.01270.01240.0080.02160.00680.02630.0144max.
beta1.11850018911.34701230111.31857492331.02606541291.35094999650.90389584431.25591093351.2961143173le200
lots431322522352320349596148le100000
upper5050505050505050upperbd.
lower55555555lowerbd.
integer12345678integer.
;
proclpdata=weight4imaxit=200primalout=lp_out4dualout=d_out;
run;
/*imaxit设置最大迭代次数,默认100次,primalout和dualout是输出整型规划的主要解和对偶解到数据集*/
以下程序语句是对结果进行整理:
datalp_out4a(keep=_var__value_rename=_var_=name);
setlp_out4;
if_n_>8thendelete;
run;
procprintdata=lp_out4a;
title'整数规划';
title2'购买手数';
run;
打印出对偶数据集中的投资组合收益、最佳投资金额、最佳投资组合风险水平(结果分别为:
3.6423,71975,199.51):
procprintdata=d_out;
title'整数规划';
title2'收益、风险和投资金额';
run;
以下程序还是数据集操作——为了进行结果对比,没什么可说的,soeasy的
proctransposedata=weight4out=wt1;
run;
datawt2(drop=col4col5col6);
setwt1;
if_n_>8thendelete;
rename_name_=namecol1=returncol2=betacol3=lots;
run;
procprintdata=wt2;
title'整数规划';
title2'转置和修改后的输入数据集';
datawt3;
mergelp_out4awt2;
procprintdata=wt3;
title'整数规划';
title2'合并数据集';
run;
以下程序计算每只股票对风险和收益的贡献,并求其累积值,理解其意义就easy了,结果为:
8只股票的投资组合的风险为1.2213942,
datawt4;
setwt3;
amt=71975;
fraction=_value_*lots/amt;
risk=fraction*beta;
exp_ret=fraction*return;
run;
procmeansdata=wt4sum;
varriskexp_ret;
title2'风险和收益的比较量度';
run;
允许卖空时的投资组合计算
设定组合风险水平小于1,组合权重在-1~1之间,组合权重的绝对值为1,这样设定是为了体现卖空,期望收益中加了负号的表示卖空。
dataweight5;
input_id_:
$10.r000002_1r000007_1r000011_1r000016_1r600601_1r600604_1r600651_1r600653_1r000002_2r000007_2r000011_2r000016_2r600601_2r600604_2r600651_2r600653_2
_type_$_rhs_;
cards;
exp_return0.02470.01270.01240.0080.02160.00680.02630.0144-0.0247-0.0127-0.0124-0.008-0.0216-0.0068-0.0263-0.0144max.
beta1.11850018911.34701230111.31857492331.02606541291.35094999650.90389584431.25591093351.2961143173-1.1185001891-1.3470123011-1.3185749233-1.0260654129-1.3509499965-0.9038958443-1.2559109335-1.2961143173le1.0
sum_wts1.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.0eq1.0
available1111111111111111upperbd.
;run;
datalp_out5a;
setlp_out5;
if_n_>16thendelete;
if_value_=0thendelete;
amount=_value_*100000;
rename_var_=asset;
run;
procprintdata=lp_out5a;
varassetamount;
title'整数规划';
title2'每只股票的投资金额';
run;
不再展示以上程序的输出结果,这种设定更符合实际,因为某一只股票的期望收益可能为负值,并且绝对值还会比较大,因此,持有和卖空的收益是不同的。
值得注意的是,在线性约束条件下的优化求解中可能会出现全部非0的权值(这个应该能够理解吧,得细细斟酌!
),如果全部非0的话,那么就说明某只股票的期望收益的正负与你设定的持有还是卖空不对应,还有可能是期望收益的绝对量都相差不大。
设定投资组合风险小于等于0.75,和上文
的程序差不多
这里明示一个小观念:
可以设定投资组合风险为负值,如果这样,则说明投资组合与市价波动相反,当市价上涨时投资组合收益下降,反之投资组合收益上升。
dataweight5b;
setweight5;
if_id_='beta'then_rhs_=.75;
run;
proclpdata=weight5bprimalout=lp_out5b;
run;
quit;
设最优的权重边界——没啥好说的,主要是修改约束条件,重在理解经济意义啦!
设定持有每只股票数量的上界为0.25,卖空的下界为0.3时
dataweight6;
input_id_:
$10.r000002_1r000007_1r000011_1r000016_1r600601_1r600604_1r600651_1r600653_1
r000002_2r000007_2r000011_2r000016_2r600601_2r600604_2r600651_2r600653_2
_type_$_rhs_;
cards;
exp_return0.02470.01270.01240.0080.02160.00680.02630.0144-0.0247-0.0127-0.0124-0.008-0.0216-0.0068-0.0263-0.0144max.
beta1.11850018911.34701230111.31857492331.02606541291.35094999650.90389584431.25591093351.2961143173-1.1185001891-1.3470123011-1.3185749233-1.0260654129-1.3509499965-0.9038958443-1.2559109335-1.2961143173eq1.0
sum_wts1.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.0eq1.0
available.25.25.25.25.25.25.25.25.3.3.3.3.3.3.3.3upperbd.
;
proclpdata=weight6primalout=lp_out6;run;
quit;
datalp_out6a;
setlp_out6;
if_n_>16thendelete;
if_value_=0thendelete;
amount=_value_*100000;
rename_var_=asset;
run;
procprintdata=lp_out6a;
varassetamount;
title'整数规划';
title2'每只股票的投资金额';
run;
非线性规划
马柯维茨模型是非线性规划问题,因为它考虑到了股票间的相关性。
建立数据集——用到了对数据的转置操作
datareturn1;
setreturn;
wherestkcdin('000002''000007''000011');run;
proctransposedata=return1out=return1(drop=_name__label_);
bystkcd;
varmonret;run;
proctransposedata=return1out=return1(drop=_name_);run;
求3只股票期望收益的协方差
proccorrdata=return1covoutp=cov_out1nosimple;
varcol1col2col3;
title'Markowitz模型';
quit;
计算投资组合收益
两只股票的组合收益为:
,x是自主设定的权重值。
用循环建立了一个新变量x
datacov_out2(drop=_name_);
setcov_out1;
if_type_ne'MEAN'thendelete;
dox=0to1by.05;
output;
end;
renamecol1=r000002col2=r000007col3=r000011;
labelx='投资组合的权重';
run;
计算不同权重下的组合收益:
datamean1;
setcov_out2;
pfol_m1=x*r000002+(1-x)*r000007;
pfol_m2=x*r000002+(1-x)*r000011;
pfol_m3=x*r000007+(1-x)*r000011;
run;
procprintdata=mean1;
title'Markowitz模型';
title2'两种股票投资组合的收益';
run;
图形展示——直接看图就能明白程序啦
procgplotdata=mean1;
plotpfol_m1*x=1pfol_m2*x=2pfol_m3*x=3/overlay;
symbol1v=stari=nonec=black;
symbol2v==i=nonec=red;
symbol3v=plusi=nonec=green;
title1'';/*貌似无用*/
title2'投资组合收益与投资组合权重散点图';
run;
quit;
计算投资组合风险——我们的目的是找到在不同的x下的最低风险水平——找最小值或图形化展示
两只