Skip to content

API Reference

Clean ratings

Module contains functions to clean ratings.

get_pure_ratings

get_pure_ratings(ratings)

Remove rating watches/outlooks and other non-actual-rating related information.

Ratings may contain watch, such as 'AA- *+', 'BBB+ (CwNegative)'. Outlook/watch should be seperated by a blank from the actual rating. Also, ratings may also contain the letter 'u' (unsolicited) or be prefixed by '(P)' (public information only). This kind of information will be removed to retrieve the actual rating(s).

Parameters:

Name Type Description Default
ratings str | pd.Series | pd.DataFrame

Uncleaned rating(s).

required

Returns:

Type Description
Union[str, pd.Series, pd.DataFrame]

Regular ratings stripped off of watches. The name of the resulting Series or the columns of the returning DataFrame will be suffixed with _clean.

Examples:

Cleaning a single rating:

>>> get_pure_ratings("AA- *+")
'AA-'
>>> get_pure_ratings("Au")
'A'
>>> get_pure_ratings("(P)P-2")
'P-2'

Cleaning a pd.Series:

>>> import numpy as np
>>> import pandas as pd
>>> rating_series=pd.Series(
...    data=[
...        "BB+ *-",
...        "(P)BBB *+",
...        np.nan,
...        "AA- (Developing)",
...        np.nan,
...        "CCC+ (CwPositive)",
...        "BB+u",
...    ],
...    name="rtg_SP",
... )
>>> get_pure_ratings(rating_series)
0     BB+
1     BBB
2     NaN
3     AA-
4     NaN
5    CCC+
6     BB+
Name: rtg_SP_clean, dtype: object

Cleaning a pd.DataFrame:

>>> rtg_df = pd.DataFrame(
...    data={
...        "rtg_SP": [
...            "BB+ *-",
...            "BBB *+",
...            np.nan,
...            "AA- (Developing)",
...            np.nan,
...            "CCC+ (CwPositive)",
...            "BB+u",
...        ],
...        "rtg_Fitch": [
...            "BB+ *-",
...            "BBB *+",
...            pd.NA,
...            "AA- (Developing)",
...            np.nan,
...            "CCC+ (CwPositive)",
...            "BB+u",
...        ],
...    },
... )
>>> get_pure_ratings(rtg_df)
  rtg_SP_clean rtg_Fitch_clean
0          BB+             BB+
1          BBB             BBB
2          NaN            <NA>
3          AA-             AA-
4          NaN             NaN
5         CCC+            CCC+
6          BB+             BB+

Consolitdate ratings

Module contains functions to consolidate ratings from different rating agencies.

consolidate_ratings

consolidate_ratings(
    ratings,
    method="worst",
    rating_provider_input=None,
    rating_provider_output="S&P",
    tenor="long-term",
)

Consolidate ratings on a security level basis across rating agencies .

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
method Literal['best', 'second_best', 'worst']

Defines the method that will be used in order to consolidate the ratings on a security level basis across rating agencies. Valid methods are {"best", "second_best", "worst"}.

'worst'
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_input will be inferred from the dataframe column names.

None
rating_provider_output Literal['Fitch', 'Moody', 'S&P', 'Bloomberg', 'DBRS']

Indicates which rating scale will be used for output results. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

'S&P'
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Consolidated ratings on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )

Identify the best ratings:

>>> consolidate_ratings(
...     ratings=ratings_df,
...     method="best",
...     rating_provider_input=["S&P", "Moody", "Fitch"],
...     rating_provider_output="Moody",
... )
0    Aaa
1    Aa3
2    Aa1
3    Ba3
4    Ca
Name: best_rtg, dtype: object

Identify the second-best ratings:

>>> consolidate_ratings(
...     ratings=ratings_df,
...     method="second_best",
...     rating_provider_input=["S&P", "Moody", "Fitch"],
...     rating_provider_output="DBRS",
... )
0    AAH
1    AAL
2    AA
3    BBL
4    C
Name: second_best_rtg, dtype: object

Identify the worst ratings:

>>> consolidate_ratings(
...     ratings=ratings_df,
...     method="worst",
...     rating_provider_input=["S&P", "Moody", "Fitch"]
... )
0    AA-
1    AA-
2    AA-
3    B+
4    C
Name: worst_rtg, dtype: object

get_best_ratings

get_best_ratings(
    ratings,
    rating_provider_input=None,
    rating_provider_output="S&P",
    tenor="long-term",
)

Compute the best rating on a security level basis across rating agencies.

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_input will be inferred from the dataframe column names.

None
rating_provider_output Literal['Fitch', 'Moody', 'S&P', 'Bloomberg', 'DBRS']

Indicates which rating scale will be used for output results. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

'S&P'
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Best ratings on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )
>>> get_best_ratings(ratings_df, rating_provider_input=["S&P", "Moody", "Fitch"])
0    AAA
1    AA-
2    AA+
3    BB-
4    CC
Name: best_rtg, dtype: object

