S&P500は米国を代表する500銘柄で構成される株価指数です。この500銘柄を自動取得し、一括分析・スクリーニングするPythonコードを紹介します。
S&P500構成銘柄の自動取得
import pandas as pd
import yfinance as yf
import numpy as np
from bs4 import BeautifulSoup
import requests
def get_sp500_tickers():
"""WikipediaからS&P500構成銘柄を取得"""
url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies"
res = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
soup = BeautifulSoup(res.text, "html.parser")
table = soup.find("table", {"id": "constituents"})
df = pd.read_html(str(table))[0]
return df[["Symbol", "Security", "GICS Sector", "GICS Sub-Industry"]]
sp500_df = get_sp500_tickers()
print(f"S&P500銘柄数: {len(sp500_df)}")
print(sp500_df.head())
# セクター別集計
sector_counts = sp500_df["GICS Sector"].value_counts()
print("\nセクター別銘柄数:")
print(sector_counts)
セクター別パフォーマンス分析
def analyze_sector_performance(sp500_df, period="1y"):
"""セクター別ETFのパフォーマンスを比較"""
sector_etfs = {
"Technology": "XLK",
"Health Care": "XLV",
"Financials": "XLF",
"Consumer Discretionary": "XLY",
"Industrials": "XLI",
"Communication Services": "XLC",
"Consumer Staples": "XLP",
"Energy": "XLE",
"Utilities": "XLU",
"Real Estate": "XLRE",
"Materials": "XLB",
}
etf_tickers = list(sector_etfs.values()) + ["SPY"]
data = yf.download(etf_tickers, period=period, progress=False)["Close"]
returns = (data.iloc[-1] / data.iloc[0] - 1) * 100
results = []
for sector, etf in sector_etfs.items():
if etf in returns:
results.append({"Sector": sector, "ETF": etf, "Return(%)": round(returns[etf], 1)})
df = pd.DataFrame(results).sort_values("Return(%)", ascending=False)
spy_return = round(returns.get("SPY", 0), 1)
print(f"SPY(S&P500): {spy_return}%")
print(df.to_string(index=False))
return df
analyze_sector_performance(sp500_df)
全銘柄の一括スクリーニング
def batch_screen_sp500(tickers, batch_size=50):
"""S&P500銘柄を一括スクリーニング(バッチ処理)"""
all_results = []
# バッチに分けて処理(yfinanceの負荷軽減)
for i in range(0, len(tickers), batch_size):
batch = tickers[i:i+batch_size]
print(f"処理中: {i}/{len(tickers)} ({i/len(tickers)*100:.0f}%)")
try:
data = yf.download(batch, period="1y", progress=False)["Close"]
returns_1y = (data.iloc[-1] / data.iloc[0] - 1) * 100
returns_1m = (data.iloc[-1] / data.iloc[-22] - 1) * 100
vol = data.pct_change().std() * np.sqrt(252) * 100
for t in batch:
if t in data.columns:
all_results.append({
"Ticker": t,
"1M騰落(%)": round(returns_1m.get(t, 0), 1),
"1Y騰落(%)": round(returns_1y.get(t, 0), 1),
"ボラ(%)": round(vol.get(t, 0), 1),
})
except Exception as e:
print(f"エラー: {e}")
return pd.DataFrame(all_results).set_index("Ticker")
# 上位50銘柄でテスト
test_tickers = sp500_df["Symbol"].head(50).tolist()
results = batch_screen_sp500(test_tickers)
# 直近1ヶ月パフォーマンス上位10銘柄
print("\n1ヶ月パフォーマンス Top10:")
print(results.nlargest(10, "1M騰落(%)"))
S&P500ヒートマップ生成
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
def create_sp500_heatmap(performance_df, sp500_info_df, top_n=100):
"""S&P500銘柄のパフォーマンスヒートマップを生成"""
merged = sp500_info_df.merge(
performance_df.reset_index(),
left_on="Symbol", right_on="Ticker", how="inner"
)
top = merged.nlargest(top_n, "1M騰落(%)")
fig, ax = plt.subplots(figsize=(20, 12))
for idx, (_, row) in enumerate(top.iterrows()):
x = idx % 20
y = idx // 20
color = "green" if row["1M騰落(%)"] > 0 else "red"
alpha = min(abs(row["1M騰落(%)"]) / 20 + 0.3, 1.0)
rect = plt.Rectangle([x, y], 0.95, 0.95, color=color, alpha=alpha)
ax.add_patch(rect)
ax.text(x + 0.475, y + 0.6, row["Symbol"], ha="center", va="center",
fontsize=8, fontweight="bold", color="white")
ax.text(x + 0.475, y + 0.25, f"{row['1M騰落(%)']:.1f}%", ha="center",
va="center", fontsize=7, color="white")
ax.set_xlim(0, 20)
ax.set_ylim(0, 5)
ax.axis("off")
ax.set_title(f"S&P500 パフォーマンスヒートマップ(上位{top_n}銘柄)", fontsize=16)
plt.tight_layout()
plt.show()
# create_sp500_heatmap(results, sp500_df)
まとめ
PythonでS&P500全銘柄を自動取得・分析することで、手動では不可能なスケールのスクリーニングが実現できます。セクター分析とモメンタムスクリーニングを組み合わせて、有望銘柄を効率的に発掘しましょう。

