米国株のPERなどの指標を取得してスクリーニングする【Python, pandas datareader】
最近ではYahoo!financeや証券口座のページで株のデータをスクリーニング(※)できてしまいますが,もう少し自分流にアレンジした分析を行ってみたいときは,Pythonなどのプログラミング言語を使ってデータを取得し,スクリーニングしたくなります.
特定の条件で選別すること。例えば、PER(Price Earnings Ratio)が低い銘柄だけを抽出するなど。
そこで今回は,Pythonで株式に関するデータを取得しスクリーニングする方法について解説します.

スクリーニングのプログラミング部分は目的によって異なるので,今回紹介するのはあくまで一例です
本記事では,Pythonがインストールされていることを前提に話を述べます.
Pythonのインストールがお済でない方は,以下の記事を参考にPythonをインストールをしましょう.
データ収集する方法は?
今回は,『pandas_datareader』というPythonライブラリでデータを取得することを考えます.
pandas_datareaderの基本的な使い方に関してはpandas datareaderをインストールして株価データを取得する方法【日本株・米国株】で解説していますが,本記事の下でもインストール方法から改めて解説します.
また,以前の記事Pythonでデータを取得して米国株チャートをプロット【yfinance】で紹介したyfinanceではPERなどの重要な指標が取得できないみたいなので,今回はpandas_datareaderを使います.
ただし,pandas_datareaderでも取得できない指標があるので,その場合は他のツールを使う必要があることに注意してください.
また,pandas_datareaderでデータを取得するには,当然ですがインターネットに接続されている必要があります.
pandas_datareaderをインストール
pipでインストールできます.
pip install pandas_datareader
株価を取得してチャートをプロット
株価が取得できるかの確認のために,株価データをプロットしてみます.
以下のコードを実行すると,下のグラフが表示されると思います.
import datetime
import pandas_datareader.data as web
import matplotlib.pyplot as plt
start = datetime.date(2008,1,1)
end = datetime.date.today()
codelist = ["KO","PG","MSFT"]
df= web.DataReader(codelist, 'yahoo', start, end)["Adj Close"]
df.plot(figsize=(8,6),fontsize=18)
plt.legend(bbox_to_anchor=(0, 1), loc='upper left', borderaxespad=1, fontsize=18)
plt.grid(True)
plt.show()

