Documentation Center

  • Trial Software
  • Product Updates

Postprocessing Results

After obtaining efficient portfolios or estimates for expected portfolio risks and returns, use your results to set up trades to move toward an efficient portfolio.

Setting Up Tradable Portfolios

Suppose you set up a portfolio optimization problem and obtained portfolios on the efficient frontier. Use the dataset object from Statistics Toolbox™ to form a blotter that lists your portfolios with the names for each asset. For example, suppose you want to obtain five portfolios along the efficient frontier. You can set up a blotter with weights multiplied by 100 to view the allocations for each portfolio:

m = [ 0.05; 0.1; 0.12; 0.18 ];
C = [ 0.0064 0.00408 0.00192 0;
0.00408 0.0289 0.0204 0.0119;
0.00192 0.0204 0.0576 0.0336;
0 0.0119 0.0336 0.1225 ];

pwgt0 = [ 0.3; 0.3; 0.2; 0.1 ];

p = PortfolioCVaR;
p = p.setAssetList('Bonds','Large-Cap Equities','Small-Cap Equities','Emerging Equities');
p = p.setInitPort(pwgt0);
p = p.simulateNormalScenariosByMoments(m, C, 20000);
p = p.setDefaultConstraints;
p = p.setProbabilityLevel(0.9);

pwgt = p.estimateFrontier(5);

pnames = cell(1,5);
for i = 1:5
pnames{i} = sprintf('Port%d',i);
end

Blotter = dataset([{100*pwgt},pnames],'obsnames',p.AssetList);
display(Blotter);
Blotter = 

                          Port1     Port2     Port3     Port4         Port5     
    Bonds                 79.287    44.896    9.6374    3.8019e-30    1.0891e-12
    Large-Cap Equities    8.3518    26.945    46.445        25.769    7.7125e-13
    Small-Cap Equities    5.9597     8.438    11.578        12.743    6.5326e-14
    Emerging Equities     6.4018    19.722     32.34        61.489           100

    Note:   Your results may differ from this result due to the simulation of scenarios.

This result indicates that you would invest primarily in bonds at the minimum-risk/minimum-return end of the efficient frontier (Port1), and that you would invest completely in emerging equity at the maximum-risk/maximum-return end of the efficient frontier (Port5). You can also select a particular efficient portfolio, for example, suppose you want a portfolio with 15% risk and you add purchase and sale weights outputs obtained from the "estimateFrontier" methods to set up a trade blotter:

m = [ 0.05; 0.1; 0.12; 0.18 ];
C = [ 0.0064 0.00408 0.00192 0;
0.00408 0.0289 0.0204 0.0119;
0.00192 0.0204 0.0576 0.0336;
0 0.0119 0.0336 0.1225 ];

pwgt0 = [ 0.3; 0.3; 0.2; 0.1 ];

p = PortfolioCVaR;
p = p.setAssetList('Bonds','Large-Cap Equities','Small-Cap Equities','Emerging Equities');

p = p.setInitPort(pwgt0);
p = p.simulateNormalScenariosByMoments(m, C, 20000);
p = p.setDefaultConstraints;
p = p.setProbabilityLevel(0.9);

[pwgt, pbuy, psell] = p.estimateFrontierByRisk(0.15);

Blotter = dataset([{100*[pwgt0, pwgt, pbuy, psell]}, ...
{'Initial','Weight', 'Purchases','Sales'}],'obsnames',p.AssetList);
display(Blotter);
Blotter = 

                          Initial    Weight    Purchases    Sales 
    Bonds                 30         19.362         0       10.638
    Large-Cap Equities    30         41.979    11.979            0
    Small-Cap Equities    20         10.999         0       9.0012
    Emerging Equities     10          27.66     17.66            0

If you have prices for each asset (in this example, they can be ETFs), add them to your blotter and then use the tools of the dataset object to obtain shares and shares to be traded.

Working with Other Portfolio Objects

The PortfolioCVaR object is for CVaR portfolio optimization. The Portfolio object is for mean-variance portfolio optimization. In some cases, you might want to examine portfolio optimization problems according to different combinations of return and risk proxies. A common example is that you want to do a CVaR portfolio optimization and then want to work primarily with moments of portfolio returns. Suppose you set up a CVaR portfolio optimization problem with:

m = [ 0.05; 0.1; 0.12; 0.18 ];
C = [ 0.0064 0.00408 0.00192 0;
0.00408 0.0289 0.0204 0.0119;
0.00192 0.0204 0.0576 0.0336;
0 0.0119 0.0336 0.1225 ];