get_best_scores

get_best_scores(
    ratings, rating_provider_input=None, tenor="long-term"
)

Compute the best rating scores on a security level basis across rating agencies.

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_input will be inferred from the dataframe column names.

None
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Best rating scores on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )
>>> get_best_scores(
...     ratings=ratings_df,
...     rating_provider_input=["S&P", "Moody", "Fitch"]
... )
0     1
1     4
2     2
3    13
4    20
Name: best_scores, dtype: int64

get_second_best_ratings

get_second_best_ratings(
    ratings,
    rating_provider_input=None,
    rating_provider_output="S&P",
    tenor="long-term",
)

Compute the second-best rating on a security level basis across rating agencies.

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_input will be inferred from the dataframe column names.

None
rating_provider_output Literal['Fitch', 'Moody', 'S&P', 'Bloomberg', 'DBRS']

Indicates which rating scale will be used for output results. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

'S&P'
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Second-best ratings on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )
>>> get_second_best_ratings(
...     ratings_df, rating_provider_input=["S&P", "Moody", "Fitch"]
... )
0    AA+
1    AA-
2     AA
3    BB-
4      C
Name: second_best_rtg, dtype: object

get_second_best_scores

get_second_best_scores(
    ratings, rating_provider_input=None, tenor="long-term"
)

Compute the second-best scores on a security level basis across rating agencies.

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_input will be inferred from the dataframe column names.

None
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Second-best scores on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )
>>> get_second_best_scores(
...     ratings_df, rating_provider_input=["S&P", "Moody", "Fitch"]
... )
0     2.0
1     4.0
2     3.0
3    13.0
4    21.0
Name: second_best_scores, dtype: float64

get_worst_ratings

get_worst_ratings(
    ratings,
    rating_provider_input=None,
    rating_provider_output="S&P",
    tenor="long-term",
)

Compute the worst rating on a security level basis across rating agencies.

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_innput will be inferred from the dataframe column names.

None
rating_provider_output Literal['Fitch', 'Moody', 'S&P', 'Bloomberg', 'DBRS']

Indicates which rating scale will be used for output results. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

'S&P'
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Worst ratings on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )
>>> get_worst_ratings(ratings_df, rating_provider_input=["S&P", "Moody", "Fitch"])
0    AA-
1    AA-
2    AA-
3     B+
4      C
Name: worst_rtg, dtype: object

get_worst_scores

get_worst_scores(
    ratings, rating_provider_input=None, tenor="long-term"
)

Compute the worst scores on a security level basis across rating agencies.

Parameters:

Name Type Description Default
ratings pd.DataFrame

Dataframe consisting of clean ratings (i.e. stripped off of watches/outlooks)

required
rating_provider_input list[str]

Indicates rating providers within ratings. Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider_innput will be inferred from the dataframe column names.

None
tenor Literal['long-term', 'short-term']

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
pd.Series

Worst scores on a security level basis.

Examples:

>>> import pandas as pd
>>> ratings_df = pd.DataFrame(
...     data=(
...         {
...             "rating_S&P": ['AAA', 'AA-', 'AA+', 'BB-', 'C'],
...             "rating_Moody's": ['Aa1', 'Aa3', 'Aa2', 'Ba3', 'Ca'],
...             "rating_Fitch": ['AA-', 'AA-', 'AA-', 'B+', 'C'],
...         }
...     )
... )
>>> get_worst_scores(ratings_df, rating_provider_input=["S&P", "Moody", "Fitch"])
0     4
1     4
2     4
3    14
4    21
Name: worst_scores, dtype: int64

Get rating scores

Module contains functions to translate ratings / WARF into rating scores.

All functions use the following table in order to translate between long-term ratings/WARF and numerical rating scores.

Moody S&P Fitch DBRS Bloomberg Score WARF MinWARF* MaxWARF*
Aaa AAA AAA AAA AAA 1 1 1 5
Aa1 AA+ AA+ AAH AA+ 2 10 5 15
Aa2 AA AA AA AA 3 20 15 30
Aa3 AA- AA- AAL AA- 4 40 30 55
A1 A+ A+ AH A+ 5 70 55 95
A2 A A A A 6 120 95 150
A3 A- A- AL A- 7 180 150 220
Baa1 BBB+ BBB+ BBBH BBB+ 8 260 220 310
Baa2 BBB BBB BBB BBB 9 360 310 485
Baa3 BBB- BBB- BBBL BBB- 10 610 485 775
Ba1 BB+ BB+ BBH BB+ 11 940 775 1145
Ba2 BB BB BB BB 12 1350 1145 1558
Ba3 BB- BB- BBL BB- 13 1766 1558 1993
B1 B+ B+ BH B+ 14 2220 1993 2470
B2 B B B B 15 2720 2470 3105
B3 B- B- BL B- 16 3490 3105 4130
Caa1 CCC+ CCC+ CCCH CCC+ 17 4770 4130 5635
Caa2 CCC CCC CCC CCC 18 6500 5635 7285
Caa3 CCC- CCC- CCCL CCC- 19 8070 7285 9034
Ca CC CC CC CC 20 9998 9034 9998.5
C C C C C 21 9999 9998.5 9999.5
D D D D DDD 22 10000 9999.5 10000

