FX、株価などの値動きを見る上で、テクニカル指標はすごく重要です。以前の投稿ではローソク足のチャートをプログラムを使ってシグナルをチェックしましたが、今回は移動平均線などのテクニカル指標をPythonのプログラムで描いて、シグナルをチェックしていきたいと思います。
ローソク足の投稿はこちらを御覧ください
10倍株銘柄のローソク足シグナルをプログラミングで自動察知する
着目するテクニカル指標
テクニカル指標には様々なものがありますが、私の持論としては、
「有名なテクニカル指標 」
=「たくさんの人がその指標を見て取引している」
=「その指標のシグナル部分で多くのが人が取引する」
=「テクニカル指標のシグナルのルール通りに値動きが起こりやすい」
逆に言うと、
「マイナーなテクニカル指標」
=「限られた人しか見ていない」
=「その指標のシグナル部分で取引する人が少ない」
=「テクニカル指標のシグナルがルール通りに値動きしにくい」
と考えています。
これは統計的な考え方で、「取引数が多ければ多いほど、多くの人が認知しているシグナル通りの動きに価格が収束しやすい」ということです。サイコロを10回だけ振るよりも、10万回振った方が1つの目の出る確率が1/6に収束しやすいのと同じ考えになります。
ただ、これは出来高(取引数)が大きい銘柄で言える可能性が高く、出来高が小さいような銘柄は、ファンドや仕手などが資金力でシグナルの動きを無視してチャートを変えられてしまうと思うので、一概には言えないと思います。あくまで個人的な見解です。
ということで、とりあえず有名なテクニカル指標の中で私が重要視しているテクニカル指標を以下にリストアップしました。カッコ内の数字はタイムピリオドを示しています。おおよそSBI証券のグラフのデフォルトの設定です。この数字もできる限り多くの人が利用している数字を用いるのが良いと思います。
- 単純移動平均線(5、25、50、75、100)
- ボリンジャーバンド(25)
- 一目均衡表(基準線26、転換線9、遅行スパン26、先行スパン1 26、先行スパン2 26)
- MACD(12、26、シグナル9)
- RSI(9、14)
- RCI(9)
- 価格帯別出来高
Pythonで株価のテクニカル指標のグラフを描く
必要なモジュールのインポート
例の如く必要なモジュールをインポートします。今回もTA-Libを活用したいと思います。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import talib
import datetime
import pickle
株価データの読み込み
株価のデータを読み込みます。今回は3992 ニーズウェルという銘柄を使って確認します。
株価の取得方法は以前の投稿をご確認ください。
【Python】スクレイピングで株価データを取得する
k,v = '3992','ニーズウェル'
load_directory = 'kabuka'
load_path = load_directory + '/{}-{}.pkl'.format(k,v)
with open(load_path, mode='rb') as f:
df = pickle.load(f)
Pythonを用いて株価のテクニカル指標を計算して、グラフを描く
まずはデータをTA-Libに渡しやすいように分けます。
open = df['始値']
high = df['高値']
low = df['安値']
close = df['終値']
volume = df['出来高']
次にTA-Libの関数を用いて、移動平均、ボリンジャーバンド、MACD、RSIをそれぞれ以下のコードで計算します。
#Simple Moving Average
sma5 = talib.SMA(close, timeperiod=5)
sma25 = talib.SMA(close, timeperiod=25)
sma50 = talib.SMA(close, timeperiod=50)
sma75 = talib.SMA(close, timeperiod=75)
sma100 = talib.SMA(close, timeperiod=100)
#Bollinger Bands
upper1, middle,lower1 = talib.BBANDS(close, timeperiod=25, nbdevup=1, nbdevdn=1, matype=0)
upper2, middle, lower2 = talib.BBANDS(close, timeperiod=25, nbdevup=2, nbdevdn=2, matype=0)
upper3, middle, lower3 = talib.BBANDS(close, timeperiod=25, nbdevup=3, nbdevdn=3, matype=0)
#MACD - Moving Average Convergence/Divergence
macd, macdsignal, macdhist = talib.MACD(close, fastperiod=12, slowperiod=26, signalperiod=9)
#RSI - Relative Strength Index
rsi9 = talib.RSI(close, timeperiod=9)
rsi14 = talib.RSI(close, timeperiod=14)
それぞれ正しく計算されているかグラフを描いてみましょう。
移動平均線
plt.plot(sma5,label='sma5')
plt.plot(sma25,label='sma25')
plt.plot(sma50,label='sma50')
plt.plot(sma75,label='sma75')
plt.plot(sma100,label='sma100')
plt.xlabel('index')
plt.ylabel('price')
plt.legend()
plt.show()

ボリンジャーバンド
plt.plot(upper1,label='upper1')
plt.plot(lower1,label='lower1')
plt.plot(upper2,label='upper2')
plt.plot(lower2,label='lower2')
plt.plot(upper3,label='upper3')
plt.plot(lower3,label='lower3')
plt.xlabel('index')
plt.ylabel('price')
plt.legend()
plt.show()

MACD
plt.plot(macd,label='macd')
plt.plot(macdsignal,label='macdsignal')
plt.bar(macdhist.index,macdhist ,label='macdhist')
plt.xlabel('index')
plt.ylabel('indicator value')
plt.legend()
plt.show()

RSI
plt.plot(rsi9,label='rsi9')
plt.plot(rsi14,label='rsi14')
plt.xlabel('index')
plt.ylabel('indicator value')
plt.legend()
plt.show()

