Visualize Transitions Data for transprob

This example shows how to visualize credit rating transitions that are used as an input to the transprob function. The example also describes how the transprob function treats rating transitions when the company data starts after the start date of the analysis, or when the end date of the analysis is after the last transition observed.

Sample Data

Set up fictitious sample data for illustration purposes.

data = {'ABC','17-Feb-2015','AA';
    'ABC','6-Jul-2017','A';
    'LMN','12-Aug-2014','B';
    'LMN','9-Nov-2015','CCC';
    'LMN','7-Sep-2016','D';
    'XYZ','14-May-2013','BB';
    'XYZ','21-Jun-2016','BBB'};
data = cell2table(data,'VariableNames',{'ID','Date','Rating'});
disp(data)
      ID            Date          Rating 
    _______    _______________    _______

    {'ABC'}    {'17-Feb-2015'}    {'AA' }
    {'ABC'}    {'6-Jul-2017' }    {'A'  }
    {'LMN'}    {'12-Aug-2014'}    {'B'  }
    {'LMN'}    {'9-Nov-2015' }    {'CCC'}
    {'LMN'}    {'7-Sep-2016' }    {'D'  }
    {'XYZ'}    {'14-May-2013'}    {'BB' }
    {'XYZ'}    {'21-Jun-2016'}    {'BBB'}

The transprob function understands that this panel-data format indicates the dates when a new rating is assigned to a given company. transprob assumes that such ratings remain unchanged, unless a subsequent row explicitly indicates a rating change. For example, for company 'ABC', transprob understands that the 'A' rating is unchanged for any date after '6-Jul-2017' (indefinitely).

Compute Transition Matrix and Transition Counts

The transprob function returns a transition probability matrix as the primary output. There are also optional outputs that contain additional information for how many transitions occurred. For more information, see transprob for information on the optional outputs for both the 'cohort' and the 'duration' methods.

For illustration purposes, this example allows you to pick the StartYear (limited to 2014 or 2015 for this example) and the EndYear (2016 or 2017). This example also uses the hDisplayTransitions helper function (see the Local Functions section) to format the transitions information for ease of reading.

StartYear = 2014;
EndYear = 2017;
startDate = datetime(StartYear,12,31,'Locale','en_US');
endDate = datetime(EndYear,12,31,'Locale','en_US');
RatingLabels = ["AAA","AA","A","BBB","BB","B","CCC","D"];

[tm,st,it] = transprob(data,'startDate',startDate,'endDate',endDate,'algorithm','cohort','labels',RatingLabels);

The transition probabilities of the TransMat output indicate the probability of migrating between ratings. The probabilities are expressed in %, that is, they are multiplied by 100.

hDisplayTransitions(tm,RatingLabels,"Transition Matrix")
Transition Matrix

           AAA    AA     A     BBB    BB    B    CCC     D 
           ___    __    ___    ___    __    _    ___    ___

    AAA    100     0      0      0     0    0      0      0
    AA       0    50     50      0     0    0      0      0
    A        0     0    100      0     0    0      0      0
    BBB      0     0      0    100     0    0      0      0
    BB       0     0      0     50    50    0      0      0
    B        0     0      0      0     0    0    100      0
    CCC      0     0      0      0     0    0      0    100
    D        0     0      0      0     0    0      0    100

The transition counts are stored in the sampleTotals optional output and indicate how many transitions occurred between ratings for the entire sample (that is, all companies).

hDisplayTransitions(st.totalsMat,RatingLabels,"Transition counts, all companies")
Transition counts, all companies

           AAA    AA    A    BBB    BB    B    CCC    D
           ___    __    _    ___    __    _    ___    _

    AAA     0     0     0     0     0     0     0     0
    AA      0     1     1     0     0     0     0     0
    A       0     0     0     0     0     0     0     0
    BBB     0     0     0     1     0     0     0     0
    BB      0     0     0     1     1     0     0     0
    B       0     0     0     0     0     0     1     0
    CCC     0     0     0     0     0     0     0     1
    D       0     0     0     0     0     0     0     1

The third output of transprob is idTotals that contains information about transitions at an ID level, company by company (in the same order that the companies appear in the input data).

Select a company to display the transition counts and a corresponding visualization of the transitions. The hPlotTransitions helper function (see the Local Functions section) shows the transitions history for a company.

