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. For information on the workflow when using PortfolioCVaR objects, see PortfolioCVaR Object Workflow.
Suppose that you set up a portfolio optimization problem and
obtained portfolios on the efficient frontier. Use the dataset
object from Statistics and Machine Learning Toolbox™ to
form a blotter that lists your portfolios with the names for each
asset. For example, suppose that 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 = setAssetList(p, 'Bonds','Large-Cap Equities','Small-Cap Equities','Emerging Equities'); p = setInitPort(p, pwgt0); p = simulateNormalScenariosByMoments(p, m, C, 20000); p = setDefaultConstraints(p); p = setProbabilityLevel(p, 0.9); pwgt = estimateFrontier(p, 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 78.84 43.688 8.3448 0 1.2501e-12 Large-Cap Equities 9.3338 29.131 48.467 23.602 9.4219e-13 Small-Cap Equities 4.8843 8.1284 12.419 16.357 8.281e-14 Emerging Equities 6.9419 19.053 30.769 60.041 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
that you want a portfolio with 15% risk and you add purchase and sale
weights outputs obtained from the "estimateFrontier"
functions 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 = setAssetList(p, 'Bonds','Large-Cap Equities','Small-Cap Equities','Emerging Equities'); p = setInitPort(p, pwgt0); p = simulateNormalScenariosByMoments(p, m, C, 20000); p = setDefaultConstraints(p); p = setProbabilityLevel(p, 0.9); [pwgt, pbuy, psell] = estimateFrontierByRisk(p, 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 15.036 0 14.964 Large-Cap Equities 30 45.357 15.357 0 Small-Cap Equities 20 12.102 0 7.8982 Emerging Equities 10 27.505 17.505 0
dataset
object to obtain shares and shares
to be traded. 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 that 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 = setAssetList(p, 'Bonds','Large-Cap Equities','Small-Cap Equities','Emerging Equities'); p = setInitPort(p, pwgt0); p = simulateNormalScenariosByMoments(p, m, C, 20000); p = setDefaultConstraints(p); p = setProbabilityLevel(p, 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 = estimateAssetMoments(q, p.getScenarios);
q = setDefaultConstraints(q);
pwgt = estimateFrontier(p);
qwgt = estimateFrontier(q);
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 functions associated with each object to obtain:
pret = estimatePortReturn(p, pwgt); pstd = estimatePortStd(p, pwgt); qret = estimatePortReturn(q, qwgt); qstd = estimatePortStd(q, qwgt); [pret, qret] [pstd, qstd]
ans = 0.0665 0.0585 0.0787 0.0716 0.0910 0.0848 0.1033 0.0979 0.1155 0.1111 0.1278 0.1243 0.1401 0.1374 0.1523 0.1506 0.1646 0.1637 0.1769 0.1769 ans = 0.0797 0.0774 0.0912 0.0835 0.1095 0.0995 0.1317 0.1217 0.1563 0.1472 0.1823 0.1746 0.2135 0.2059 0.2534 0.2472 0.2985 0.2951 0.3499 0.3499
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 = estimateFrontierByReturn(q, pret); qret = estimatePortReturn(q, qwgt); qstd = estimatePortStd(q, qwgt); [pret, qret] [pstd, qstd]
ans = 0.0665 0.0665 0.0787 0.0787 0.0910 0.0910 0.1033 0.1033 0.1155 0.1155 0.1278 0.1278 0.1401 0.1401 0.1523 0.1523 0.1646 0.1646 0.1769 0.1769 ans = 0.0797 0.0797 0.0912 0.0912 0.1095 0.1095 0.1317 0.1317 0.1563 0.1563 0.1823 0.1823 0.2135 0.2135 0.2534 0.2534 0.2985 0.2985 0.3499 0.3499
If a PortfolioCVaR object is destroyed when modifying, remember
to pass an existing object into the PortfolioCVaR
function
if you want to modify it, otherwise it creates a new object. See Creating the PortfolioCVaR Object for
details.
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.
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 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.
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, ...
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.
If asset return data has missing or NaN
values,
the simulateNormalScenariosByData
function
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, that is, 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 functions.
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);
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);
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. |
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.
checkFeasibility
| estimateScenarioMoments
| PortfolioCVaR