macbook pro beside papers

pandas-datareaderでyahooファイナンスのデータを取得する方法

日本の株価データをPythonで取得する方法を探していたところ、pandas-datareaderという便利そうなライブラリを見つけました。

pandas-datareaderは、様々なデータをインターネットから取得し、pandas.DataFrame形式に格納してくれるライブラリです。マニュアルによれば、次のようなデータが取得できるそうです。

  • Tiingo
  • IEX
  • Alpha Vantage
  • Econdb
  • Enigma
  • Quandl
  • St.Louis FED (FRED)
  • Kenneth French’s data library
  • World Bank
  • OECD
  • Eurostat
  • Thrift Savings Plan
  • Nasdaq Trader symbol definitions
  • Stooq
  • MOEX
  • Naver Finance
  • Yahoo Finance

日本の株価データは、米国のYahoo Financeから取得できます。それ以外にも、OECDや世界銀行のデータも取得できるので、マクロ環境分析に利用できそうですね。

Yahoo Financeデータ取得エラーの対処方法

しかし、チュートリアルに従って、Yahoo Financeのデータを取得しようとすると、次のようなエラーになります。

Traceback (most recent call last):
  File "/Users/xxx/test/01.ReaderTest/sample.py", line 15, in <module>
    df = web.DataReader(symbol,data_source='yahoo', start=start, end=end )
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pandas/util/_decorators.py", line 210, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pandas_datareader/data.py", line 379, in DataReader
    ).read()
      ^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pandas_datareader/base.py", line 253, in read
    df = self._read_one_data(self.url, params=self._get_params(self.symbols))
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pandas_datareader/yahoo/daily.py", line 153, in _read_one_data
    data = j["context"]["dispatcher"]["stores"]["HistoricalPriceStore"]
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: string indices must be integers, not 'str'

これは、Yahoo FinanceのAPIで取得できるデータが、暗号化(base64形式)されたことが原因のようです。pandas-datareaderの最終更新は、この仕様変更前なので、仕様変更に未対応なんでしょうね。

このエラーへの対処方法は、すでに多くのサイトで解説されている通り、yfinanceライブラリでpandas-datareaderの関数をオーバーロードしてしまうことです。コードは次のようになります。

import pandas_datareader.data as web
import datetime as dt
import yfinance as yf

yf.pdr_override()

ticker = "7203"
symbol = ticker + ".T"

start  = dt.datetime(2016,3,1)
end    = dt.date.today()

df = web.get_data_yahoo(tickers=symbol,start=start,end=end)
#df = web.DataReader(symbol,data_source='yahoo', start=start, end=end )
print(df)
df.to_csv( "y_stock_data_"+ticker+".csv")

yfinance.pdr_override()関数でオーバーライドさせた後、pandas_datareader.data.get_data_yahoo()を使って呼び出すと、次のように無事に株価データを取得できました。(トヨタ自動車の例です)

                   Open         High  ...    Adj Close    Volume
Date                                  ...                       
2016-03-01  1170.599976  1187.000000  ...   869.600647  55466000
2016-03-02  1213.800049  1237.000000  ...   899.704102  70179500
2016-03-03  1219.400024  1241.800049  ...   911.656555  55276500
2016-03-04  1234.000000  1246.400024  ...   919.182556  48802500
2016-03-07  1241.000000  1244.599976  ...   900.146606  61889000
...                 ...          ...  ...          ...       ...
2023-05-15  1939.500000  1942.000000  ...  1933.000000  16791400
2023-05-16  1933.000000  1939.500000  ...  1923.500000  18728200
2023-05-17  1925.000000  1935.500000  ...  1928.000000  16295600
2023-05-18  1945.000000  1958.000000  ...  1955.500000  28317600
2023-05-19  1963.500000  1973.500000  ...  1959.500000  23600700

[1784 rows x 6 columns]

上記のサンプルコードでは、何度もアクセスするとサーバに負荷をかけてしまうので、データはすぐにCSVに保存しています。

複数の株価データを取得する方法

pandas_datareaderでは、get_data_yahoo()関数のtickers引数に株式シンボルのリストを渡すと、複数の株価データを一度に取得してくれます。

