Parallel Computing Toolbox

Distributed Portfolio Optimization

This example 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_optimview the code for pctdemo_setup_optim.


Related examples:

Analyze the Sequential Problem

First, we look at how the computations in this example fit into the model introduced in the Dividing MATLAB Computations into Tasks example. 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 Example Settings and the Data

The example uses the default profile when identifying the cluster to use. The profiles documentationprofiles documentation explains how to create new profiles and how to change the default profile. See Customizing the Settings for the Examples in the Parallel Computing Toolbox for instructions on how to change the example difficulty level or the number of tasks created.

[difficulty, myCluster, 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 example 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_optimview 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 example will submit a job with %d task(s) ' ...
         'to the cluster.\n'], numTasks);
This example will submit a job with 4 task(s) to the cluster.

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_optimview the code for pctdemo_task_optim for full details.

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

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


Retrieve the Results

Let us obtain the job results, verify that all the tasks finished successfully and then delete the job. fetchOutputs will throw an error if the tasks did not complete successfully, in which case we need to delete the job before throwing the error.

    jobResults = fetchOutputs(job);
catch err

We combine the results from the individual tasks into two vectors, the risks and the returns.

risk = [jobResults{:, 1}];
ret = [jobResults{:, 2}];

We have now finished all the verifications, so we can delete the 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 example. 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 23.9 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_optimview the code for pctdemo_plot_optim for full details.

pctdemo_plot_optim(fig, risk, ret);