Main Content

Modeling Correlated Defaults with Copulas

This example explores how to simulate correlated counterparty defaults using a multifactor copula model.

Potential losses are estimated for a portfolio of counterparties, given their exposure at default, default probability, and loss given default information. A creditDefaultCopula object is used to model each obligor's credit worthiness with latent variables. Latent variables are composed of a series of weighted underlying credit factors, as well as, each obligor's idiosyncratic credit factor. The latent variables are mapped to an obligor's default or nondefault state for each scenario based on their probability of default. Portfolio risk measures, risk contributions at a counterparty level, and simulation convergence information are supported in the creditDefaultCopula object.

This example also explores the sensitivity of the risk measures to the type of copula (Gaussian copula versus t copula) used for the simulation.

Load and Examine Portfolio Data

The portfolio contains 100 counterparties and their associated credit exposures at default (EAD), probability of default (PD), and loss given default (LGD). Using a creditDefaultCopula object, you can simulate defaults and losses over some fixed time period (for example, one year). The EAD, PD, and LGD inputs must be specific to a particular time horizon.

In this example, each counterparty is mapped onto two underlying credit factors with a set of weights. The Weights2F variable is a NumCounterparties-by-3 matrix, where each row contains the weights for a single counterparty. The first two columns are the weights for the two credit factors and the last column is the idiosyncratic weights for each counterparty. A correlation matrix for the two underlying factors is also provided in this example (FactorCorr2F).

load CreditPortfolioData.mat
whos EAD PD LGD Weights2F FactorCorr2F
  Name                Size            Bytes  Class     Attributes

  EAD               100x1               800  double              
  FactorCorr2F        2x2                32  double              
  LGD               100x1               800  double              
  PD                100x1               800  double              
  Weights2F         100x3              2400  double              

Initialize the creditDefaultCopula object with the portfolio information and the factor correlation.

rng('default');
cc = creditDefaultCopula(EAD,PD,LGD,Weights2F,'FactorCorrelation',FactorCorr2F);

% Change the VaR level to 99%.
cc.VaRLevel = 0.99;

disp(cc)
  creditDefaultCopula with properties:

            Portfolio: [100x5 table]
    FactorCorrelation: [2x2 double]
             VaRLevel: 0.9900
          UseParallel: 0
      PortfolioLosses: []
cc.Portfolio(1:5,:)
ans=5×5 table
    ID     EAD         PD        LGD           Weights       
    __    ______    _________    ____    ____________________

    1     21.627    0.0050092    0.35    0.35       0    0.65
    2     3.2595     0.060185    0.35       0    0.45    0.55
    3     20.391      0.11015    0.55    0.15       0    0.85
    4     3.7534    0.0020125    0.35    0.25       0    0.75
    5     5.7193     0.060185    0.35    0.35       0    0.65

Simulate the Model and Plot Potential Losses

Simulate the multifactor model using the simulate function. By default, a Gaussian copula is used. This function internally maps realized latent variables to default states and computes the corresponding losses. After the simulation, the creditDefaultCopula object populates the PortfolioLosses and CounterpartyLosses properties with the simulation results.

cc = simulate(cc,1e5);
disp(cc)
  creditDefaultCopula with properties:

            Portfolio: [100x5 table]
    FactorCorrelation: [2x2 double]
             VaRLevel: 0.9900
          UseParallel: 0
      PortfolioLosses: [30.1008 3.6910 3.2895 19.2151 7.5761 44.5088 19.5419 1.7909 72.1443 12.6933 36.0228 1.7909 4.8512 23.0230 54.0877 35.9298 35.3757 26.1678 36.8868 24.6242 2.9770 15.3030 0 0 10.5546 61.2268 32.5802 42.5504 ... ] (1x100000 double)

The portfolioRisk function returns risk measures for the total portfolio loss distribution, and optionally, their respective confidence intervals. The value-at-risk (VaR) and conditional value-at-risk (CVaR) are reported at the level set in the VaRLevel property for the creditDefaultCopula object.

[pr,pr_ci] = portfolioRisk(cc);

fprintf('Portfolio risk measures:\n');
Portfolio risk measures:
disp(pr)
      EL       Std       VaR      CVaR 
    ______    ______    _____    ______

    24.876    23.778    102.4    121.28
fprintf('\n\nConfidence intervals for the risk measures:\n');
Confidence intervals for the risk measures:
disp(pr_ci)
           EL                 Std                 VaR                 CVaR      
    ________________    ________________    ________________    ________________

    24.729    25.023    23.674    23.883    101.19     103.5    120.13    122.42

