Private credit expansion #
This category group includes metrics of the expansion of private credit (local convention) with statistical adjustment for jumps and spikes in the series’, based on concurrently available vintages. Adjustments for outliers are particularly important for these series’, due to the occasional distortionary influences of legal and regulatory changes.
Nominal private credit growth #
Ticker : PCREDITBN_SJA_P1M1ML12
Label : Private bank credit, jump-adjusted, % over a year ago.
Definition : Private bank credit at the end of the latest reported month, % change over a year ago, seasonally and jump-adjusted.
Notes :
-
For most countries, the indicator is limited to bank loans to private households and companies.
-
The stock of credit is denominated in local currency.
-
Jump adjustment means that two types of outliers are adjusted for. Firstly, large “spikes” (i.e. two subsequent large moves of the seasonal index in opposite directions) are averaged. Holiday patterns or tax effects can be responsible for these spikes. Secondly, large one-off jumps in the index are replaced by the local trend. The causes of one-off jumps can be balance sheet restructurings in the banking systems and tax-related asset shifts. The criteria for adjustments are statistical, based on pattern recognition.
Private credit expansion as % of GDP #
Ticker : PCREDITGDP_SJA_D1M1ML12
Label : Banks’ private credit expansion, jump-adjusted, as % of GDP over 1 year.
Definition : Change of private credit over 1 year ago, seasonally and jump-adjusted, as % of nominal GDP (1-year moving average) in the base period.
Notes :
-
For most countries, the indicator is limited to bank loans to private households and companies.
-
The expansion is calculated as the change in the stock of bank credit over the latest reported 12 months as a % of the annual nominal GDP at the beginning of this 12 month period.
-
Jump adjustment means that two types of outliers are adjusted for. Firstly, large “spikes” (i.e. two subsequent large moves of the seasonal index in opposite directions) are averaged. Holiday patterns or tax effects can be responsible for these spikes. Secondly, large one-off jumps in the index are replaced by the local trend. The causes of one-off jumps can be balance sheet restructurings in the banking systems and tax-related asset shifts. The criteria for adjustments are statistical, based on pattern recognition.
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 matplotlib.pyplot as plt
import seaborn as sns
import math
import json
import yaml
import macrosynergy.management as msm
import macrosynergy.panel as msp
import macrosynergy.signal as mss
import macrosynergy.pnl as msn
from macrosynergy.download import JPMaQSDownload
from timeit import default_timer as timer
from datetime import timedelta, date, datetime
import warnings
from IPython.display import HTML
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 obtain the data. Here
tickers
is an array of ticker strings,
start_date
is the first release date to be considered and
metrics
denotes the types of information requested.
# Cross-sections of interest
cids_dmca = [
"AUD",
"CAD",
"CHF",
"EUR",
"GBP",
"JPY",
"NOK",
"NZD",
"SEK",
"USD",
] # DM currency areas
cids_dmec = ["DEM", "ESP", "FRF", "ITL", "NLG"] # DM euro area countries
cids_latm = ["BRL", "COP", "CLP", "MXN", "PEN"] # Latam countries
cids_emea = ["CZK", "HUF", "ILS", "PLN", "RON", "RUB", "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)
# Quantamental categories of interest
main = ["PCREDITBN_SJA_P1M1ML12", "PCREDITGDP_SJA_D1M1ML12"]
econ = ["NIR_NSA", "RIR_NSA"] # economic context
mark = [
"EQXR_NSA",
"EQXR_VT10",
"FXXR_NSA",
"DU05YXR_NSA",
"DU05YXR_VT10",
"FXTARGETED_NSA",
"FXUNTRADABLE_NSA",
] # market links
xcats = main + econ + 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:
start = timer()
df = downloader.download(
tickers=tickers,
start_date=start_date,
metrics=["value", "eop_lag", "mop_lag", "grading"],
suppress_warning=True,
show_progress=True,
)
end = timer()
dfd = df
print("Download time from DQ: " + str(timedelta(seconds=end - start)))
Maximum number of tickers is 418
Downloading data from JPMaQS.
Timestamp UTC: 2024-11-12 10:04:53
Connection successful!
Requesting data: 100%|██████████| 84/84 [00:16<00:00, 4.96it/s]
Downloading data: 100%|██████████| 84/84 [00:35<00:00, 2.39it/s]
Some expressions are missing from the downloaded data. Check logger output for complete list.
460 out of 1672 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.
2 out of 9099 dates are missing.
Download time from DQ: 0:00:57.373203
Availability #
cids_exp = sorted(
list(set(cids) - set(cids_dmec + ["ARS", "HKD"]))
) # cids expected in category panels
Real-time quantamental indicators of private credit expansion are available from the 1990s for most developed markets and some emerging markets. Most EM indicators, however, start in the early 2000s.
For the explanation of currency symbols, which are related to currency areas or countries for which categories are available, please view Appendix 1 .
xcatx = main
cidx = cids_exp
dfx = msm.reduce_df(dfd, xcats=xcatx, cids=cidx)
dfs = msm.check_startyears(dfx)
msm.visual_paneldates(dfs, size=(18, 2))
print("Last updated:", date.today())
Last updated: 2024-11-12
plot = msm.check_availability(
dfd, xcats=xcatx, cids=cidx, start_size=(18, 2), start_years=False, start=start_date
)
Average grades are currently quite mixed across countries and times, with USD the only cross-section with high grade vintages consistently available across indicators.
plot = msp.heatmap_grades(
dfd,
xcats=xcatx,
cids=cidx,
start=start_date,
size=(18, 2),
title=f"Average vintage grades, from {start_date} onwards",
)
xcatx = main
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cids_exp,
val="eop_lag",
title="End of observation period lags (ranges of time elapsed since end of observation period in days)",
start="2000-01-01",
kind="box",
size=(16, 4),
)
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cids_exp,
val="mop_lag",
title="Median of observation period lags (ranges of time elapsed since middle of observation period in days)",
start="2000-01-01",
kind="box",
size=(16, 4),
)
History #
Nominal private credit growth #
Long-term credit growth has been in a range of 5-15% for most countries. Across time, most countries have experienced pronounced fluctuations in private credit expansion, illustrating the importance of boom-bust patterns in credit cycles.
xcatx = ["PCREDITBN_SJA_P1M1ML12"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="mean",
title="Means and standard deviations of nominal private credit growth since 2000",
kind="bar",
start="2000-01-01",
size=(16, 8),
)
xcatx = ["PCREDITBN_SJA_P1M1ML12"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Private bank credit, % change over a year ago, seasonally and jump-adjusted",
title_fontsize=27,
title_xadj=0.5,
title_adj=1.02,
ncol=4,
same_y=False,
size=(12, 7),
aspect=1.7,
all_xticks=True,
)
Correlations across currency areas have been mostly positive, with a small group of outliers. The outliers have been countries that experienced pronounced idiosyncratic credit cycles: China, Japan, the Philippines, Thailand, Taiwan, and Turkey.
msp.correl_matrix(
dfd,
xcats="PCREDITBN_SJA_P1M1ML12",
cids=cids_exp,
size=(20, 14),
title="Cross-sectional correlation of private credit growth, since 2000",
)
Private credit expansion as % of GDP #
Unlike percent growth, credit growth in relation to GDP is strongly influenced by existing leverage. All other things equal, countries with larger financial systems post higher values and greater fluctuations. The order of countries in terms of magnitude of expansion is quite different from the order according to simple nominal credit growth.
xcatx = ["PCREDITGDP_SJA_D1M1ML12"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="mean",
start="2000-01-01",
kind="bar",
size=(16, 8),
title="Means and standard deviations of private credit expansion, % of GDP, since 2000",
)
xcatx = ["PCREDITGDP_SJA_D1M1ML12"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Private credit expansion over a year ago, as % of GDP",
title_fontsize=27,
title_xadj=0.5,
title_adj=1.02,
ncol=4,
same_y=False,
size=(12, 7),
aspect=1.7,
all_xticks=True,
)
Importance #
Research links #
“Global banks drive lending booms in local currency markets (explaining) how currency strength fuels rather than curbs financial expansion in small and emerging economies, leading to escalating dynamics.” Macrosynergy
“A 145-year empirical analysis suggests that asset price surges are most dangerous when they are associated with rising financial leverage. The combination of housing price bubbles and credit booms has been the most detrimental of all.” Macrosynergy
Empirical clues #
Historically, currency areas with high credit growth have delivered higher FX forward returns. The connection plausibly arises from the positive effect of credit growth on local real interest rates.
dfb = dfd[dfd["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")
xcatx = ["PCREDITBN_SJA_P1M1ML12", "FXXR_NSA"]
cidx = cids_exp
cr_crr = msp.CategoryRelations(
dfd,
xcats=xcatx,
cids=cidx,
blacklist=fxblack,
freq="M",
lag=0,
xcat_aggs=["mean", "sum"],
start=start_date,
years=5,
)
cr_crr.reg_scatter(
title="Private credit growth and FX returns across 30 countries and 5-year episodes",
labels=True,
coef_box="upper right",
ylab="1-month FX forward return",
xlab="Domestic private credit, % over a year ago",
# reg_robust=True,
)
FXXR_NSA misses: ['USD'].
There is corresponding evidence of a positive correlation between private credit growth and real interest rates.
xcatx = ["PCREDITBN_SJA_P1M1ML12", "RIR_NSA"]
cidx = cids_exp
cr_crr = msp.CategoryRelations(
dfd,
xcats=xcatx,
cids=cidx,
blacklist=fxblack,
freq="M",
lag=0,
xcat_aggs=["mean", "mean"],
start=start_date,
years=5,
)
cr_crr.reg_scatter(
title="Private credit growth and real interest rates across 30 countries and 5-year episodes",
labels=True,
ylab="1-month real interest rate",
xlab="Domestic private credit, % over a year ago",
reg_robust=True,
)
Strong credit growth increases the probability of policy tightening and thus - all other things equal - bodes ill for long duration positions. Indeed, historically there has been a negative and signficant predictive relation between credit growth z-scores (normalized by country-specific means and standard deviation) and subsequent IRS receiever returns.
# Compute Zn scores
xcatx = ["PCREDITGDP_SJA_D1M1ML12"]
cidx = cids_exp
for xcat in xcatx:
dfa = msp.make_zn_scores(
df=dfd,
cids=list(cidx),
xcat=xcat,
start="2000-01-01",
est_freq="m",
neutral="mean",
# thresh=0,
pan_weight=0,
)
dfd = msm.update_df(dfd, dfa)
xcatx = ["PCREDITGDP_SJA_D1M1ML12ZN", "DU05YXR_VT10"]
cidx = list(set(cids_exp) - set(["BRL", "PEN", "PHP", "RON"]))
cr = msp.CategoryRelations(
dfd,
xcats=xcatx,
cids=cidx,
freq="Q",
lag=1,
xcat_aggs=["last", "sum"],
start="2000-01-01",
years=None,
xcat_trims=[100, 100], # remove invalid outliers
)
cr.reg_scatter(
title="Private credit growth, z-scores, and next quarter duration returns across all currency areas",
coef_box="upper left",
ylab="5-year IRS return, next quarter sum",
xlab="Domestic private credit expansion, as % of GDP, z-scores based on cross-section, quarter last value",
prob_est="map",
)
Appendices #
Appendix 1: Currency symbols #
The word ‘cross-section’ refers to currencies, currency areas or economic areas. In alphabetical order, these are AUD (Australian dollar), 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), ESP (Spanish peseta), EUR (Euro), FRF (French franc), GBP (British pound), HKD (Hong Kong dollar), HUF (Hungarian forint), IDR (Indonesian rupiah), ITL (Italian lira), JPY (Japanese yen), KRW (Korean won), MXN (Mexican peso), MYR (Malaysian ringgit), NLG (Dutch guilder), NOK (Norwegian krone), NZD (New Zealand dollar), PEN (Peruvian sol), PHP (Phillipine peso), PLN (Polish zloty), RON (Romanian leu), RUB (Russian ruble), SEK (Swedish krona), SGD (Singaporean dollar), THB (Thai baht), TRY (Turkish lira), TWD (Taiwanese dollar), USD (U.S. dollar), ZAR (South African rand).
Appendix 2: Floating rates #
In several countries, following the discontinuation of LIBOR, floating rates transitioned to Overnight Indexed Swaps (OIS). The table below also includes the new OIS rates in use and the date of each transition.
data = {
"Indicator": [
"AUD_PCREDITBN_SA", "BRL_PCREDITBN_NSA", "CAD_PCREDITBN_NSA", "CHF_PCREDITBN_NSA",
"CLP_PCREDITBN_NSA", "CNY_PCREDITBN_NSA", "COP_PCREDITBN_NSA", "CZK_PCREDITBN_NSA",
"DEM_PCREDITBN_NSA", "ESP_PCREDITBN_NSA", "EUR_PCREDITBN_NSA", "FRF_PCREDITBN_NSA",
"GBP_PCREDITBN_NSA", "HUF_PCREDITBN_NSA", "IDR_PCREDITBN_NSA", "ILS_PCREDITBN_NSA",
"INR_PCREDITBN_NSA", "ITL_PCREDITBN_NSA", "JPY_PCREDITBN_NSA", "KRW_PCREDITBN_NSA",
"MXN_PCREDITBN_NSA", "MYR_PCREDITBN_NSA", "NLG_PCREDITBN_NSA", "NOK_PCREDITBN_NSA",
"NZD_PCREDITBN_NSA", "PEN_PCREDITBN_NSA", "PHP_PCREDITBN_NSA", "PLN_PCREDITBN_NSA",
"RON_PCREDITBN_NSA", "RUB_PCREDITBN_NSA", "SEK_PCREDITBN_NSA", "SGD_PCREDITBN_NSA",
"THB_PCREDITBN_NSA", "TRY_PCREDITBN_NSA", "TWD_PCREDITBN_NSA", "USD_PCREDITBN_SA",
"ZAR_PCREDITBN_NSA"
],
"Underlying data": [
"Total narrow credit lending excluding financial businesses", "Total credit operation outstanding",
"Total credit liabilities of households and private non-financial corporations", "Total domestic loans",
"Total domestic credit for the private sector from the banking sector", "Depository Corporations Survey - Domestic credit for non-financial sectors",
"Gross domestic credit to the private sector", "Credit to other residents (non-government) (loans)",
"Loans to domestic non-banks", "Domestic loans to other resident sectors",
"Loans to other EA residents (excl. governments and MFIs)", "Domestic loans to the private sector",
"Domestic loans to the private sector", "Loans to other residents", "Loans to the private sector",
"Domestic private sector credit", "Domestic credit from commercial banks",
"Other MFIs (excl. Central Bank) loans to other sectors", "Outstanding loans from domestic banks (excl. Shinkin Banks)",
"Domestic loans to non-financial corporations and households", "Domestic loans to the private sector",
"Total claims on the private sector", "Loan to EA residents (private sector)",
"Domestic credit to non-financial corporations and households", "Loans to Housing & Personal Consumption and Businesses",
"Total credit to the private sector", "Domestic claims to the private sector",
"Total loans to domestic residents (non-MFI and non-government)", "Loans to the private sector",
"Loans in local currency to individuals and organizations", "MFIs lending to households and non-financial corporations",
"Domestic credit to the private sector", "Depository Corporations Survey - Domestic credit",
"Loans to the private sector", "All banks loans outstanding", "Loan and leases in bank credit, all commecial banks",
"Domestic private sector claims"
],
"Source": [
"Reserve Bank of Australia", "Central Bank of Brazil", "Statistics Canada", "National Bank of Switzerland",
"Central Bank of Chile", "The People's Bank of China", "Central Bank of Colombia", "Czech National Bank",
"Deutsche Bundesbank", "Bank of Spain", "ECB", "Banque de France", "Bank of England",
"Central Bank of Hungary", "Bank Indonesia", "Bank of Israel", "Reserve Bank of India", "Banca d'Italia",
"Bank of Japan", "Bank of Korea", "Bank of Mexico", "Central Bank of Malaysia",
"Central Bank of Netherlands", "Statistics Norway", "Reserve Bank of New Zealand", "Central Reserve Bank of Peru",
"Central Bank of the Philippines", "National Bank of Poland", "National Bank of Romania",
"Central Bank of the Russian Federation", "Statistics Sweden", "Monetary Authority of Singapore",
"Bank of Thailand", "Central Bank of the Republic of Türkiye", "Central Bank of Taiwan",
"Federal Reserve", "Reserve Bank of South Africa"
]
}
df = pd.DataFrame(data)
HTML(df.to_html(index=False))
Indicator | Underlying data | Source |
---|---|---|
AUD_PCREDITBN_SA | Total narrow credit lending excluding financial businesses | Reserve Bank of Australia |
BRL_PCREDITBN_NSA | Total credit operation outstanding | Central Bank of Brazil |
CAD_PCREDITBN_NSA | Total credit liabilities of households and private non-financial corporations | Statistics Canada |
CHF_PCREDITBN_NSA | Total domestic loans | National Bank of Switzerland |
CLP_PCREDITBN_NSA | Total domestic credit for the private sector from the banking sector | Central Bank of Chile |
CNY_PCREDITBN_NSA | Depository Corporations Survey - Domestic credit for non-financial sectors | The People's Bank of China |
COP_PCREDITBN_NSA | Gross domestic credit to the private sector | Central Bank of Colombia |
CZK_PCREDITBN_NSA | Credit to other residents (non-government) (loans) | Czech National Bank |
DEM_PCREDITBN_NSA | Loans to domestic non-banks | Deutsche Bundesbank |
ESP_PCREDITBN_NSA | Domestic loans to other resident sectors | Bank of Spain |
EUR_PCREDITBN_NSA | Loans to other EA residents (excl. governments and MFIs) | ECB |
FRF_PCREDITBN_NSA | Domestic loans to the private sector | Banque de France |
GBP_PCREDITBN_NSA | Domestic loans to the private sector | Bank of England |
HUF_PCREDITBN_NSA | Loans to other residents | Central Bank of Hungary |
IDR_PCREDITBN_NSA | Loans to the private sector | Bank Indonesia |
ILS_PCREDITBN_NSA | Domestic private sector credit | Bank of Israel |
INR_PCREDITBN_NSA | Domestic credit from commercial banks | Reserve Bank of India |
ITL_PCREDITBN_NSA | Other MFIs (excl. Central Bank) loans to other sectors | Banca d'Italia |
JPY_PCREDITBN_NSA | Outstanding loans from domestic banks (excl. Shinkin Banks) | Bank of Japan |
KRW_PCREDITBN_NSA | Domestic loans to non-financial corporations and households | Bank of Korea |
MXN_PCREDITBN_NSA | Domestic loans to the private sector | Bank of Mexico |
MYR_PCREDITBN_NSA | Total claims on the private sector | Central Bank of Malaysia |
NLG_PCREDITBN_NSA | Loan to EA residents (private sector) | Central Bank of Netherlands |
NOK_PCREDITBN_NSA | Domestic credit to non-financial corporations and households | Statistics Norway |
NZD_PCREDITBN_NSA | Loans to Housing & Personal Consumption and Businesses | Reserve Bank of New Zealand |
PEN_PCREDITBN_NSA | Total credit to the private sector | Central Reserve Bank of Peru |
PHP_PCREDITBN_NSA | Domestic claims to the private sector | Central Bank of the Philippines |
PLN_PCREDITBN_NSA | Total loans to domestic residents (non-MFI and non-government) | National Bank of Poland |
RON_PCREDITBN_NSA | Loans to the private sector | National Bank of Romania |
RUB_PCREDITBN_NSA | Loans in local currency to individuals and organizations | Central Bank of the Russian Federation |
SEK_PCREDITBN_NSA | MFIs lending to households and non-financial corporations | Statistics Sweden |
SGD_PCREDITBN_NSA | Domestic credit to the private sector | Monetary Authority of Singapore |
THB_PCREDITBN_NSA | Depository Corporations Survey - Domestic credit | Bank of Thailand |
TRY_PCREDITBN_NSA | Loans to the private sector | Central Bank of the Republic of Türkiye |
TWD_PCREDITBN_NSA | All banks loans outstanding | Central Bank of Taiwan |
USD_PCREDITBN_SA | Loan and leases in bank credit, all commecial banks | Federal Reserve |
ZAR_PCREDITBN_NSA | Domestic private sector claims | Reserve Bank of South Africa |