一目均衡表
一目均衡表はTA-Libの関数に含まれていないので、自分で作成する必要があります。
下のように関数を定義しました。
他のデータとインデックスずれやすいのでその点が注意です。
def ichimoku(close):
max9 = close.rolling(9).max()
min9 = close.rolling(9).min()
max26 = close.rolling(26).max()
min26 = close.rolling(26).min()
max52 = close.rolling(52).max()
min52 = close.rolling(52).min()
kijun = (max26 + min26) / 2
tenkan = (max9 + min9) / 2
chiko = close.copy()
chiko_index = np.arange(-26,len(close)-26)
chiko.index = chiko_index
senko1 = (tenkan + kijun) / 2
senko2 = (max52 + min52) / 2
senko_index = np.arange(26,len(close)+26)
senko1.index = senko_index
senko2.index = senko_index
return tenkan,kijun,chiko,senko1,senko2
tenkan,kijun,chiko,senko1,senko2 = ichimoku(close)
一目均衡表のグラフを描くと以下のようになります。雲の網掛けまではできていないのでやや見づらいですが、正しく計算されていると思われます。
plt.plot(tenkan,label='tenkan')
plt.plot(kijun,label='kijun')
plt.plot(chiko,label='chiko')
plt.plot(senko1,label='senko1')
plt.plot(senko2,label='senko2')
plt.xlabel('index')
plt.ylabel('price')
plt.legend()
plt.show()

RCI
RCIもTA-Libの関数には含まれていないので、自分で関数を作成したいと思います。
RCIの計算方法は以下だそうです。
RCI=(1-(6×d)÷(nの3乗-n))×100
マネーパートナーズ:https://www.moneypartners.co.jp/support/tech/rci.html
d:「日付の順位」と「価格の順位」の差を2乗し、合計した数値
n:期間
日付の順位:当日(最新の日付)=1、として遡りながら、2,3,4・・・と順位をつけます
価格の順位:期間中の最高値=1、として、高い順に2,3,4・・・と順位をつけます
結構ややこしいのですが、それをコードにすると以下のようになります。
もう少し格好よく書くこともできると思いますが、一つ一つ何しているかわかりやすいように書いています。1行ずつprint文を入れて確認していただければと思います。
def RCI(close, timeperiod = 9):
rci = []
for j in range(len(close)):
if j < timeperiod:
rci.append(np.nan)
else:
data = pd.DataFrame()
data['close'] = list(close[j-timeperiod:j])
data = data.reset_index()
data = data.rename(columns = {'index':'original_index'}) #最初のindex情報を残しておきます
data = data.sort_values('close',ascending=False).reset_index(drop = True) #closeの値が高い順に並べ替えます
data = data.reset_index() #indexをresetします
data['index'] = [i+1 for i in data['index']] #resetしたindexは0〜8なので、1〜9の順位に変換するために1を足します
data = data.rename(columns = {'index':'price_rank'}) #closeの高い順に並べたindexをprice rankという列名にします
data = data.set_index('original_index') #元のindexに戻します
data = data.sort_index() #元のindexに戻します
data['date_rank'] = np.arange(timeperiod,0,-1) #元のindexに日付順位をつけます
data['delta'] = [(data.loc[ii,'price_rank']-data.loc[ii,'date_rank'])**2 for ii in range(len(data))] #dの値を計算します
d = data['delta'].sum() #dの値を計算します
value = (1-(6*d)/(timeperiod**3-timeperiod))*100 #rciを計算します
rci.append(value)
return rci
rci = RCI(close)
RCIのグラフを書くと以下のようになります。
plt.plot(rci,label='rci')
plt.xlabel('index')
plt.ylabel('indicator')
plt.legend()
plt.show()

今使用しているデータは2019年1月からのデータなのですが、SBIのRCI(9)のグラフと比較しても同じように計算できていることがわかります。

価格帯別出来高
最後に価格帯別出来高ですが、グラフを描くのに結構手こずりました。
そもそも、どの証券会社も価格帯別高の算出方法を明確に記載したりしていないので、正しさは検証できないところではあります。
今回は、取得した全データの最小値から最大値の範囲を40分割くらいし、そのレンジの中の出来高を計算して表示しました。
#1日の平均価格を計算
ave = talib.AVGPRICE(open, high, low, close)
#価格のレンジを確認
minimum = np.floor(ave.min())
maximum = np.ceil(ave.max())
print('価格のレンジ:{}-{}'.format(minimum,maximum))
>> 価格のレンジ:473.0-764.0
#価格のレンジをビン分割する
supposed_bin_num = 40
bin_range = int((maximum - minimum)/supposed_bin_num)
print('各価格帯の刻み:{}'.format(bin_range))
>> 各価格帯の刻み:7
#ビン分割の境界値のリストとリストの長さ
bins = np.arange(minimum,maximum,bin_range)
print('境界値リスト:{}'.format(bins))
print('境界値リスト長さ:{}'.format(len(bins)))
>>
境界値リスト:[473. 480. 487. 494. 501. 508. 515. 522. 529. 536. 543. 550. 557. 564.
571. 578. 585. 592. 599. 606. 613. 620. 627. 634. 641. 648. 655. 662.
669. 676. 683. 690. 697. 704. 711. 718. 725. 732. 739. 746. 753. 760.]
境界値リスト長さ:42
#1日の平均価格をビン分割
cut = pd.cut(ave, bins)
#出来高データと統合
data = pd.DataFrame()
data['cut'] = cut
data['volume'] = volume
#価格帯別の出来高を合計する
dekidaka = data.groupby('cut').sum()
labels = [str(ctgr) for ctgr in dekidaka.index]
plt.figure(figsize = (10,8))
plt.barh(labels,dekidaka['volume'])
plt.xlabel('出来高')
plt.ylabel('価格帯')
plt.show()
上記のコードを実行すると以下のようなグラフが得られると思います。

今回はテクニカル指標のグラフを描くところまでにして、後ほどシグナルのチェックができるようにしていきたいと思います。