簡単に説明すると,
start = datetime.date(2008,1,1)
end = datetime.date.today()
でデータの取得開始日と終了日を決め,
codelist = ["KO","PG","MSFT"]
で取得する銘柄を決め,
df= web.DataReader(codelist, 'yahoo', start, end)["Adj Close"]
でデータを取得しています.データ型はpandasのDataFarameです.ここでは,[“Adj Close"](終値)だけを取得しています.
取得できる指標を確認する
それでは,株価のほかにどんなデータが取れるのか見てみましょう.
次のコードで,銘柄のいくつかの情報が取得できます.以下はコカ・コーラ(KO)での例です.
KO = web.get_quote_yahoo('KO')
何が取得できているのか,見てみましょう.以下で,情報の種類が確認できます.
print(KO.columns)
実行結果
Index(['language', 'region', 'quoteType', 'quoteSourceName', 'triggerable',
'currency', 'exchange', 'shortName', 'longName', 'messageBoardId',
'exchangeTimezoneName', 'exchangeTimezoneShortName',
'gmtOffSetMilliseconds', 'market', 'esgPopulated',
'firstTradeDateMilliseconds', 'priceHint', 'preMarketChange',
'preMarketChangePercent', 'preMarketTime', 'preMarketPrice',
'regularMarketChange', 'regularMarketChangePercent',
'regularMarketTime', 'regularMarketPrice', 'regularMarketDayHigh',
'regularMarketDayRange', 'regularMarketDayLow', 'regularMarketVolume',
'regularMarketPreviousClose', 'bid', 'ask', 'bidSize', 'askSize',
'fullExchangeName', 'financialCurrency', 'regularMarketOpen',
'averageDailyVolume3Month', 'averageDailyVolume10Day',
'fiftyTwoWeekLowChange', 'fiftyTwoWeekLowChangePercent',
'fiftyTwoWeekRange', 'fiftyTwoWeekHighChange',
'fiftyTwoWeekHighChangePercent', 'fiftyTwoWeekLow', 'fiftyTwoWeekHigh',
'dividendDate', 'earningsTimestamp', 'earningsTimestampStart',
'earningsTimestampEnd', 'trailingAnnualDividendRate', 'trailingPE',
'trailingAnnualDividendYield', 'epsTrailingTwelveMonths', 'epsForward',
'epsCurrentYear', 'priceEpsCurrentYear', 'sharesOutstanding',
'bookValue', 'fiftyDayAverage', 'fiftyDayAverageChange',
'fiftyDayAverageChangePercent', 'twoHundredDayAverage',
'twoHundredDayAverageChange', 'twoHundredDayAverageChangePercent',
'marketCap', 'forwardPE', 'priceToBook', 'sourceInterval',
'exchangeDataDelayedBy', 'tradeable', 'marketState', 'displayName',
'price'],
dtype='object')
74種類の情報があることが分かりました.
銘柄のPERを取得する
例えば,コカ・コーラの「実績PER」(trailingPE)が知りたい場合は,
KO = web.get_quote_yahoo('KO')['trailingPE']
print(KO)
とすればOKです.
実行結果
KO 28.508379
KOのPERって意外と低くないんですね.
複数の銘柄のPERを取得したい場合は,次のようにすればできます.
codelist = ["KO","PG","MSFT"]
pers = web.get_quote_yahoo(codelist)['trailingPE']
print(pers)
実行結果
KO 28.508379
PG 24.293274
MSFT 35.009693
低PERの銘柄をスクリーニングする
それでは本題に入りましょう.あらゆる銘柄の中から,低PERの銘柄のみを抽出します.
流れとしては「多数の銘柄を用意する」→「低PERなら残す」という順番でしかやりようがないですから,まずは多数の銘柄を用意します.
Pythonなら,get_nasdaq_symbolsでナスダック銘柄(約1万銘柄)を取得できます.
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
codelist = get_nasdaq_symbols()
print(codelist)
実行結果
Nasdaq Traded Security Name ... NASDAQ Symbol NextShares
Symbol ...
A True Agilent Technologies, Inc. Common Stock ... A False
AA True Alcoa Corporation Common Stock ... AA False
AAA True Listed Funds Trust AAF First Priority CLO Bond... ... AAA False
AAAU True Goldman Sachs Physical Gold ETF Shares ... AAAU False
AAC.U True Ares Acquisition Corporation Units, each consi... ... AAC= False
... ... ... ... ... ...
ZXYZ.A True Nasdaq Symbology Test Common Stock ... ZXYZ.A False
ZXZZT True NASDAQ TEST STOCK ... ZXZZT False
ZYME True Zymeworks Inc. Common Shares ... ZYME False
ZYNE True Zynerba Pharmaceuticals, Inc. - Common Stock ... ZYNE False
ZYXI True Zynex, Inc. - Common Stock ... ZYXI False
10120銘柄ありました.
これを用意したら,後は先ほどのPERを取得するコードと組み合わせるだけです.
まとめると,以下のコードになります.実行すれば,ナスダック銘柄のうちPERが10以下の銘柄のみを取得できます.
import datetime
import pandas as pd
import pandas_datareader.data as web
import matplotlib.pyplot as plt
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
codelist = get_nasdaq_symbols() #ナスダック銘柄を取得
pers = pd.DataFrame({'PER':['']}, index=['銘柄'])
error_symbols = []
for c in codelist.index:
try:
per = web.get_quote_yahoo(c)['trailingPE'] #銘柄cのPERを取得
if per[c] < 10: #PERが10以下ならpersに保存
pers.loc[c] = per[c]
except:
error_symbols.append(c)
print(pers)
実行結果
PER
銘柄
AAMC 0.802986
AAWW 4.42074
ACGLO 7.90361
ACGLP 7.63855
...
銘柄ひとつひとつを見ていくコードになっているので,結果が出るまでにものすごく時間がかかりますから覚悟してください.
ここでは,一部の結果しか表示していません.
S&P500の銘柄に絞る場合
ナスダック銘柄すべてをチェックしていると時間がかかりすぎるので,S&P500銘柄(約500銘柄)に絞ってからスクリーニングしたい場合もあります.
ナスダック銘柄からS&P500を選んでいては結局時間がかかるので,S&P500銘柄がすでに一覧になっているデータをどこかから持ってくるのが良いです.
Wikipediaに記載されている銘柄をまとめたと考えられているCSVデータが,以下のURLにあります.
https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv
(参考:配当再投資でのんびり投資:S&P500の構成銘柄の在処と取得方法(google Spreadsheet、Excel))
ただし,公式かどうかは怪しいので,正確ではないかもしれません.また,S&P500の組入れ銘柄は定期的に入れ替わるので,最新の銘柄を取得し続ける必要があります.公式で一覧になっているものが見つかれば,再掲します.
これを以下のようにPythonで呼んでやれば,S&P500だけのデータを取得できます.
import pandas as pd
url = "https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv"
df = pd.read_csv(url, encoding="SHIFT_JIS")
print(df)
実行結果
Symbol Name Sector
0 MMM 3M Company Industrials
1 AOS A.O. Smith Corp Industrials
2 ABT Abbott Laboratories Health Care
3 ABBV AbbVie Inc. Health Care
4 ABMD Abiomed Health Care
.. ... ... ...
500 YUM Yum! Brands Inc Consumer Discretionary
501 ZBRA Zebra Technologies Information Technology
502 ZBH Zimmer Biomet Health Care
503 ZION Zions Bancorp Financials
504 ZTS Zoetis Health Care
あとは先ほどのスクリーニングコードに同様にすれば良いですが,DataFarameの構造が少し違うので,合わせて書き換えます.
以下が,S&P500からPERが10以下の銘柄をスクリーニングするコードです.
import pandas as pd
import pandas_datareader.data as web
url = "https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv"
codelist = pd.read_csv(url, encoding="SHIFT_JIS")
pers = pd.DataFrame({'PER':['']}, index=['銘柄'])
error_symbols = []
for c in codelist['Symbol']:
try:
per = web.get_quote_yahoo(c)['trailingPE']
if per[c] < 10:
pers.loc[c] = per[c]
except:
error_symbols.append(c)
print(pers)
実行結果
PER
銘柄
AFL 7.81709
ALL 6.7747
BIO 4.51307
CE 8.71157
EBAY 7.3074
KIM 8.76055
MHK 3.7743
PGR 9.66667
PHM 9.60201
COO 8.52827
UNM 7.40874
3分ほどでスクリーニングできました.これだけの銘柄しかありませんでしたね.やはり,米国株でPER10以下というのは厳しめのようです.
何度もスクリーニングしたい場合は、実行時間(株価データ取得時間)を短くするために、データをキャッシュすることをお勧めします(毎回、株価を取得するのは非効率ですからね)。以下の記事も参考にしてみてください。
全コードまとめ

最後に,改めてコードをまとめておきます
ナスダック銘柄から低PERの銘柄を抽出するコード
import pandas as pd
import pandas_datareader.data as web
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
codelist = get_nasdaq_symbols() #ナスダック銘柄を取得
pers = pd.DataFrame({'PER':['']}, index=['銘柄'])
error_symbols = []
for c in codelist.index:
try:
per = web.get_quote_yahoo(c)['trailingPE'] #銘柄cのPERを取得
if per[c] < 10: #PERが10以下ならpersに保存
pers.loc[c] = per[c]
except:
error_symbols.append(c)
print(pers)
S&P500銘柄から低PERの銘柄を抽出するコード
import pandas as pd
import pandas_datareader.data as web
url = "https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv"
codelist = pd.read_csv(url, encoding="SHIFT_JIS")
pers = pd.DataFrame({'PER':['']}, index=['銘柄'])
error_symbols = []
for c in codelist['Symbol']:
try:
per = web.get_quote_yahoo(c)['trailingPE']
if per[c] < 10:
pers.loc[c] = per[c]
except:
error_symbols.append(c)
print(pers)
ディスカッション
コメント一覧
まだ、コメントがありません