日本の株価データを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
- pandas-datareader : https://pydata.github.io/pandas-datareader/index.html
- yfinance : https://pypi.org/project/yfinance/