Show me the trend in interest rates and multifamily cap rates over the past 24 months, how the spread between them has moved, and what that trend implies for underwriting new acquisitions right now
import json
# Multifamily cap rates by metro and quarter (GreenStreet Market Cap Rates via RealAI datamart)
caprate_data = {
"3Q24": {"Phoenix":0.0509,"LosAngeles":0.0519,"Seattle":0.0517,"Chicago":0.0600,"Dallas":0.0520,"DC":0.0541,"Atlanta":0.0513,"Miami":0.0516,"NewYork":0.0486,"Houston":0.0544},
"4Q24": {"Seattle":0.0501,"Miami":0.0515,"Phoenix":0.0488,"NewYork":0.0486,"Atlanta":0.0533,"DC":0.0550,"Houston":0.0560,"Dallas":0.0520,"LosAngeles":0.0519,"Chicago":0.0599},
"1Q25": {"Dallas":0.0520,"NewYork":0.0486,"Chicago":0.0599,"Miami":0.0515,"LosAngeles":0.0519,"Atlanta":0.0534,"DC":0.0551,"Seattle":0.0501,"Phoenix":0.0509,"Houston":0.0560},
"2Q25": {"Houston":0.0549,"Miami":0.0515,"LosAngeles":0.0519,"DC":0.0566,"NewYork":0.0486,"Seattle":0.0501,"Phoenix":0.0535,"Atlanta":0.0533,"Dallas":0.0519,"Chicago":0.0579},
"3Q25": {"Chicago":0.0579,"LosAngeles":0.0519,"DC":0.0566,"Seattle":0.0501,"Phoenix":0.0535,"Miami":0.0515,"Dallas":0.0519,"Atlanta":0.0534,"NewYork":0.0486,"Houston":0.0549},
"4Q25": {"Miami":0.0515,"Dallas":0.0519,"Seattle":0.0501,"Atlanta":0.0533,"Chicago":0.0578,"Houston":0.0549,"DC":0.0566,"NewYork":0.0486,"LosAngeles":0.0519,"Phoenix":0.0535},
"1Q26": {"Dallas":0.0521,"DC":0.0567,"Seattle":0.0502,"Chicago":0.0563,"LosAngeles":0.0519,"Phoenix":0.0525,"Atlanta":0.0534,"Houston":0.0550,"Miami":0.0515,"NewYork":0.0486},
"2Q26": {"Seattle":0.0507,"DC":0.0573,"Miami":0.0505,"Chicago":0.0563,"Phoenix":0.0525,"Atlanta":0.0533,"Houston":0.0549,"LosAngeles":0.0519,"Dallas":0.0519,"NewYork":0.0486},
}
# Quarter-end 10yr treasury yield and Fed Funds rate, and 30yr mortgage rate (national_metrics_daily / monthly)
rates_data = {
"3Q24": {"treasury_10y":0.0381,"fed_funds":0.0513,"mortgage_30y":0.0618},
"4Q24": {"treasury_10y":0.0458,"fed_funds":0.0448,"mortgage_30y":0.0672},
"1Q25": {"treasury_10y":0.0423,"fed_funds":0.0433,"mortgage_30y":0.0665},
"2Q25": {"treasury_10y":0.0424,"fed_funds":0.0433,"mortgage_30y":0.0682},
"3Q25": {"treasury_10y":0.0416,"fed_funds":0.0422,"mortgage_30y":0.0635},
"4Q25": {"treasury_10y":0.0414,"fed_funds":0.0372,"mortgage_30y":0.0619},
"1Q26": {"treasury_10y":0.0435,"fed_funds":0.0364,"mortgage_30y":0.0618},
"2Q26": {"treasury_10y":0.0444,"fed_funds":0.0363,"mortgage_30y":0.0649},
}
quarters = list(caprate_data.keys())
results = []
for q in quarters:
caps = list(caprate_data[q].values())
avg_cap = sum(caps)/len(caps)
t10 = rates_data[q]["treasury_10y"]
ff = rates_data[q]["fed_funds"]
m30 = rates_data[q]["mortgage_30y"]
spread_t10 = avg_cap - t10
spread_ff = avg_cap - ff
results.append({
"quarter": q,
"avg_mf_cap_rate_pct": round(avg_cap*100,2),
"treasury_10y_pct": round(t10*100,2),
"fed_funds_pct": round(ff*100,2),
"mortgage_30y_pct": round(m30*100,2),
"cap_minus_10y_bps": round(spread_t10*10000),
"cap_minus_fedfunds_bps": round(spread_ff*10000),
})
# Most recent daily snapshot (Sept 2026) for current spread
latest_treasury_10y = 0.0479 # 2026-09-03
latest_fed_funds = 0.0363 # Aug 2026 (Sept FOMC unchanged per monthly series through Aug)
latest_mortgage_30y = 0.0667 # Aug 2026
latest_avg_cap = results[-1]["avg_mf_cap_rate_pct"]/100 # use 2Q26 cap rate (most recent reported print, 3Q26 not yet out)
current_spread_10y_bps = round((latest_avg_cap - latest_treasury_10y)*10000)
current_spread_ff_bps = round((latest_avg_cap - latest_fed_funds)*10000)
print(json.dumps(results, indent=2))
print("---")
print(f"3Q24 -> 2Q26 change in avg cap rate (bps): {round((results[-1]['avg_mf_cap_rate_pct']-results[0]['avg_mf_cap_rate_pct'])*100)}")
print(f"3Q24 -> 2Q26 change in 10yr treasury (bps): {round((results[-1]['treasury_10y_pct']-results[0]['treasury_10y_pct'])*100)}")
print(f"3Q24 -> 2Q26 change in fed funds (bps): {round((results[-1]['fed_funds_pct']-results[0]['fed_funds_pct'])*100)}")
print(f"3Q24 -> 2Q26 change in cap-over-10y spread (bps): {results[-1]['cap_minus_10y_bps']-results[0]['cap_minus_10y_bps']}")
print(f"3Q24 -> 2Q26 change in cap-over-fedfunds spread (bps): {results[-1]['cap_minus_fedfunds_bps']-results[0]['cap_minus_fedfunds_bps']}")
print("---")
print(f"Current (Sep 2026) 10yr treasury: {latest_treasury_10y*100:.2f}%, Fed funds: {latest_fed_funds*100:.2f}%, 30yr mortgage: {latest_mortgage_30y*100:.2f}%")
print(f"Current spread (2Q26 avg MF cap rate {latest_avg_cap*100:.2f}% minus 10yr treasury): {current_spread_10y_bps} bps")
print(f"Current spread (2Q26 avg MF cap rate minus fed funds): {current_spread_ff_bps} bps")
# Agency debt cost vs cap rate (going-in leverage math)
fannie_10yr_65ltv = 0.0601 # Fannie Mae Conventional, 10yr, 65% LTV, avg rate
cap_rate_now = latest_avg_cap
print("---")
print(f"Fannie Mae 10yr/65% LTV avg rate: {fannie_10yr_65ltv*100:.2f}% vs avg MF cap rate {cap_rate_now*100:.2f}% -> going-in cap rate minus loan rate: {round((cap_rate_now-fannie_10yr_65ltv)*10000)} bps (negative = negative leverage)")
cd /vercel/sandbox && python3 rate_trend_analysis.py
The rate math turned upside down over the past 24 months — and it's still upside down.
Since 3Q24, the Fed cut the funds rate by 150 bps (5.13% → 3.63%) , but the 10-year Treasury did the opposite — it rose 63 bps over that stretch and now sits at 4.79%, up nearly a full point from its September 2024 low . Multifamily cap rates barely moved through all of it: a 10-metro average tracked at 5.26% in 3Q24 and 5.28% today — essentially flat.
That divergence flipped the spread story on its head:
| Quarter | Avg MF Cap Rate | 10yr Treasury | Fed Funds | Cap Rate minus 10yr Treasury (bps) | Cap Rate minus Fed Funds (bps) |
|---|---|---|---|---|---|
| 3Q24 | 5.26% | 3.81% | 5.13% | 145 | 13 |
| 4Q24 | 5.27% | 4.58% | 4.48% | 69 | 79 |
| 1Q25 | 5.29% | 4.23% | 4.33% | 106 | 96 |
| 2Q25 | 5.30% | 4.24% | 4.33% | 106 | 97 |
| 3Q25 | 5.30% | 4.16% | 4.22% | 114 | 108 |
| 4Q25 | 5.30% | 4.14% | 3.72% | 116 | 158 |
| 1Q26 | 5.28% | 4.35% | 3.64% | 93 | 164 |
| 2Q26 | 5.28% | 4.44% | 3.63% | 84 | 165 |
| Current (Sep 2026) | 5.28% | 4.79% | 3.63% | 49 | 165 |
The cap-rate-over-Treasury spread — the market's real risk premium on long-duration CRE risk — compressed from 145 bps to roughly 50-85 bps , thin by historical standards (CRE has typically priced 150-200 bps over the 10yr). Meanwhile the cap-rate-over-fed-funds spread widened from 13 bps to 165 bps — cap rates look "cheap" relative to short rates only because short rates fell so far, not because cap rates actually moved.
What this means for underwriting today:
Happy to size any specific deal against this — e.g., what a bridge-to-agency structure or a 5-year hold clears against the current negative-leverage gap.
This is a read-only snapshot of a RealAI analysis.