Asset Returns and Scenarios Using PortfolioCVaR Object
How Stochastic Optimization Works
The CVaR of a portfolio is a conditional expectation. (For the definition of the CVaR function, see Risk Proxy.) Therefore, the CVaR portfolio optimization problem is a stochastic optimization problem. Given a sample of scenarios, the conditional expectation that defines the sample CVaR of the portfolio can be expressed as a finite sum, a weighted average of losses. The weights of the losses depend on their relative magnitude; for a confidence level α, only the worst (1 − α) x 100% losses get a positive weight. As a function of the portfolio weights, the CVaR of the portfolio is a convex function (see [48], [49] Rockafellar & Uryasev at Portfolio Optimization). It is also a nonsmooth function, but its edges are less sharp as the sample size increases.
There are reformulations of the CVaR portfolio optimization problem (see [48],
[49] at Rockafellar & Uryasev) that result in a linear programming problem,
which can be solved either with standard linear programming techniques or with
stochastic programming solvers. The PortfolioCVaR
object,
however, does not reformulate the problem in such a manner. The
PortfolioCVaR
object computes the CVaR as a nonlinear
function. The convexity of the CVaR, as a function of the portfolio weights and the
dull edges when the number of scenarios is large, make the CVaR portfolio
optimization problem tractable, in practice, for certain nonlinear programming
solvers, such as fmincon
from Optimization Toolbox™. The problem can also be solved using a cutting-plane method (see
Kelley [45] at Portfolio Optimization). For more information,
see Algorithms section of setSolver
. To learn more about the
workflow when using PortfolioCVaR
objects, see PortfolioCVaR Object Workflow.
What Are Scenarios?
Since conditional value-at-risk portfolio optimization works with scenarios of asset returns to perform the optimization, several ways exist to specify and simulate scenarios. In many applications with CVaR portfolio optimization, asset returns may have distinctly nonnormal probability distributions with either multiple modes, binning of returns, truncation of distributions, and so forth. In other applications, asset returns are modeled as the result of various simulation methods that might include Monte-Carlo simulation, quasi-random simulation, and so forth. Often, the underlying probability distribution for risk factors may be multivariate normal but the resultant transformations are sufficiently nonlinear to result in distinctively nonnormal asset returns.
For example, this occurs with bonds and derivatives. In the case of bonds with a nonzero probability of default, such scenarios would likely include asset returns that are −100% to indicate default and some values slightly greater than −100% to indicate recovery rates.
Although the PortfolioCVaR
object has functions to simulate
multivariate normal scenarios from either data or moments (simulateNormalScenariosByData
and
simulateNormalScenariosByMoments
),
the usual approach is to specify scenarios directly from your own simulation
functions. These scenarios are entered directly as a matrix with a sample for all
assets across each row of the matrix and with samples for an asset down each column
of the matrix. The architecture of the CVaR portfolio optimization tools references
the scenarios through a function handle so scenarios that have been set cannot be
accessed directly as a property of the PortfolioCVaR
object.
Setting Scenarios Using the PortfolioCVaR Function
Suppose that you have a matrix of scenarios in the
AssetScenarios
variable. The scenarios are set through the
PortfolioCVaR
object
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 ];
m = m/12;
C = C/12;
AssetScenarios = mvnrnd(m, C, 20000);
p = PortfolioCVaR('Scenarios', AssetScenarios);
disp(p.NumAssets)
disp(p.NumScenarios)
4 20000
Notice that the PortfolioCVaR
object determines and fixes the
number of assets in NumAssets
and the number of scenarios in
NumScenarios
based on the scenario’s matrix. You can change
the number of scenarios by calling the PortfolioCVaR
object with a different
scenario matrix. However, once the NumAssets
property has been
set in the object, you cannot enter a scenario matrix with a different number of
assets. The getScenarios
function lets you
recover scenarios from a PortfolioCVaR
object. You can also
obtain the mean and covariance of your scenarios using estimateScenarioMoments
.
Although not recommended for the casual user, an alternative way exists to recover
scenarios by working with the function handle that points to scenarios in the
PortfolioCVaR
object. To access some or all the scenarios
from a PortfolioCVaR
object, the hidden property
localScenarioHandle
is a function handle that points to a
function to obtain scenarios that have already been set. To get scenarios directly
from a PortfolioCVaR
object p
,
use
scenarios = p.localScenarioHandle([], []);
startrow
to
endrow
,
usescenarios = p.localScenarioHandle(startrow, endrow);
1
≤ startrow
≤ endrow
≤
numScenarios
.Setting Scenarios Using the setScenarios Function
You can also set scenarios using setScenarios
. For example, given
the mean and covariance of asset returns in the variables m
and
C
, the asset moment properties can be set:
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 ]; m = m/12; C = C/12; AssetScenarios = mvnrnd(m, C, 20000); p = PortfolioCVaR; p = setScenarios(p, AssetScenarios); disp(p.NumAssets) disp(p.NumScenarios)
4 20000
Estimating the Mean and Covariance of Scenarios
The estimateScenarioMoments
function
obtains estimates for the mean and covariance of scenarios in a
PortfolioCVaR
object.
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 ]; m = m/12; C = C/12; AssetScenarios = mvnrnd(m, C, 20000); p = PortfolioCVaR; p = setScenarios(p, AssetScenarios); [mean, covar] = estimateScenarioMoments(p)
mean = 0.0043 0.0085 0.0098 0.0153 covar = 0.0005 0.0003 0.0002 0.0000 0.0003 0.0024 0.0017 0.0010 0.0002 0.0017 0.0049 0.0029 0.0000 0.0010 0.0029 0.0102
Simulating Normal Scenarios
As a convenience, the two functions (simulateNormalScenariosByData
and
simulateNormalScenariosByMoments
)
exist to simulate scenarios from data or moments under an assumption that they are
distributed as multivariate normal random asset returns.
Simulating Normal Scenarios from Returns or Prices
Given either return or price data, use the function simulateNormalScenariosByData
to
simulate multivariate normal scenarios. Either returns or prices are stored as
matrices with samples going down the rows and assets going across the columns. In
addition, returns or prices can be stored in a table
or timetable
(see Simulating Normal Scenarios from Time Series Data). To illustrate using
simulateNormalScenariosByData
,
generate random samples of 120 observations of asset returns for four assets from
the mean and covariance of asset returns in the variables m
and
C
with portsim
. The default behavior of
portsim
creates simulated data with
estimated mean and covariance identical to the input moments m
and C
. In addition to a return series created by portsim
in the variable
X, a price series is created in the variable
Y:
m = [ 0.0042; 0.0083; 0.01; 0.15 ]; C = [ 0.005333 0.00034 0.00016 0; 0.00034 0.002408 0.0017 0.000992; 0.00016 0.0017 0.0048 0.0028; 0 0.000992 0.0028 0.010208 ]; X = portsim(m', C, 120); Y = ret2tick(X);
Note
Portfolio optimization requires that you use total returns and not just price returns. So, “returns” should be total returns and “prices” should be total return prices.
Given asset returns and prices in variables X and
Y from above, this sequence of examples demonstrates
equivalent ways to simulate multivariate normal scenarios for the
PortfolioCVaR
object. Assume a
PortfolioCVaR
object created in p
that
uses the asset returns in X uses simulateNormalScenariosByData
:
p = PortfolioCVaR; p = simulateNormalScenariosByData(p, X, 20000); [passetmean, passetcovar] = estimateScenarioMoments(p)
passetmean = 0.0043 0.0083 0.0102 0.1507 passetcovar = 0.0053 0.0003 0.0002 0.0000 0.0003 0.0024 0.0017 0.0010 0.0002 0.0017 0.0049 0.0028 0.0000 0.0010 0.0028 0.0101
The default behavior of simulateNormalScenariosByData
is to
work with asset returns. If, instead, you have asset prices as in the variable
Y, simulateNormalScenariosByData
accepts a name-value pair argument name 'DataFormat'
with a
corresponding value set to 'prices'
to indicate that the input to
the function is in the form of asset prices and not returns (the default value for
the 'DataFormat'
argument is 'returns'
). This
example simulates scenarios with the asset price data in Y for
the PortfolioCVaR
object
q
:
p = PortfolioCVaR; p = simulateNormalScenariosByData(p, Y, 20000, 'dataformat', 'prices'); [passetmean, passetcovar] = estimateScenarioMoments(p)
passetmean = 0.0043 0.0084 0.0094 0.1490 passetcovar = 0.0054 0.0004 0.0001 -0.0000 0.0004 0.0024 0.0016 0.0009 0.0001 0.0016 0.0048 0.0028 -0.0000 0.0009 0.0028 0.0100
Simulating Normal Scenarios with Missing Data
Often when working with multiple assets, you have missing data indicated by
NaN
values in your return or price data. Although Multivariate Normal Regression goes into detail about regression with
missing data, the simulateNormalScenariosByData
function has a name-value pair argument name 'MissingData'
that
indicates with a Boolean value whether to use the missing data capabilities of
Financial Toolbox™. The default value for 'MissingData'
is
false
which removes all samples with NaN
values. If, however, 'MissingData'
is set to
true
, simulateNormalScenariosByData
uses
the ECM algorithm to estimate asset moments. This example shows how this works on
price data with missing values:
m = [ 0.0042; 0.0083; 0.01; 0.15 ]; C = [ 0.005333 0.00034 0.00016 0; 0.00034 0.002408 0.0017 0.000992; 0.00016 0.0017 0.0048 0.0028; 0 0.000992 0.0028 0.010208 ]; X = portsim(m', C, 120); Y = ret2tick(X); Y(1:20,1) = NaN; Y(1:12,4) = NaN;
Notice that the prices above in Y
have missing values in the
first and fourth series.
p = PortfolioCVaR; p = simulateNormalScenariosByData(p, Y, 20000, 'dataformat', 'prices'); q = PortfolioCVaR; q = simulateNormalScenariosByData(q, Y, 20000, 'dataformat', 'prices', 'missingdata', true); [passetmean, passetcovar] = estimateScenarioMoments(p) [qassetmean, qassetcovar] = estimateScenarioMoments(q)
passetmean = 0.0020 0.0074 0.0078 0.1476 passetcovar = 0.0055 0.0003 -0.0001 -0.0003 0.0003 0.0024 0.0019 0.0012 -0.0001 0.0019 0.0050 0.0028 -0.0003 0.0012 0.0028 0.0101 qassetmean = 0.0024 0.0085 0.0106 0.1482 qassetcovar = 0.0071 0.0004 -0.0001 -0.0004 0.0004 0.0032 0.0022 0.0012 -0.0001 0.0022 0.0063 0.0034 -0.0004 0.0012 0.0034 0.0127
PortfolioCVaR
object, p
, contains
scenarios obtained from price data in Y
where
NaN
values are discarded and the second
PortfolioCVaR
object, q
, contains
scenarios obtained from price data in Y
that accommodate missing
values. Each time you run this example, you get different estimates for the moments
in p
and q
. Simulating Normal Scenarios from Time Series Data
The simulateNormalScenariosByData
function implicitly works with matrices of data or data in a table
or timetable
object using the same rules for whether the data are
returns or prices. To illustrate, use array2timetable
to create a timetable for 14 assets from
CAPMuniverse
and the use the timetable to simulate scenarios
for PortfolioCVaR.
load CAPMuniverse time = datetime(Dates,'ConvertFrom','datenum'); stockTT = array2timetable(Data,'RowTimes',time, 'VariableNames', Assets); stockTT.Properties % Notice that GOOG has missing data, because it was not listed before Aug 2004 head(stockTT, 5)
ans = TimetableProperties with properties: Description: '' UserData: [] DimensionNames: {'Time' 'Variables'} VariableNames: {'AAPL' 'AMZN' 'CSCO' 'DELL' 'EBAY' 'GOOG' 'HPQ' 'IBM' 'INTC' 'MSFT' 'ORCL' 'YHOO' 'MARKET' 'CASH'} VariableDescriptions: {} VariableUnits: {} VariableContinuity: [] RowTimes: [1471×1 datetime] StartTime: 03-Jan-2000 SampleRate: NaN TimeStep: NaN CustomProperties: No custom properties are set. Use addprop and rmprop to modify CustomProperties. ans = 5×14 timetable Time AAPL AMZN CSCO DELL EBAY GOOG HPQ IBM INTC MSFT ORCL YHOO MARKET CASH ___________ _________ _________ _________ _________ _________ ____ _________ _________ _________ _________ _________ _________ _________ __________ 03-Jan-2000 0.088805 0.1742 0.008775 -0.002353 0.12829 NaN 0.03244 0.075368 0.05698 -0.001627 0.054078 0.097784 -0.012143 0.00020522 04-Jan-2000 -0.084331 -0.08324 -0.05608 -0.08353 -0.093805 NaN -0.075613 -0.033966 -0.046667 -0.033802 -0.0883 -0.067368 -0.03166 0.00020339 05-Jan-2000 0.014634 -0.14877 -0.003039 0.070984 0.066875 NaN -0.006356 0.03516 0.008199 0.010567 -0.052837 -0.073363 0.011443 0.00020376 06-Jan-2000 -0.086538 -0.060072 -0.016619 -0.038847 -0.012302 NaN -0.063688 -0.017241 -0.05824 -0.033477 -0.058824 -0.10307 0.011743 0.00020266 07-Jan-2000 0.047368 0.061013 0.0587 -0.037708 -0.000964 NaN 0.028416 -0.004386 0.04127 0.013091 0.076771 0.10609 0.02393 0.00020157
Use the 'MissingData'
option offered by PortfolioCVaR to
account for the missing
data.
p = PortfolioCVaR;
p = simulateNormalScenariosByData(p, stockTT, 20000 ,'missingdata',true);
[passetmean, passetcovar] = estimateScenarioMoments(p)
passetmean = 0.0012 0.0007 -0.0005 -0.0000 0.0016 0.0043 -0.0001 0.0000 0.0001 -0.0002 0.0000 0.0004 0.0001 0.0001 passetcovar = 0.0013 0.0005 0.0006 0.0005 0.0006 0.0003 0.0005 0.0003 0.0006 0.0004 0.0005 0.0006 0.0002 -0.0000 0.0005 0.0024 0.0007 0.0005 0.0010 0.0005 0.0005 0.0003 0.0006 0.0004 0.0006 0.0011 0.0002 -0.0000 0.0006 0.0007 0.0013 0.0006 0.0007 0.0004 0.0006 0.0004 0.0008 0.0005 0.0008 0.0008 0.0002 -0.0000 0.0005 0.0005 0.0006 0.0009 0.0006 0.0002 0.0005 0.0003 0.0006 0.0004 0.0005 0.0006 0.0002 -0.0000 0.0006 0.0010 0.0007 0.0006 0.0018 0.0007 0.0005 0.0003 0.0006 0.0005 0.0007 0.0011 0.0002 -0.0000 0.0003 0.0005 0.0004 0.0002 0.0007 0.0013 0.0002 0.0002 0.0002 0.0002 0.0003 0.0011 0.0001 -0.0000 0.0005 0.0005 0.0006 0.0005 0.0005 0.0002 0.0010 0.0003 0.0005 0.0003 0.0005 0.0006 0.0002 -0.0000 0.0003 0.0003 0.0004 0.0003 0.0003 0.0002 0.0003 0.0005 0.0004 0.0002 0.0004 0.0004 0.0002 0.0000 0.0006 0.0006 0.0008 0.0006 0.0006 0.0002 0.0005 0.0004 0.0011 0.0005 0.0007 0.0007 0.0002 -0.0000 0.0004 0.0004 0.0005 0.0004 0.0005 0.0002 0.0003 0.0002 0.0005 0.0006 0.0004 0.0005 0.0002 -0.0000 0.0005 0.0006 0.0008 0.0005 0.0007 0.0003 0.0005 0.0004 0.0007 0.0004 0.0014 0.0007 0.0002 -0.0000 0.0006 0.0011 0.0008 0.0006 0.0011 0.0011 0.0006 0.0004 0.0007 0.0005 0.0007 0.0020 0.0002 -0.0000 0.0002 0.0002 0.0002 0.0002 0.0002 0.0001 0.0002 0.0002 0.0002 0.0002 0.0002 0.0002 0.0001 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000
Use the name-value input 'DataFormat'
to handle return or price
data and 'MissingData'
to ignore or use samples with missing
values. In addition, simulateNormalScenariosByData
extracts asset names or identifiers from a table
or timetable
if the argument 'GetAssetList'
is set
to true
(the default value is false
). If the
'GetAssetList'
value is true
, the
identifiers are used to set the AssetList
property of the
PortfolioCVaR
object. Thus, repeating the formation of the
PortfolioCVaR
object p
from the previous
example with the 'GetAssetList'
flag set to
true
extracts the column names from the timetable object:
p = simulateNormalScenariosByData(p, stockTT, 20000 ,'missingdata',true, 'GetAssetList', true); disp(p.AssetList)
'AAPL' 'AMZN' 'CSCO' 'DELL' 'EBAY' 'GOOG' 'HPQ' 'IBM' 'INTC' 'MSFT' 'ORCL' 'YHOO' 'MARKET' 'CASH'
If you set the'GetAssetList'
flag set to
true
and your input data is in a matrix, simulateNormalScenariosByData
uses
the default labeling scheme from setAssetList
as described in
Setting Up a List of Asset Identifiers.
Simulating Normal Scenarios with Mean and Covariance
Given the mean and covariance of asset returns, use the simulateNormalScenariosByMoments
function to simulate multivariate normal scenarios. The mean can be either a row or
column vector and the covariance matrix must be a symmetric positive-semidefinite
matrix. Various rules for scalar expansion apply. To illustrate using simulateNormalScenariosByMoments
,
start with moments in m
and C
and generate
20,000 scenarios:
m = [ 0.0042; 0.0083; 0.01; 0.15 ]; C = [ 0.005333 0.00034 0.00016 0; 0.00034 0.002408 0.0017 0.000992; 0.00016 0.0017 0.0048 0.0028; 0 0.000992 0.0028 0.010208 ]; p = PortfolioCVaR; p = simulateNormalScenariosByMoments(p, m, C, 20000); [passetmean, passetcovar] = estimateScenarioMoments(p)
passetmean = 0.0049 0.0083 0.0101 0.1503 passetcovar = 0.0053 0.0003 0.0002 -0.0000 0.0003 0.0024 0.0017 0.0010 0.0002 0.0017 0.0047 0.0028 -0.0000 0.0010 0.0028 0.0101
simulateNormalScenariosByMoments
performs scalar expansion on arguments for the moments of asset returns. If
NumAssets
has not already been set, a scalar argument is
interpreted as a scalar with NumAssets
set to
1
. simulateNormalScenariosByMoments
provides an additional optional argument to specify the number of assets so that
scalar expansion works with the correct number of assets. In addition, if either a
scalar or vector is input for the covariance of asset returns, a diagonal matrix is
formed such that a scalar expands along the diagonal and a vector becomes the
diagonal.
See Also
PortfolioCVaR
| setCosts
| setProbabilityLevel
| setScenarios
| estimatePortVaR
| simulateNormalScenariosByMoments
| simulateNormalScenariosByData
Related Examples
- Working with a Riskless Asset
- Working with Transaction Costs
- Creating the PortfolioCVaR Object
- Working with CVaR Portfolio Constraints Using Defaults
- Validate the CVaR Portfolio Problem
- Estimate Efficient Portfolios for Entire Frontier for PortfolioCVaR Object
- Estimate Efficient Frontiers for PortfolioCVaR Object
- Hedging Using CVaR Portfolio Optimization
- Compute Maximum Reward-to-Risk Ratio for CVaR Portfolio