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 |
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 If None, |
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 If None, |
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 If None, |
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 If None, |
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 If None, |
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 If None, |
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 If None, |
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, |
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 If return a |
Raises:
Type | Description |
---|---|
ValueError
|
If providing a single rating and |
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, |
None
|
Returns:
Type | Description |
---|---|
Union[int, pd.Series, pd.DataFrame]
|
Numerical WARF. If returns a If return a |
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 If return a |
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, |
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 Compare https://hsbc.github.io/pyratings/short-term-rating/#there's-one-more-catch...
|
None
|
Returns:
Type | Description |
---|---|
Union[str, pd.Series, pd.DataFrame]
|
Regular ratings according to |
Raises:
Type | Description |
---|---|
ValueError
|
If providing a single rating score and |
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 |
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 |
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