米国株のPERなどの指標を取得してスクリーニングする【Python, pandas datareader】

4月 19, 2021

最近ではYahoo!financeや証券口座のページで株のデータをスクリーニング(※)できてしまいますが,もう少し自分流にアレンジした分析を行ってみたいときは,Pythonなどのプログラミング言語を使ってデータを取得し,スクリーニングしたくなります.

※スクリーニング…特定の条件で選別すること.例えば,PER(Price Earnings Ratio)が低い銘柄だけを抽出するなど.

そこで今回は,Pythonで株式に関するデータを取得しスクリーニングする方法について解説します.

スクリーニングのプログラミング部分は目的によって異なるので,今回紹介するのはあくまで一例です

本記事では,Pythonがインストールされていることを前提に話を述べます.

Pythonのインストールがお済でない方は,以下の記事を参考にPythonをインストールをしましょう.

データ収集する方法は?

今回は,『pandas_datareader』というPythonライブラリでデータを取得することを考えます.

pandas_datareaderの基本的な使い方に関してはpandas datareaderをインストールして株価データを取得する方法【日本株・米国株】で解説していますが,本記事の下でもインストール方法から改めて解説します.

また,以前の記事Pythonでデータを取得して米国株チャートをプロット【fix_yahoo_finance】で紹介したfix_yahoo_financeでは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)