Look at the distribution of portfolio losses. The expected loss (EL), VaR, and CVaR are marked as the vertical lines. The economic capital, given by the difference between the VaR and the EL, is shown as the shaded area between the EL and the VaR.

histogram(cc.PortfolioLosses)
title('Portfolio Losses');
xlabel('Losses ($)')
ylabel('Frequency')
hold on

% Overlay the risk measures on the histogram.
xlim([0 1.1 * pr.CVaR])
plotline = @(x,color) plot([x x],ylim,'LineWidth',2,'Color',color);
plotline(pr.EL,'b');
plotline(pr.VaR,'r');
cvarline = plotline(pr.CVaR,'m');

% Shade the areas of expected loss and economic capital.
plotband = @(x,color) patch([x fliplr(x)],[0 0 repmat(max(ylim),1,2)],...
    color,'FaceAlpha',0.15);
elband = plotband([0 pr.EL],'blue');
ulband = plotband([pr.EL pr.VaR],'red');
legend([elband,ulband,cvarline],...
    {'Expected Loss','Economic Capital','CVaR (99%)'},...
    'Location','north');

Figure contains an axes object. The axes object with title Portfolio Losses, xlabel Losses ($), ylabel Frequency contains 6 objects of type histogram, line, patch. These objects represent CVaR (99%), Expected Loss, Economic Capital.

Find Concentration Risk for Counterparties

Find the concentration risk in the portfolio using the riskContribution function. riskContribution returns the contribution of each counterparty to the portfolio EL and CVaR. These additive contributions sum to the corresponding total portfolio risk measure.

rc = riskContribution(cc);

% Risk contributions are reported for EL and CVaR.
rc(1:5,:)
ans=5×5 table
    ID       EL          Std           VaR         CVaR   
    __    ________    __________    _________    _________

    1     0.036031      0.022762     0.083828      0.13625
    2     0.068357      0.039295      0.23373      0.24984
    3       1.2228       0.60699       2.3184       2.3775
    4     0.002877    0.00079014    0.0024248    0.0013137
    5      0.12127      0.037144      0.18474      0.24622

Find the riskiest counterparties by their CVaR contributions.

[rc_sorted,idx] = sortrows(rc,'CVaR','descend');
rc_sorted(1:5,:)
ans=5×5 table
    ID      EL        Std       VaR       CVaR 
    __    _______    ______    ______    ______

    89     2.2647    2.2063    8.2676    8.9997
    96     1.3515    1.6514    6.6157    7.7062
    66    0.90459     1.474    6.4168    7.5149
    22     1.5745    1.8663    6.0121    7.3814
    16     1.6352    1.5288    6.3404    7.3462

Plot the counterparty exposures and CVaR contributions. The counterparties with the highest CVaR contributions are plotted in red and orange.

figure;
pointSize = 50;
colorVector = rc_sorted.CVaR;
scatter(cc.Portfolio(idx,:).EAD, rc_sorted.CVaR,...
    pointSize,colorVector,'filled')
colormap('jet')
title('CVaR Contribution vs. Exposure')
xlabel('Exposure')
ylabel('CVaR Contribution')
grid on

Figure contains an axes object. The axes object with title CVaR Contribution vs. Exposure, xlabel Exposure, ylabel CVaR Contribution contains an object of type scatter.

Investigate Simulation Convergence with Confidence Bands

Use the confidenceBands function to investigate the convergence of the simulation. By default, the CVaR confidence bands are reported, but confidence bands for all risk measures are supported using the optional RiskMeasure argument.

cb = confidenceBands(cc);

% The confidence bands are stored in a table.
cb(1:5,:)
ans=5×4 table
    NumScenarios    Lower      CVaR     Upper 
    ____________    ______    ______    ______

        1000         106.7    121.99    137.28
        2000        109.18    117.28    125.38
        3000        114.68    121.63    128.58
        4000        114.02    120.06    126.11
        5000        114.77    120.36    125.94

Plot the confidence bands to see how quickly the estimates converge.

figure;
plot(...
    cb.NumScenarios,...
    cb{:,{'Upper' 'CVaR' 'Lower'}},...
    'LineWidth',2);

title('CVaR: 95% Confidence Interval vs. # of Scenarios');
xlabel('# of Scenarios');
ylabel('CVaR + 95% CI')
legend('Upper Band','CVaR','Lower Band');
grid on