MinWARF is inclusive, while MaxWARF is exclusive.

For short-term ratings, the rating will be translated into an equivalent long-term rating score. The translation will depend on a "translation strategy". The following translation table will be used:

Agency Strategy Rating MinLTScore MaxLTScore AvgLTScore
Moody's best P-1 1 7 4.00
Moody's best P-2 8 9 8.50
Moody's best P-3 10 10 10.00
Moody's best NP 11 22 16.50
Moody's base P-1 1 6 3.50
Moody's base P-2 7 8 7.50
Moody's base P-3 9 10 9.50
Moody's base NP 11 22 16.50
Moody's worst P-1 1 5 3.00
Moody's worst P-2 6 8 7.00
Moody's worst P-3 9 10 9.50
Moody's worst NP 11 22 16.50
S&P best A-1+ 1 5 3.00
S&P best A-1 6 7 6.50
S&P best A-2 8 9 8.50
S&P best A-3 10 11 10.50
S&P best B 12 16 14.00
S&P best C 17 21 19.00
S&P best D 22 22 22.00
S&P base A-1+ 1 4 2.50
S&P base A-1 5 6 5.50
S&P base A-2 7 9 8.00
S&P base A-3 10 10 10.00
S&P base B 11 16 13.50
S&P base C 17 21 19.00
S&P base D 22 22 22.00
S&P worst A-1+ 1 4 2.50
S&P worst A-1 5 6 5.50
S&P worst A-2 7 9 8.00
S&P worst A-3 10 10 10.00
S&P worst B 11 16 13.50
S&P worst C 17 21 19.00
S&P worst D 22 22 22.00
Fitch best F1+ 1 6 3.50
Fitch best F1 7 8 7.50
Fitch best F2 9 9 9.00
Fitch best F3 10 10 10.00
Fitch best B 11 16 13.50
Fitch best C 17 20 18.50
Fitch best D 21 22 21.50
Fitch base F1+ 1 5 3.00
Fitch base F1 6 7 6.50
Fitch base F2 8 8 8.00
Fitch base F3 9 10 9.50
Fitch base B 11 16 13.50
Fitch base C 17 20 18.50
Fitch base D 21 22 21.50
Fitch worst F1+ 1 4 2.50
Fitch worst F1 5 6 5.50
Fitch worst F2 7 8 7.50
Fitch worst F3 9 10 9.50
Fitch worst B 11 16 13.50
Fitch worst C 17 20 18.50
Fitch worst D 21 22 21.50
DBRS best R-1 H 1 3 2.00
DBRS best R-1 M 4 5 4.50
DBRS best R-1 L 6 8 7.00
DBRS best R-2 H 9 9 9.00
DBRS best R-2 M 10 10 10.00
DBRS best R-3 11 11 11.00
DBRS best R-4 12 15 13.50
DBRS best R-5 16 21 18.50
DBRS best D 22 22 22.00
DBRS base R-1 H 1 2 1.50
DBRS base R-1 M 3 4 3.50
DBRS base R-1 L 5 7 6.00
DBRS base R-2 H 8 8 8.00
DBRS base R-2 M 9 9 9.00
DBRS base R-2 L / R-3 10 10 10.00
DBRS base R-4 11 14 12.50
DBRS base R-5 15 21 18.00
DBRS base D 22 22 22.00
DBRS worst R-1 H 1 1 1.00
DBRS worst R-1 M 2 3 2.50
DBRS worst R-1 L 4 6 5.00
DBRS worst R-2 H 7 8 7.50
DBRS worst R-2 M 9 9 9.00
DBRS worst R-3 10 10 10.00
DBRS worst R-4 11 14 12.50
DBRS worst R-5 15 21 18.00
DBRS worst D 22 22 22.00

get_scores_from_ratings

get_scores_from_ratings(
    ratings, rating_provider=None, tenor="long-term"
)

Convert regular ratings into numerical rating scores.

Parameters:

Name Type Description Default
ratings str | pd.Series | pd.DataFrame

Rating(s) to be translated into rating score(s).

required
rating_provider str | list[str] | None

Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider will be inferred from the series name or dataframe column names.

None
tenor str

Should contain any valid tenor out of {"long-term", "short-term"}

'long-term'

Returns:

Type Description
Union[int, pd.Series, pd.DataFrame]

Numerical rating score(s)

If returns a pd.Series, the series name will be rtg_score suffixed by ratings.name.

