全部版块 我的主页
论坛 金融投资论坛 六区 金融实务版
516 0
2025-11-13

1. 主程序框架
%% 基于遗传算法的债券投资组合优化
clear; clc; close all;
%% 债券数据生成(实际应用中替换为真实数据)
nBonds = 50; % 债券数目
bondData = generateBondData(nBonds);
%% 遗传算法参数设置
gaOptions = setupGAOptions();
%% 运行遗传算法优化
fprintf('开始债券投资组合优化...\n');
[optimalWeights, optimalFitness, exitFlag, output] = ...
runBondPortfolioGA(bondData, gaOptions);
%% 结果分析与可视化
analyzeResults(optimalWeights, optimalFitness, bondData, output);

2. 债券数据结构
function bondData = generateBondData(nBonds)
% 生成模拟债券数据
rng(42); % 设置随机种子保证可重复性
bondData = struct();
bondData.nBonds = nBonds;
% 债券基本属性
bondData.yield = 0.02 + 0.08 * rand(nBonds, 1); % 收益率 2%-10%
bondData.duration = 1 + 9 * rand(nBonds, 1); % 久期 1-10年
bondData.convexity = 0.5 + 4.5 * rand(nBonds, 1); % 凸性
bondData.creditRating = randi([1, 10], nBonds, 1); % 信用评级 (1最好,10最差)
bondData.sector = randi([1, 5], nBonds, 1); % 行业分类
bondData.liquidity = 0.1 + 0.9 * rand(nBonds, 1); % 流动性指标
% 风险参数
bondData.targetDuration = 5.0; % 目标久期
bondData.maxSectorWeight = 0.3; % 单一行业最大权重
bondData.budget = 1.0; % 总预算
end

3. 遗传算法配置
function gaOptions = setupGAOptions()
% 配置遗传算法参数
gaOptions = optimoptions('ga');
% 算法参数
gaOptions.PopulationSize = 100; % 种群规模
gaOptions.MaxGenerations = 200; % 最大代数
gaOptions.CrossoverFraction = 0.8; % 交叉比例
gaOptions.EliteCount = 2; % 精英个体数量
% 显示设置
gaOptions.Display = 'iter';
gaOptions.PlotFcn = {@gaplotbestf, @gaplotdistance};
% 停止条件
gaOptions.FunctionTolerance = 1e-6;
gaOptions.StallGenLimit = 50;
end

