Will the Recession Ever Arrive? A Data-Driven Look at the Yield Curve and Jobless Rate
I’m always keeping an eye on economic data for clues about where the broader market and sentiment might be headed. Since I’m a visual thinker, I like to create charts—like my egg price and median house price charts. In this post, I’ll share my Python code for generating a chart that overlays the 2-year/10-year Treasury yield spread with the current jobless rate, highlighting recession periods for context.
I track this chart closely because the 2-year/10-year spread has historically predicted recessions whenever it turns negative. However, the timing of a recession remains uncertain. This is where jobless rates become a crucial indicator—when employers start shedding jobs, the likelihood of a recession increases.

So, what is this chart telling us right now? As long as jobless rates remain low, a recession is delayed. However, I’ll be watching closely now that government cuts under President Trump and Elon Musk are in motion.
Here’s the Python code to generate the same chart.
import pandas as pd
import matplotlib.pyplot as plt
from pandas_datareader.data import DataReader
from datetime import datetime
save_path = "./results/jobless-claims-2yr-10yr-recessions.png"
# Fetch 2-Year and 10-Year Treasury yield data from FRED
def fetch_treasury_spread():
"""
Fetches the 2-Year and 10-Year Treasury yields from FRED and calculates the spread.
Returns:
DataFrame with date index and the treasury spread.
"""
two_year_code = "DGS2"
ten_year_code = "DGS10"
start_date = "1988-01-01"
end_date = datetime.now()
two_year = DataReader(two_year_code, "fred", start_date, end_date)
ten_year = DataReader(ten_year_code, "fred", start_date, end_date)
data = pd.concat([ten_year, two_year], axis=1)
data.columns = ["10-Year Yield", "2-Year Yield"]
data["Spread (10Y - 2Y)"] = data["10-Year Yield"] - data["2-Year Yield"]
return data.dropna()
# Fetch jobless rate data from FRED
def fetch_jobless_rate():
"""
Fetches US unemployment rate data from FRED.
Returns:
DataFrame with date index and jobless rate.
"""
start_date = "1988-01-01"
end_date = datetime.now()
jobless_rate = DataReader("UNRATE", "fred", start_date, end_date)
jobless_rate.rename(columns={"UNRATE": "Jobless Rate"}, inplace=True) # Fix column name
return jobless_rate
# Fetch recession data from FRED
def fetch_recession_data():
start_date = "1988-01-01"
end_date = datetime.now()
recession_data = DataReader("USREC", "fred", start_date, end_date)
return recession_data
def get_recession_periods(recessions):
recession_periods = []
in_recession = False
start_date = None
for date, value in recessions["USREC"].items():
if value == 1 and not in_recession:
in_recession = True
start_date = date
elif value == 0 and in_recession:
in_recession = False
end_date = date
recession_periods.append((start_date, end_date))
return recession_periods
def plot_treasury_spread_with_jobless(data, jobless_rate, recession_periods):
fig, ax1 = plt.subplots(figsize=(14, 8))
ax1.plot(data.index, data["Spread (10Y - 2Y)"], color="blue", linewidth=1.5, label="10Y - 2Y Spread")
ax1.axhline(0, color="red", linestyle="--", linewidth=1, alpha=0.7, label="Zero Spread")
ax1.set_xlabel("Year", fontsize=14, labelpad=10)
ax1.set_ylabel("Spread (%)", fontsize=14, labelpad=10, color="blue")
ax1.tick_params(axis="y", labelcolor="blue")
ax1.grid(visible=True, which="major", linestyle="--", linewidth=0.5, alpha=0.7)
for start_date, end_date in recession_periods:
ax1.axvspan(start_date, end_date, color="gray", alpha=0.3, label="Recession" if start_date == recession_periods[0][0] else "")
ax2 = ax1.twinx()
ax2.plot(jobless_rate.index, jobless_rate["Jobless Rate"], color="green", linewidth=1.5, label="Jobless Rate")
ax2.set_ylabel("Jobless Rate (%)", fontsize=14, labelpad=10, color="green")
ax2.tick_params(axis="y", labelcolor="green")
lines, labels = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines + lines2, labels + labels2, fontsize=12, loc="upper left")
# Add copyright text
fig.text(0.94, 0.10, "(c) neuralmarkettrends.com", fontsize=10, color="red", ha="right", va="bottom")
plt.title("2-Year and 10-Year Treasury Spread, Jobless Rate, and Recessions", fontsize=18, fontweight="bold", pad=20)
plt.suptitle("Spread = (10-Year Yield - 2-Year) Yield", fontsize=12, color="gray", style="italic", y=0.91)
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches="tight")
plt.show()
if __name__ == "__main__":
try:
treasury_spread = fetch_treasury_spread()
jobless_rate = fetch_jobless_rate()
recession_data = fetch_recession_data()
recession_periods = get_recession_periods(recession_data)
plot_treasury_spread_with_jobless(treasury_spread, jobless_rate, recession_periods)
except Exception as e:
print(f"An error occurred: {e}")
Member discussion