If return a pd.DataFrame, the column names will be rtg_score suffixed by the respective ratings.columns.

Raises:

Type Description
ValueError

If providing a single rating and rating_provider is None.

Examples:

Converting a single long-term rating:

>>> get_scores_from_ratings(
...     ratings="BBB-", rating_provider="S&P", tenor="long-term"
... )
10

Converting a single short-term rating score:

>>> get_scores_from_ratings(
...     ratings="P-1", rating_provider="Moody", tenor="short-term"
... )
3.5

Converting a pd.Series of ratings:

>>> import pandas as pd
>>> ratings_series = pd.Series(
...     data=["Baa1", "C", "NR", "WD", "D", "B1", "SD"], name='Moody'
... )
>>> get_scores_from_ratings(
...     ratings=ratings_series, rating_provider="Moody's", tenor="long-term"
... )
0     8.0
1    21.0
2     NaN
3     NaN
4    22.0
5    14.0
6    22.0
Name: rtg_score_Moody, dtype: float64

Providing a pd.Series without specifying a rating_provider:

>>> ratings_series = pd.Series(
...     data=["Baa1", "C", "NR", "WD", "D", "B1", "SD"], name="Moody"
... )
>>> get_scores_from_ratings(ratings=ratings_series)
0     8.0
1    21.0
2     NaN
3     NaN
4    22.0
5    14.0
6    22.0
Name: rtg_score_Moody, dtype: float64

Converting a pd.DataFrame with ratings:

>>> ratings_df = pd.DataFrame(
...     data=[["BB+", "B3", "BBB-"], ["AA-", "Aa1", "AAA"], ["D", "NR", "D"]],
...     columns=["SP", "Moody", "DBRS"],
... )
>>> get_scores_from_ratings(
...     ratings=ratings_df,
...     rating_provider=["S&P", "Moody's", "DBRS"],
...     tenor="long-term",
... )
   rtg_score_SP  rtg_score_Moody  rtg_score_DBRS
0            11             16.0             NaN
1             4              2.0             1.0
2            22              NaN            22.0

When providing a pd.DataFrame without explicitly providing the rating_provider, they will be inferred from the dataframe's columns.

>>> ratings_df = pd.DataFrame(
...     data={
...         "rtg_fitch": ["BB+", "AA-", "D"],
...         "rtg_Bloomberg": ["B-", "AA+", "NR"],
...         "DBRS Ratings": ["BBB-", "AAA", "D"],
...     }
... )
>>> get_scores_from_ratings(ratings=ratings_df)
   rtg_score_rtg_fitch  rtg_score_rtg_Bloomberg  rtg_score_DBRS Ratings
0                   11                     16.0                     NaN
1                    4                      2.0                     1.0
2                   22                      NaN                    22.0

get_scores_from_warf

get_scores_from_warf(warf)

Convert weighted average rating factors (WARFs) into numerical rating scores.

Parameters:

Name Type Description Default
warf int | float | pd.Series | pd.DataFrame

Weighted average rating factor (WARF).

required

Returns:

Type Description
Union[int, float, pd.Series, pd.DataFrame]

Numerical rating score(s).

Examples:

Converting a single WARF:

>>> get_scores_from_warf(500)
10
>>> get_scores_from_warf(1992.9999)
13

Converting a pd.Series of WARFs:

>>> import numpy as np
>>> import pandas as pd
>>> warf_series = pd.Series(data=[260, 9999.49, np.nan, 10000, 2469.99, 2470])
>>> get_scores_from_warf(warf=warf_series)
0     8.0
1    21.0
2     NaN
3    22.0
4    14.0
5    15.0
Name: rtg_score, dtype: float64

Converting a pd.DataFrame of WARFs:

>>> warf_df = pd.DataFrame(
...     data={
...         "provider1": [900, 40, 10000],
...         "provider2": [3000, 10, np.nan],
...         "provider3": [610, 1, 9999.49],
...     }
... )
>>> get_scores_from_warf(warf=warf_df)
   rtg_score_provider1  rtg_score_provider2  rtg_score_provider3
0                   11                 15.0                   10
1                    4                  2.0                    1
2                   22                  NaN                   21

Get WARF

Module contains functions to translate ratings / rating scores into WARF(s).

All functions use the following table in order to translate between long-term ratings/numerical scores and WARF.

