Code covered by the BSD License  

Highlights from
Using MATLAB to Optimize Portfolios with Financial Toolbox

image thumbnail

Using MATLAB to Optimize Portfolios with Financial Toolbox

by

 

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

part2_strategy.m
%% part2_strategy - Performance evaluation of maximum return/risk ratio portfolios
%
% Copyright 2011 The MathWorks, Inc.

load BlueChipStocks

% control parameters for backtest

numportfolio = 20;					% number of portfolios on each efficient frontier
window = 60;						% historical estimation window in months
offset = 3;							% shift in time for each frontier in months
cutoff = 0.4;						% this fraction of data in a series must be non-NaN values
relative = true;					% true if relative returns, false if absolute returns
accumulate = true;					% true if accumulation of assets, false if current universe only

imarket = strcmpi('Market', Asset);	% locate "market" series
icash = strcmpi('Cash', Asset);		% locate "cash" series (riskfree rate proxy)

% bookkeeping

pfactor = 12/offset;				% factor to convert periodicity to annual period

if relative
	criterion = 'Information Ratio';
else
	criterion = 'Sharpe Ratio';
end

% form cumulative map of assets (include all prior active assets that are still listed)

if accumulate
	for t = 2:size(Map,1)
		Map(t,:) = Map(t - 1,:) | Map(t,:);
	end
end

% ex-ante and ex-post analysis

PortDate = [];
PortRisk = [];
PortReturn = [];
PortSigma = [];
PortMean = [];
PerfDate = [];
PerfPort = [];
PerfMarket = [];
PerfCash = [];

for t = window:offset:numel(Date)

	% set up date indices for current period

	startindex = t - window + 1;
	endindex = t;
	
	% select "market" series

	Xmarket = Data(startindex:endindex,imarket);
	
	% select assets that are active on the endindex date
	
	iasset = Map(endindex,:);

	% keep series with sufficient numbers of non-NaN values

	imissing = sum(isnan(Data(startindex:endindex,:))) > cutoff*window;
	
	% form active universe for current endindex date

	iasset = logical(iasset) & ~logical(imissing);
	iasset(end-1:end) = 0;		% last two series are not stocks (not used in this step)
		
	% select data for active universe

	A = Asset(iasset);
	X = Data(startindex:endindex,iasset);
	
	fprintf('Estimation period %s to %s with %d assets ...\n', ...
		datestr(Date(startindex)), datestr(Date(endindex)), numel(A));

	% remove "market" from the data (market-neutral relative returns)

	if relative
		X = X - repmat(Xmarket, 1, numel(A));
	end
	
	% construct portfolio object (use RiskFreeRate if not market-neutral)

	p = PortfolioDemo('AssetList', A, 'Name', sprintf('Universe %s', datestr(Date(endindex))));
	if ~relative
		p = PortfolioDemo(p, 'RiskFreeRate', Data(endindex,icash));
	end
	p = p.setDefaultConstraints;
	p = p.estimateAssetMoments(X, 'MissingData', true);
	
	% estimate portfolios on efficient frontier

	pwgt = p.estimateFrontier(numportfolio);

	% estimate portfolio that maximizes the ratio of relative risk to relative return
	%	if absolute returns, then maximize the Sharpe ratio
	
	[swgt, sbuy, ssell] = p.maximizeSharpeRatio;
	[srsk, sret] = p.estimatePortMoments(swgt);
	    
	disp(p.AssetList(swgt > 1.0e-4));
	
	% enter data for 3D frontier

	PortDate = [ PortDate; Date(endindex) ];
	PortRisk = [ PortRisk; sqrt(pfactor)*(p.estimatePortRisk(pwgt))' ];
	PortReturn = [ PortReturn; pfactor*(p.estimatePortReturn(pwgt))' ];

	PortSigma = [ PortSigma; sqrt(pfactor)*srsk ];
	PortMean = [ PortMean; pfactor*sret ];
	
	% evaluate performance

	if (endindex + offset) <= numel(Date)
		Xret = ret2tick(Data(endindex+1:endindex+offset,:));
		Xret = Xret(end,:) - 1;

		PerfDate = [ PerfDate; Date(endindex+offset) ];
		
		PerfPort = [ PerfPort; Xret(iasset)*swgt ];
		PerfMarket = [ PerfMarket; Xret(imarket) ];
		PerfCash = [ PerfCash; Xret(icash) ];
	end
end

% set up dates across 3D frontier

PortDate = repmat(PortDate, 1, numportfolio);

%% plot 3D frontier

figure(1);
surf(PortDate, PortRisk, PortReturn, ...
	'FaceColor', 'interp', 'EdgeColor', 'none', 'FaceLighting', 'phong');
hold on
plot3(PortDate(:,1), PortSigma, PortMean + 1.0e-6, 'w', 'LineWidth', 3);
datetick('x');
ylabel('Portfolio Risk');
zlabel('Portfolio Returns');
title('\bfTime Evolution of Efficient Frontier');
camlight right
view(30, 30);
hold off

figure(2);
plot([datenum(Date(window)); PerfDate], ret2tick([PerfPort, PerfMarket, PerfCash]));
datetick('x');
title('\bfBacktest Performance of Portfolio Strategy');
ylabel('Cumulative Value of $1 Invested 31-Dec-1984');
legend(criterion, 'Market', 'Cash', 'Location', 'NorthWest');

%% summarize results

perf = [PerfPort, PerfMarket, PerfCash];
pmean = pfactor*mean(perf);
pstdev = sqrt(pfactor)*std(perf);
perfret = ret2tick(perf);
ptotret = (perfret(end,:) .^ (pfactor/size(perf,1))) - 1;
pmaxdd = maxdrawdown(perfret);

fprintf('Results for Backtest Period from %s to %s\n',datestr(PortDate(1,1)),datestr(PortDate(end,1)));
fprintf('%18s %12s %12s %12s %12s\n','','Mean','Std.Dev.','Tot.Ret.','Max.DD');
fprintf('%18s %12g %12g %12g %12g\n',criterion, ...
	100*pmean(1),100*pstdev(1),100*ptotret(1),100*pmaxdd(1));
fprintf('%18s %12g %12g %12g %12g\n','Market', ...
	100*pmean(2),100*pstdev(2),100*ptotret(2),100*pmaxdd(2));
fprintf('%18s %12g %12g %12g %12g\n','Cash', ...
	100*pmean(3),100*pstdev(3),100*ptotret(3),100*pmaxdd(3));

Contact us