pwgt0 = [ 0.3; 0.3; 0.2; 0.1 ];

p = PortfolioCVaR;
p = p.setAssetList('Bonds','Large-Cap Equities','Small-Cap Equities','Emerging Equities');
p = p.setInitPort(pwgt0);
p = p.simulateNormalScenariosByMoments(m, C, 20000);
p = p.setDefaultConstraints;
p = p.setProbabilityLevel(0.9);

To work with the same problem in a mean-variance framework, you can use the scenarios from the PortfolioCVaR object to set up a Portfolio object so that p contains a CVaR optimization problem and q contains a mean-variance optimization problem based on the same data.

q = Portfolio('AssetList', p.AssetList);
q = q.estimateAssetMoments(p.getScenarios);
q = q.setDefaultConstraints;

pwgt = p.estimateFrontier;
qwgt = q.estimateFrontier;

Note that since each object has a different risk proxy, it is not possible to compare results side by side. To obtain means and standard deviations of portfolio returns, you can use the methods associated with each object to obtain:

pret = p.estimatePortReturn(pwgt);
pstd = p.estimatePortStd(pwgt);
qret = q.estimatePortReturn(qwgt);
qstd = q.estimatePortStd(qwgt);

[pret, qret]
[pstd, qstd]
ans =

    0.0675    0.0595
    0.0801    0.0730
    0.0928    0.0865
    0.1054    0.1000
    0.1180    0.1136
    0.1307    0.1271
    0.1433    0.1406
    0.1559    0.1541
    0.1685    0.1676
    0.1812    0.1812


ans =

    0.0794    0.0771
    0.0911    0.0834
    0.1097    0.0999
    0.1325    0.1225
    0.1575    0.1485
    0.1839    0.1763
    0.2159    0.2083
    0.2563    0.2502
    0.3017    0.2984
    0.3506    0.3506

To produce comparable results, you can use the returns or risks from one portfolio optimization as target returns or risks for the other portfolio optimization.

qwgt = q.estimateFrontierByReturn(pret);
qret = q.estimatePortReturn(qwgt);
qstd = q.estimatePortStd(qwgt);

[pret, qret]
[pstd, qstd]
ans =

    0.0675    0.0675
    0.0801    0.0801
    0.0928    0.0928
    0.1054    0.1054
    0.1180    0.1180
    0.1307    0.1307
    0.1433    0.1433
    0.1559    0.1559
    0.1685    0.1685
    0.1812    0.1812


ans =

    0.0794    0.0794
    0.0911    0.0911
    0.1097    0.1097
    0.1325    0.1325
    0.1575    0.1575
    0.1839    0.1839
    0.2159    0.2159
    0.2563    0.2563
    0.3017    0.3017
    0.3506    0.3506

Now it is possible to compare standard deviations of portfolio returns from either type of portfolio optimization.

Troubleshooting CVaR Portfolio Optimization Results

PortfolioCVaR Object Destroyed When Modifying

If a PortfolioCVaR object is destroyed when modifying, remember to pass an existing object into the constructor if you want to modify it, otherwise it creates a new object. See Constructing the PortfolioCVaR Object for details.

Matrix Incompatibility and "Non-Conformable" Errors

If you get matrix incompatibility or "non-conformable" errors, the representation of data in the tools follows a specific set of basic rules described in Conventions for Representation of Data.

CVaR Portfolio Optimization Warns About "Max Iterations"

If the 'cuttingplane' solver displays the following warning:

Warning: Max iterations reached. Consider modifying the solver options, or using fmincon. 
> In @PortfolioCVaR\private\cvar_cuttingplane_solver at 255
  In @PortfolioCVaR\private\cvar_optim_min_risk at 85
  In PortfolioCVaR.estimateFrontier at 69

this warning indicates that some of the reported efficient portfolios may not be accurate enough.

This warning is usually related to portfolios in the lower-left end of the efficient frontier. The cutting plane solver may have gotten very close to the solution, but there may be too many portfolios with very similar risks and returns in that neighborhood, and the solver runs out of iterations before reaching the desired accuracy.

To correct this problem, you can use setSolver to make any of these changes:

  • Increase the maximum number of iterations ('MaxIter').

  • Relax the stopping tolerances ('AbsTol' and/or 'RelTol').

  • Use a different master solver algorithm ('MasterSolverOptions').

  • Alternatively, you can try the 'fmincon' solver.