Moody’s S&P Fitch DBRS Bloomberg Score WARF
Aaa AAA AAA AAA AAA 1 1
Aa1 AA+ AA+ AAH AA+ 2 10
Aa2 AA AA AA AA 3 20
Aa3 AA- AA- AAL AA- 4 40
A1 A+ A+ AH A+ 5 70
A2 A A A A 6 120
A3 A- A- AL A- 7 180
Baa1 BBB+ BBB+ BBBH BBB+ 8 260
Baa2 BBB BBB BBB BBB 9 360
Baa3 BBB- BBB- BBBL BBB- 10 610
Ba1 BB+ BB+ BBH BB+ 11 940
Ba2 BB BB BB BB 12 1350
Ba3 BB- BB- BBL BB- 13 1766
B1 B+ B+ BH B+ 14 2220
B2 B B B B 15 2720
B3 B- B- BL B- 16 3490
Caa1 CCC+ CCC+ CCCH CCC+ 17 4770
Caa2 CCC CCC CCC CCC 18 6500
Caa3 CCC- CCC- CCCL CCC- 19 8070
Ca CC CC CC CC 20 9998
C C C C C 21 9999
D D D D DDD 22 10000

get_warf_from_ratings

get_warf_from_ratings(ratings, rating_provider=None)

Convert regular rating(s) to numerical WARF(s).

Parameters:

Name Type Description Default
ratings str | pd.Series | pd.DataFrame

Regular rating(s) to be translated into WARF(s).

required
rating_provider str | list[str] | None

Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider will be inferred from the series name or dataframe column names.

None

Returns:

Type Description
Union[int, pd.Series, pd.DataFrame]

Numerical WARF.

If returns a pd.Series, the series name will be warf suffixed by ratings.name.

If return a pd.DataFrame, the column names will be warf suffixed by the respective ratings.columns.

Examples:

Converting a single rating:

>>> get_warf_from_ratings(ratings="BB-", rating_provider="Fitch")
1766

Converting a pd.Series with ratings:

>>> import numpy as np
>>> import pandas as pd
>>> ratings_series = pd.Series(data=["A1", "A3", "Aaa", np.nan, "D", pd.NA])
>>> get_warf_from_ratings(
...     ratings=ratings_series, rating_provider="Moody's"
... )
0       70.0
1      180.0
2        1.0
3        NaN
4    10000.0
5        NaN
Name: warf, dtype: float64

Providing a pd.Series without specifying a rating_provider:

>>> ratings_series = pd.Series(
...     data=["A1", "A3", "Aaa", np.nan, "D", pd.NA],
...     name="Moody's"
... )
>>> get_warf_from_ratings(ratings=ratings_series)
0       70.0
1      180.0
2        1.0
3        NaN
4    10000.0
5        NaN
Name: warf_Moody's, dtype: float64

Converting a pd.DataFrame with ratings:

>>> ratings_df = pd.DataFrame(
...     data=[["BB+", "B-", "foo"], ["AA-", "AA+", "AAA"], ["D", "bar", "C"]],
...     columns=["Fitch", "Bloomberg", "DBRS"],
... )
>>> get_warf_from_ratings(
...     ratings= ratings_df, rating_provider=["Fitch", "Bloomberg", "DBRS"]
... )
   warf_Fitch  warf_Bloomberg  warf_DBRS
0         940          3490.0        NaN
1          40            10.0        1.0
2       10000             NaN     9999.0

When providing a pd.DataFrame without explicitly providing the rating_provider, they will be inferred by the dataframe's columns.

>>> ratings_df = pd.DataFrame(
...     data={
...         "rtg_fitch": ["BB+", "AA-", "D"],
...         "rtg_Bloomberg": ["B-", "AA+", "bar"],
...         "DBRS Ratings": ["foo", "AAA", "C"]
...     }
... )
>>> get_warf_from_ratings(ratings=ratings_df)
   warf_rtg_fitch  warf_rtg_Bloomberg  warf_DBRS Ratings
0             940              3490.0                NaN
1              40                10.0                1.0
2           10000                 NaN             9999.0

get_warf_from_scores

get_warf_from_scores(rating_scores)

Convert numerical rating score(s) to numerical WARF(s).

Parameters:

Name Type Description Default
rating_scores int | float | pd.Series | pd.DataFrame

Numerical rating score(s).

required

Returns:

