Detecting Inflationary Regimes via Producer–Consumer Price Divergence

A reproducible statistical specification based on monthly US price indices (2005–present).

Abstract

This paper formalises a rule-based indicator of inflationary pressure that exploits divergence between the Producer Price Index (PPI) and the Consumer Price Index (CPI). Year-on-year rates are transformed into a differential series and standardised using a rolling median and median absolute deviation (MAD) to obtain a robust z-score. Thresholds applied to the robustised differential, conditional on the absolute level of CPI, yield categorical regimes—HOT, NEUTRAL, and COOL. The specification is designed for operational use in macro monitoring and portfolio overlays.

1. Data

This model uses monthly US price indices published by the Bureau of Labor Statistics (BLS) and distributed via FRED. Unless explicitly stated, use not seasonally adjusted (NSA) series for the core signal to reduce sensitivity to annual seasonal-factor revisions.

1.1 CPI (consumer prices)

1.2 PPI (producer prices)

1.3 Optional context overlays

1.4 Recommended robustness choices

Observations are merged on Date using an outer join, restricted to 2005‑01‑01 onwards to focus on the modern inflation regime. Where higher-frequency irregularities occur, the series are conformed to month-end by last observation carried forward within the month.

2. Methodology

  1. Convert Date to timezone-naïve monthly timestamps; sort ascending.
  2. Compute year-on-year inflation rates:
    CPIYoY,t = 100 × (CPIt − CPIt−12)/CPIt−12
    PPIYoY,t = 100 × (PPIt − PPIt−12)/PPIt−12
  3. Calculate divergence and robust z‑score:
    Dt = PPIYoY,t − CPIYoY,t
    zt = (Dt − Median(Dt−w+1:t)) / (1.4826 × MAD(Dt−w+1:t))
  4. Apply classification rules:
    • HOT: zt ≥ 1.0 or (zt ≥ 0.75 and CPIYoY,t ≥ 3.0%)
    • COOL: zt ≤ −1.0 or (zt ≤ −0.5 and CPIYoY,t ≤ 1.5%)
    • SMALL DIVERGENCE (band): if |zt| < zband, treat as NEUTRAL (recommended zband = 0.35) to reduce regime “flip‑flopping” in noisy months.
    • NEUTRAL: otherwise

The robust standardisation uses a 60‑month rolling window to balance responsiveness and stability. Version 1.1 adds a z-band around zero (zband) to avoid frequent flips due to PPI volatility and revision noise. Prefer NSA inputs for the core signal; if SA series are used, expect annual factor-driven revisions. Windows with MAD = 0 are excluded from classification.

3. Sensitivity and Limitations

4. Implementation Notes

def _robust_zscore(s, window=60):
    s = s.astype(float)
    med = s.rolling(window, min_periods=1).median()
    mad = (s - med).abs().rolling(window, min_periods=1).median()
    z = (s - med) / (mad.replace(0, float('nan')) * 1.4826)
    return z

monthly['CPI_YoY'] = monthly['CPIAUCSL_Value'].pct_change(12) * 100
monthly['PPI_YoY'] = monthly['PPIACO_Value'].pct_change(12) * 100
monthly['PPI_minus_CPI_YoY'] = monthly['PPI_YoY'] - monthly['CPI_YoY']
monthly['divergence_z'] = _robust_zscore(monthly['PPI_minus_CPI_YoY'], window=60)

# Classification
def map_inflation_signal(row, z_band=0.35):
    if pd.isna(row['CPI_YoY']) or pd.isna(row['PPI_YoY']) or pd.isna(row['divergence_z']):
        return 'NEUTRAL'

    # Small divergence band (reduces flip-flopping around zero)
    if abs(row['divergence_z']) < z_band:
        return 'NEUTRAL'

    if (row['CPI_YoY'] >= 3.0 and row['divergence_z'] >= 0.75) or row['divergence_z'] >= 1.0:
        return 'HOT'
    if (row['CPI_YoY'] <= 1.5 and row['divergence_z'] <= -0.5) or row['divergence_z'] <= -1.0:
        return 'COOL'
    return 'NEUTRAL'

5. Reproducibility

6. Applications

This indicator can be integrated into macroeconomic dashboards, inflation‑linked asset overlays, and multi‑factor allocation models. Combining it with recession overlays and survey price expectations enhances signal validation.

7. Model Interpretation (with literature cues)

7.1 What the divergence is capturing

7.2 Why use a rolling z‑score

7.3 Practical reading of regimes

HOT means the PPI–CPI gap is unusually high versus its recent history (and/or CPI is already elevated). Interpret as pipeline pressure and a higher probability of upside inflation surprises or delayed disinflation.

COOL means the gap is unusually low/negative, especially when CPI is already low. Interpret as pipeline relief and a higher probability of continued disinflation or downside surprises.

NEUTRAL means divergence is not statistically unusual (or within the small-band). Treat as “no strong information” rather than “inflation is stable.”

7.4 Evidence and cautions from the literature

7.5 Suggested validation checks

Keep the interpretation anchored in the model’s design: it is intended to flag unusual divergence and the associated risk of inflation persistence/surprise, not to estimate the level of future CPI.