修正(2021.11.27)
データ(株価データ)によっては,
高値と安値の線を引くためのデータ(hlinesに渡すデータ)がfloatでないというエラーが発生しましたので,
# エラー箇所
hlines=[df['High'].max(), df['Low'].min()]
次のように修正しています
# float変換
max = float(df['High'].max())
min = float(df['Low'].min())
hlines=[max, min]
はじめに
【Python】株価データ分析 株価チャートを描く~mplfinance編 その1~で描いた線が思ったより良い感じだったので,トレンドラインっぽい線を描きたいと思った
今回は線形回帰トレンドラインを描いてみる
株価チャートに,線形回帰で導いた一次関数
$y = ax + b$
$y$ … 株価
$x$ … 日付
$a$ … 係数
$b$ … 切片
を重ね,トレンドを把握しようというものだ
準備
線形回帰は,scikit-learn を使うのでインストール
conda であれば
conda install scikit-learn
データ用意
自分銘柄一覧(my.xlsx)と東証上場銘柄一覧(date_j.xls)を読み込む
この記事などを参考にしてほしいが,自分銘柄一覧(my.xlsx)とは,自分の保有銘柄の一覧で(仮に,トヨタ,日産,ホンダ,ANA,JALを保有しているとしている),
東証上場銘柄一覧(data_j.xls)とは,日本取引所グループにある東証上場銘柄の一覧ファイルのことだ
まずは,自分銘柄と東証上場銘柄一覧を読み込んで,自分銘柄のDataFrameを作る
import numpy as np
import pandas as pd
import pandas_datareader.data as pdr
import datetime
from dateutil.relativedelta import relativedelta
import mplfinance as mpf
my_df = pd.read_excel('my.xlsx', sheet_name = 'Sheet1', dtype = str)
topix_df = pd.read_excel('data_j.xls', dtype = str)
code_set = set(my_df['コード'].tolist())
df = topix_df[topix_df['コード'].isin(code_set)]
df
日付 | コード | 銘柄名 | 市場・商品区分 | 33業種コード | 33業種区分 | 17業種コード | 17業種区分 | 規模コード | 規模区分 | |
---|---|---|---|---|---|---|---|---|---|---|
2886 | 20211029 | 7201 | 日産自動車 | 市場第一部(内国株) | 3700 | 輸送用機器 | 6 | 自動車・輸送機 | 2 | TOPIX Large70 |
2888 | 20211029 | 7203 | トヨタ自動車 | 市場第一部(内国株) | 3700 | 輸送用機器 | 6 | 自動車・輸送機 | 1 | TOPIX Core30 |
2926 | 20211029 | 7267 | 本田技研工業 | 市場第一部(内国株) | 3700 | 輸送用機器 | 6 | 自動車・輸送機 | 1 | TOPIX Core30 |
3793 | 20211029 | 9201 | 日本航空 | 市場第一部(内国株) | 5150 | 空運業 | 12 | 運輸・物流 | 4 | TOPIX Mid400 |
3794 | 20211029 | 9202 | ANAホールディングス | 市場第一部(内国株) | 5150 | 空運業 | 12 | 運輸・物流 | 2 | TOPIX Large70 |
トヨタのトレンドを調べてみる
まずは普通にローソク足
code = df['コード'].tolist()[1]
company = df['銘柄名'].tolist()[1]
ed = datetime.datetime.now() # 本日
st = ed - relativedelta(months = 12) # 12か月前
df = pdr.DataReader(code + '.T', 'yahoo', st, ed)
kwargs = dict(type = 'candle', style = 'starsandstripes', title = code)
mpf.plot(data = df, **kwargs)
この辺までは,前回やってきたことだ
線形回帰(fitでモデルを作成)
インポートと線形回帰を使う準備
from sklearn.linear_model import LinearRegression
linearModel = LinearRegression()
正解のやり方
# fitでモデルを作成
linearModel.fit(X = np.arange(len(df.index)).reshape(-1,1), y = df['Close'].values)
# 係数
coef = linearModel.coef_[0]
# 切片
intercept = linearModel.intercept_
# 係数と切片
(coef, intercept)
結果は
係数(coef) = 2.615044958208052, 切片(intercept) = 1476.6834173686243
係数がプラスなので,右肩上がりのトレンドだ
$y = 2.615044958208052x + 1476.6834173686243$
正解にたどり着くまでに,何度か失敗したので,その失敗例を残しておく
失敗例1
# fitでモデルを作成
linearModel.fit(X = df.index.values.reshape(-1,1), y = df['Close'].values)
# 係数
coef = linearModel.coef_[0]
# 切片
intercept = linearModel.intercept_
# 係数と切片
(coef, intercept)
結果は,おかしい値に
係数(coef) = 2.0299990617873803e-14, 切片(intercept) = -31132.82774519947
fit の X に日付データを渡したのがまずかったようだ
失敗例2
# fit
linearModel.fit(np.arange(len(df.index)), df['Close'].values)
結果は,エラー
ValueError: Expected 2D array, got 1D array instead:
array=[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 …以降省略]
本来は,
array=[[0], [1], …以降省略]
となってなければならない
reshape(-1, 1) で2次元配列にする必要がある
列数は1を指定し,行数は-1でよろしくやってもらう
線形回帰(predictで予測値を出す)
fit で与えた X を predict に与えればよい
# predict で予測値を出す
predict = linearModel.predict(X = np.arange(len(df.index)).reshape(-1,1))
predict
結果は
array([1476.68341737, 1479.29846233, 1481.91350729, 1484.52855224, …以降省略])
トレンドラインを引く
前回の線の引き方と同じやり方でやってみる
# 全部の点を結ぶ線を引く場合は
#multi_points = [(pd.to_datetime(idx), price) for idx, price in zip(df.index.values, predict)]
#multi_points
# 2点を結ぶ線を引く場合は
multi_points = [(pd.to_datetime(df.index.values[0]), predict[0]), (pd.to_datetime(df.index.values[-1]), predict[-1])]
multi_points
multi_pointsには,(株価データの最初の日,最初の日の予測値),(株価データの最後の日,最後の日の予測値)を渡している
multi_pointsの中身は
[(Timestamp('2020-11-26 00:00:00'), 1476.7034957070596),
(Timestamp('2021-11-26 00:00:00'), 2117.32902858791)]
チャート描画
max = float(df['High'].max())
min = float(df['Low'].min())
mpf.plot(df, **kwargs,
hlines = dict(hlines=[max, min], linewidths=(.5, .5), colors=('r','r')),
alines = dict(alines=two_points, linewidths=(40), colors=('b'), alpha=0.2))
うん,教科書のような?右肩上がり
まとめると
import numpy as np
import pandas as pd
import pandas_datareader.data as pdr
import datetime
from dateutil.relativedelta import relativedelta
import mplfinance as mpf
from sklearn.linear_model import LinearRegression
my_df = pd.read_excel('my.xlsx', sheet_name = 'Sheet1', dtype = str)
topix_df = pd.read_excel('data_j.xls', dtype = str)
code_set = set(my_df['コード'].tolist())
df = topix_df[topix_df['コード'].isin(code_set)]
code = df['コード'].tolist()[1]
company = df['銘柄名'].tolist()[1]
ed = datetime.datetime.now() # 本日
st = ed - relativedelta(months = 12) # 12か月前
df = pdr.DataReader(code + '.T', 'yahoo', st, ed)
# fitでモデルを作成
linearModel = LinearRegression()
linearModel.fit(X = np.arange(len(df.index)).reshape(-1,1), y = df['Close'].values)
# 係数
coef = linearModel.coef_[0]
# 切片
intercept = linearModel.intercept_
# 係数と切片
#(coef, intercept)
# 係数
coef = linearModel.coef_[0]
# 切片
intercept = linearModel.intercept_
# predict で予測値を出す
predict = linearModel.predict(X = np.arange(len(df.index)).reshape(-1,1))
# 全部の点を結ぶ線を引く場合は
#multi_points = [(pd.to_datetime(idx), price) for idx, price in zip(df.index.values, predict)]
# 2点を結ぶ線を引く場合は
multi_points = [(pd.to_datetime(df.index.values[0]), predict[0]), (pd.to_datetime(df.index.values[-1]), predict[-1])]
# チャート描画
kwargs = dict(type = 'candle', style = 'starsandstripes', title = code)
max = float(df['High'].max())
min = float(df['Low'].min())
mpf.plot(df, **kwargs,
hlines = dict(hlines=[max, min], linewidths=(.5, .5), colors=('r','r')),
alines = dict(alines=multi_points, linewidths=(40), colors=('b'), alpha=0.2))
おわりに
今回のトヨタの例は,きれいな右肩上がりだったのでトレンドラインを描くまでもなかったが
複数の銘柄のトレンドラインを並べて表示するような場合は
トレンド判断が一瞬でできそうなので良いなと思った
次回こそ,前回宣言した通り,
MACDやボリンジャーバンドを描いたり,
複数銘柄を並べて描くようなことをやってみたい