Private‑Credit Impulse
Composite signal tracking growth momentum in private credit creation using bank credit, business loans, and total consumer loans.
Abstract
The Private‑Credit Impulse signal quantifies acceleration or deceleration in aggregate private‑sector credit growth. It blends six‑month annualised growth rates of total bank credit, commercial & industrial loans, and consumer loans. Each growth series is robust‑standardised and averaged to create a momentum composite that identifies Accelerating, Stable, and Decelerating credit regimes.
1. Data
- TOTBKCR — Total Bank Credit, Level (FRED:
TOTBKCR). - BUSLOANS — Commercial & Industrial Loans, All Commercial Banks (FRED:
BUSLOANS). - TOTALSL — Total Consumer Loans Owned by Banks (FRED:
TOTALSL).
All inputs are monthly levels in USD billions; resample and forward‑fill missing observations if required.
2. Growth‑Rate Transformation
To capture short‑term momentum, compute six‑month annualised growth:
g_t = \left(\frac{X_t}{X_{t-6}}\right)^2 − 1
This approximates the rate that would prevail if six‑month growth continued for a full year, doubling the observed half‑year change.
3. Normalisation
z\_{rob}(X)_t = \dfrac{X_t − \mathrm{median}(X)_{t,w}}{1.4826·\mathrm{MAD}(X)_{t,w}}
with rolling window w = 48 months (minimum 18). Median absolute deviation (MAD) provides robust scaling resistant to extreme episodes.
4. Composite Construction
- Compute ann6 growth for each source.
- Apply robust_z to the growth series.
- Average the z‑scores across components:
Private\_{Credit\_Impulse,t} = \tfrac{1}{3}\big(Z\_{TOTBKCR,t} + Z\_{BUSLOANS,t} + Z\_{TOTALSL,t}\big)
5. Regime Mapping
If\ C_t > 0.75 → \textit{Accelerating};\quad |C_t| ≤ 0.75 → \textit{Stable};\quad C_t < −0.75 → \textit{Decelerating}
6. Implementation (Python)
import pandas as pd
import numpy as np
def robust_z(s, win=48, min_win=18):
x = pd.to_numeric(s, errors="coerce").astype(float)
w = max(min_win, min(win, x.dropna().size))
med = x.rolling(w, min_periods=min_win).median()
mad = (x - med).abs().rolling(w, min_periods=min_win).median()
return (x - med) / (1.4826 * mad.replace(0, np.nan))
def ann6(series):
return (series / series.shift(6))**2 - 1.0
d = df_priv_credit.copy()
for col in ["TOTBKCR","BUSLOANS","TOTALSL"]:
d[f"{col}_ann6"] = ann6(d[col])
zcols = []
for col in ["TOTBKCR_ann6","BUSLOANS_ann6","TOTALSL_ann6"]:
z = robust_z(d[col])
d[f"Z_{col}"] = z
zcols.append(f"Z_{col}")
d["Private_Credit_Impulse"] = d[zcols].mean(axis=1)
hi, lo = 0.75, -0.75
def _regime(v):
if pd.isna(v): return np.nan
return "Accelerating" if v > hi else ("Decelerating" if v < lo else "Stable")
d["Credit_Impulse_Regime"] = d["Private_Credit_Impulse"].apply(_regime)
df_sig_priv_credit = d
display(df_sig_priv_credit.tail())
7. Interpretation
- Accelerating: rapid credit creation — often early‑cycle or liquidity‑driven expansions.
- Stable: steady credit growth consistent with trend GDP expansion.
- Decelerating: tightening credit supply or falling demand — leading indicator of slowdown.
8. Limitations
- Data revisions are frequent in bank‑level series; lagging updates may distort recent momentum.
- Structural changes (e.g., accounting rules, loan‑sale adjustments) can create artificial swings.
- Fixed ±0.75 thresholds are heuristic; calibration to macro phases may enhance accuracy.