4. 适应度函数
function fitness = bondPortfolioFitness(weights, bondData)
% 债券投资组合适应度函数
% 确保权重为行向量
weights = weights(:)';
% 约束检查
[valid, penalty] = checkConstraints(weights, bondData);
if ~valid
fitness = -1e6 * penalty; % 严重惩罚违反约束
return;
end
% 计算收益目标
portfolioReturn = sum(weights .* bondData.yield');
% 计算风险惩罚项
riskPenalty = calculateRiskPenalty(weights, bondData);
% 适应度函数:收益 - 风险调整
fitness = portfolioReturn - riskPenalty;
end

function [valid, penalty] = checkConstraints(weights, bondData)
% 检查投资组合约束
penalty = 0;
% 预算约束
weightSum = sum(weights);

if abs(weightSum - bondData.budget) > 1e-6
penalty = penalty + 100 * abs(weightSum - bondData.budget);
end
% 非负限制
negativeWeights = sum(weights(weights < 0));
if negativeWeights < 0
penalty = penalty + 1000 * abs(negativeWeights);
end
% 单一债券权重限制 (最大20%)
maxWeightViolation = max(0, max(weights) - 0.2);
penalty = penalty + 500 * maxWeightViolation;
% 行业分散限制
sectorPenalty = checkSectorConstraints(weights, bondData);
penalty = penalty + sectorPenalty;
valid = (penalty == 0);
end

function sectorPenalty = checkSectorConstraints(weights, bondData)
% 检查行业分散限制
sectorPenalty = 0;
uniqueSectors = unique(bondData.sector);
for i = 1:length(uniqueSectors)
sectorMask = (bondData.sector == uniqueSectors(i));
sectorWeight = sum(weights(sectorMask));
% 检查是否超过最大行业权重
if sectorWeight > bondData.maxSectorWeight
sectorPenalty = sectorPenalty + 200 * (sectorWeight - bondData.maxSectorWeight);
end
end
end

function riskPenalty = calculateRiskPenalty(weights, bondData)
% 计算风险惩罚项
% 久期偏差惩罚
portfolioDuration = sum(weights .* bondData.duration');
durationDeviation = abs(portfolioDuration - bondData.targetDuration);
durationPenalty = 0.1 * durationDeviation;
% 信用风险惩罚
creditRisk = sum(weights .* (bondData.creditRating' / 10));
creditPenalty = 0.05 * creditRisk;
% 流动性惩罚
liquidityPenalty = 0.02 * sum(weights .* (1 - bondData.liquidity'));
% 集中度风险惩罚
concentrationPenalty = 0.1 * (sum(weights.^2));  % Herfindahl指数
riskPenalty = durationPenalty + creditPenalty + liquidityPenalty + concentrationPenalty;
end

5. 遗传算法执行
function [optimalWeights, optimalFitness, exitFlag, output] = runBondPortfolioGA(bondData, gaOptions)
% 运行遗传算法优化
nVars = bondData.nBonds;
% 约束定义
A = []; b = [];  % 线性不等式约束 A*x <= b
Aeq = ones(1, nVars);  % 权重和为1
beq = bondData.budget;
% 变量边界 [0, 0.2]
lb = zeros(1, nVars);
ub = 0.2 * ones(1, nVars);
% 非线性约束
nonlcon = @(weights) nonLinearConstraints(weights, bondData);
% 适应度函数
fitnessFcn = @(weights) -bondPortfolioFitness(weights, bondData);
% 运行遗传算法
[optimalWeights, optimalFitness, exitFlag, output] = ...
ga(fitnessFcn, nVars, A, b, Aeq, beq, lb, ub, nonlcon, gaOptions);
% 转换回正向适应度值
optimalFitness = -optimalFitness;
end

function [c, ceq] = nonLinearConstraints(weights, bondData)
% 非线性约束函数
c = [];  % 非线性不等式限制 c(x) <= 0
% 行业权重限制 (非线性等式限制)
uniqueSectors = unique(bondData.sector);
ceq = zeros(length(uniqueSectors), 1);
for i = 1:length(uniqueSectors)
    sectorMask = (bondData.sector == uniqueSectors(i));
    sectorWeight = sum(weights(sectorMask));
    % 允许轻微差异
    ceq(i) = max(0, sectorWeight - bondData.maxSectorWeight);
end
end

6. 结果分析
function analyzeResults(optimalWeights, optimalFitness, bondData, output)
% 分析并展示优化结果
fprintf('\n=== 优化结果分析 ===\n');
fprintf('最佳适应度值: %.4f\n', optimalFitness);
fprintf('投资组合收益率: %.4f%%\n', 100 * sum(optimalWeights .* bondData.yield'));
fprintf('投资组合久期: %.4f 年\n', sum(optimalWeights .* bondData.duration'));
% 投资组合统计
nSelected = sum(optimalWeights > 0.001);
fprintf('选定的债券数量: %d/%d\n', nSelected, bondData.nBonds);
% 权重分布
figure('Position', [100, 100, 1200, 800]);
subplot(2, 3, 1);
bar(optimalWeights(optimalWeights > 0.001));
title('债券权重分布');
xlabel('债券编号');
ylabel('权重');
grid on;
% 收益率 vs 久期散点图
subplot(2, 3, 2);
scatter(bondData.duration, bondData.yield, 50, optimalWeights, 'filled');
colorbar;
xlabel('久期 (年)');
ylabel('收益率');
title('债券特征与权重');
grid on;
% 行业分布
subplot(2, 3, 3);
uniqueSectors = unique(bondData.sector);
sectorWeights = zeros(size(uniqueSectors));
for i = 1:length(uniqueSectors)
    sectorMask = (bondData.sector == uniqueSectors(i));
    sectorWeights(i) = sum(optimalWeights(sectorMask));
end
pie(sectorWeights);
title('行业权重分布');
legend(arrayfun(@(x) sprintf('行业 %d', x), uniqueSectors, 'UniformOutput', false));
% 收敛曲线
subplot(2, 3, 4);
plot(output.fitness);
title('遗传算法收敛曲线');
xlabel('代数');
ylabel('最佳适应度');
grid on;
% 风险贡献分析
subplot(2, 3, 5);
riskContribution = optimalWeights .* bondData.creditRating';
riskContribution = riskContribution / sum(riskContribution);
bar(riskContribution(optimalWeights > 0.001));
title('信用风险贡献');
xlabel('债券编号');
ylabel('风险贡献比例');
grid on;
% 权重与流动性关系
subplot(2, 3, 6);
scatter(bondData.liquidity(optimalWeights > 0.001), ...
optimalWeights(optimalWeights > 0.001), 50, 'filled');
xlabel('流动性指标');
ylabel('权重');
title('权重 vs 流动性');
grid on;
% 详细统计信息
fprintf('\n投资组合详细统计:\n');
fprintf('信用风险加权均值: %.4f\n', sum(optimalWeights .* bondData.creditRating'));
fprintf('流动性加权均值: %.4f\n', sum(optimalWeights .* bondData.liquidity'));
fprintf('凸性加权均值: %.4f\n', sum(optimalWeights .* bondData.convexity'));
% 显示前10大持仓
[sortedWeights, sortedIdx] = sort(optimalWeights, 'descend');
fprintf('\n前10大持仓:\n');
fprintf('债券#\t权重\t收益率\t久期\t信用评级\n');
for i = 1:min(10, nSelected)
idx = sortedIdx(i);
fprintf('%d\t%.4f\t%.4f\t%.2f\t%d\n', ...
idx, sortedWeights(i), bondData.yield(idx), ...
bondData.duration(idx), bondData.creditRating(idx));
end
end
7. 高级功能扩展
%% 多目标优化版本
function [weights, scores] = multiObjectiveBondOptimization(bondData)
% 多目标优化:同时优化收益和风险
fitnessFcn = @(weights) [ -sum(weights .* bondData.yield'), ...  % 目标1: 最大化收益
calculateTotalRisk(weights, bondData) ]; % 目标2: 减少风险
nVars = bondData.nBonds;
A = []; b = [];
Aeq = ones(1, nVars);
beq = 1;
lb = zeros(1, nVars);
ub = 0.2 * ones(1, nVars);
[weights, scores] = gamultiobj(fitnessFcn, nVars, A, b, Aeq, beq, lb, ub);
end
function totalRisk = calculateTotalRisk(weights, bondData)
% 计算总风险度量
durationRisk = abs(sum(weights .* bondData.duration') - bondData.targetDuration);
creditRisk = sum(weights .* (bondData.creditRating' / 10));
concentrationRisk = sum(weights.^2);
totalRisk = 0.1 * durationRisk + 0.05 * creditRisk + 0.1 * concentrationRisk;
end
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群