Edited at

[Python] 株価データをプロットし,さらにCSVファイルを出力する

More than 1 year has passed since last update.


はじめに

Web上で長期間の株価データを探してもなかなか見つからないので,Pythonを用いて株価のヒストリカルデータを取得し,CSV形式で出力,さらに出力したデータをプロットするプログラムを作成しました.

日本株・外国株いずれにも対応しています.

参考までに,例として出力した日経平均株価1のCSVファイルはこちら,さらにプロットすると以下のようになります.

Nikkei225.png


ソースコードの紹介

まず,作成したソースコードを紹介します.


stockprice.py

#!/usr/bin/env python3

# -*- coding:utf-8 -*-

'''
株価データのプロット・CSVへの出力
'''

import datetime as dt
from pandas import DataFrame
import jsm
import pandas_datareader.data as web
import matplotlib.pyplot as plt

def jpstock(code, start_date, end_date):
year, month, day = start_date.split("-")
start = dt.date(int(year), int(month), int(day))
year, month, day = end_date.split("-")
end = dt.date(int(year), int(month), int(day))

print('CSVを出力中...')
q = jsm.Quotes()
target = q.get_historical_prices(code, jsm.DAILY, start_date=start, end_date=end)

date = [data.date for data in target]
open = [data.open for data in target]
high = [data.high for data in target]
low = [data.low for data in target]
close = [data.close for data in target]
volume = [data.volume for data in target]
adj_close = [data._adj_close for data in target]

Date = date[::-1]
Open = open[::-1]
High = high[::-1]
Low = low[::-1]
Close = close[::-1]
Adj = adj_close[::-1]
Vol = volume[::-1]

cdf = DataFrame(index=Date)
cdf.index.name = "Date"
cdf["Open"] = Open
cdf["High"] = High
cdf["Low"] = Low
cdf["Close"] = Close
cdf["Adj Close"] = Adj
cdf["Volume"] = Vol

cdf.to_csv(code + '.csv')
print(code + '.csvを出力しました.')

print('株価データをプロット中...')
df = DataFrame(index=Date)
df['Adj Close'] = Adj

return df

def usstock(ticker, start_date, end_date):
year, month, day = start_date.split("-")
start = dt.date(int(year), int(month), int(day))
year, month, day = end_date.split("-")
end = dt.date(int(year), int(month), int(day))

print('CSVを出力中...')
df2 = web.DataReader(ticker, 'yahoo', start, end)

df2.to_csv(ticker + '.csv')
print(ticker + '.csvを出力しました.')

print('株価データをプロット中...')
df3 = DataFrame(index=[])
df3['Adj Close'] = df2['Adj Close']

return df3

def brand():
print('業種コード一覧を表示します...')

lists = [
"'0050': 農林・水産業",
"'1050': 鉱業",
"'2050': 建設業",
"'3050': 食料品",
"'3100': 繊維製品",
"'3150': パルプ・紙",
"'3200': 化学",
"'3250': 医薬品",
"'3300': 石油・石炭製品",
"'3350': ゴム製品",
"'3400': ガラス・土石製品",
"'3450': 鉄鋼",
"'3500': 非鉄金属",
"'3550': 金属製品",
"'3600': 機械",
"'3650': 電気機器",
"'3700': 輸送機器",
"'3750': 精密機器",
"'3800': その他製品",
"'4050': 電気・ガス業",
"'5050': 陸運業",
"'5100': 海運業",
"'5150': 空運業",
"'5200': 倉庫・運輸関連業",
"'5250': 情報・通信",
"'6050': 卸売業",
"'6100': 小売業",
"'7050': 銀行業",
"'7100': 証券業",
"'7150': 保険業",
"'7200': その他金融業",
"'8050': 不動産業",
"'9050': サービス業"
]

for item in lists:
print(item)

gcode = input('業種コード? ')
print('リストファイルを出力中...')
q = jsm.Quotes()
target2 = q.get_brand(gcode)
ccode = [data.ccode for data in target2]
market = [data.market for data in target2]
name = [data.name for data in target2]
info = [data.info for data in target2]
df4 = DataFrame(index=ccode)
df4.index.name = "Code"
df4["Name"] = name
df4["Market"] = market
df4["Info"] = info
df4.to_csv(gcode + '.csv')
print(gcode + '.csvを出力しました.')

cont = str(input('引き続き個別銘柄のデータを取得する場合は「y」,やめる場合は「n」を入力 [y/n]: '))
if cont == 'n':
return None
else:
main()

def main():
country = str(input('日本株の場合は「ja」,そうでない場合は「us」を入力 [ja/us]: '))
if country == 'ja':
code = input('証券コード? ')
if str(code) == "search":
try:
brand()
except:
print('データの取得中にエラーが発生しました.')
main()
else:
start_date = input('取得期間の初めの日付を入力 [yyyy-mm-dd]: ')
end_date = input('取得期間の終わりの日付を入力 [yyyy-mm-dd]: ')
try:
jstock = jpstock(code, start_date, end_date)
jstock['Adj Close'].plot()
plt.show()
main()
except:
print('データの取得中にエラーが発生しました.')
main()

