Yield Curve Slope
Composite signal measuring the structural shape of the U.S. Treasury curve using 10Y–2Y and 10Y–3M spreads. Captures cyclical steepening and inversion phases that reflect monetary stance and growth expectations.
Abstract
The yield curve slope signal evaluates macro‑financial regimes via the shape of the Treasury term structure. Two primary spreads are used: T10Y2Y (10‑year minus 2‑year yield) and T10Y3M (10‑year minus 3‑month yield). Each is normalised using a robust rolling z‑score, then averaged to form a composite slope index. Thresholds of ±0.75 classify curve phases as Steepening, Flat/Neutral, or Inverted.
1. Data
- T10Y2Y — 10‑Year Treasury Constant Maturity minus 2‑Year Treasury Constant Maturity (FRED).
- T10Y3M — 10‑Year Treasury Constant Maturity minus 3‑Month Treasury Bill (FRED).
Both inputs are daily series from FRED, resampled to month‑end for consistency with other macro composites.
2. Normalisation
z\_{rob}(X)_t = \dfrac{X_t − \mathrm{median}(X)_{t, w}}{1.4826 · \mathrm{MAD}(X)_{t, w}}
where w = 60 months (minimum 24). The constant 1.4826 scales the median absolute deviation to σ under normality, providing resilience to outliers and structural breaks.
3. Composite Construction
- Compute z‑scores: derive Z\_{10Y2Y} and Z\_{10Y3M} via robust rolling method.
- Blend: arithmetic mean to reduce idiosyncratic noise:
YC\_{Composite,t} = \frac{Z\_{10Y2Y,t} + Z\_{10Y3M,t}}{2}
4. Regime Classification
\text{If } C_t > 0.75 → \textit{Steepening};\quad |C_t| ≤ 0.75 → \textit{Flat/Neutral};\quad C_t < −0.75 → \textit{Inverted}
A steepening curve typically coincides with early‑cycle reflation or easing expectations; inversion indicates restrictive policy and forward‑growth stress.
5. Implementation (Python)
import pandas as pd
import numpy as np
def robust_z(s, win=60, min_win=24):
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))
df_sig_yc = df_yield_curve.copy()
df_sig_yc["Z_T10Y2Y"] = robust_z(df_sig_yc["T10Y2Y"])
df_sig_yc["Z_T10Y3M"] = robust_z(df_sig_yc["T10Y3M"])
df_sig_yc["YC_Composite"] = df_sig_yc[["Z_T10Y2Y", "Z_T10Y3M"]].mean(axis=1)
hi, lo = 0.75, -0.75
def _regime(v):
if pd.isna(v): return np.nan
return "Steepening" if v > hi else ("Inverted" if v < lo else "Flat/Neutral")
df_sig_yc["YC_Regime"] = df_sig_yc["YC_Composite"].apply(_regime)
display(df_sig_yc.tail())
6. Interpretation
- Steepening: policy easing, improving risk sentiment, or recovery expectations.
- Flat/Neutral: late‑cycle balance between growth and inflation pressures.
- Inverted: contractionary policy stance; historically precedes recessions by 6–18 months.
7. Limitations
- Structural distortions (QE, RRP balances) can flatten curves without classic cycle signals.
- Short‑term volatility may reflect liquidity or issuance factors rather than macro regime change.
- Thresholds ±0.75 are static; dynamic optimisation could improve predictive accuracy.