数模实操|自适应温控记忆优化的模拟退火解决组合投资问题(Markowitz均值方差模型)

摘要

        由于模拟退火的本质是一种暴力搜索,且相比遗传算法和粒子群算法更容易陷入局部最优解,因此本文采用的自适应温控记忆模型优化的思路,目的是使其迭代出来的解尽可能接近全局最优解。自适应温控记忆优化的步骤有三:初始温度、Metropolis准则、回温公式。回温公式的设定需要具体问题具体分析,其目的是增加迭代次数,避免陷入局部最优解,我这里因为例子简单,故没有设定。关于目标函数的建立,同样也是具体问题具体分析,我这里拿的是投资组合的例子。

        题目如下:基于135天的收盘价数据,对评价出来的十支最优股票进行组合投资,要求每支股票的仓位不能超过25%。

        十支重要股票的评价见博客:数模实操演示|投影寻踪法评价十支最值得购买的股票

        数据和代码见百度网盘:

        链接:https://pan.baidu.com/s/1p9uSNuDBFubvTNfI03PC_g?pwd=hvaz 

        提取码:hvaz


目录

         摘要

Step.1 建立 目标函数

Step.2 初始温度

Step. 3 Metropolis准则

Step. 4 完整源码   

结果展示


Step.1 建立 目标函数

均值公式:

e576e7a4cea044ed877133679b1a33ce.png

32fd2515ea134d69b3c870fb97e392eb.png

 方差公式:

9ac9e4f49d42487ab3d183b6836c99e6.png

7e886e0308a9469dace9869bb85eb9c5.png

故目标函数为:

1d248a33991940b6af2c5aad800f3849.png

Step.2 初始温度

改进的初始温度公式如下:我用的例子求出来的温度接近5万度

 11117a4a4d074577bb49b1b51e5d9a16.png

        首先生成多个权重,代入目标函数,求得多个目标函数值,E(max)和E(min)即是这些值里面的最大值和最小值,P可取[0.9,0.99],本文取0.99。

%% 生成自适应温控的权重
% 初始化
temp_w=zeros(10000,10);
temp_total_get=zeros(10000,1);
temp_total_std1=zeros(10000,1);
temp_total_std2=zeros(10000,1);
temp_total_std=zeros(10000,1);
temp_target=zeros(10000,1);

for h=1:10000
    temp_w(h,:)=0.25*rand(1,10);% 生成权重
    % 计算10000个投资权重下的期望收益,即日收益率相加
    temp_total_get(h)=sum(sum(100*daily_get.*temp_w(h,:)));
    % 计算方差公式的第一项
    temp_total_std1(h)=sum(temp_w(h,:).^2.*per_std);
    % 计算方差公式的第二项
    for i=1:m
        for j=1:m
            temp_total_std2(h)=2*sum(sum(temp_w(h,i)*temp_w(h,j)*per_std(i)*per_std(j))*every_corr(i,j));
        end
    end
    % 两项整合在一起,即为当前投资权重的模型方差
    temp_total_std(h)=temp_total_std1(h)+temp_total_std2(h);
    % 当前投资权重下的目标函数
    temp_target(h)=temp_total_get(h)/temp_total_std(h);
end

% 计算需要用到的自适应温控数值
Emax=max(temp_target);
Emin=min(temp_target);
Eave=mean(temp_target);

Step. 3 Metropolis准则

将Metropolis准则修改为如下公式:

c6d56c8ab2c54b76934991da811db2ad.png

 其中:

3c9cd216478e43b6a6eaeae0f2c5c830.png

其他参数如下:

4abb157d998d4303b87f1c4adb8829b9.png

模拟退火部分代码如下:

%% 模拟退火
for L=1:300% 外层迭代次数
    sensitivity=[];% 灵敏度分析矩阵,用来记录目标函数值寻优过程中是否收敛
    temper=(Emin-Emax)/log(0.99);% 初始温度
    iter=100;% 内层循环次数

    w1=0.25*rand(1,10);% 产生初始权重1
    while sum(w1)>1 | sum(w1)<0.75% 限定权重之和在0.75~1之间
        w1=0.25*rand(1,10);
    end

    % 计算当前权重下的期望收益
    total_get1=sum(sum(100*daily_get.*w1));

    % 计算模型方差的第一项
    total_std11=sum(w1.^2.*per_std);
    % 计算模型方差的第二项
    for i=1:m
        for j=1:m
            total_std12=2*sum(sum(w1(i)*w1(j)*per_std(i)*per_std(j))*every_corr(i,j));
        end
    end
    % 当前投资权重下的模型方差
    total_std1=total_std11+total_std12;
    % 当前投资权重下的目标函数
    target1=total_get1/total_std1;

    sensitivity=[target1];

    % 退火过程
    while temper > 0.0001
        for j=1:iter

                w2=0.25*rand(1,10);% 产生初始权重2
                while sum(w2)>1 | sum(w2)<0.75% 限定权重之和在0.75~1之间
                    w2=0.25*rand(1,10);
                end

                % 计算当前权重下的期望收益
                total_get2=sum(sum(100*daily_get.*w2));
            
                % 计算模型方差的第一项
                total_std21=sum(w2.^2.*per_std);
                % 计算模型方差的第二项
                for i=1:m
                    for j=1:m
                        total_std22=2*sum(sum(w2(i)*w2(j)*per_std(i)*per_std(j))*every_corr(i,j));
                    end
                end
                % 当前投资权重下的模型方差
                total_std2=total_std21+total_std22;
                % 当前投资权重下的目标函数
                target2=total_get2/total_std2;

                if target2 > target1
                    target1 = target2;
                    best_w=w2;
                else
                    S=exp(Emin-Eave)/temper;
                    if exp((target2-target1)/S*temper)>rand(1)
                        target1 = target2;
                        best_w=w2; 
                        sensitivity=[sensitivity,target1];
                    end
                end
        end
        sensitivity=[sensitivity,target1];
        temper=temper*0.999
    end
