##はじめに
この記事はSFC Advent Calendar 2019の22日目の記事です。何について書くか悩みましたが、今回は最近書いたコードをリライトして記事にすることにしました。
##背景
近年、様々なソフトウェアやライブラリの発展に伴い、株価データの活用が個人でも行われるようになってきています。ところが、日本株の株価データは著作権法上の問題で扱いが難しいため(詳細はこちら)、現時点で大量の株価データを無料で一括ダウンロードできるサービスは存在しません。
しかしながら、銘柄ごとに1年ずつなら日足データをダウンロードできるサービスなら幾つか存在します。例えば、株式投資メモさんやバフェット・コードさんです。
これらのサービスは1年分の株価の分析をしたいときには大変便利なのですが、複数年の株価を分析したいときには大量のファイルを処理しなければならないため多少不便です。
そこで今回は、株式投資メモさんからダウンロードした複数のCSVを結合させるコードを作成することで、複数年分の株価データの利用を可能にしてみましょう。また、PythonのライブラリであるPandasのDataFrameを用いることで、そのままPythonで分析を行う際にも使いやすいように設計しています。
##データのダウンロードについて
上記をお読みになった方で、「ダウンロード部分のコードはないのか?」と思われた方もいらっしゃると思います。その点に関して、もちろん自動化することは可能なのですが、株式投資メモさんのサイトにてスクレイピングや自動化が許可されているかどうかが不明であるため、本稿でのコードの紹介は見送ります。
その代わりに、フリーランスに憧れてさんが紹介されているこちらのコードを使用することでダウンロードの完全自動化が可能です。
また、その際に2点変更すべき点がありますので、以下に記します。
1.ファイルの保存場所について
download_dir = 'C:\\Python\\'
となっているところを、download_dir = './csv'
とすることをお勧めします。こうすることで、ダウンロードしたファイルをカレントディレクトリ直下のフォルダに配置することができます。
2.繰り返し処理について
for i in range(year,2019):
となっているところを、2019年までのデータが取得したいのであればfor i in range(year,2020):
、2020年までのデータが取得したいのであればfor i in range(year,2021):
のように1年ずつ増やす必要があります。
##データの準備
まず最初に、上項などの方法を用いて株式投資メモから特定の銘柄の株価データを複数年分ダウンロードし、保存します。
###注意点
・データのダウンロードは必ず時間をかけて行うようにし、サーバーに負荷をかけないよう気をつけてください。
・データに漏れがあるとエラーになってしまうので、必ず必要年数分全てのデータをダウンロードしてください。
・ファイル名は変更しないでください。
・全てのファイルは1つのフォルダにまとめ、また、同じフォルダに複数の銘柄のデータを入れないようにしてください。
##CSVからのデータの読み込み
ダウンロードしたcsvを読み込むコードを作成します。
###コード
import pandas as pd
import codecs
def read_csv(file_name: str) -> pd.core.frame.DataFrame:
'''
kabuoji3.comからダウンロードしたcsvをファイル名[file_name]を指定して読み込み、整形してDataFrame[df]として返します。
'''
with codecs.open(file_name, 'r', 'Shift_JIS', 'ignore') as f:
df = pd.read_csv(f)
df.columns = df.iloc[0]
df.drop(df.index[[0,1]],inplace=True)
df.index = pd.to_datetime(df.index, format='%Y-%m-%d')
df.index.name = "日付"
return df
###解説
株式投資メモでダウンロードできるCSVの文字コードはShift_JIS
なので、通常の方法でCSVを読み込むと文字化けが起こる可能性があります。それを防ぐため、ここではcodecs
を利用して文字コードを指定してファイルを開き、pandas
の機能であるread_csv()
を用いてCSVをDataFrame
として読み込んでいます。
また、株式投資メモでダウンロードしたCSVファイルはヘッダー部分に銘柄情報が含まれており、columns
やindex
が正しく認識されないため、これらを直接指定した上でヘッダーを削除する処理を含めています。更に、index
の日付
列に対し、to_datetime
処理を行うことで、index
の日付をそのままdatetime
型として扱うことができるようになっています。
最終的に出力されるのは1年分の株価データを含んだpandas
のDataFrame
です。
##ファイルリストの読み込み
1つのフォルダにまとまっているCSVのファイル名のリストを作成すると共に、それぞれのファイルが何年の株価データを含んでいるかどうかを認識して取得できるようにします。
###コード
from glob import glob
def get_price_data_by_year(year: int) -> pd.core.frame.DataFrame:
'''
フォルダ内のファイルリスト[FILES_DICT]から指定年[year]の株価csvのファイル名を参照し、読み込んでDataFrame[df]として返します。
'''
file_name = FILES_DICT[str(year)]
df = read_csv(file_name)
return df
if __name__ == "__main__":
#ダウンロードしたCSVが入っているフォルダのディレクトリを指定(相対パスでも絶対パスでも可、フォルダ名の後に/*を忘れずに)
CSV_FOLDER_DIRECTORY = './csv/*'
#上記のCSV_FOLDER_DIRECTORYを元にCSVファイルの辞書FILES_DICTを自動で作成する部分(編集不要)
FILES_DICT = {}
files = glob(CSV_FOLDER_DIRECTORY)
files.sort()
for file_name in files:
FILES_DICT[file_name[-8:-4]] = file_name
###解説
CSV_FOLDER_DIRECTORY = './csv/*'
の部分でCSVがまとまっているフォルダを指定します。相対パスでも絶対パスでも指定は可能ですが、フォルダ名の後に/*を忘れずにつけるようにしてください。
その後の部分で、CSVファイルの辞書FILES_DICT
を作成します。これはグローバル変数として定義し、関数の中から参照できるようにする必要があります。
株式投資メモでダウンロードできるCSVは、例えば7203_2012.csv
のような名前で保存されています。この中から2012
(年数)の部分を抽出し、これをkey
とし、ファイル名をvalue
とするDictionary
を作成することで、特定の年の株価データを含むCSVのファイル名を簡単に参照できるようになります。
##データの結合(年指定)
指定年から指定年までの数年分の株価データを順に読み込んで結合し、1つのデータとして出力します。
###コード
def create_historical_data(open: int,last: int) -> pd.core.frame.DataFrame:
'''
指定年[open]から指定年[last]までの株価データを読み込み、結合して1つのDataFrame[df]として返します。
'''
df = get_price_data_by_year(open)
for i in range(int(open) + 1,int(last) + 1):
df = pd.concat([df, get_price_data_by_year(i)])
return df
###解説
指定年open
から指定年last
までの株価データを順に読み込み、得られたDataFrame
をpd.concat()
を用いて結合しています。最後に全てのデータが結合されたDataFrame
が出力されます。なお、指定年のファイルが存在しない場合、エラーが発生します。指定年数分のデータを予めダウンロードしているか確認してから実行するようにしてください。
##データの結合(年数指定)
実行日から遡ってちょうど指定年数分の株価データを作成し、1つのデータとして出力します。これは日付単位での出力となりますが、遡ってちょうど指定年数となる日付が取引所の営業日ではなかった場合は、その直後の営業日から現在までの株価データを含んだDataFrame
が出力されます。同じように、実行日が取引所の営業日ではなかった場合は、直前の営業日までのデータを含んだDataFrame
が出力されます。
###コード
import datetime as dt
from dateutil import relativedelta
def create_historical_data_by_date(years: int) -> pd.core.frame.DataFrame:
'''
実行日から遡ってちょうど指定年数[years]分の株価データを作成し、1つのDataFrame[df]として返します。
'''
this_year = int(dt.datetime.now().year)
df = create_historical_data(this_year - years,this_year)
open = dt.datetime.now() - relativedelta.relativedelta(years=years)
df = df[df.index >= open]
return df
###解説
まず最初にdatetime
を利用して現在の年を取得し、指定年数years
分の株価データを前出のcreate_historical_data()
を用いて取得します。
次に、relativedelta
を利用し、現在から遡ってちょうど指定年数となる日付をdatetime
型で取得しています。前のステップで取得したDataFrame
のindex
には既にdatetime
型への変換を行っているので、比較演算子>=
を利用することで簡単にDataFrame
をフィルタリングし、指定年数分のデータを取り出すことができます。最終的に出力されるのは、指定年数分の株価データを含んだDataFrame
です。
##CSVへの書き出し(保存)
上項で利用したいデータを出力することができましたが、外部でこのデータを扱うにはファイルに保存する必要があります。ここでは例として、CSVへの保存方法を紹介します。
###コード
if __name__ == "__main__":
#指定年から指定年までの株価データを保存したい場合
df = create_historical_data(2015,2019)
df.to_csv("2015-2019.csv")
#実行日から遡ってちょうど指定年数分の株価データを保存したい場合
df = create_historical_data_by_date(5)
df.to_csv("5years_price.csv")
###解説
まず、上項で作成したcreate_historical_data()
やcreate_historical_data_by_date()
などの関数を利用し、得られた結果を変数df
に保存します。このdf
は、pandas
の機能であるto_csv()
を用いて簡単にCSVとして書き出すことができます。なお、この時保存するファイル名を指定する必要があり、to_csv()
の引数として、""
で囲った文字列を渡します。これには、必ず語尾に.csv
を含めるようにしてください。
なお、この時保存されるファイルの文字コードはUTF-8
で、区切り文字は,
になります。Excelで読み込む際は、データ>テキストファイル
を選択し、文字コードと区切り文字を指定するようにしてください。
##コード(まとめ)
今回使用したコードは、GitHubにて公開しています。興味のある方はこちらからご確認ください。
##最後に
最後までお読みいただきありがとうございました。皆様の株式分析とクリスマスがより豊かになることを願っております。