株価バカ上げにちなんでシステムトレードの入り口Stochastic Oscillatorをやってみた。pythonコードは参考①にあるので、3年前のコードだから、まんまだと思っていたらほぼ動かない。
ということで、忘れないように記事にまとめておこうと思う。
【参考】
①Investing with Python: Stochastic Oscillator
②ImmediateDeprecationError of Google Finance data #587
③pandas.core.window.rolling.Rolling.min
やったこと
・シストレ入門
・コードを動かす
・今はどうなの
・シストレ入門
基本は
①下がったら買う
②上がったら売る
ということをシステムで自動化できればOKです。
①はこれ以上下がらないか
②はこれ以上上がらないか
ってリスクがあるので、それも見極めたいところです。
この見極めでよく使われるのが参考①に示されているStochastic Oscillatorのグラフを使うという方法があり、今回はこれを利用出来るようにコード化することを記載します。
The Stochastic Oscillator is calculated as follows:
%K = (Current Close - Lowest Low)/(Highest High - Lowest Low) * 100
%D = 3-day SMA of %K
Lowest Low = ルックバック期間の最低値(lowest low for the look-back period)
Highest High = ルックバック期間の最高値(highest high for the look-back period)
3-day SMA = 3日単純移動平均(simple moving average)
ルックバック期間としては、通常14日が使われる。
単純移動平均の求め方は以下のとおり
SMA(n) = \frac {\sum_{i=0}^{n-1}(CLOSE_i)} {n}
【参考】
④企業の業績を把握するために株式を分析する
・コードを動かす
実は参考①のコードは動きません。
おまけにYahooFinanceがスクレイピング禁止です。
※参考②をじっくり読めばできます
ということで、以下の参考情報を利用して指定銘柄で同じことを行いました。
【参考】
⑤最新の日本株価を 無料かつ高速で取得する 【Python】
利用するLibは以下のとおりです。
データは以下から取得
・https://stooq.com/
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
from pandas_datareader import data
yahooやgoogle、その他有料サイトでは日付を指定して取得できますが、このサイトだとend日の指定が使えません。しかし以下のとおり、取得したデータから必要なものを抽出することにより同じ関数として機能します。またデータ並びが反転しているので反転しています。
【参考】
⑥Pandas でデータフレームから特定の行・列を取得する
⑦Right way to reverse pandas.DataFrame?
def get_stock(stock,start,end):
    df = data.DataReader(stock, 'stooq',start)["Close"]
    df = df.iloc[::-1]
    return df[start:end]
def get_high(stock,start,end):
    df = data.DataReader(stock, 'stooq',start)['High']
    df = df.iloc[::-1]
    return df[start:end]
def get_low(stock,start,end):
    df = data.DataReader(stock, 'stooq',start)['Low']
    df = df.iloc[::-1]
    return df[start:end]
以下で上記の%Kを計算します。
ここでpandasのrolling().max()が変更になっており、参考③により以下のようにすると計算できます。
def STOK(close, low, high, n): 
    STOK = ((close - low.rolling(n).min()) / (high.rolling(n).max() - low.rolling(n).min())) * 100
    return STOK
以下が%Dを計算する関数です。
%Kを計算して3日単純移動平均を計算しています。
def STOD(close, low, high, n):
    STOK = ((close - low.rolling(n).min()) / (high.rolling(n).max() - low.rolling(n).min())) * 100
    STOD = STOK.rolling(3).mean()
    return STOD
銘柄はsonyを使います。
期間は、上記の参考①と同じ期間を使っています。
そもそも%K,%Dの振り返る日数も14日としています。
stock = '6758.JP' #sony
start = dt.date(2016,1,1)
end = dt.date(2016,12,31)
df = pd.DataFrame(get_stock(stock, start, end))
df['High'] = get_high(stock, start, end)
df['Low'] = get_low(stock, start, end)
df['%K'] = STOK(df['Close'], df['Low'], df['High'], 14)
df['%D'] = STOD(df['Close'], df['Low'], df['High'], 14)
以下で確認のためにデータを出力してみます。
print(df[0:30])
print(df.tail())
              Close     High      Low         %K         %D