CompanyID = "ABC";
UniqueIDs = unique(data.ID,'stable');
[~,CompanyIndex] = ismember(CompanyID,UniqueIDs);
hDisplayTransitions(it(CompanyIndex).totalsMat,RatingLabels,strcat("Transition counts, company ID: ",CompanyID))
Transition counts, company ID: ABC

           AAA    AA    A    BBB    BB    B    CCC    D
           ___    __    _    ___    __    _    ___    _

    AAA     0     0     0     0     0     0     0     0
    AA      0     1     1     0     0     0     0     0
    A       0     0     0     0     0     0     0     0
    BBB     0     0     0     0     0     0     0     0
    BB      0     0     0     0     0     0     0     0
    B       0     0     0     0     0     0     0     0
    CCC     0     0     0     0     0     0     0     0
    D       0     0     0     0     0     0     0     0
hPlotTransitions(CompanyID,startDate,endDate,data,RatingLabels)

To understand how transprob handles data when the first observed date is after the start date of the analysis, or whose last observed date occurs before the end date of the analysis, consider the following example. For company 'ABC' suppose that the analysis has a start date of 31-Dec-2014 and end date of 31-Dec-2017. There are only two transitions reported for this company for that analysis time window. The first observation for 'ABC' happened on 17-Feb-2015. So the 31-Dec-2015 snapshot is the first time the company is observed. By 31-Dec-2016, the company remained in the original 'AA' rating. By 31-Dec-2017, a downgrade to 'A' is recorded. Consistent with this, the transition counts show one transition from 'AA' to 'AA' (from the end of 2015 to the end of 2016), and one transition from 'AA' to 'A' (from the end of 2016 to the end of 2017). The plot shows the last rating as a dotted red line to emphasize that the last rating in the data is extrapolated indefinitely into the future. There is no extrapolation into the past; the company's history is ignored until a company rating is known for an entire transition period (31-Dec-2015 through 31-Dec-2016 in the case of 'ABC').

Compute Transition Matrix Containing NR (Not Rated) Rating

Consider a different sample data containing only a single company 'DEF'. The data contains transitions of company 'DEF' from 'A' to 'NR' rating and a subsequent transition from 'NR' to 'BBB'.

dataNR = {'DEF','17-Mar-2011','A';
    'DEF','24-Mar-2014','NR';
    'DEF','26-Sep-2016','BBB'};
dataNR = cell2table(dataNR,'VariableNames',{'ID','Date','Rating'});
disp(dataNR)
      ID            Date          Rating 
    _______    _______________    _______

    {'DEF'}    {'17-Mar-2011'}    {'A'  }
    {'DEF'}    {'24-Mar-2014'}    {'NR' }
    {'DEF'}    {'26-Sep-2016'}    {'BBB'}

transprob treats 'NR' as another rating. The transition matrix below shows the estimated probability of transitioning into and out of 'NR'.

StartYearNR = 2010;
EndYearNR = 2018;
startDateNR = datetime(StartYearNR,12,31,'Locale','en_US');
endDateNR = datetime(EndYearNR,12,31,'Locale','en_US');
CompanyID_NR = "DEF";

RatingLabelsNR = ["AAA","AA","A","BBB","BB","B","CCC","D","NR"];

[tmNR,~,itNR] = transprob(dataNR,'startDate',startDateNR,'endDate',endDateNR,'algorithm','cohort','labels',RatingLabelsNR);
hDisplayTransitions(tmNR,RatingLabelsNR,"Transition Matrix")
Transition Matrix

           AAA    AA       A       BBB    BB      B     CCC     D       NR  
           ___    ___    ______    ___    ___    ___    ___    ___    ______

    AAA    100      0         0      0      0      0      0      0         0
    AA       0    100         0      0      0      0      0      0         0
    A        0      0    66.667      0      0      0      0      0    33.333
    BBB      0      0         0    100      0      0      0      0         0
    BB       0      0         0      0    100      0      0      0         0
    B        0      0         0      0      0    100      0      0         0
    CCC      0      0         0      0      0      0    100      0         0
    D        0      0         0      0      0      0      0    100         0
    NR       0      0         0     50      0      0      0      0        50

Display the transition counts and corresponding visualization of the transitions.

hDisplayTransitions(itNR.totalsMat,RatingLabelsNR,strcat("Transition counts, company ID: ",CompanyID_NR))
Transition counts, company ID: DEF

           AAA    AA    A    BBB    BB    B    CCC    D    NR
           ___    __    _    ___    __    _    ___    _    __

    AAA     0     0     0     0     0     0     0     0    0 
    AA      0     0     0     0     0     0     0     0    0 
    A       0     0     2     0     0     0     0     0    1 
    BBB     0     0     0     2     0     0     0     0    0 
    BB      0     0     0     0     0     0     0     0    0 
    B       0     0     0     0     0     0     0     0    0 
    CCC     0     0     0     0     0     0     0     0    0 
    D       0     0     0     0     0     0     0     0    0 
    NR      0     0     0     1     0     0     0     0    1 