When the default maximum number of iterations of the 'cuttingplane' solver is reached, the solver usually needs many more iterations to reach the accuracy required by the default stopping tolerances. You may want to combine increasing the number of iterations (e.g., multiply by 5) with relaxing the stopping tolerances (e.g., multiply by 10 or 100). Since the CVaR is a stochastic optimization problem, the accuracy of the solution is relative to the scenario sample, so a looser stopping tolerance may be acceptable. Keep in mind that the solution time may increase significantly when you increase the number of iterations. For example, doubling the number of iterations more than doubles the solution time. Sometimes using a different master solver (e.g., switching to 'interior-point' if you are using the default 'simplex') can get the 'cuttingplane' solver to converge without changing the maximum number of iterations.

Alternatively, the 'fmincon' solver may be faster than the 'cuttingplane' solver for problems where cutting plane reaches the maximum number of iterations.

CVaR Portfolio Optimization Errors with "Could Not Solve" Message

If the 'cuttingplane' solver generates the following error:

Error using cvar_cuttingplane_solver (line 251)
Could not solve the problem. Consider modifying the solver options, or using fmincon.

Error in cvar_optim_by_return (line 100)
		[x,~,~,exitflag] = cvar_cuttingplane_solver(...

Error in PortfolioCVaR/estimateFrontier (line 80)
	pwgt = cvar_optim_by_return(obj, r(2:end-1), obj.NumAssets, ...

this error means the master solver failed to solve one of the master problems. The error may be due to numerical instability or other problem-specific situation.

To correct this problem, you can use setSolver to make any of these changes:

  • Modify the master solver options ('MasterSolverOptions'), for example, change the algorithm ('Algorithm') or the termination tolerance ('TolFun').

  • Alternatively, you can try the 'fmincon' solver.

Missing Data Estimation Fails

If asset return data has missing or NaN values, the method simulateNormalScenariosByData with the 'missingdata' flag set to true may fail with either too many iterations or a singular covariance. To correct this problem, consider this:

  • If you have asset return data with no missing or NaN values, you can compute a covariance matrix that may be singular without difficulties. If you have missing or NaN values in your data, the supported missing data feature requires that your covariance matrix must be positive-definite, i.e., nonsingular.

  • simulateNormalScenariosByData uses default settings for the missing data estimation procedure that might not be appropriate for all problems.

In either case, you might want to estimate the moments of asset returns separately with either the ECM estimation functions such as ecmnmle or with your own methods.

cvar_optim_transform Errors

If you obtain optimization errors such as:

Error using cvar_optim_transform (line 276)
Portfolio set appears to be either empty or unbounded. Check constraints.

Error in PortfolioCVaR/estimateFrontier (line 64)
	[AI, bI, AE, bE, lB, uB, f0, f, x0] = cvar_optim_transform(obj);

or

Error using cvar_optim_transform (line 281)
Cannot obtain finite lower bounds for specified portfolio set.

Error in PortfolioCVaR/estimateFrontier (line 64)
	[AI, bI, AE, bE, lB, uB, f0, f, x0] = cvar_optim_transform(obj);

Since the portfolio optimization tools require a bounded portfolio set, these errors (and similar errors) can occur if your portfolio set is either empty and, if nonempty, unbounded. Specifically, the portfolio optimization algorithm requires that your portfolio set have at least a finite lower bound. The best way to deal with these problems is to use the validation methods in Validate the CVaR Portfolio Problem. Specifically, use estimateBounds to examine your portfolio set, and use checkFeasibility to ensure that your initial portfolio is either feasible and, if infeasible, that you have sufficient turnover to get from your initial portfolio to the portfolio set.

    Tip   To correct this problem, try solving your problem with larger values for turnover and gradually reduce to the value that you want.

Efficient Portfolios Do Not Make Sense

If you obtain efficient portfolios that do not seem to make sense, this can happen if you forget to set specific constraints or you set incorrect constraints. For example, if you allow portfolio weights to fall between 0 and 1 and do not set a budget constraint, you can get portfolios that are 100% invested in every asset. Although it may be hard to detect, the best thing to do is to review the constraints you have set with display of the PortfolioCVaR object. If you get portfolios with 100% invested in each asset, you can review the display of your object and quickly see that no budget constraint is set. Also, you can use estimateBounds and checkFeasibility to determine if the bounds for your portfolio set make sense and to determine if the portfolios you obtained are feasible relative to an independent formulation of your portfolio set.

See Also

| |

Related Examples

More About

Was this topic helpful?