LoginSignup
1
3

More than 1 year has passed since last update.

【Python】株価データ分析 株価チャートを描く~mplfinance トレンドライン編~

Last updated at Posted at 2021-11-26

修正(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を保有しているとしている),
image.png
東証上場銘柄一覧(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)

mpl2-1.png

この辺までは,前回やってきたことだ

線形回帰(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))

mpl2-2.png

うん,教科書のような?右肩上がり

まとめると

mplfinance2.py
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やボリンジャーバンドを描いたり,
複数銘柄を並べて描くようなことをやってみたい

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3