Main Content

Estimate VaR for Equity Portfolio Using Parametric Methods

This example shows how to estimate the value-at-risk (VaR) for a portfolio of equity positions using two parametric methods, normal VaR and exponentially weighted moving average (EWMA) VaR. Parametric VaR methods, also known as variance-covariance methods when the returns are normally distributed, assume a closed form for the return distribution of the portfolio. Using a parametric model simplifies the problem of VaR calculation to that of estimating the parameters of the distribution. Parametric methods are often contrasted with nonparametric approaches, such as Monte Carlo VaR or historical VaR, that do not assume an analytic formula for the return distribution of the portfolio. For a similar example of VaR calculation on a single index, see Value-at-Risk Estimation and Backtesting.

Normal VaR Calculation

The VaR of a portfolio is the maximum loss that the portfolio can incur over a given time window and still fall within the designated confidence bound. For example, if a portfolio has a one-day 95% VaR of 1,000,000 USD, then 95% of the time the portfolio should lose less than 1,000,000 USD over the course of the following day. That is, the portfolio should lose more than 1,000,000 USD only about once every 20 business days.

This example focuses on the one day 95% VaR for a portfolio of stocks. With the assumption that the one day returns of the portfolio are normally distributed, the problem of calculating a VaR value reduces to finding the parameters of the normal distribution. That is, VaR = μ-σportfolio*zscore [1,2], where μ is the mean return of the portfolio, σportfolio is the standard deviation of the portfolio returns, and zscore is the z-score for the confidence level. This example assumes μ=0, which is a common assumption and is approximately true for a one-day time period. The most common confidence intervals are the 95% and 99% values, with z-scores of 1.6449 and 2.3263, respectively. In general, you can compute z-scores using the norminv function.

Computing σportfoliois the primary task in Normal VaR computation. Suppose the portfolio contains a set of financial assets, and let Σ be the covariance matrix for the returns of those assets. Then σportfolio=vΣv, where v=<v1,v2,...,vn> is the vector of dollar values invested in each financial asset. In practice, correlations are often easier to work with [2], and so Σ is decomposed into correlations R and standard deviations σ=(σ1,σ2,...,σn). This yields σportfolio=σvRσv, where σv=(v1σ1,v2σ2,...,vnσn). In addition, some workflows use weights rather than dollar values [2]. In this case, v is replaced by ω=(v1Vtotalσ1,v2Vtotalσ2,...,vnVtotalσn), where Vtotal is the total portfolio value. This yields σportfolio=VtotalωRω.

To calculate the one day 95% VaR for a single trading day, begin by loading the data. The data set SharePrices.mat contains share prices for 87 stocks over 782 trading days. The following VaR calculations use the last 250 data points, which correspond to a year of data.

% Load equity prices
equityPrices = load("SharePrices.mat","data");
equityPrices = equityPrices.data;

Calculate the arithmetic returns for the share prices, then load the number of shares the portfolio holds for each stock from SimulatedRiskParityPortfolio.mat. This data set contains the shares for a simulated portfolio generated using a risk parity approach, as demonstrated in Estimate Expected Shortfall for Asset Portfolios.

% Calculate the arithmetic returns
returns = tick2ret(equityPrices);

% Load simulated portfolio
numShares = load("SimulatedRiskParityPortfolio.mat","RiskParityPortfolio");
numShares = numShares.RiskParityPortfolio;

The three VaR formulas previously discussed in Normal VaR Calculation use zScore, v, covarianceMatrix, R, sigmas, sigma_v, vTotal, and w.

% Calculate the zscore for 95% VaR
pVaR = 0.95;
zScore = norminv(pVaR);

% Calculate dollar values for the assets
V = equityPrices(end,:).*numShares(end,:);

% Calculate covariance matrix
covarianceMatrix = cov(returns);

% Calculate correlation matrix and standard deviations
R = corr(returns);
sigmas = std(returns);

