Compute portfolio WARF¶
The following case-study demonstrates how to compute the weighted average rating factor for a portfolio.
Preliminary tasks¶
As a first step, we are going to import a portfolio into a pd.DataFrame
. We'll call
it port_df
. This dataframe comprises a number of securities with respective weights
and ratings.
import pandas as pd
import pyratings as rtg
port_df = pd.read_excel("portfolio.xlsx", sheet_name="long_term_ratings_worst")
port_df.head()
ISIN | weight | worst_rtg | |
---|---|---|---|
0 | ISIN00000001 | 0.518515 | AAA |
1 | ISIN00000002 | 0.950810 | AA+ |
2 | ISIN00000003 | 0.497176 | AA |
3 | ISIN00000004 | 0.648453 | AA- |
4 | ISIN00000005 | 0.674328 | AA- |
Computing portfolio WARF¶
The column worst_rtg will be used in order to translate the ratings into WARFs according to the following table.
We will use
get_warf_from_ratings
to translate the human-readable ratings into WARFs. The function needs a
rating provider (here: "S&P") in order to select an appropriate translation dictionary.
port_warf_df = pd.concat(
[
port_df,
rtg.get_warf_from_ratings(
ratings=port_df["worst_rtg"],
rating_provider="S&P",
)
],
axis=1
)
port_warf_df
ISIN | weight | worst_rtg | warf_worst_rtg | |
---|---|---|---|---|
0 | ISIN00000001 | 0.518515 | AAA | 1.0 |
1 | ISIN00000002 | 0.950810 | AA+ | 10.0 |
2 | ISIN00000003 | 0.497176 | AA | 20.0 |
3 | ISIN00000004 | 0.648453 | AA- | 40.0 |
4 | ISIN00000005 | 0.674328 | AA- | 40.0 |
... | ... | ... | ... | ... |
82 | ISIN00000083 | 2.321185 | BBB+ | 260.0 |
83 | ISIN00000084 | 1.389043 | BBB+ | 260.0 |
84 | ISIN00000085 | 2.296711 | BBB+ | 260.0 |
85 | ISIN00000086 | 1.015105 | AAA | 1.0 |
86 | ISIN00000087 | 0.964399 | AA | 20.0 |
87 rows × 4 columns
Finally, we need to compute the WARF on a portfolio basis, which we subsequently
convert back into a human-readable rating. For the former, we use the
get_weighted_average
function and the
get_ratings_from_warf
function for the latter.
avg_warf = rtg.get_weighted_average(
data=port_warf_df["warf_worst_rtg"],
weights=port_warf_df["weight"] / 100,
)
print(f"WARF: {avg_warf:.2f}")
WARF: 165.58
avg_warf_equivalent_rating = rtg.get_ratings_from_warf(
warf=avg_warf,
rating_provider="SP",
)
print(f"Portfolio equivalent WARF rating: {avg_warf_equivalent_rating}")
Portfolio equivalent WARF rating: A-
There you go. The portfolio WARF is A-.
Do you prefer to show the rating using Moody’s rating scale? — It’s as simple as
changing the rating_provider
argument to “Moody”.
avg_warf_equivalent_rating = rtg.get_ratings_from_warf(
warf=avg_warf,
rating_provider="Moody"
)
print(f"Portfolio equivalent WARF rating: {avg_warf_equivalent_rating}")
Portfolio equivalent WARF rating: A3
Compute the WARF buffer¶
The WARF buffer is the distance from the current WARF to the next maxWARF
level. It
determines the room until a further rating downgrade takes place.
Earlier, we determined that the portfolio WARF is equal to 165.58. Let's compute the WARF buffer.
The corresponding maxWARF
value is 220. The buffer is then equal to 220 - 165.58
= 54.42.
pyratings provides the function
get_warf_buffer
to help
you compute the WARF buffer.
print(f"WARF buffer: {rtg.get_warf_buffer(avg_warf):.2f}")
WARF buffer: 54.42