# Using MATLAB to Develop Portfolio Optimization Models

### Bob Taylor (view profile)

29 Sep 2005 (Updated )

Scripts to create time-evolving efficient frontiers and to backtest results.

ecmnobj(Data, Mean, Covar, CholCovar)
```function Objective = ecmnobj(Data, Mean, Covar, CholCovar)
%ECMNOBJ Evaluate negative log-likelihood function for ECMNMLE.
%	Observed negative log-likelihood function based on current maximum
%	likelihood parameter estimates.
%
%   Objective = ecmnobj(Data, Mean, Covar);
%   Objective = ecmnobj(Data, Mean, Covar, CholCovar);
%
% Inputs:
%   Data - NUMSAMPLES x NUMSERIES matrix of observed multivariate normal data
%		with NaNs to represent missing values.
%   Mean - NUMSERIES x 1 column vector with current mean estimate of Data.
%   Covar - NUMSERIES x NUMSERIES matrix with current covariance estimate of
%		Data.
%
% Optional Inputs:
%   CholCovar - Cholesky decomposition of covariance matrix, i.e., chol(Covar).
%
% Outputs:
%   Objective - Value of the observed negative log-likelihood function over
%		the Data given current estimates for the Mean and Covar of the data.
%

%	Author(s): R.Taylor, 4-21-2005
%	Copyright 2005 The MathWorks, Inc.
%	\$Revision: \$ \$Date: \$

% Step 1 - check arguments

if nargin < 3
error('Finance:ecmnobj:MissingInputArg', ...
'One or more of the required input arguments Data, Mean, and Covar is missing.');
else
if isempty(Data)
error('Finance:ecmnobj:EmptyInputData', ...
'The required input argument Data is empty.');
end
if isempty(Mean)
error('Finance:ecmnobj:EmptyInputMean', ...
'The required input argument Mean is empty.');
end
if isempty(Covar)
error('Finance:ecmnobj:EmptyInputCovar', ...
'The required input argument Covar is empty.');
end

[NumSamples, NumSeries] = size(Data);

Mean = Mean(:);
if ~all(size(Mean) == [NumSeries, 1])
error('Finance:ecmnobj:IncompatibleMean', ...
'The required input argument Mean has wrong dimensions.');
end
if ~all(size(Covar) == [NumSeries, NumSeries])
error('Finance:ecmnobj:IncompatibleCovar', ...
'The required input argument Covar has wrong dimensions.');
end
end
if nargin < 4 || isempty(CholCovar) || ~all(size(CholCovar) == size(Covar))
[CholCovar, CholState] = chol(Covar);
if CholState > 0
error('Finance:ecmnobj:NonPosDefCovar', ...
'Full covariance not positive-definite.');
end
end

LogDetCovar = 2.0 * sum(log(diag(CholCovar)));

% Step 2 - initialization

LogTwoPi = log(2.0 * pi);

% Step 3 - main loop over data records

Objective = 0.0;
Count = 0;

for k = 1:NumSamples

P = ~isnan(Data(k,:));
Available = sum(P);

if Available > 0				% skip over empty records
Count = Count + 1;

Objective = Objective - 0.5 * Available * LogTwoPi;

if Available < NumSeries
[SubChol, CholState] = chol(Covar(P,P));

if CholState > 0
error('Finance:ecmnobj:NonPosDefSubCovar', ...
'Sub-covariance not positive-definite.');
end

SubResid = SubChol' \ (Data(k,P)' - Mean(P));

Objective = Objective - 0.5 * SubResid' * SubResid;
Objective = Objective - sum(log(diag(SubChol)));
else
Resid = CholCovar' \ (Data(k,:)' - Mean);

Objective = Objective - 0.5 * Resid' * Resid;
Objective = Objective - 0.5 * LogDetCovar;
end
end
end

if Count < 1
error('Finance:ecmnobj:AllNaNData', ...
'All data are missing. Cannot compute negative log-likelihood.');
end
```