Figure contains an axes object. The axes object with title CVaR: 95% Confidence Interval vs. # of Scenarios, xlabel # of Scenarios, ylabel CVaR + 95% CI contains 3 objects of type line. These objects represent Upper Band, CVaR, Lower Band.

Find the necessary number of scenarios to achieve a particular width of the confidence bands.

width = (cb.Upper - cb.Lower) ./ cb.CVaR;

figure;
plot(cb.NumScenarios,width * 100,'LineWidth',2);
title('CVaR: 95% Confidence Interval Width vs. # of Scenarios');
xlabel('# of Scenarios');
ylabel('Width of CI as %ile of Value')
grid on

% Find point at which the confidence bands are within 1% (two sided) of the
% CVaR.
thresh = 0.02;

scenIdx = find(width <= thresh,1,'first');
scenValue = cb.NumScenarios(scenIdx);
widthValue = width(scenIdx);
hold on
plot(xlim,100 * [widthValue widthValue],...
    [scenValue scenValue], ylim,...
    'LineWidth',2);
title('Scenarios Required for Confidence Interval with 2% Width');

Figure contains an axes object. The axes object with title Scenarios Required for Confidence Interval with 2% Width, xlabel # of Scenarios, ylabel Width of CI as %ile of Value contains 3 objects of type line.

Compare Tail Risk for Gaussian and t Copulas

Switching to a t copula increases the default correlation between counterparties. This results in a fatter tail distribution of portfolio losses, and in higher potential losses in stressed scenarios.

Rerun the simulation using a t copula and compute the new portfolio risk measures. The default degrees of freedom (dof) for the t copula is five.

cc_t = simulate(cc,1e5,'Copula','t');
pr_t = portfolioRisk(cc_t);

See how the portfolio risk changes with the t copula.

fprintf('Portfolio risk with Gaussian copula:\n');
Portfolio risk with Gaussian copula:
disp(pr)
      EL       Std       VaR      CVaR 
    ______    ______    _____    ______

    24.876    23.778    102.4    121.28
fprintf('\n\nPortfolio risk with t copula (dof = 5):\n');
Portfolio risk with t copula (dof = 5):
disp(pr_t)
      EL       Std       VaR       CVaR 
    ______    ______    ______    ______

    24.808    38.749    186.08    250.59

Compare the tail losses of each model.

% Plot the Gaussian copula tail.
figure;
subplot(2,1,1)
p1 = histogram(cc.PortfolioLosses);
hold on
plotline(pr.VaR,[1 0.5 0.5])
plotline(pr.CVaR,[1 0 0])
xlim([0.8 * pr.VaR  1.2 * pr_t.CVaR]);
ylim([0 1000]);
grid on
legend('Loss Distribution','VaR','CVaR')
title('Portfolio Losses with Gaussian Copula');
xlabel('Losses ($)');
ylabel('Frequency');

% Plot the t copula tail.
subplot(2,1,2)
p2 = histogram(cc_t.PortfolioLosses);
hold on
plotline(pr_t.VaR,[1 0.5 0.5])
plotline(pr_t.CVaR,[1 0 0])
xlim([0.8 * pr.VaR  1.2 * pr_t.CVaR]);
ylim([0 1000]);
grid on
legend('Loss Distribution','VaR','CVaR');
title('Portfolio Losses with t Copula (dof = 5)');
xlabel('Losses ($)');
ylabel('Frequency');

Figure contains 2 axes objects. Axes object 1 with title Portfolio Losses with Gaussian Copula, xlabel Losses ($), ylabel Frequency contains 3 objects of type histogram, line. These objects represent Loss Distribution, VaR, CVaR. Axes object 2 with title Portfolio Losses with t Copula (dof = 5), xlabel Losses ($), ylabel Frequency contains 3 objects of type histogram, line. These objects represent Loss Distribution, VaR, CVaR.

The tail risk measures VaR and CVaR are significantly higher using the t copula with five degrees of freedom. The default correlations are higher with t copulas, therefore there are more scenarios where multiple counterparties default. The number of degrees of freedom plays a significant role. For very high degrees of freedom, the results with the t copula are similar to the results with the Gaussian copula. Five is a very low number of degrees of freedom and, consequentially, the results show striking differences. Furthermore, these results highlight that the potential for extreme losses are very sensitive to the choice of copula and the number of degrees of freedom.

See Also

| | | | |

Related Examples

More About