end

Step. 4 完整源码   

clear;clc
tic
data=xlsread("股票数据.xlsx");
data(1,:)=[];
[n,m]=size(data);

%% 建立Markeowitz均值方差模型,假设投资资金为100块
% 计算日收益率
daily_get=zeros(n-1,m);% 初始化
for i=1:n-1
    for j=1:m
        daily_get(i,j)=(data(i+1,j)-data(i,j))/data(i,j);
    end
end
% 计算方差
per_std=std(data);% 每支股票的方差
every_corr=corrcoef(data);% 各支股票的相关系数

%% 生成自适应温控的权重
% 初始化
temp_w=zeros(10000,10);
temp_total_get=zeros(10000,1);
temp_total_std1=zeros(10000,1);
temp_total_std2=zeros(10000,1);
temp_total_std=zeros(10000,1);
temp_target=zeros(10000,1);

for h=1:10000
    temp_w(h,:)=0.25*rand(1,10);% 生成权重
    % 计算10000个投资权重下的期望收益,即日收益率相加
    temp_total_get(h)=sum(sum(100*daily_get.*temp_w(h,:)));
    % 计算方差公式的第一项
    temp_total_std1(h)=sum(temp_w(h,:).^2.*per_std);
    % 计算方差公式的第二项
    for i=1:m
        for j=1:m
            temp_total_std2(h)=2*sum(sum(temp_w(h,i)*temp_w(h,j)*per_std(i)*per_std(j))*every_corr(i,j));
        end
    end
    % 两项整合在一起,即为当前投资权重的模型方差
    temp_total_std(h)=temp_total_std1(h)+temp_total_std2(h);
    % 当前投资权重下的目标函数
    temp_target(h)=temp_total_get(h)/temp_total_std(h);
end

% 计算需要用到的自适应温控数值
Emax=max(temp_target);
Emin=min(temp_target);
Eave=mean(temp_target);

%% 模拟退火
for L=1:300% 外层迭代次数
    sensitivity=[];% 灵敏度分析矩阵,用来记录目标函数值寻优过程中是否收敛
    temper=(Emin-Emax)/log(0.99);% 初始温度
    iter=100;% 内层循环次数

    w1=0.25*rand(1,10);% 产生初始权重1
    while sum(w1)>1 | sum(w1)<0.75% 限定权重之和在0.75~1之间
        w1=0.25*rand(1,10);
    end

    % 计算当前权重下的期望收益
    total_get1=sum(sum(100*daily_get.*w1));

    % 计算模型方差的第一项
    total_std11=sum(w1.^2.*per_std);
    % 计算模型方差的第二项
    for i=1:m
        for j=1:m
            total_std12=2*sum(sum(w1(i)*w1(j)*per_std(i)*per_std(j))*every_corr(i,j));
        end
    end
    % 当前投资权重下的模型方差
    total_std1=total_std11+total_std12;
    % 当前投资权重下的目标函数
    target1=total_get1/total_std1;

    sensitivity=[target1];

    % 退火过程
    while temper > 0.0001
        for j=1:iter

                w2=0.25*rand(1,10);% 产生初始权重2
                while sum(w2)>1 | sum(w2)<0.75% 限定权重之和在0.75~1之间
                    w2=0.25*rand(1,10);
                end

                % 计算当前权重下的期望收益
                total_get2=sum(sum(100*daily_get.*w2));
            
                % 计算模型方差的第一项
                total_std21=sum(w2.^2.*per_std);
                % 计算模型方差的第二项
                for i=1:m
                    for j=1:m
                        total_std22=2*sum(sum(w2(i)*w2(j)*per_std(i)*per_std(j))*every_corr(i,j));
                    end
                end
                % 当前投资权重下的模型方差
                total_std2=total_std21+total_std22;
                % 当前投资权重下的目标函数
                target2=total_get2/total_std2;

                if target2 > target1
                    target1 = target2;
                    best_w=w2;
                else
                    S=exp(Emin-Eave)/temper;
                    if exp((target2-target1)/S*temper)>rand(1)
                        target1 = target2;
                        best_w=w2; 
                        sensitivity=[sensitivity,target1];
                    end
                end
        end
        sensitivity=[sensitivity,target1];
        temper=temper*0.999
    end
end

%% 绘图及展示结果
plot(sensitivity,'--')
title('灵敏度分析');
xlabel('迭代次数');
ylabel('目标函数值');
toc

结果展示

a61aaeabe1d54ddc921b5b01d94c9392.png

 c5aeeb0291bb47d386c4441cc686d9ac.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值