Sovereign credit rating indices #
This category group contains numeric indices of sovereign credit ratings, based on the ratings and outlooks of three large rating agencies. These categories can be used as qualifiers of other indicators, such as external liabilities, in order to adjust them for the credit risk of a currency area or a government. Information on index construction is provided in Appendix 1 .
Foreign currency credit ratings indices #
Ticker : LTFCRATING_NSA
Label : Long-term foreign-currency sovereign credit ratings index
Definition : Long-term foreign-currency sovereign credit index based on ratings and outlooks of three large rating agencies
Notes :
-
The ratings index level is a synthetic value calculated from the weighted average of ratings and outlook data of Fitch, S&P, and Moody’s. The values go from 1 to 23, with a higher value indicating a better credit rating and/or outlook. A single agency’s one-notch upgrade or downgrade is equivalent to a change of 1/3 in the index level. A single agency’s outlook change is equivalent to a change of 1/9 in the index level.
-
The ratings and outlook for most countries are available for their foreign currency debt, but if there are missing datapoints, the local rating is used as a proxy of the rating or outlook to calculate the index level. For details see Appendix 1 .
Local currency credit ratings indices #
Ticker : LTLCRATING_NSA
Label : Long-term local-currency sovereign credit ratings index
Definition : Long-term local-currency sovereign credit index based on ratings and outlooks of three large rating agencies
Notes :
-
The ratings index level is a synthetic value calculated from the weighted average of ratings and outlook data of Fitch, S&P, and Moody’s. The values go from 1 to 23, with a higher value indicating a better credit rating and/or outlook.
Imports #
Only the standard Python data science packages and the specialized
macrosynergy
package are needed.
import os
import numpy as np
import pandas as pd
import seaborn as sns
import macrosynergy.management as msm
import macrosynergy.panel as msp
import macrosynergy.signal as mss
import macrosynergy.pnl as msn
import macrosynergy.visuals as msv
from macrosynergy.download import JPMaQSDownload
import warnings
warnings.simplefilter("ignore")
The
JPMaQS
indicators we consider are downloaded using the J.P. Morgan Dataquery API interface within the
macrosynergy
package. This is done by specifying
ticker strings
, formed by appending an indicator category code
<category>
to a currency area code
<cross_section>
. These constitute the main part of a full quantamental indicator ticker, taking the form
DB(JPMAQS,<cross_section>_<category>,<info>)
, where
<info>
denotes the time series of information for the given cross-section and category. The following types of information are available:
-
value
giving the latest available values for the indicator -
eop_lag
referring to days elapsed since the end of the observation period -
mop_lag
referring to the number of days elapsed since the mean observation period -
grade
denoting a grade of the observation, giving a metric of real time information quality.
After instantiating the
JPMaQSDownload
class within the
macrosynergy.download
module, one can use the
download(tickers,start_date,metrics)
method to easily download the necessary data, where
tickers
is an array of ticker strings,
start_date
is the first collection date to be considered and
metrics
is an array comprising the times series information to be downloaded.
Currency areas are identified by currency symbols as explained in Appendix 2
cids_dmca = ['AUD', 'CAD', 'CHF', 'GBP', 'JPY', 'NOK', 'NZD', 'SEK', 'USD'] # DM currency areas
cids_dmec = ['DEM', 'ESP', 'FRF', 'ITL', 'NLG'] # DM euro area countries
cids_latm = ['ARS', 'BRL', 'COP', 'CLP', 'DOP', 'MXN', 'PAB', 'PEN', 'UYU', 'VEF'] # Latam countries
cids_emea = ['AED', 'BHD', 'CZK', 'EGP', 'HUF', 'ILS', 'NGN', 'OMR', 'PLN', 'QAR', 'RON', 'RSD', 'RUB', 'SAR', 'TRY', 'ZAR'] # EMEA countries
cids_emas = ['CNY', 'HKD', 'IDR', 'INR', 'KRW', 'MYR', 'PHP', 'SGD', 'THB', 'TWD'] # EM Asia countries
cids_dm = cids_dmca + cids_dmec
cids_em = cids_latm + cids_emea + cids_emas
cids = sorted(cids_dm + cids_em)
main = ['LTFCRATING_NSA', 'LTLCRATING_NSA']
mark = [
"FXXR_NSA",
"LCBIR_NSA",
"CDS02YXR_NSA",
"CDS05YXR_VT10",
"CDS05YXR_NSA",
"FXTARGETED_NSA",
"FXUNTRADABLE_NSA"
]
xcats = main + mark
# Download series from J.P. Morgan DataQuery by tickers
start_date = "1990-01-01"
tickers = [cid + "_" + xcat for cid in cids for xcat in xcats]
print(f"Maximum number of tickers is {len(tickers)}")
# Retrieve credentials
client_id: str = os.getenv("DQ_CLIENT_ID")
client_secret: str = os.getenv("DQ_CLIENT_SECRET")
# Download from DataQuery
with JPMaQSDownload(client_id=client_id, client_secret=client_secret) as downloader:
df = downloader.download(
tickers=tickers,
start_date=start_date,
metrics=["all"],
suppress_warning=True,
show_progress=True,
)
Maximum number of tickers is 450
Downloading data from JPMaQS.
Timestamp UTC: 2024-08-29 16:00:47
Connection successful!
Requesting data: 100%|██████████| 90/90 [00:18<00:00, 4.86it/s]
Downloading data: 100%|██████████| 90/90 [00:33<00:00, 2.69it/s]
Some expressions are missing from the downloaded data. Check logger output for complete list.
572 out of 1800 expressions are missing. To download the catalogue of all available expressions and filter the unavailable expressions, set `get_catalogue=True` in the call to `JPMaQSDownload.download()`.
Some dates are missing from the downloaded data.
1033 out of 9046 dates are missing.
Availability #
msm.missing_in_df(df, xcats=main, cids=cids)
No missing XCATs across DataFrame.
Missing cids for LTFCRATING_NSA: []
Missing cids for LTLCRATING_NSA: []
msm.check_availability(df, xcats=main, cids=cids)
Blacklisted periods #
Following the Russian invasion of Ukraine in 2022 and international sanctions, the EU announced a ban on providing credit ratings to legal persons, entities, or bodies established in Russia. Following this, the ratings for Russia were withdrawn by rating agencies. Although the most recent ratings are still in the database, they are effectively meaningless due to the lack of ongoing monitoring. For further details, refer to S&P’s announcement . We have blacklisted Russian rating history starting from the date of the invasion.
# For analytical purposes Russia's ratings after 2022 should be blacklisted
current_date = pd.Timestamp('now').strftime('%Y-%m-%d')
rub_na = ["2022-02-24", current_date]
black = {"RUB": rub_na}
df = msm.reduce_df(df, blacklist=black).reset_index(drop=True)
History #
Average ratings differ between developed and emerging countries. The variation in rating values is greater for sovereigns with lower ratings. There are exceptions to developed countries’ high ratings and low variability, such as Italy and Spain, which have suffered several credit rating downgrades since 2000.
msp.view_ranges(df, xcats=main, cids=cids, sort_cids_by='mean', start = '2000-01-01',
xcat_labels=["Foreign currency ratings index", "Local currency ratings index"])
Rating indices are slow-moving indicators reflecting the gradual nature of changes in a country’s creditworthiness. For many countries, particularly those with stable economies and political systems, there may be little to no change in their credit ratings over extended periods. CHF (Swiss franc) and NOK (Norwegian krone) had no change in their (highest possible) rating since 2000.
msp.view_timelines(
df,
xcats=main,
cids=cids,
start="2000-01-01",
title="Foreign currency (blue) and local currency (orange) credit ratings indices",
title_fontsize=30,
ncol=4,
same_y=True,
size=(12, 7),
all_xticks=True,
)
Emerging countries in Latin America (LatAm) and Asia tend to exhibit strong positive correlations in their foreign currency credit ratings. In contrast, the correlation among foreign currency ratings for countries in the EMEA (Europe, Middle East, and Africa) region is mixed.
msp.correl_matrix(df, xcats='LTFCRATING_NSA',
cids=cids_emas,
title = "Correlation matrix of foreign currency ratings index for EM Asia countries",
size = (10, 5))
msp.correl_matrix(df, xcats='LTFCRATING_NSA',
cids= list(set(cids_latm) - set(["VEF"])),
title = "Correlation matrix of foreign currency ratings index for EM Latam countries",
size = (10, 5))
msp.correl_matrix(df, xcats='LTFCRATING_NSA',
cids= cids_emea,
title = "Correlation matrix of foreign currency ratings index for EMEA countries",
size = (10, 5))
Long-term local currency ratings and long-term foreign currency ratings are strongly, almost perfectly correlated, reflecting their shared but also distinct risk factors. Differences between the two ratings may arise from factors like currency risk, market perceptions, or external shocks, which may impact foreign currency ratings more significantly than local currency ratings.
xcatx = ["LTLCRATING_NSA", "LTFCRATING_NSA"]
cr = msp.CategoryRelations(
df,
xcats=xcatx,
cids=cids,
freq="M",
lag=0,
start="2000-01-01",
years=None,
xcat_aggs=["last", "last"],
)
cr.reg_scatter(
title=f"Long-term local currency and foreign currency ratings, {len(cids)} Countries",
labels=False,
coef_box="lower right",
ylab="Long-term local currency sovereign credit ratings index",
xlab="Long-term foreign currency sovereign credit ratings index",
prob_est="map",
)
Importance #
Over the past 20 years, the influence of credit rating agencies (CRAs) has grown substantially. Credit ratings have become deeply integrated into investment processes, financial contracts, and regulatory frameworks. Ratings play a critical role in guiding investment decisions, determining the terms of financial agreements, and shaping regulatory policies. The reliance on these ratings has expanded the agencies’ impact on global financial markets.
Research Links #
On timing and importance of rating changes:
“ changes in credit ratings and outlooks have a stronger effect on both domestic markets and foreign financial markets during crises. Spillover effects are also stronger during crises.” … “rating changes have a stronger effect on more nontransparent economies than on transparent ones, as these changes reveal more information about nontransparent countries “ Kaminsky & Schmukler
“…The local and spillover effects of sovereign credit news on foreign exchange markets in the ‘EU–CA’ region are stronger during the crisis period. The effect of negative sovereign credit events are most marked for higher-rated countries during the crisis period, while the impact is most marked for lower-rated countries in the pre-crisis period.” R Alsakka & O Gwilym
On rating changes and bond returns:
“… changes in ratings and outlook significantly affect bond … markets, with average yield spreads increasing 2 percentage points … in response to a domestic downgrade. Outlook changes appear to be at least as important as rating changes.” Kaminsky & Schmukler
On rating changes and equity returns:
“… changes in ratings and outlook significantly affect… stock markets, with … average stock returns declining about 1 percentage point in response to a domestic downgrade. Outlook changes appear to be at least as important as rating changes.” Kaminsky & Schmukler
“… rating changes contribute to contagion or spillover effects, with rating changes of bonds in one emerging market triggering changes in … stock returns in other emerging economies.” Kaminsky & Schmukler
“… we find rating changes in one country incorporate valuable information for the aggregate stock market returns of other countries. The spillover effect is asymmetric, both in direction of the reaction and in terms of economic impact. A one-notch rating downgrade abroad is associated with a statistically significant negative return spread of 51 basis points on average across non-event countries. No significant impact is found for rating upgrades” M Ferreira & P Gama
On rating changes and CDS:
“… a country’s rating downgrade has a significant negative effect on the sovereign bond spreads of other countries” R Arezki, et al
Empirical Clues #
Sovereign rating index and CDS returns #
While the concurrent relation between rating changes and CDS returns has been positive, the subsequent relationship reveals significant payback. This means that the initial positive reaction to long-term foreign currency rating upgrades is typically followed by a negative reaction in the subsequent period and the opposite tends to be the case for downgrades.
xcatx = ["LTFCRATING_NSA", "CDS05YXR_NSA"]
cidx = msm.common_cids(df, xcatx)
start_date = "2000-01-01"
cr_cds = msp.CategoryRelations(
df,
xcats=xcatx,
cids=cidx,
freq="q",
lag=1,
xcat1_chg="diff",
xcat_aggs=["mean", "sum"],
start=start_date,
xcat_trims=[10, 10]
)
cr_cds.reg_scatter(
title=f"Sovereign credit rating changes and subsequent CDS returns, {len(cidx)} EM/DM countries, since 2000",
xlab="Long-term foreign-currency sovereign credit ratings index, diff q/q",
ylab="Next quarter's 5-year CDS return, %",
prob_est="map",
coef_box="lower right",
size=(10, 6),
)
Sovereign credit rating indices and FX returns #
dfx=df.copy()
dfb = dfx[dfx["xcat"].isin(["FXTARGETED_NSA", "FXUNTRADABLE_NSA"])].loc[
:, ["cid", "xcat", "real_date", "value"]
]
dfba = (
dfb.groupby(["cid", "real_date"])
.aggregate(value=pd.NamedAgg(column="value", aggfunc="max"))
.reset_index()
)
dfba["xcat"] = "FXBLACK"
fxblack = msp.make_blacklist(dfba, "FXBLACK")
fxblack
{'BRL': (Timestamp('2012-12-03 00:00:00'), Timestamp('2013-09-30 00:00:00')),
'CHF': (Timestamp('2011-10-03 00:00:00'), Timestamp('2015-01-30 00:00:00')),
'CNY': (Timestamp('1999-01-01 00:00:00'), Timestamp('2024-08-28 00:00:00')),
'CZK': (Timestamp('2014-01-01 00:00:00'), Timestamp('2017-07-31 00:00:00')),
'HKD': (Timestamp('1999-01-01 00:00:00'), Timestamp('2024-08-28 00:00:00')),
'ILS': (Timestamp('1999-01-01 00:00:00'), Timestamp('2005-12-30 00:00:00')),
'INR': (Timestamp('1999-01-01 00:00:00'), Timestamp('2004-12-31 00:00:00')),
'MYR_1': (Timestamp('1999-01-01 00:00:00'), Timestamp('2007-11-30 00:00:00')),
'MYR_2': (Timestamp('2018-07-02 00:00:00'), Timestamp('2024-08-28 00:00:00')),
'PEN': (Timestamp('2021-07-01 00:00:00'), Timestamp('2021-07-30 00:00:00')),
'RON': (Timestamp('1999-01-01 00:00:00'), Timestamp('2005-11-30 00:00:00')),
'RUB_1': (Timestamp('1999-01-01 00:00:00'), Timestamp('2005-11-30 00:00:00')),
'RUB_2': (Timestamp('2022-02-01 00:00:00'), Timestamp('2022-02-23 00:00:00')),
'SGD': (Timestamp('1999-01-01 00:00:00'), Timestamp('2024-08-28 00:00:00')),
'THB': (Timestamp('2007-01-01 00:00:00'), Timestamp('2008-11-28 00:00:00')),
'TRY_1': (Timestamp('1999-01-01 00:00:00'), Timestamp('2003-09-30 00:00:00')),
'TRY_2': (Timestamp('2020-01-01 00:00:00'), Timestamp('2024-07-31 00:00:00'))}
Higher sovereign credit ratings tend to predict negatively directional FX forward returns for emerging markets, consistent with the idea of credit-related risk premia in FX markets. This applies to both directional FX forward returns and relative returns versus a basket of EM currencies.
xcatx = ["LTFCRATING_NSA", "FXXR_NSA", "FXXR_NSAvEFX"]
cidx =list(set( msm.common_cids(dfx, xcatx)) & set(cids_em))
start_date = "2000-01-01"
cr_fxem = msp.CategoryRelations(
dfx,
xcats=["LTFCRATING_NSA", "FXXR_NSA"],
cids = cidx,
freq="q",
lag=1,
xcat_aggs=["last", "sum"],
blacklist=fxblack,
start=start_date,
)
cr_rfxem = msp.CategoryRelations(
dfx,
xcats=["LTFCRATING_NSA", "FXXR_NSAvEFX"],
cids = cidx,
freq="q",
lag=1,
xcat_aggs=["last", "sum"],
blacklist=fxblack,
start=start_date,
)
msv.multiple_reg_scatter(
cat_rels=[cr_fxem] + [cr_rfxem],
title=f"Sovereign credit rating and subsequent FX returns, {len(cidx)} EMs, since 2000",
xlab="Long-term foreign-currency sovereign credit ratings index",
ylab="Next quarter's FX forward return, %",
ncol=2,
nrow=1,
figsize=(15, 7),
prob_est="map",
coef_box="lower left",
subplot_titles=["Directional EM FX forward returns", "Relative EM FX returns versus EM basket"],
)
Sovereign rating index and local currency bond index returns #
The risk-premium effect also shows for local-currency bond index returns. Sovereign credit ratings exhibit a strong and significant negative correlation with subsequent directional and relative local emerging markets bond returns on a monthly and quarterly basis.
xcatx = ["LTLCRATING_NSA", "LCBIR_NSA"]
cidx =list(set( msm.common_cids(dfx, xcatx)) & set(cids_em))
start_date = "2000-01-01"
dfa = msp.make_relative_value(
dfx,
xcats=["LCBIR_NSA"],
cids=cidx,
start="2000-01-01",
rel_meth="subtract",
postfix="vEB",
)
dfx = msm.update_df(dfx, dfa)
start_date = "2000-01-01"
cr_demb = msp.CategoryRelations(
dfx,
xcats=["LTLCRATING_NSA", "LCBIR_NSA"],
cids = cidx,
freq="m",
lag=1,
xcat_aggs=["last", "sum"],
start=start_date,
)
cr_remb = msp.CategoryRelations(
dfx,
xcats=["LTLCRATING_NSA", "LCBIR_NSAvEB"],
cids=cidx,
freq="m",
lag=1,
xcat_aggs=["last", "sum"],
start=start_date,
)
msv.multiple_reg_scatter(
cat_rels=[cr_demb] + [cr_remb],
title=f"Sovereign credit rating and subsequent local bond index returns, {len(cidx)} EMs, since 2000",
ylab="Next month's local currency bond index (GBI-EM): cash returns, %",
ncol=2,
nrow=1,
figsize=(15, 7),
prob_est="map",
coef_box="lower left",
subplot_titles=["Directional local-currency bond returns, %", "Relative local-currency bond returns, %"],
)
Appendix 1: Index levels #
This table maps numerical indices and credit ratings from three major rating agencies: Fitch, Moody’s, and S&P (Standard & Poor’s). “Standardized Rating” aligns these ratings across the different agencies.
Numerical Index |
Fitch |
Moody’s |
S&P |
Standardized Rating |
---|---|---|---|---|
23 |
AAA |
Aaa |
AAA |
AAA |
22 |
AA+ |
Aa1 |
AA+ |
AA+ |
21 |
AA |
Aa2 |
AA |
AA |
20 |
AA- |
Aa3 |
AA- |
AA- |
19 |
A+ |
A1 |
A+ |
A+ |
18 |
A |
A2 |
A |
A |
17 |
A- |
A3 |
A- |
A- |
16 |
BBB+ |
Baa1 |
BBB+ |
BBB+ |
15 |
BBB |
Baa2 |
BBB |
BBB |
14 |
BBB- |
Baa3 |
BBB- |
BBB- |
13 |
BB+ |
Ba1 |
BB+ |
BB+ |
12 |
BB |
Ba2 |
BB |
BB |
11 |
BB- |
Ba3 |
BB- |
BB- |
10 |
B+ |
B1 |
B+ |
B+ |
9 |
B |
B2 |
B |
B |
8 |
B- |
B3 |
B- |
B- |
7 |
CCC+ |
Caa1 |
CCC+ |
CCC+ |
6 |
CCC |
Caa2 |
CCC |
CCC |
5 |
CCC- |
Caa3 |
CCC- |
CCC- |
4 |
CC |
|
CC |
CC |
3 |
|
Ca |
|
CC/C |
2 |
C |
|
C |
C |
1 |
RD/D |
C |
SD/D |
RD/D/SD |
The formula for the Rating Index is designed to provide a composite score based on both credit ratings and outlooks from three major credit rating agencies: Fitch, Moody’s, and S&P (Standard & Poor’s). The Rating Index combines both the current credit ratings and the forward-looking outlooks to provide a more comprehensive assessment of a credit entity’s creditworthiness. The formula gives more weight to the current ratings than to the outlooks. This reflects the idea that current ratings are more indicative of the present credit status, while outlooks are more speculative.
The formula is structured as follows:
Appendix 2: Currency symbols #
The word ‘cross-section’ refers to currencies, currency areas or economic areas. In alphabetical order, these are
-
AED (Emirates dirham)
-
ARS (Argentine pesos)
-
AUD (Australian dollar)
-
BHD (Bahraini Dinar)
-
BRL (Brazilian real)
-
CAD (Canadian dollar)
-
CHF (Swiss franc)
-
CLP (Chilean peso)
-
CNY (Chinese yuan renminbi)
-
COP (Colombian peso)
-
CZK (Czech Republic koruna)
-
DEM (German mark)
-
DOP (Dominican Peso)
-
EGP (Egyptian Pound)
-
ESP (Spanish peseta)
-
FRF (French franc)
-
GBP (British pound)
-
HKD (Hong Kong dollar)
-
HUF (Hungarian forint)
-
IDR (Indonesian rupiah)
-
ILS (Israeli shekel)
-
INR (Indian rupee)
-
ITL (Italian lira)
-
JPY (Japanese yen)
-
KRW (Korean won)
-
MXN (Mexican peso)
-
MYR (Malaysian ringgit)
-
NGN (Nigerian Naira)
-
NLG (Dutch guilder)
-
NOK (Norwegian krone)
-
NZD (New Zealand dollar)
-
OMR (Omani Rial)
-
QAR (Qatari Riyal)
-
PAB (Panamanian balboa)
-
PEN (Peruvian sol)
-
PHP (Philipine peso)
-
PLN (Polish zloty)
-
QAR (Qatari riyal)
-
RON (Romanian leu)
-
RSD (Serbian Dinar)
-
RUB (Russian ruble)
-
SEK (Swedish krona)
-
SAR (Saudi riyal)
-
SGD (Singaporean dollar)
-
THB (Thai baht)
-
TRY (Turkish lira)
-
TWD (Taiwanese dollar)
-
UYU (Peso Uruguayo)
-
USD (U.S. dollar)
-
VEF (Venezuelan bolívar)
-
ZAR (South African rand).