Type Description
Union[int, pd.Series, pd.DataFrame

Numerical WARF(s).

If returns a pd.Series, the series name will be warf suffixed by rating_scores.name.

If return a pd.DataFrame, the column names will be warf suffixed by the respective rating_scores.columns.

Examples:

Converting a single rating score:

>>> get_warf_from_scores(10)
610

Converting a pd.Series with rating scores:

>>> import pandas as pd
>>> rating_scores_series = pd.Series(data=[5, 7, 1, np.nan, 22, pd.NA])
>>> get_warf_from_scores(rating_scores=rating_scores_series)
0       70.0
1      180.0
2        1.0
3        NaN
4    10000.0
5        NaN
Name: warf, dtype: float64

Converting a pd.DataFrame with rating scores:

>>> rating_scores_df = pd.DataFrame(
...     data=[[11, 16, "foo"], [4, 2, 1], [22, "bar", 22]],
...     columns=["provider1", "provider2", "provider3"],
... )
>>> get_warf_from_scores(rating_scores=rating_scores_df)
   warf_provider1  warf_provider2  warf_provider3
0             940          3490.0             NaN
1              40            10.0             1.0
2           10000             NaN         10000.0

Get ratings

Module contains functions to translate rating scores / WARF into ratings.

All functions use the following table in order to translate between numerical scores/WARF and long-term ratings.

Moody’s S&P Fitch DBRS Bloomberg Score WARF MinWARF* MaxWARF*
Aaa AAA AAA AAA AAA 1 1 1 5
Aa1 AA+ AA+ AAH AA+ 2 10 5 15
Aa2 AA AA AA AA 3 20 15 30
Aa3 AA- AA- AAL AA- 4 40 30 55
A1 A+ A+ AH A+ 5 70 55 95
A2 A A A A 6 120 95 150
A3 A- A- AL A- 7 180 150 220
Baa1 BBB+ BBB+ BBBH BBB+ 8 260 220 310
Baa2 BBB BBB BBB BBB 9 360 310 485
Baa3 BBB- BBB- BBBL BBB- 10 610 485 775
Ba1 BB+ BB+ BBH BB+ 11 940 775 1145
Ba2 BB BB BB BB 12 1350 1145 1558
Ba3 BB- BB- BBL BB- 13 1766 1558 1993
B1 B+ B+ BH B+ 14 2220 1993 2470
B2 B B B B 15 2720 2470 3105
B3 B- B- BL B- 16 3490 3105 4130
Caa1 CCC+ CCC+ CCCH CCC+ 17 4770 4130 5635
Caa2 CCC CCC CCC CCC 18 6500 5635 7285
Caa3 CCC- CCC- CCCL CCC- 19 8070 7285 9034
Ca CC CC CC CC 20 9998 9034 9998.5
C C C C C 21 9999 9998.5 9999.5
D D D D DDD 22 10000 9999.5 10000

For short-term ratings, the rating will be translated into an equivalent long-term rating score. The translation will depend on the a "translation strategy". The following translation table will be used:

Agency Strategy Rating MinLTScore MaxLTScore AvgLTScore
Moody's best P-1 1 7 4.00
Moody's best P-2 8 9 8.50
Moody's best P-3 10 10 10.00
Moody's best NP 11 22 16.50
Moody's base P-1 1 6 3.50
Moody's base P-2 7 8 7.50
Moody's base P-3 9 10 9.50
Moody's base NP 11 22 16.50
Moody's worst P-1 1 5 3.00
Moody's worst P-2 6 8 7.00
Moody's worst P-3 9 10 9.50
Moody's worst NP 11 22 16.50
S&P best A-1+ 1 5 3.00
S&P best A-1 6 7 6.50
S&P best A-2 8 9 8.50
S&P best A-3 10 11 10.50
S&P best B 12 16 14.00
S&P best C 17 21 19.00
S&P best D 22 22 22.00
S&P base A-1+ 1 4 2.50
S&P base A-1 5 6 5.50
S&P base A-2 7 9 8.00
S&P base A-3 10 10 10.00
S&P base B 11 16 13.50
S&P base C 17 21 19.00
S&P base D 22 22 22.00
S&P worst A-1+ 1 4 2.50
S&P worst A-1 5 6 5.50
S&P worst A-2 7 9 8.00
S&P worst A-3 10 10 10.00
S&P worst B 11 16 13.50
S&P worst C 17 21 19.00
S&P worst D 22 22 22.00
Fitch best F1+ 1 6 3.50
Fitch best F1 7 8 7.50
Fitch best F2 9 9 9.00
Fitch best F3 10 10 10.00
Fitch best B 11 16 13.50
Fitch best C 17 20 18.50
Fitch best D 21 22 21.50
Fitch base F1+ 1 5 3.00
Fitch base F1 6 7 6.50
Fitch base F2 8 8 8.00
Fitch base F3 9 10 9.50
Fitch base B 11 16 13.50
Fitch base C 17 20 18.50
Fitch base D 21 22 21.50
Fitch worst F1+ 1 4 2.50
Fitch worst F1 5 6 5.50
Fitch worst F2 7 8 7.50
Fitch worst F3 9 10 9.50
Fitch worst B 11 16 13.50
Fitch worst C 17 20 18.50
Fitch worst D 21 22 21.50
DBRS best R-1 H 1 3 2.00
DBRS best R-1 M 4 5 4.50
DBRS best R-1 L 6 8 7.00
DBRS best R-2 H 9 9 9.00
DBRS best R-2 M 10 10 10.00
DBRS best R-3 11 11 11.00
DBRS best R-4 12 15 13.50
DBRS best R-5 16 21 18.50
DBRS best D 22 22 22.00
DBRS base R-1 H 1 2 1.50
DBRS base R-1 M 3 4 3.50
DBRS base R-1 L 5 7 6.00
DBRS base R-2 H 8 8 8.00
DBRS base R-2 M 9 9 9.00
DBRS base R-2 L / R-3 10 10 10.00
DBRS base R-4 11 14 12.50
DBRS base R-5 15 21 18.00
DBRS base D 22 22 22.00
DBRS worst R-1 H 1 1 1.00
DBRS worst R-1 M 2 3 2.50
DBRS worst R-1 L 4 6 5.00
DBRS worst R-2 H 7 8 7.50
DBRS worst R-2 M 9 9 9.00
DBRS worst R-3 10 10 10.00
DBRS worst R-4 11 14 12.50
DBRS worst R-5 15 21 18.00
DBRS worst D 22 22 22.00

get_ratings_from_scores

get_ratings_from_scores(
    rating_scores,
    rating_provider=None,
    tenor="long-term",
    short_term_strategy=None,
)

Convert numerical rating scores into regular ratings.

Parameters:

Name Type Description Default
rating_scores int | float | pd.Series | pd.DataFrame

Numerical rating score(s).

required
rating_provider str | list[str] | None

Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

If None, rating_provider will be inferred from the series name or dataframe column names.

None
tenor str

Should contain any valid tenor out of {"long-term", "short-term"}.

'long-term'
short_term_strategy str | None

Will only be used, if tenor is "short-term". Choose between three distinct strategies in order to translate a long-term rating score into a short-term rating. Must be in {"best", "base", "worst"}.

Compare https://hsbc.github.io/pyratings/short-term-rating/#there's-one-more-catch...

  • Strategy 1 (best): Always choose the best possible short-term rating. That's the optimistic approach.
  • Strategy 2 (base-case): Always choose the short-term rating that a rating agency would usually assign if there aren't any special liquidity issues (positive or negative). That's the base-case approach.
  • Strategy 3 (worst): Always choose the worst possible short-term rating. That's the conservative approach.
None

Returns:

Type Description
Union[str, pd.Series, pd.DataFrame]

Regular ratings according to rating_provider's rating scale.

Raises:

Type Description
ValueError

If providing a single rating score and rating_provider is None.

Examples:

Converting a single long-term rating score:

>>> get_ratings_from_scores(rating_scores=9, rating_provider="Fitch")
'BBB'

Converting a single short-term rating score with different short_term_strategy arguments:

>>> get_ratings_from_scores(
...     rating_scores=10,
...     rating_provider="DBRS",
...     tenor="short-term",
...     short_term_strategy="best",
... )
'R-2M'
>>> get_ratings_from_scores(
...     rating_scores=10,
...     rating_provider="DBRS",
...     tenor="short-term",
...     short_term_strategy="base",
... )
'R-3'
>>> get_ratings_from_scores(
...     rating_scores=10,
...     rating_provider="DBRS",
...     tenor="short-term",
...     short_term_strategy="worst",
... )
'R-3'

Converting a pd.Series with scores:

>>> import pandas as pd
>>> rating_scores_series = pd.Series(data=[5, 7, 1, np.nan, 22, pd.NA])
>>> get_ratings_from_scores(
...     rating_scores=rating_scores_series,
...     rating_provider="Moody's",
...     tenor="long-term",
... )
0     A1
1     A3
2    Aaa
3    NaN
4      D
5    NaN
Name: rtg_Moody, dtype: object

Providing a pd.Series without specifying a rating_provider:

>>> rating_scores_series = pd.Series(
...     data=[5, 7, 1, np.nan, 22, pd.NA],
...     name="Moody",
... )
>>> get_ratings_from_scores(rating_scores=rating_scores_series)
0     A1
1     A3
2    Aaa
3    NaN
4      D
5    NaN
Name: rtg_Moody, dtype: object

Converting a pd.DataFrame with scores:

>>> rating_scores_df = pd.DataFrame(
...     data=[[11, 16, "foo"], [4, 2, 1], [22, "bar", 22]]
... )
>>> get_ratings_from_scores(
...     rating_scores=rating_scores_df,
...     rating_provider=["Fitch", "Bloomberg", "DBRS"],
...     tenor="long-term",
... )
  rtg_Fitch rtg_Bloomberg rtg_DBRS
0       BB+            B-      NaN
1       AA-           AA+      AAA
2         D           NaN        D

When providing a pd.DataFrame without explicitly providing the rating_provider, they will be inferred by the dataframe's columns.

>>> rating_scores_df = pd.DataFrame(
...     data={
...         "rtg_fitch": [11, 4, 22],
...         "rtg_Bloomberg": [16, 2, "foo"],
...         "DBRS Ratings": ["bar", 1, 22],
...     }
... )
>>> get_ratings_from_scores(rating_scores=rating_scores_df)
  rtg_Fitch rtg_Bloomberg rtg_DBRS
0       BB+            B-      NaN
1       AA-           AA+      AAA
2         D           NaN        D

get_ratings_from_warf

get_ratings_from_warf(warf, rating_provider=None)

Convert WARFs into regular ratings.

Parameters:

Name Type Description Default
warf int | float | pd.Series | pd.DataFrame

Numerical WARF(s).

required
rating_provider str | list[str] | None

Should contain any valid rating provider out of {"Fitch", "Moody's", "S&P", "Bloomberg", "DBRS"}.

None

Returns:

Type Description
Union[str, pd.Series, pd.DataFrame]

Regular rating(s) according to rating_provider's rating scale.

Examples:

Converting a single WARF:

>>> get_ratings_from_warf(warf=610, rating_provider="DBRS")
'BBBL'
>>> get_ratings_from_warf(warf=1234.5678, rating_provider="SP")
'BB'

Converting a pd.Series with WARFs:

>>> import pandas as pd
>>> warf_series = pd.Series(data=[90, 218.999, 1, np.nan, 10000, pd.NA])
>>> get_ratings_from_warf(
...     warf=warf_series,
...     rating_provider="Moody's",
... )
0     A1
1     A3
2    Aaa
3    NaN
4      D
5    NaN
Name: rtg_Moody, dtype: object

Converting a pd.DataFrame with WARFs:

>>> warf_df = pd.DataFrame(
...     data=[[940, 4000, "foo"], [54, 13.5, 1], [10000, "bar", 9999]]
... )
>>> get_ratings_from_warf(
...     warf=warf_df,
...     rating_provider=["Fitch", "Bloomberg", "DBRS"],
... )
  rtg_Fitch rtg_Bloomberg rtg_DBRS
0       BB+            B-      NaN
1       AA-           AA+      AAA
2         D           NaN        C

Aggregate functions

Module contains aggregation functions.

get_weighted_average

get_weighted_average(data, weights)

Compute weighted average.

Parameters:

Name Type Description Default
data pd.Series

Contains numerical values.

required
weights pd.Series

Contains weights (between 0 and 1) with respect to data.

required

Returns:

Type Description
float

Weighted average data.

Notes

Computing the weighted average is simply the sumproduct of data and weights. nan in data will be excluded from calculating the weighted average. All corresponding weights will be ignored. As a matter of fact, the remaining weights will be upscaled so that the weights of all non-nan rows in data will sum up to 1 (100%).

Examples:

>>> import numpy as np
>>> import pandas as pd
>>> rtg_scores = pd.Series(data=[5, 7, 9])
>>> wgt = pd.Series(data=[0.5, 0.3, 0.2])
>>> get_weighted_average(data=rtg_scores, weights=wgt)
6.4
>>> warf = pd.Series(data=[500, 735, np.nan, 93, np.nan])
>>> wgt = pd.Series(data=[0.4, 0.1, 0.1, 0.2, 0.2])
>>> get_weighted_average(data=warf, weights=wgt)
417.29

WARF functions

Module holds functions to work with WARFs.

All functions use the following translation table.

Moody’s S&P Fitch DBRS Bloomberg Score WARF MinWARF* MaxWARF*
Aaa AAA AAA AAA AAA 1 1 1 5
Aa1 AA+ AA+ AAH AA+ 2 10 5 15
Aa2 AA AA AA AA 3 20 15 30
Aa3 AA- AA- AAL AA- 4 40 30 55
A1 A+ A+ AH A+ 5 70 55 95
A2 A A A A 6 120 95 150
A3 A- A- AL A- 7 180 150 220
Baa1 BBB+ BBB+ BBBH BBB+ 8 260 220 310
Baa2 BBB BBB BBB BBB 9 360 310 485
Baa3 BBB- BBB- BBBL BBB- 10 610 485 775
Ba1 BB+ BB+ BBH BB+ 11 940 775 1145
Ba2 BB BB BB BB 12 1350 1145 1558
Ba3 BB- BB- BBL BB- 13 1766 1558 1993
B1 B+ B+ BH B+ 14 2220 1993 2470
B2 B B B B 15 2720 2470 3105
B3 B- B- BL B- 16 3490 3105 4130
Caa1 CCC+ CCC+ CCCH CCC+ 17 4770 4130 5635
Caa2 CCC CCC CCC CCC 18 6500 5635 7285
Caa3 CCC- CCC- CCCL CCC- 19 8070 7285 9034
Ca CC CC CC CC 20 9998 9034 9998.5
C C C C C 21 9999 9998.5 9999.5
D D D D DDD 22 10000 9999.5 10000

MinWARF is inclusive, while MaxWARF is exclusive.

get_warf_buffer

get_warf_buffer(warf)

Compute WARF buffer.

The WARF buffer is the distance from current WARF to the next maxWARF level. It determines the room until a further rating downgrade.

Parameters:

Name Type Description Default
warf float | int

Numerical WARF.

required

Returns:

Type Description
Union[float, int]

WARF buffer.

Examples:

>>> get_warf_buffer(warf=480)
5.0
>>> get_warf_buffer(warf=54)
1.0