前言
本文展示实际操作的代码和效果,不作数学推导哦~本文用到的源码和数据都会给出,小伙伴们有需要自行领取。网上有许许多多使用遗传算法优化,我的观点是根本跑不出来,为了保证迭代的效果,迭代次数较多,模拟退火跑出来的时间都非常长,更别说在实际建模过程中的数据量和遗传的复杂度了。不过建模用遗传,结果用退火跑,也是可以的(狡猾)。
本文一共四个步骤进行求解:
建立无监督评价指标。这是因为附录只给出收盘价,只用这一指标进行求解太过单调,参考价值过低。
数据和代码见百度网盘:
链接:https://pan.baidu.com/s/1p9uSNuDBFubvTNfI03PC_g?pwd=hvaz
提取码:hvaz
目录
题目
已有50支股票135天内的收盘价,请评价出十支最值得购买的股票。
图1 股票收盘价数据(局部)
Step 1. 建立无监督评价指标
最大回辙率(极小型):
drawdown0=zeros(n-1,m);%回辙率初始化
drawdown=zeros(1,m);% 最大回辙率初始化
for j=1:m
for i=1:n-1
drawnow0(i,j)=(close_price(i,j)-close_price(i+1,j))/close_price(i,j);
end
end
drawdown=max(drawnow0);
图2 最大回辙率代码
收盘价稳定度(极小型):
stability=zeros(1,m);% 收盘价稳定度初始化
for j=1:m
stability(j)=((max(close_price(:,j))-min(close_price(:,j)))/max(close_price(:,j))+min(close_price(:,j)))*std(close_price(:,j));
end
图3 收盘价稳定度代码
平均日收益率(极大型):
dailyrate0=zeros(n,m);% 日收益率初始化
for j=1:m
for i=1:n-1
dailyrate0(i,j)=(close_price(i+1,j)-close_price(i,j))/close_price(i,j);
end
end
dailyrate=sum(dailyrate0)/n;
% 整理成一个表格
indicators(:,1)=drawdown';
indicators(:,2)=stability';
indicators(:,3)=dailyrate';
图4 平均日收益率代码
Step2. 数据预处理
对两个极小型指标进行正向化:
[n1,m1]=size(indicators);
for j=1:m1-1
indicators(:,j)=max(indicators(:,j))-indicators(:,j);% 对两个极小型指标进行正向化
end
图5 正向化代码
然后对三个评价指标进行归一化:
normal_indicators=zeros(50,3);% 归一化矩阵初始化
for j=1:m1
for i=1:n1
normal_indicators(i,j)=(indicators(i,j)-0.02*min(indicators(:,j)))/(0.98*max(indicators(:,j))-0.02*min(indicators(:,j)));
end
end
图6 归一化代码
Step3. 投影寻踪
n为股票数,值为50,m为指标数,值为3。
计算各支股票的一维线性投影:
定义投影寻踪的目标函数为:
其中Sa为一维线性投影的标准差:
定义一维线性投影之间的距离:
定义阶跃函数:
因此投影寻踪优化模型如下:
function Qa=LinearPr(X,a)
% 计算线性投影
[n,m]=size(X);
for i=1:n
sum1=0;
for j=1:m
sum1=sum1+a(j)*X(i,j);
end
Z(i)=sum1;
end
Sa=std(Z);% 线性投影值的方差 类间距离
R=0.1*Sa;% 领域半径
% 计算局部密度
Da=0;% 类内密度
for i=1:n
for j=1:n
r=abs(Z(i)-Z(j));% 线性投影间距
t=R-r;% 阶跃信号
if t<0
u=0;
else
u=1;
end
Da=Da+t*u;
end
end
Qa=Sa*Da;% 目标函数
end
图7 投影寻踪线性函数代码
Step4. 模拟退火
外层循环迭代次数:100次
初始温度:temper=1000
内层循环迭代次数:iter=10
退火速率:0.999
退火终止温度:0.0001
灵敏度分析:用一个sensitivity数组去记录每次内层循环迭代出来的最优目标函数值,在退火过程结束后绘制出sensitivity的折线图,观察其是否收敛,若收敛则可以说明模拟退火求解的结果有效。
% 模拟退火优化投影寻踪
% sensitivity=[];% 灵敏度分析矩阵
for i=1:100
sensitivity=[];% 灵敏度分析矩阵
temper=1000;% 初始温度
iter=10;% 迭代次数
temp=rand(1,3);% 生成一个线性投影初始解
templinear=temp;% 存储最优线性投影
Qa=LinearPr(normal_indicators,temp);% 生成初始目标函数值
sensitivity =[Qa];
while temper>0.0001% 退火
for j=1:iter
temp1=rand(1,3);
Qa1=LinearPr(normal_indicators,temp1);
if Qa1>Qa
Qa=Qa1;
templinear=temp1;
else
if exp((Qa1-Qa)/temper)>rand()
Qa=Qa1;
templinear=temp1;
sensitivity = [sensitivity, Qa];
end
end
sensitivity = [sensitivity, Qa];
end
temper=temper*0.999;
TempLinear(i,:)=templinear;% 存储各样本的线性投影值
end
% plot(sensitivity)
Y(i)=Qa;
i
end
plot(sensitivity)% 绘制灵敏度分析图
target=TempLinear(find(max(Y)==Y),:)% 先找出最大的评价值,然后在从投影向量矩阵TempLinear中寻找该向量
score=sum(normal_indicators.*target,2);
图8 模拟退火代码
Step5 .结果展示
最优投影值:
图9 最优投影向量
最值得购买的十支股票:
图10 最优股票
灵敏度分析:
可以看出目标函数值在经过狠多次迭代之后已经收敛了,本文认为模拟退火有效。因为时间的关系,我的迭代次数没有设置那么多,大家可以试试迭代更久。
图11 灵敏度分析
Step6 .完整源码
clear;clc
tic
close_price=xlsread("50支股票的收盘价.xlsx");
[n,m]=size(close_price);
close_price=close_price([2:136],:);
% 建立无监督评价指标
drawdown0=zeros(n-1,m);%回辙率初始化
drawdown=zeros(1,m);% 最大回辙率初始化
for j=1:m
for i=1:n-1
drawnow0(i,j)=(close_price(i,j)-close_price(i+1,j))/close_price(i,j);
end
end
drawdown=max(drawnow0);
stability=zeros(1,m);% 收盘价稳定度初始化
for j=1:m
stability(j)=((max(close_price(:,j))-min(close_price(:,j)))/max(close_price(:,j))+min(close_price(:,j)))*std(close_price(:,j));
end
dailyrate0=zeros(n,m);% 日收益率初始化
for j=1:m
for i=1:n-1
dailyrate0(i,j)=(close_price(i+1,j)-close_price(i,j))/close_price(i,j);
end
end
dailyrate=sum(dailyrate0)/n;
% 整理成一个表格
indicators(:,1)=drawdown';
indicators(:,2)=stability';
indicators(:,3)=dailyrate';
% 数据预处理
[n1,m1]=size(indicators);
for j=1:m1-1
indicators(:,j)=max(indicators(:,j))-indicators(:,j);% 对两个极小型指标进行正向化
end
normal_indicators=zeros(50,3);% 归一化矩阵初始化
for j=1:m1
for i=1:n1
normal_indicators(i,j)=(indicators(i,j)-0.02*min(indicators(:,j)))/(0.98*max(indicators(:,j))-0.02*min(indicators(:,j)));
end
end
% 模拟退火优化投影寻踪
% sensitivity=[];% 灵敏度分析矩阵
for i=1:100
sensitivity=[];% 灵敏度分析矩阵
temper=1000;% 初始温度
iter=10;% 迭代次数
temp=rand(1,3);% 生成一个线性投影初始解
templinear=temp;% 存储最优线性投影
Qa=LinearPr(normal_indicators,temp);% 生成初始目标函数值
sensitivity =[Qa];
while temper>0.0001% 退火
for j=1:iter
temp1=rand(1,3);
Qa1=LinearPr(normal_indicators,temp1);
if Qa1>Qa
Qa=Qa1;
templinear=temp1;
else
if exp((Qa1-Qa)/temper)>rand()
Qa=Qa1;
templinear=temp1;
sensitivity = [sensitivity, Qa];
end
end
sensitivity = [sensitivity, Qa];
end
temper=temper*0.999;
TempLinear(i,:)=templinear;% 存储各样本的线性投影值
end
Y(i)=Qa;
i
end
plot(sensitivity)% 绘制灵敏度分析图
target=TempLinear(find(max(Y)==Y),:)% 先找出最大的评价值,然后在从投影向量矩阵TempLinear中寻找该向量
score=sum(normal_indicators.*target,2);
toc
function Qa=LinearPr(X,a)
% 计算线性投影
[n,m]=size(X);
for i=1:n
sum1=0;
for j=1:m
sum1=sum1+a(j)*X(i,j);
end
Z(i)=sum1;
end
Sa=std(Z);% 线性投影值的方差 类间距离
R=0.1*Sa;% 领域半径
% 计算局部密度
sum2=0;
for i=1:n
for j=1:n
r=abs(Z(i)-Z(j));% 线性投影间距
t=R-r;% 阶跃信号
if t<0
u=0;
else
u=1;
end
sum2=sum2+t*u;
end
end
da=sum2;% 类内密度
Qa=Sa*da;% 目标函数
end