hPlotTransitions(CompanyID_NR,startDateNR,endDateNR,dataNR,RatingLabelsNR)

To remove the 'NR' from the transition matrix, use the 'excludeLabels' name-value input argument in transprob. The list of labels to exclude may or may not be specified in the name-value pair argument labels. For example, both RatingLabels and RatingLabelsNR generate the same output from transprob.

[tmNR,stNR,itNR] = transprob(dataNR,'startDate',startDateNR,'endDate',endDateNR,'algorithm','cohort','labels',RatingLabelsNR,'excludeLabels','NR');
hDisplayTransitions(tmNR,RatingLabels,"Transition Matrix")
Transition Matrix

           AAA    AA      A     BBB    BB      B     CCC     D 
           ___    ___    ___    ___    ___    ___    ___    ___

    AAA    100      0      0      0      0      0      0      0
    AA       0    100      0      0      0      0      0      0
    A        0      0    100      0      0      0      0      0
    BBB      0      0      0    100      0      0      0      0
    BB       0      0      0      0    100      0      0      0
    B        0      0      0      0      0    100      0      0
    CCC      0      0      0      0      0      0    100      0
    D        0      0      0      0      0      0      0    100

Display the transition counts and corresponding visualization of the transitions.

hDisplayTransitions(itNR.totalsMat,RatingLabels,strcat("Transition counts, company ID: ",CompanyID_NR))
Transition counts, company ID: DEF

           AAA    AA    A    BBB    BB    B    CCC    D
           ___    __    _    ___    __    _    ___    _

    AAA     0     0     0     0     0     0     0     0
    AA      0     0     0     0     0     0     0     0
    A       0     0     2     0     0     0     0     0
    BBB     0     0     0     2     0     0     0     0
    BB      0     0     0     0     0     0     0     0
    B       0     0     0     0     0     0     0     0
    CCC     0     0     0     0     0     0     0     0
    D       0     0     0     0     0     0     0     0
hPlotTransitions(CompanyID_NR,startDateNR,endDateNR,dataNR,RatingLabels)

Consistent with the previous plot, the transition counts still show two transitions from 'A' to 'A' (from the end of 2012 to the end of 2014), and two transitions from 'BBB' to 'BBB' (from the end of 2017 to the end of 2019).

However, different from the previous plot, specifying 'NR' using the 'excludeLabels' name-value input argument of transprob removes any transitions into and out of the 'NR' rating.

Local Functions

function hDisplayTransitions(TransitionsData,RatingLabels,Title)
% Helper function to format transition information outputs

TransitionsAsTable = array2table(TransitionsData,...
   'VariableNames',RatingLabels,'RowNames',RatingLabels);

fprintf('\n%s\n\n',Title)
disp(TransitionsAsTable)

end

function hPlotTransitions(CompanyID,startDate,endDate,data,RatingLabels)
% Helper function to visualize transitions between ratings

   Ind = string(data.ID)==CompanyID;
   DatesOriginal = datetime(data.Date(Ind),'Locale','en_US');
   RatingsOriginal = categorical(data.Rating(Ind),flipud(RatingLabels(:)),flipud(RatingLabels(:)));
   
   stairs(DatesOriginal,RatingsOriginal,'LineWidth',2)
   hold on;

   % Indicate rating extrapolated into the future (arbitrarily select 91
   % days after endDate as the last date on the plot)
   endDateExtrap = endDate+91;
   if endDateExtrap>DatesOriginal(end)
      DatesExtrap = [DatesOriginal(end); endDateExtrap];
      RatingsExtrap = [RatingsOriginal(end); RatingsOriginal(end)];
      stairs(DatesExtrap,RatingsExtrap,'LineWidth',2,'LineStyle',':')
   end
   hold off;

   % Add lines to indicate the snapshot dates
   % transprob uses 1 as the default for 'snapsPerYear', hardcoded here for simplicity
   % The call to cfdates generates the exact same snapshot dates that transprob uses
   snapsPerYear = 1;
   snapDates = cfdates(startDate-1,endDate,snapsPerYear)';
   yLimits = ylim;
   for ii=1:length(snapDates)
      line([snapDates(ii) snapDates(ii)],yLimits,'Color','m')
   end
   title(strcat("Company ID: ",CompanyID))
end