Code covered by the BSD License

# Using MATLAB to Optimize Portfolios with Financial Toolbox

### Bob Taylor (view profile)

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

part3_costs.m
```%% part3_costs - Impact of Transaction Costs on Portfolio Optimization
%
% Copyright 2011 The MathWorks, Inc.

% 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

sellcost = 0.0020;

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 analysis

PerfDate = [];
GrossPerfPort = [];
ExtrinsicPerfPort = [];
IntrinsicPerfPort = [];
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));

% map prior portfolios into current universe

if t > window
pinit = zeros(numel(iasset0),1);
qinit = zeros(numel(iasset0),1);
rinit = zeros(numel(iasset0),1);

% adjust prior portfolio weights for prior period's returns
retinit = Xret(iasset0);

pinit(iasset0) = (1/(1 + retinit*pwgt))*((1 + retinit') .* pwgt);
qinit(iasset0) = (1/(1 + retinit*qwgt))*((1 + retinit') .* qwgt);
rinit(iasset0) = (1/(1 + retinit*rwgt))*((1 + retinit') .* rwgt);
end

% 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);
if t > window
p = p.setInitPort(pinit(iasset));
end

% set up portfolio objects for net returns

q = p;		% extrinsic net returns

r = p.setCosts(buycost, sellcost, 0);		% intrinsic net returns
if t > window
r = r.setInitPort(rinit(iasset));
end

% estimate portfolio that maximizes the ratio of relative risk to relative return
%	if absolute returns, then maximize the Sharpe ratio

pwgt = p.maximizeSharpeRatio;
[prsk, pret] = p.estimatePortMoments(pwgt);

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

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

% evaluate performance

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

PerfDate = [ PerfDate; Date(endindex+offset) ];

% gross portfolio return
if t > window
pcurrent = zeros(numel(iasset),1);
pcurrent(iasset) = pwgt;
pbuy = max(0, pcurrent - pinit);
psell = max(0, pinit - pcurrent);
pcost = 0;
pturnover = pturnover + 0.5*(sum(pbuy) + sum(psell));
else
pcost = 0;
pturnover = 0;
end
GrossPerfPort = [ GrossPerfPort; Xret(iasset)*pwgt ];

% extrinsic net portfolio return
if t > window
qcurrent = zeros(numel(iasset),1);
qcurrent(iasset) = qwgt;
qbuy = max(0, qcurrent - qinit);
qsell = max(0, qinit - qcurrent);
qturnover = qturnover + 0.5*(sum(qbuy) + sum(qsell));
else
qcost = 0;
qturnover = 0;
end
ExtrinsicPerfPort = [ ExtrinsicPerfPort; (Xret(iasset)*qwgt - qcost) ];

% intrinsic net portfolio return
if t > window
rcurrent = zeros(numel(iasset),1);
rcurrent(iasset) = rwgt;
rbuy = max(0, rcurrent - rinit);
rsell = max(0, rinit - rcurrent);
rturnover = rturnover + 0.5*(sum(rbuy) + sum(rsell));
else
rcost = 0;
rturnover = 0;
end
IntrinsicPerfPort = [ IntrinsicPerfPort; (Xret(iasset)*rwgt - rcost) ];

PerfMarket = [ PerfMarket; Xret(imarket) ];
PerfCash = [ PerfCash; Xret(icash) ];
end

% save information from current period to be used in next period

iasset0 = iasset;
end

%% plot results

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

%% summarize results

perf = [GrossPerfPort, ExtrinsicPerfPort, IntrinsicPerfPort, 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(Date(window)),datestr(PerfDate(end)));
fprintf('%14s %12s %12s %12s %12s %12s\n','','Mean','Std.Dev.','Tot.Ret.','Max.DD','Turnover');
fprintf('%14s %12g %12g %12g %12g %12g\n','Gross', ...
100*pmean(1),100*pstdev(1),100*ptotret(1),100*pmaxdd(1),100*pfactor*pturnover/numel(PerfDate));
fprintf('%14s %12g %12g %12g %12g %12g\n','Extrinsic Net', ...
100*pmean(2),100*pstdev(2),100*ptotret(2),100*pmaxdd(2),100*pfactor*qturnover/numel(PerfDate));
fprintf('%14s %12g %12g %12g %12g %12g\n','Intrinsic Net', ...
100*pmean(3),100*pstdev(3),100*ptotret(3),100*pmaxdd(3),100*pfactor*rturnover/numel(PerfDate));
fprintf('%14s %12g %12g %12g %12g\n','Market', ...
100*pmean(4),100*pstdev(4),100*ptotret(4),100*pmaxdd(4));
fprintf('%14s %12g %12g %12g %12g\n','Cash', ...
100*pmean(5),100*pstdev(5),100*ptotret(5),100*pmaxdd(5));
```