{"slug":"what-happens-when-the-yield-curve-un-inverts","qid":"steepener","label":"Which leg did the work: 2-year and 10-year moves over the 91 days before each crossing","post_title":"What Happens When the Yield Curve Un-Inverts","post_url":"/blog/what-happens-when-the-yield-curve-un-inverts#q-steepener","columns":["episode","crossed_on","y2_91d_before","y2_at_cross","y10_91d_before","y10_at_cross","y2_change_bp","y10_change_bp","steepener_type"],"rows":[{"episode":"May 1980","crossed_on":"1980-05-02","y2_91d_before":12.04,"y2_at_cross":10.04,"y10_91d_before":11.29,"y10_at_cross":10.24,"y2_change_bp":-200,"y10_change_bp":-105,"steepener_type":"bull steepener (2-year fell most)"},{"episode":"Oct 1981","crossed_on":"1981-10-28","y2_91d_before":15.76,"y2_at_cross":15.42,"y10_91d_before":14.61,"y10_at_cross":15.44,"y2_change_bp":-34,"y10_change_bp":83,"steepener_type":"bear steepener (10-year rose most)"},{"episode":"Jul 1982","crossed_on":"1982-07-19","y2_91d_before":14.18,"y2_at_cross":13.52,"y10_91d_before":13.66,"y10_at_cross":13.68,"y2_change_bp":-66,"y10_change_bp":2,"steepener_type":"bull steepener (2-year fell most)"},{"episode":"Jun 1989","crossed_on":"1989-06-30","y2_91d_before":9.73,"y2_at_cross":8.08,"y10_91d_before":9.3,"y10_at_cross":8.1,"y2_change_bp":-165,"y10_change_bp":-120,"steepener_type":"bull steepener (2-year fell most)"},{"episode":"Dec 2000","crossed_on":"2000-12-27","y2_91d_before":6,"y2_at_cross":5.1,"y10_91d_before":5.83,"y10_at_cross":5.11,"y2_change_bp":-90,"y10_change_bp":-72,"steepener_type":"bull steepener (2-year fell most)"},{"episode":"Mar 2007","crossed_on":"2007-03-21","y2_91d_before":4.71,"y2_at_cross":4.51,"y10_91d_before":4.6,"y10_at_cross":4.53,"y2_change_bp":-20,"y10_change_bp":-7,"steepener_type":"bull steepener (2-year fell most)"},{"episode":"Sep 2024","crossed_on":"2024-09-04","y2_91d_before":4.72,"y2_at_cross":3.76,"y10_91d_before":4.29,"y10_at_cross":3.77,"y2_change_bp":-96,"y10_change_bp":-52,"steepener_type":"bull steepener (2-year fell most)"}],"shape":"table","sql":"WITH\ndaily AS\n(\n    SELECT\n        date,\n        dateDiff('day', toDate('1970-01-01'), date)   AS dnum,\n        ifNull(toFloat64(max(yield_2_year)), 0.)      AS y2,\n        ifNull(toFloat64(max(yield_10_year)), 0.)     AS y10,\n        y10 - y2                                      AS spread\n    FROM global_markets.treasury_yields\n    WHERE yield_2_year > 0 AND yield_10_year > 0\n    GROUP BY date\n),\nscored AS\n(\n    SELECT\n        date, dnum, y2, y10, spread,\n        count()         OVER (ORDER BY date ROWS BETWEEN 60 PRECEDING AND 1 PRECEDING) AS rows_prior,\n        sum(spread < 0) OVER (ORDER BY date ROWS BETWEEN 60 PRECEDING AND 1 PRECEDING) AS neg_prior,\n        sum(spread > 0) OVER (ORDER BY date ROWS BETWEEN CURRENT ROW AND 20 FOLLOWING) AS pos_next\n    FROM daily\n),\ncandidates AS\n(\n    SELECT\n        date, dnum, y2, y10, spread,\n        lagInFrame(dnum, 1, toInt64(-100000)) OVER (ORDER BY dnum ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS prev_dnum\n    FROM scored\n    WHERE spread > 0 AND rows_prior = 60 AND neg_prior >= 35 AND pos_next >= 19\n),\nepisodes AS\n(\n    SELECT date AS cross_date, y2, y10, spread\n    FROM candidates\n    WHERE dnum - prev_dnum > 180\n      AND date <= today() - 380\n)\nSELECT\n    episode,\n    crossed_on,\n    y2_91d_before,\n    y2_at_cross,\n    y10_91d_before,\n    y10_at_cross,\n    y2_change_bp,\n    y10_change_bp,\n    multiIf(\n        y2_change_bp < 0 AND abs(y2_change_bp) >= abs(y10_change_bp), 'bull steepener (2-year fell most)',\n        y10_change_bp > 0 AND abs(y10_change_bp) > abs(y2_change_bp), 'bear steepener (10-year rose most)',\n        'mixed'\n    ) AS steepener_type\nFROM\n(\n    SELECT\n        formatDateTime(e.cross_date, '%b %Y')                                       AS episode,\n        toString(toDate(e.cross_date))                                              AS crossed_on,\n        round(argMinIf(d.y2, d.date, d.date >= addDays(e.cross_date, -91)), 2)      AS y2_91d_before,\n        round(any(e.y2), 2)                                                         AS y2_at_cross,\n        round(argMinIf(d.y10, d.date, d.date >= addDays(e.cross_date, -91)), 2)     AS y10_91d_before,\n        round(any(e.y10), 2)                                                        AS y10_at_cross,\n        round((any(e.y2)  - argMinIf(d.y2,  d.date, d.date >= addDays(e.cross_date, -91))) * 100) AS y2_change_bp,\n        round((any(e.y10) - argMinIf(d.y10, d.date, d.date >= addDays(e.cross_date, -91))) * 100) AS y10_change_bp\n    FROM episodes AS e\n    CROSS JOIN daily AS d\n    WHERE d.date BETWEEN addDays(e.cross_date, -100) AND e.cross_date\n    GROUP BY e.cross_date\n)\nORDER BY crossed_on","computed_at":"2026-09-19T15:13:11.970275+00:00","elapsed":1.573273095}