Code covered by the BSD License

Analyzing Investment Strategies with CVaR Portfolio Optimization

Bob Taylor (view profile)

18 Dec 2012 (Updated )

Scripts and data to demonstrate the new PortfolioCVaR object in Financial Toolbox.

cvarwebinar_optimization.m
```%% Analyzing Investment Strategies with CVaR Portfolio Optimization in MATLAB - Optimization
%
% Robert Taylor
% The MathWorks, Inc.

% Copyright (C) 2012 The MathWorks, Inc.

%% Introduction

% Portfolio weights generated by this script.

% pwgt - CVaR efficient portfolios for covered and uncovered positions
% qwgt - MV efficient portfolios for covered and uncovered positions
% rwgt - MV efficient portfolios for uncovered only
% qmatchwgt - MV efficient portfolios from qwgt with std that match std for pwgt

%% Set up CVaR portfolio optimization

AU = Assets;
AC1 = Assets;
for i = 1:26
AU{i} = [ AU{i} ' Uncovered' ];
AC1{i} = [ AC1{i} ' Covered @ 5%' ];
end

AssetList = [ AU; AC1 ];
Scenarios = [ XU, XC1 ];

% Uncomment these lines and comment out previous lines in this section to incorporate two strike
% prices in the portfolio optimization. No other changes are needed in this script.

% AU = Assets;
% AC1 = Assets;
% AC2 = Assets;
% for i = 1:26
% 	AU{i} = [ AU{i} ' Uncovered' ];
% 	AC1{i} = [ AC1{i} ' Covered @ 5%' ];
% 	AC2{i} = [ AC2{i} ' Covered @ 10%' ];
% end
%
% AssetList = [ AU; AC1; AC2 ];
% Scenarios = [ XU, XC1; XC2 ];

%% Do CVaR Portfolio Optimization

tic

p = PortfolioCVaR('AssetList', AssetList);
p = p.setScenarios(Scenarios);
p = p.setDefaultConstraints;
p = p.setProbabilityLevel(0.9);

pwgt = p.estimateFrontier(10);

pstd = p.estimatePortStd(pwgt);
pret = p.estimatePortReturn(pwgt);
pcvar = p.estimatePortRisk(pwgt);

toc_frontier = toc;

fprintf('Time to estimate CVaR efficient frontier %g\n',toc_frontier);

%% Do Mean-Variance Portfolio Optimization

q = Portfolio('AssetList', AssetList);
q = q.estimateAssetMoments(p.getScenarios);		% use scenarios from PortfolioCVaR object
q = q.setDefaultConstraints;

qwgt = q.estimateFrontier(10);

[qstd, qret] = q.estimatePortMoments(qwgt);

%% Do Mean-Variance Portfolio Optimization with Uncovered Positions Only

r = Portfolio('AssetList', Assets);
r = r.estimateAssetMoments(XU);
r = r.setDefaultConstraints;

rwgt = r.estimateFrontier;

[rstd, rret] = r.estimatePortMoments(rwgt);

%% Match Risks

qmatchwgt = q.estimateFrontierByRisk(pstd);

[qmatchstd, qmatchret] = q.estimatePortMoments(qmatchwgt);

%% Look at Raw Distribution of Portfolio Weights

% For one covered position -
%	"Bluer" bands are uncovered positions, "redder" bands are covered positions.
% For two covered positions -
%	"Bluer" bands are uncovered positions, "yellow/green" bands are covered positions at lower strike,
%	"redder" bands are covered positions at higher strike

figure(1);

subplot(2,1,1);
area(qwgt');
axis([1,10,0,1]);
title('\bfMean-Variance Portfolio Weights');

subplot(2,1,2);
area(pwgt');
axis([1,10,0,1]);
title('\bfCVaR Portfolio Weights');

%% Match Risks

figure(2);

subplot(2,1,1);
area(pstd, qmatchwgt');
axis([min(pstd), max(pstd), 0, 1]);
title('\bfMean-Variance Portfolio Weights');
xlabel('Standard Deviation of Portfolio Returns');

subplot(2,1,2);
area(pstd, pwgt');
axis([min(pstd), max(pstd), 0, 1]);
title('\bfCVaR Portfolio Weights');
xlabel('Standard Deviation of Portfolio Returns');

%% Compare Efficient Frontiers

figure(3);

plot(pstd, pret, 'b');
hold on
plot(qstd, qret,'g');
plot(rstd, rret,'r');
legend('CVaR with Covered-Call','Mean-Variance with Covered-Call', ...
'Mean-Variance without Covered-Call','Location','SouthEast');
title('\bfEfficient Frontiers');
xlabel('Standard Deviation of Portfolio Returns');
ylabel('Mean of Portfolio Returns');
hold off

%% Examine Portfolios

ii = sum(pwgt,2) > 1.0e-4;					% keep only assets with at least 1 non-zero weight
iiwgt = pwgt(ii,:);
iiwgt(iiwgt < 1.0e-4) = 0;					% set negligible portfolio weights to 0
iiwgt = 0.01*floor(10000*iiwgt + 0.5);		% round weights down to nearest basis point weight

CVaRblotter = dataset({iiwgt(:,1),'CV1'},{iiwgt(:,2),'CV2'},{iiwgt(:,3),'CV3'}, ...
{iiwgt(:,4),'CV4'},{iiwgt(:,5),'CV5'},{iiwgt(:,6),'CV6'},{iiwgt(:,7),'CV7'}, ...
{iiwgt(:,8),'CV8'},{iiwgt(:,9),'CV9'},{iiwgt(:,10),'CV10'},'ObsNames', AssetList(ii));

ii = sum(qmatchwgt,2) > 1.0e-4;				% keep only assets with at least 1 non-zero weight
iiwgt = qmatchwgt(ii,:);
iiwgt(iiwgt < 1.0e-4) = 0;					% set negligible portfolio weights to 0
iiwgt = 0.01*floor(10000*iiwgt + 0.5);		% round weights down to nearest basis point weight

MVblotter = dataset({iiwgt(:,1),'MV1'},{iiwgt(:,2),'MV2'},{iiwgt(:,3),'MV3'}, ...
{iiwgt(:,4),'MV4'},{iiwgt(:,5),'MV5'},{iiwgt(:,6),'MV6'},{iiwgt(:,7),'MV7'}, ...
{iiwgt(:,8),'MV8'},{iiwgt(:,9),'MV9'},{iiwgt(:,10),'MV10'},'ObsNames', AssetList(ii));

CVaRblotter
MVblotter
```