elif country == 'us':
ticker = input('Ticker Symbol?: ')
start_date = input('取得期間の初めの日付を入力 [yyyy-mm-dd]: ')
end_date = input('取得期間の終わりの日付を入力 [yyyy-mm-dd]: ')
try:
ustock = usstock(ticker, start_date, end_date)
ustock['Adj Close'].plot()
plt.show()
main()
except:
print('データの取得中にエラーが発生しました.')
main()

elif country == 'exit':
return

else:
print('[ja/us] を入力してください.')
main()

if __name__ == "__main__":
main()


このソースコードは,Githubにて管理しています.

2017/11/25 追記:証券コード入力の際に「search」と入力することで,業種別銘柄リスト(日本株のみ)を取得できる機能を追加しました.

2017/11/28 追記:GUIバージョンを作成しました.ソースコードはこちらにあるので,見てみてください.UIは以下のようになります.また,PyQt5というパッケージが追加で必要になります.

ui.jpg


必要な環境・ライブラリと,そのインストール方法

必要なものは主に以下の通りです.


  • Python 3.x

  • matplotlib

  • pandas

  • pandas_datareader

  • jsm

まず,Python 3.x について,これは Python 3.x でのみ実行の検証をしているという意味であり,Python 2.x で問題なく動くかどうかは不明です.

おそらく print関数を修正すれば動くと思います.

また,他4つについて,Python 単体の環境ではデフォルトでは入っていません.さらにjsm ライブラリを使用するために BeautifulSoup 等もインストールする必要があります.

一方,Anaconda の環境では,デフォルトで matplotlib,pandas,BeautifulSoup 等が含まれているため,Anaconda 環境の導入を推奨します.Anaconda のダウンロードはこちらから.

ここでは Anaconda 環境に含まれていない pandas_datareader と,jsm のインストールのしかたを紹介します.

まず,デスクトップ左下の Windows マークを右クリックし,「Windows PowerShell(管理者)」または「コマンドプロンプト(管理者)」を起動し,Anaconda のプログラムファイルの置かれたディレクトリに移動します.

例えば Anaconda のプログラムファイルが C:\Program Files\Anaconda3\Scripts にあるのならば,

C:\Windows\System32> cd \

C:\> cd "Program Files"
C:\Program Files> cd Anaconda3\Scripts
C:\Program Files\Anaconda3\Scripts>

次に,pipコマンドを使ってライブラリをインストールします.

C:\Program Files\Anaconda3\Scripts> .\pip install pandas_datareader

さらに,

C:\Program Files\Anaconda3\Scripts> .\pip install jsm

これで必要な環境は揃いました.


使用方法

まずstockprice.pyがあるディレクトリと同じディレクトリにて,何も選択していない状態でShift+右クリックします.

出てきた右クリックメニューのうち,「Windows PowerShellをここに開く」または「コマンドプロンプトをここに開く」を選択します.

次のコマンドで実行してください.

python stockprice.py

このコマンドで実行できなかった場合は,python.exeにパスが通っていない可能性があります.

Windowsキーを押して環境変数を検索し,「環境変数を編集」を選択します.

ユーザー環境変数のうち,「Path」を選択して「編集」をクリック,さらに出てきた「環境変数名の編集」ウィンドウの右側「新規」をクリックします.

そこに Anaconda のプログラムファイルの置いてあるディレクトリのパスを書き込みます.

先ほどの例でいうとC:\Program Files\Anaconda3となります.

その後 PowerShell またはコマンドプロンプトを再起動してもう一度試すと,実行できるはずです.

実行すると,まず取得したいデータが日本株であるか外国株であるかの選択が求められます.

これは日本株と外国株の株価データの取得方法が異なるからです.

次に日本株の場合は証券コード,外国株の場合はティッカーシンボルを入力し,さらに取得したい期間を指定してしばらく待つと,データのプロット・CSV出力が実行されます.


エラーに関して

株価データの取得中にエラーが発生することがあります.

その場合はもう一度実行してください.

また,ライブラリ jsm を原因として,以下のようなエラーが発生することがあります.

/Program Files/anaconda3/lib/site-packages/bs4/__init__.py:166: UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("lxml"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.

To get rid of this warning, change this:

BeautifulSoup([your markup])

to this:

BeautifulSoup([your markup], "lxml")

markup_type=markup_type))

この場合は,先程の例でいうと,C:\Program Files\Anaconda3\lib\site-packages\jsm\util.pyの10行目から,


util.py

def html_parser(html):

try:
soup = BeautifulSoup(html)
except:
soup = BeautifulSoup(html, "html5lib")
return soup

となっているのを以下のように変更してください.


util.py

def html_parser(html):

try:
soup = BeautifulSoup(html, "html5lib")
except:
soup = BeautifulSoup(html)
return soup

これで jsm によるエラーは発生しなくなるはずです.


おわりに

以上で紹介は終わりです.

jsm や pandas_datareader 便利なので使ってみてください.





  1. 外国株を選択した上でティッカーシンボル「^N225」を指定して取得したデータです.あとから調べて知ったのですが日経平均株価も証券コード「998407」を持つみたいなので,そちらでも取得できます.