% Calculate sigma weighted asset values (v vector)
sigma_v = V.*sigmas;

% Total portfolio value
vTotal = sum(V,2);

% Portfolio weights
w = sigma_v./vTotal;

To calculate the one day 95% VaR, use these variables in the relevant formulas. Each formula yields an identical result.

% Calculate VaR with asset values and covariance
portfolioSigma = sqrt(V*covarianceMatrix*V')
portfolioSigma = 7.0417e+03
covarianceVaR = portfolioSigma*zScore
covarianceVaR = 1.1583e+04
% Calculate VaR with correlations and sigma weighted asset values
portfolioSigma = sqrt(sigma_v*R*sigma_v')
portfolioSigma = 7.0417e+03
correlationsVaR = portfolioSigma*zScore
correlationsVaR = 1.1583e+04
% Calculate VaR with weights
portfolioSigma = vTotal*sqrt(w*R*w')
portfolioSigma = 7.0417e+03
weightsVaR = portfolioSigma*zScore
weightsVaR = 1.1583e+04

Exponentially Weighted Moving Average (EWMA) VaR Calculation

Moving averages are common in time series algorithms. A typical example of a moving average is the covariance formula:

COV(X,Y)=1ni=1i=n(xi-μx)(yi-μy).

In Normal VaR Calculation, you calculate asset covariances using this formula, which weights each day in the time series identically. However, newer observations are often considered more relevant than older observations. In these situations, an alternative covariance calculation method is preferrable. The EWMA method weights newer (i is closer to 1) data points more heavily in the covariance estimate

COV(X,Y)=1(1-λn1-λ)i=1i=nλi-1(xi-μx)(yi-μy) = 1-λ1-λni=1i=nλi-1(xi-μx)(yi-μy),

where 0<λ<1, and the new denominator(1-λn1-λ)is equal to the sum of the n weights and is derived using the formula for the partial sum of a geometric series.

Like Normal VaR, EWMA VaR assumes the portfolio returns are normally distributed. Therefore, EWMA VaR uses the same data, zscore and v values as in the Normal VaR case. However, for EWMA VaR you calculate the covariance matrix Σ, and therefore σportfolio using ewstats. ewstats implements this alternative covariance formula, which requires the returns data and a value for λ. In this example, λ=0.94, which is a commonly used exponential weight in Risk Management [2].

% Calculate covariance matrix
lambda = 0.94;
[~,ewmaCovMatrix] = ewstats(returns,lambda);

% Calculate EWMAVaR
portfolioSigma = sqrt(V*ewmaCovMatrix*V')
portfolioSigma = 7.9269e+03
ewmaVaR = portfolioSigma*zScore
ewmaVaR = 1.3039e+04

The calculated ewmaVaR is larger than the calculated Normal VaR. This is because EWMA places greater emphasis on newer data in the covariance calculations and the observed equity variances are greater towards the end of the data window. You can see this behavior in the following plot. Compared to Normal VaR, EWMA generally leads to a higher VaR estimate immediately after periods of high market volatility and a lower VaR estimate immediately after periods of low market volatility.

h = plot(returns(end-250:end,:));
ax = h.Parent;
xlabel(ax,'Trading Day');
ylabel(ax,'Asset Return');
title(ax,'Asset Returns over Time');

Calculate EWMA and Normal VaR with Rolling Data Window

VaR values are usually recalculated for a portfolio each day to account for changing market dynamics and changes to the portfolio composition. Additionally, backtesting a VaR model requires tracking the model performance over a period of time. Therefore, you can calculate a sequence of VaR estimates using a rolling data window.

Calculate the arithmetic returns using tick2ret and the price data in the variable equityPrices.

returns = tick2ret(equityPrices);

Set the window variables for windowSize (the size of the rolling data window), testSize (the number of days to calculate a VaR value), and sampleSize (the total number of observed returns in the data set).

sampleSize = length(returns);
windowSize = 250;
testWindowSize = sampleSize-windowSize;

Calculate the dollar amount invested in each stock on each day by extracting the number of shares the portfolio is holding for each stock on each day, then multiplying by the share price. Note that the portfolio composition changes from one day to the next.

% Dollar value of exposure to each stock
V = equityPrices(windowSize+1:end-1,:).*numShares;

Calculate the z-scores and initialize the VaR, σportfolio, and profit and loss (P&L) vectors.

% VaR confidence level
pVaR = 0.95;

% Get Zscores for alpha value
zScore = norminv(pVaR);

% Initialize VaR vectors
ewma95 = zeros(testWindowSize,1);
normalVaR95 = zeros(testWindowSize,1);

% Initialize portfolioSigmas vectors
ewmaPortfolioSigmas = zeros(testWindowSize,1);
normalPortfolioSigmas = zeros(testWindowSize,1);

% Initialize P&L values for backtesting
portfolioPandL = zeros(testWindowSize,1);

For each trading day in the estimation window, calculate the regular and EWMA VaR in the estimation window by passing the returns for the previous 250 trading days to cov and ewstats, respectively. Then, calculate σportfolio using the prices on that day and scale by the z-score to get the VaR. Finally, save P&L values.

% t is the index number within the estimation window,
% k is the index number within the entire data set.
for t = 1:testWindowSize
    k = windowSize + t;

    % Calculate covariance Matrix
    returnsData = returns(t:k-1,:);

    % Using ewstats to compute exponentially weighted covariance matrix.
    covMatrix = cov(returnsData);
    [~,ewmaCovMatrix] = ewstats(returnsData,lambda,windowSize);

    % Calculate the standard deviation of the portfolio returns.
    v = V(t,:);
    normalPortfolioSigmas(t) = sqrt(v*covMatrix*v');
    ewmaPortfolioSigmas(t) = sqrt(v*ewmaCovMatrix*v');

    % Save VaR values
    normalVaR95(t) = zScore*normalPortfolioSigmas(t);
    ewma95(t) = zScore*ewmaPortfolioSigmas(t);

    % Save P&L values
    portfolioPandL(t) = sum(returns(k,:).*v);
    
end

% Plot normal and EWMA VaRs by day

h = plot(1:testWindowSize,[ewma95, normalVaR95]);
ax = h.Parent;
xlabel(ax,'Trading Day');
ylabel(ax,'VaR Estimate');
title(ax,'Normal 95% VaR Versus EWMA 95% VaR');
legend(ax,{'EWMA Var','NormalVar'},'Location','Best');

The EWMA VaR is more sensitive to changes in recent volatility data and is more likely to have larger increases (or decreases) in estimated VaR levels relative to Normal VaR. This sensitvity is because the Normal VaR uses a simple moving average that does not emphasize recent data over older data in the relevant window. You can see this at the beginning of the plot where the Normal VaR begins much higher than EWMA, which is due to a period of high volatility that occurs approximately 100–200 days before the first VaR estimate. This period of instability is old enough to have a limited impact on the expontentially weighted average used in EWMA, but it is still relevant to the simple moving average used in Normal VaR. You can see this behavior in the following plot.

h = plot(-249:531,returns);
ax = h.Parent;
xlabel(ax,'Trading Day');
ylabel(ax,'Asset Return');
title(ax,'Asset Returns over Time');

VaR Backtesting Using Both VaR Types

The validation process for a VaR model requires comparing a large number of computed VaR values to the corresponding realized profit and loss values. That is, if the 95% VaR is accurate, then the realized profit and loss for the portfolio is less than the computed VaR 95% of the time and greater than the VaR only 5% of the time. This process is called VaR backtesting.

You can use varbacktest for VaR backtesting. varbacktest requires at least two input arguments: a vector of VaR values and a vector of realized profit and loss values.

vbt = varbacktest(portfolioPandL,[ewma95,normalVaR95],'VaRID',{'EWMA','Normal'});

Use the summary and runtests functions to validate the VaR estimates.

summaryResults = summary(vbt)
summaryResults=2×10 table
    PortfolioID     VaRID      VaRLevel    ObservedLevel    Observations    Failures    Expected    Ratio     FirstFailure    Missing
    ___________    ________    ________    _____________    ____________    ________    ________    ______    ____________    _______

    "Portfolio"    "EWMA"        0.95         0.9096            531            48        26.55      1.8079         20            0   
    "Portfolio"    "Normal"      0.95         0.9096            531            48        26.55      1.8079        115            0   

testResults = runtests(vbt)
testResults=2×11 table
    PortfolioID     VaRID      VaRLevel    TL      Bin       POF       TUFF       CC       CCI       TBF       TBFI 
    ___________    ________    ________    ___    ______    ______    ______    ______    ______    ______    ______

    "Portfolio"    "EWMA"        0.95      red    reject    reject    accept    reject    accept    reject    reject
    "Portfolio"    "Normal"      0.95      red    reject    reject    reject    reject    accept    reject    reject

Most of the tests performed by the varbacktest object have failed. The summaryResults table shows that the 95% VaR is greater than the realized profit and loss only about 90% of the time.

You can use plot to visualize the results.

h = plot(vbt)
h = 
  4x1 Line array:

  Line    (Portfolio)
  Line    (EWMA)
  Line    (Normal)
  Line    (Exceptions)

ax = h.Parent;
ylabel(ax,'Daily P&L');

The failures here are shown as black dots. Although the two VaRs have the same number of failures the EWMA VaR (red) and Normal VaR (yellow) are not failing on identical days. This suggests a trade-off between emphasizing new data and losing info from older data. One option is to set a VaR value equal to the maximum value of ewma95 and normalVaR95.

varMax = max(ewma95,normalVaR95);
vbtMax = varbacktest(portfolioPandL,varMax);
summaryResultsMax = summary(vbtMax)
summaryResultsMax=1×10 table
    PortfolioID    VaRID    VaRLevel    ObservedLevel    Observations    Failures    Expected    Ratio     FirstFailure    Missing
    ___________    _____    ________    _____________    ____________    ________    ________    ______    ____________    _______

    "Portfolio"    "VaR"      0.95         0.93409           531            35        26.55      1.3183        115            0   

testResultsMax = runtests(vbtMax)
testResultsMax=1×11 table
    PortfolioID    VaRID    VaRLevel      TL       Bin       POF       TUFF       CC       CCI       TBF       TBFI 
    ___________    _____    ________    ______    ______    ______    ______    ______    ______    ______    ______

    "Portfolio"    "VaR"      0.95      yellow    accept    accept    reject    accept    accept    reject    reject

The resulting VaR value when the VaR value is equal to the maximum value of ewma95 and normalVaR95 does perform better than the two alternatives (EWMA VaR and Normal VaR), although the observed VaR level is still below the 95% target.

This example assumes the portfolio returns are normally distributed. Actual financial data, however, has fatter tails than a normal distribution, so assuming a normal distribution can lead to an underestimate of the VaR values. Two potential solutions to this problem are:

  • Use a different distribution. For example, a t-distribution has fatter tails than the normal distribution. The zscores are calculated using tinv instead of norminv and the standard deviation is replaced with a scale parameter, but otherwise the process is identical. However, you do need to estimate the degrees of freedom for the t-distribution. For an example of a VaR calculation with a t-distribution, see Expected Shortfall Estimation and Backtesting.

  • Use a nonparametric method to calculate the portfolio VaR using a historical VaR method. For an example of calculating a historical VaR, see Value-at-Risk Estimation and Backtesting.

References

[1] Dowd, Kevin. Measuring Market Risk. 1st ed. Wiley, 2005.

[2] J.P. Morgan, Reuters. "RiskMetrics-Technical Document." Morgan Guaranty Trust Company of New York, 1996.

See Also

| | |

Related Topics