Skip to Main Content Skip to Search
Home |   Select Country  Choose Country  |  Contact Us  |  Cart Store 
Create Account | Log In
Products & Services Solutions Academia Support User Community Company
spacer spacer spacer spacer spacer spacer

 

Parallel Computing Toolbox 4.2

Distributed Portfolio Optimization

This demo uses the Parallel Computing Toolbox™ to perform a mean-variance portfolio optimization of a stock portfolio, and generates an efficient frontier. The portfolios on the frontier are optimal in the sense that they offer the minimal risk for some given level of expected return.

We are given the daily returns of a group of stocks over a fixed time period, and try to choose a portfolio such that it achieves some given return mu, and has minimal risk in the mean-variance sense. This leads us to solve a quadratic minimization problem with equality constraints. Solving this minimization problem for a range of values of mu gives us the efficient frontier.

For details about the computations, view the code for pctdemo_setup_optim.

Prerequisites:

Related demos:

Contents

Analyze the Sequential Problem

First, we look at how the computations in this demo fit into the model introduced in the Dividing MATLAB Computations into Tasks demo. The main computations consist of performing repeated optimizations using different values of the parameter in muVec. Each optimization takes a fairly short time, so we have each task perform many optimizations. Because the function pctdemo_task_optim is already vectorized, we can use it directly as our task function.

Load the Demo Settings and the Data

The demo uses the default configuration when identifying the scheduler to use. The configurations documentation explains how to create new configurations and how to change the default configuration. See Customizing the Settings for the Demos in the Parallel Computing Toolbox for instructions on how to change the demo difficulty level or the number of tasks created.

[difficulty, sched, numTasks] = pctdemo_helper_getDefaults();

The function pctdemo_setup_optim uses historical data about the stock returns to provide us with the mean and the covariance matrix of the stock returns. It also gives us the desired returns, muVec, for which we should find the minimal risk. The demo difficulty level controls the length of the vector muVec. Additionally, the function pctdemo_setup_optim displays for reference a graph of the daily returns of a few of the stocks in the portfolio. You can view the code for pctdemo_setup_optim for full details.

[fig, muVec, covMat, expRet ] = pctdemo_setup_optim(difficulty);
startTime = clock;

Divide the Work into Smaller Tasks

We divide the vector muVec into numTasks segments. This effectively divides the parameter space into pieces that the tasks can work on.

[muSplit, numTasks] = pctdemo_helper_split_vector(muVec, numTasks);
fprintf('This demo will submit a job with %d task(s) to the scheduler.\n', .
..
        numTasks);
This demo will submit a job with 4 task(s) to the scheduler.

Create and Submit the Job

Let us create the optimization job and the tasks in the job. We let task i perform the optimization for all the values found in muSplit{i}. You can view the code for pctdemo_task_optim for full details.

job = createJob(sched);
for i = 1:numTasks
    createTask(job, @pctdemo_task_optim, 2, ...
               {covMat, expRet, muSplit{i}});
end

We can now submit the job and wait for it to finish.

submit(job);
waitForState(job, 'finished');

Retrieve the Results

Let us obtain the job results, verify that all the tasks finished successfully and then destroy the job. We throw an error if we could not obtain any results, but display a warning if we got only some of the results.

jobResults = getAllOutputArguments(job);
if isempty(jobResults)
    taskErrorMsgs = pctdemo_helper_getUniqueErrors(job);
    destroy(job);
    error('distcomp:demo:EmptyJobOutput',  ...
          ['Could not obtain any job results.  The following error(s) ' ...
           'occurred \nduring task execution:\n\n%s'], ...
          taskErrorMsgs);
end

We combine the results from the individual tasks into two vectors, the risks and the returns, and we verify that we obtained all the results that we were expecting.

risk = [jobResults{:, 1}];
ret = [jobResults{:, 2}];
numPorts = numel(muVec);
numOk = numel(risk);
if ~(numOk == numPorts)
    taskErrorMsgs = pctdemo_helper_getUniqueErrors(job);
    warning('distcomp:demo:IncompleteJobResults', ...
            ['Some tasks did not complete. Only obtained results for %d ' ..
.
             'out of %d portfolios.  ' ...
             '\nThe following error(s) ' ...
             'occurred during task execution:\n\n%s'], ...
            numOk, numPorts, taskErrorMsgs);
end

We have now finished all the verifications, so we can destroy the job.

destroy(job);

Measure the Elapsed Time

The time used for the distributed computations should be compared against the time it takes to perform the same set of calculations in the Sequential Portfolio Optimization demo. The elapsed time varies with the underlying hardware and network infrastructure.

elapsedTime = etime(clock, startTime);
fprintf('Elapsed time is %2.1f seconds\n', elapsedTime);
Elapsed time is 29.7 seconds

Plot the Results

We use the pctdemo_plot_optim function to display a graph of the efficient frontier. You can view the code for pctdemo_plot_optim for full details.

pctdemo_plot_optim(fig, risk, ret);
Contact sales
Free technical kit
Trial software
E-mail this page

Get Pricing and
Licensing Options