Date
2016-01-04  2875.56  2981.55  2859.04        NaN        NaN
2016-01-05  2880.90  2916.39  2849.30        NaN        NaN
...
2016-01-21  2363.56  2506.53  2363.06        NaN        NaN
2016-01-22  2458.85  2470.05  2405.86  15.487720        NaN
2016-01-25  2468.09  2498.74  2439.42  18.493802        NaN
2016-01-26  2363.06  2408.78  2359.66   0.595113  11.525545
2016-01-27  2442.81  2453.99  2409.75  18.250258  12.446391
...
2016-02-15  2379.61  2408.29  2293.05  34.207540  16.258774
2016-02-16  2415.11  2459.84  2316.39  39.242858  27.149584
              Close     High      Low         %K         %D
Date
2016-12-26  3261.97  3293.31  3260.04  65.381424  70.155819
2016-12-27  3253.17  3264.93  3237.51  59.458713  65.992247
2016-12-28  3266.87  3296.23  3249.25  62.741071  62.527069
2016-12-29  3228.71  3261.97  3196.41  22.300469  48.166751
2016-12-30  3205.22  3240.46  3192.49   8.557408  31.199649
              Close     High      Low         %K         %D
最後に以下でグラフ出力します。
%Dは15日分(そもそも土日はデータが無い)のデータが欠損するので、16日目からプロットすることにより、ax1,ax2の横軸を合わせます。
fig, (ax1,ax2) = plt.subplots(2,1,figsize=(1.6180 * 4, 4*1))
ax1.plot(df['Close'][16:],label = "close")
ax2.plot(df['%K'][16:],label = "%K")
ax2.plot(df['%D'][16:],label = "%D")
ax1.legend()
ax2.legend()
ax1.grid()
ax2.grid()
plt.savefig("./stock/stc_%K%D_6758.png")
plt.show()
結果は以下のとおりになりました。

なんか安心できないので、参考サイトと同じ出力も出してみます。
"FB"の2016年のチャートが再現出来て、かつ%K,%Dのグラフも同じものが得られました。

ちなみに、FB社の2016年の株価は参考⑧で確認できます。
まあ、これらのチャートからどうするのは以下の参考⑨などを見てください。参考⑨のGoogle翻訳して引用します。
「80を超える場合、市場は買われ過ぎと見なされ、20未満の値は売られ過ぎ状態と見なされます。%K(下のグラフの青い線)と%D(下の赤い線)。これらの2つの線が交差する場合、市場の方向性の変化が近づいていることを示しています。 %Kが%Dを上回れば、値が80を超えない限り、それは買いシグナルです。また、%Kが%Dを下回ると、値が20を下回らない限り、売りシグナルと見なされます」
【参考】
⑧フェイスブック (Facebook, Inc.) 株価/米国株
⑨A trader’s guide to the stochastic oscillator
・今はどうなの
Sony;買場たくさんあるね...ちょっと買われすぎ...

日本航空9201;買われすぎだったんだ...でも月曜日は買える?

三井住友フィナンシャルグループ8316;うーん買われすぎ...

NTTドコモ9437;売られすぎで青が上に来たら買いだね♬

コード全体は以下に置きました
使いやすいから、使おう
・stock_trade/stc2.py
まとめ
・stocastic Oscilatorを描いて遊んでみた
・本気で使えるような気がする
・インディケーターつけるかな
・シストレやるかな
・これだと売買手数料で破産しそう、長周期で見る工夫がいりそう
おまけ
・YahooFinanceはスクレイピング禁止
Yahoo!ファイナンス掲載情報の自動取得(スクレイピング)は禁止しています