例えば、株式コードのリストをCSVファイルcode.csvに保存しておいたとすると、次のようなプログラムを株価データを一度に取得できます。

import pandas_datareader.data as web
import datetime as dt
import pandas as pd
import yfinance as yf

yf.pdr_override()

tickers = pd.read_csv("code.csv",index_col=0,header=0) # "コード","企業名"という形式を想定

start   = dt.datetime(2013,1,1)
end     = dt.date.today()

symbols = []
for ticker in tickers.index:
        symbol = str(ticker) + ".T"
        symbols.append(symbol)

df = web.get_data_yahoo(tickers=symbols,start=start,end=end)

df.to_csv( "y_stock_data.csv")

例えば、code.csvに大型株のコードが記載されていたとすると、次のようなデータが取得されます。

              Adj Close                            ...   Volume                   
                 1605.T       1925.T       1928.T  ...   9735.T   9983.T    9984.T
Date                                               ...                            
2013-01-04   873.625122  1135.737427   672.709351  ...   800500  1761900  12023000
2013-01-07   864.160034  1118.928223   674.774902  ...   688400  2942100  13892400
2013-01-08   860.374146  1104.311279   665.135193  ...   760300  1850400  10749800
2013-01-09   849.962463  1124.774902   663.069519  ...   848200  1901700  11551600
2013-01-10   848.069458  1145.969360   681.660278  ...   635100  1764300   8860200
...                 ...          ...          ...  ...      ...      ...       ...
2023-05-15  1464.000000  3539.000000  2850.500000  ...   959800   785000   9989400
2023-05-16  1482.000000  3554.000000  2865.000000  ...  1045900  1249300   8285300
2023-05-17  1475.000000  3565.000000  2907.500000  ...   799100  1248500  16585800
2023-05-18  1493.000000  3565.000000  2938.500000  ...   951600  1334200  12279500
2023-05-19  1500.000000  3543.000000  2911.000000  ...   818400  1530000   8635000

[2556 rows x 594 columns]

保存された複数の株式データを読み込む方法

このような複数の株価データを取得する行為は、サーバに多大な負荷をかけてしまいますので、一度取得したデータはファイルに保存して利用した方が良いでしょう。

しかしながら、取得した株価データは、ラベルが数値の意味(”Adj close”, “close”, “high”,”low”,”open”,”volume”)と株式コードの2段になっていて、csvを読み込む際にheader=[0,1]とリスト指定する必要があります。また、CSVファイルでは”Date”のみの行が存在するため、この行を読み飛ばすskiprows=0の指定も必要になります。

pandas.read_csv()での読み込みは次のようになります。

data = pd.read_csv("y_stock_data.csv",index_col=0,skiprows=0,header=[0,1])

また、このように読み込まれたdataから、調整後の終値だけを取り出す場合、次のように指定します。

adj_closes = data["Adj Close"]

adj_closesには、次のようなデータが格納されています。

                 1605.T       1925.T  ...        9983.T       9984.T
Date                                  ...                           
2013-01-04   873.625305  1135.737549  ...   6747.730957  1455.377441
2013-01-07   864.159973  1118.928223  ...   6933.141113  1427.434326
2013-01-08   860.374268  1104.311279  ...   6963.536621  1446.063232
2013-01-09   849.962341  1124.775024  ...   6936.181152  1415.791504
2013-01-10   848.069519  1145.969482  ...   6857.152344  1415.791504
...                 ...          ...  ...           ...          ...
2023-05-15  1464.000000  3539.000000  ...  31950.000000  4950.000000
2023-05-16  1482.000000  3554.000000  ...  32270.000000  4999.000000
2023-05-17  1475.000000  3565.000000  ...  32990.000000  5240.000000
2023-05-18  1493.000000  3565.000000  ...  33360.000000  5200.000000
2023-05-19  1500.000000  3543.000000  ...  34090.000000  5179.000000

[2556 rows x 99 columns]

まとめ

データ分析をしようとすると、まずデータを集めることに苦労するのですが、pandas-datareaderがあると簡単にデータが収集できて便利ですね。

インターネット上に公開されているデータで分析する際には、使ってみてはいかがでしょうか?

参照URL

コメントを残す