1998年全国大学生数学建模竞赛A题
目录
题目
问一
用lingo求解
用matlab求解
问2
市场上有n 种资产(如股票、债券、…)Si ( i=1,…n) 供投资者选择,某公司有数额为M 的一笔相当大的资金可用作一个时期的投资。公司财务分析人员对这n 种资产进行了评估,估算出在这一时期内购买Si 的平均收益率为 ri,并预测出购买Si的风险损失率为qi 。考虑到投资越分散,总的风险越小,公司确定,当用这笔资金购买若干种资产时,总体风险可用所投资的Si 中最大的一个风险来度量。
购买Si 要付交易费,费率为 pi,并且当购买额不超过给定值 ui时,交易费按购买ui 计算(不买当然无须付费)。另外,假定同期银行存款利率是r0, 且既无交易费又无风险。( r0=5% )
1)已知n = 4 时的相关数据如下:
Si ri(%) qi(%) pi(%) ui(元)
S1 28 2.5 1 103
S2 21 1.5 2 198
S3 23 5.5 4.5 52
S4 25 2.6 6.5 40
试给该公司设计一种投资组合方案,即用给定的资金 ,有选择地购买若干种资产或存银行生息,使净收益尽可能大,而总体风险尽可能小。
2)试就一般情况对以上问题进行讨论,并利用以下数据进行计算。
Si | ri/% | qi/% | pi/% | ui/元 |
S1 | 9.6 | 42 | 2.1 | 181 |
S2 | 18.5 | 54 | 3.2 | 407 |
S3 | 49.4 | 60 | 6 | 428 |
S4 | 23.9 | 42 | 1.5 | 549 |
S5 | 8.1 | 1.2 | 7.6 | 270 |
S6 | 14 | 39 | 3.4 | 397 |
S7 | 40.7 | 68 | 5.6 | 178 |
S8 | 31.2 | 33.4 | 3.1 | 220 |
S9 | 33.6 | 53.3 | 2.7 | 475 |
S10 | 36.8 | 40 | 2.9 | 248 |
S11 | 11.8 | 31 | 5.1 | 195 |
S12 | 9 | 5.5 | 5.7 | 320 |
S13 | 35 | 46 | 2.7 | 267 |
S14 | 9.4 | 5.3 | 4.5 | 328 |
S15 | 15 | 23 | 7.6 | 131 |
model:
sets:
type/1..5/:c,x;
rate/1..4/:;
link(type,rate):asset,A;
point/1..11/:w,q_lim,v_lim;
endsets
data:
asset=5 0 0 0
28 2.5 1 103
21 1.5 2 198
23 5.5 4.5 52
25 2.6 6.5 40;
w_start=0;
w_add=0.1;!权重初值和每次求解的增量;
enddata
submodel sub:
@for(type(i):c(i)=@if(x(i)#eq#0,0,@smax(A(i,3)*A(i,4),A(i,3)*x(i)))); !计算购买各资产的交易费;
q=@max(type(i):A(i,2)*x(i)); !投资组合x的风险(以各类资产中最大的风险为度量);
v=@sum(type(i):A(i,1)*x(i)-c(i)); !投资组合x的平均净利润;
@sum(type(i):x(i)+c(i))=10000; !约束条件;
endsubmodel
submodel obj:
min=w_sum*q-(1-w_sum)*v;
endsubmodel
calc:
@for(link(i,j)|j#le#3:A(i,j)=asset(i,j)*0.01); !#le#左边运算符<=右边运算符;
@for(link(i,j)|j#eq#4:A(i,j)=asset(i,j));
!系统参数设置;
!@set('terseo',1);!只输出简单的求解信息;
!@set('stawin',0);!关闭求解状态窗口;
!分别求解不同广告费上限的优化问题;
@for(point(n):w_sum=w_start+(n-1)*w_add;
@solve(obj,sub);!求解子模型;
!记录计算结果;
w(n)=w_sum;
q_lim(n)=q;
v_lim(n)=v;);
!显示所记录的结果;
@write('w 风险 净利润',@newline(1));!@write函数用于输出结果,@newline即输出新行;
@for(point(n):@write(@format(w(n),'#12.1f'),@format(q_lim(n),'#12.2f'),@format(v_lim(n),'#12.1f'),@newline(1)));
endcalc
end
结果:
还可以对权重w按0.001的间隔取值计算并作图:
lingo:
sets:
type/1..5/:c,x;
rate/1..4/:;
link(type,rate):asset,A;
point/1..1001/:w,q_lim,v_lim;
endsets
data:
asset=5 0 0 0
28 2.5 1 103
21 1.5 2 198
23 5.5 4.5 52
25 2.6 6.5 40;
w_start=0;
w_add=0.001;!权重初值和每次求解的增量;
@ole('C:\Users\烟雨潇潇\Desktop\新建文件夹\CSDN\数模4.8例2.xlsx',q)=q_lim;
@ole('C:\Users\烟雨潇潇\Desktop\新建文件夹\CSDN\数模4.8例2.xlsx',v)=v_lim;
enddata
matlab:
clc,clear
q=xlsread('C:\Users\烟雨潇潇\Desktop\新建文件夹\CSDN\数模4.8例2.xlsx',1,'A1:A1000');
v=xlsread('C:\Users\烟雨潇潇\Desktop\新建文件夹\CSDN\数模4.8例2.xlsx',1,'B1:B1000');
plot(q,v)
xlabel('风险/元')
ylabel('收益/元')
title('例2的有效前沿')
grid on %网格线
主程序:
clear,clc
global w %设定风险q和净收益v的权重分别为w,1-w
global asset
global type
%资产的数据矩阵,第一行为银行存款
%列1平均收益率,列2风险损失率,列3交易费率,列4定值
asset=[5 0 0 0;
28 2.5 1 103;
21 1.5 2 198;
23 5.5 4.5 52;
25 2.6 6.5 40];
asset(:,1:3)=asset(:,1:3)*0.01;%前三列用百分率
type=size(asset,1); %维度为1时,size返回矩阵的行数(资产种类)
% fmincon(@fun,x0,A,b,Aeq,beq,lb,ub,nonlcon(非线性约束),options) %求fun最小值,一般fval=fun(x)
%约束条件为Aeq*x = beq 和 A*x <= b
x_final=zeros(type,11);%记录x
q=[];%记录投资组合x的风险
v=[]; %投资组合x的平均净收益
gs = GlobalSearch;
for i=1:11
w=(i-1)/10;
%[x,fval]=ga(@minfun,5,[],[],[],[],zeros(5,1),[],@nonfun);
%x=x';
problem = createOptimProblem('fmincon','objective',@minfun,'x0',zeros(5,1),'Aineq',[],'bineq',[],'Aeq',[],...
'beq',[],'lb',zeros(type,1),'ub',[],'nonlcon',@nonfun);
%'options',optimset('Algorithm','SQP','Disp','none')
x = run(gs,problem);
x_final(:,i)=x;
q=[q,max(asset(:,2).*x)];
v=[v,sum(asset(:,1).*x-cfun(x))];
end
minfun.m
function[y]=minfun(x)
global w
global asset
%x=x';
q=max(asset(:,2).*x); %投资组合x的风险(以各类资产中风险最大的一个度量)
v=sum(asset(:,1).*x-cfun(x)); %投资组合x的平均净收益
y=w*q-(1-w)*v; %设定风险q和净收益v的权重分别为w,1-w
cfun.m
function[c]=cfun(x) %cfun函数计算购买各资产的交易费
global type
global asset
c=zeros(type,1); %列向量
for i=1:type
if x(i)<=0.06
c(i,1)=0;
else
c(i,1)=max(asset(i,3)*asset(i,4),asset(i,3)*x(i)); %每种资产购买额x(i)不超过定值时,交易费按购买定值计算
end
end
nonfun.m
function[g,ceq]=nonfun(x)%非线性约束:g(x)<=0 ,ceq(x)=0
%x=x';
g=[];
m=10000;
ceq=sum(x+cfun(x))-m;
matlab尝试过很多次,下图是最好的一次,但是cfun里要设置x<=0.06,x==0会和书上结果大不一样。
简单的代入就可以了,如果w以0.1为间隔,运行15秒即可出结果。