Stock Market Participation Predicts P/E Ratios
Across developed markets, the share of the population that owns stocks strongly predicts how expensive that market is. More buyers who aren’t purely return-driven bids up prices relative to earnings.
The EU is actively trying to boost retail participation through the Capital Markets Union and the Pan-European Pension Product (PEPP), both designed to push European retail participation upward over the coming decades. If they succeed, the model suggests European P/E ratios will follow. The continent is currently clustered at the low-participation, low-valuation end of this chart. Invest? 🚀

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import linregress
# Participation rate (%) vs P/E ratio, developed markets, approx 2023-2024
# Sources: participation from national surveys / ECB / Fed;
# P/E from MSCI / StarCapital country estimates
data = {
"United States": (55, 26.2),
"Australia": (38, 21.1),
"Canada": (49, 19.2),
"United Kingdom": (30, 17.5),
"Japan": (14, 15.4),
"Germany": (12, 12.9),
"Sweden": (22, 19.5),
"Netherlands": (27, 16.8),
"France": (15, 15.2),
"Italy": (10, 12.5),
"Switzerland": (30, 20.1),
"South Korea": (15, 11.8),
"Norway": (25, 16.2),
"Spain": (13, 13.1),
}
countries = list(data.keys())
x = np.array([data[c][0] for c in countries])
y = np.array([data[c][1] for c in countries])
slope, intercept, r, _, _ = linregress(x, y)
r2 = r**2
trendline_x = np.linspace(x.min()-2, x.max()+2, 100)
trendline_y = slope * trendline_x + intercept
fig, ax = plt.subplots(figsize=(12, 7))
ax.scatter(x, y, marker='x', color='blue', s=100, zorder=5)
ax.plot(trendline_x, trendline_y, 'r--', linewidth=2, label=f'Fitted line (r={r:.2f}, r²={r2:.2f})')
for c in countries:
ax.annotate(c, (data[c][0], data[c][1]), textcoords="offset points", xytext=(6, 4), fontsize=9)
ax.set_xlabel('Stock Market Participation Rate (%)', fontsize=12)
ax.set_ylabel('P/E Ratio', fontsize=12)
ax.set_title('Stock Market Participation Rate vs. P/E Ratio (Developed Markets)', fontsize=14)
ax.grid(True, linestyle='--', alpha=0.5)
ax.legend(fontsize=11)
plt.tight_layout()
plt.savefig('participation-vs-pe.png', dpi=150, bbox_inches='tight')