LoginSignup
7
3

More than 5 years have passed since last update.

ストキャスティクスアルゴリズム #QuantX

Last updated at Posted at 2018-08-01

ストキャスティクス

今日は個人投資家の間でも非常に人気があるらしいストキャスティクス(stochastics)をQuantXで書いてみたいと思います.

ストキャスティクスの計算式は非常に簡単で,基本となるファストストキャスティクスは以下の計算式でラインを引き,シグナルを探します.

%K = \frac{直近の終値-過去n日間の最安値}{過去n日間の最高値-過去n日間の最安値} \times 100 \\
%D = m日の%Kの単純移動平均

%K%Dを上抜いたら買い,逆に%K%Dを割り込んだら売りというシグナルになるのが一般的ですが,この %K%Dを使うシグナルは短期売買向きで,長期保有をしたい投資家は,%Dをさらに単純移動平均したSD(Slow D)と%D自身の動きを見るスローストキャスティクスというシグナルを使うそうです.

今回も,TA-LibにStochastic関数があり,
親切にも,ファストストキャスティクスSTOCHF とスローストキャスティクス関数STOCHが用意されていますので,それを利用したいと思います.

シグナル

ファストストキャスティクス

%K%Dを上抜いたら買い,逆に%K%Dを割り込んだら売り

スローストキャスティクス

%DSDを上抜いたら買い,逆に%DSDを割り込んだら売り
ただし,SDが20%〜80%の間にあるときは,シグナルが出ても無視する.(ダマシ減らしの工夫だそうです)
参照:オシレーター分析/ストキャスティクス | はじめてのテクニカル分析 / マネックス証券

手仕舞い

シグナルに書いた売りのタイミングで手仕舞う.

コード

import talib as ta 
import pandas as pd 
import numpy as np 


def initialize(ctx):
    # 設定
    ctx.fastK_period = 20   
    ctx.fastD_period = 3
    ctx.slowK_period = 3 
    ctx.slowD_period = 3 

    ctx.upper_thred = 80 
    ctx.lower_thred = 20 

    ctx.target = 0.10  
    ctx.codes = [1605, 1925, 2503, 4519, 4911, 6301, 6752, 7741, 8001 ]

    ctx.symbol_list  = ["jp.stock.{}".format(code) for code in ctx.codes]

    ctx.configure(
      channels={          # 利用チャンネル
        "jp.stock": {
          "symbols": ctx.symbol_list,
          "columns": [
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price_adj",    # 終値(株式分割調整後) 
          ]}})


    def _STOCHASTIC_FAST(data):
      df_high = data["high_price_adj"].fillna(method='ffill')
      df_low = data["low_price_adj"].fillna(method='ffill')
      df_close = data["close_price_adj"].fillna(method='ffill')

      d_fastK = dict()
      d_fastD = dict()

      for symbol in data.minor_axis:
        fastK, fastD = ta.STOCHF(df_high[symbol].values.astype(np.double), 
                                 df_low[symbol].values.astype(np.double), 
                                 df_close[symbol].values.astype(np.double), 
                                 fastk_period=ctx.fastK_period, 
                                 fastd_period=ctx.fastD_period,)
        d_fastK[symbol] = fastK
        d_fastD[symbol] = fastD

      df_fastK = pd.DataFrame(d_fastK, index=data.major_axis)
      df_fastD = pd.DataFrame(d_fastD, index=data.major_axis)

      buy_sig = (df_fastK > df_fastD) & (df_fastK.shift(1) < df_fastD.shift(1)) 
      sell_sig = (df_fastK < df_fastD) & (df_fastK.shift(1) > df_fastD.shift(1)) 

      return {
        "fastK":df_fastK, 
        "fastD": df_fastD, 
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,
        }


    def _STOCHASTIC(data):

      df_high = data["high_price_adj"].fillna(method='ffill')
      df_low = data["low_price_adj"].fillna(method='ffill')
      df_close = data["close_price_adj"].fillna(method='ffill')

      d_slowK = dict()
      d_slowD = dict()

      for symbol in data.minor_axis:
        slowK, slowD = ta.STOCH(df_high[symbol].values.astype(np.double), 
                                df_low[symbol].values.astype(np.double), 
                                df_close[symbol].values.astype(np.double), 
                                fastk_period=ctx.fastK_period, 
                                slowk_period=ctx.slowK_period, 
                                slowd_period=ctx.slowD_period)

        d_slowK[symbol] = slowK
        d_slowD[symbol] = slowD

      df_slowK = pd.DataFrame(d_slowK, index=data.major_axis)
      df_slowD = pd.DataFrame(d_slowD, index=data.major_axis)      

      buy_sig = (df_slowK > df_slowD) & (df_slowK.shift(1) < df_slowD.shift(1)) & (df_slowD < ctx.lower_thred)
      sell_sig = (df_slowK < df_slowD) & (df_slowK.shift(1) > df_slowD.shift(1)) & (df_slowD > ctx.upper_thred)


      return {
        "slowK": df_slowK, 
        "slowD": df_slowD,
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,        
        }


    # シグナル登録 memo 参照
    ctx.regist_signal("STOCHASTIC_FAST", _STOCHASTIC_FAST)
    #ctx.regist_signal("STOCHASTIC", _STOCHASTIC)


def handle_signals(ctx, date, current):
    df = current.copy()

    # 買いシグナル
    df_long = df[df["buy:sig"]]
    if not df_long.empty:
      for (sym, val) in df_long.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(ctx.target, comment= msg)

    # 売り(ポジションクローズ)シグナル
    df_sell = df[df["sell:sig"]]
    if not df_sell.empty:
      for (sym, val) in df_sell.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "売りシグナル"
        sec.order_target_percent(0, comment= msg)

結果

ファストストキャスティクス

2018-08-01-16:16:50.jpg

スローストキャスティクス

2018-08-01-16:17:28.jpg

memo

シグナル登録

今回はファスト用とスロー用のシグナルを作って,regist_signal関数に一つ渡す(一つはコメントアウト)という形を取りました.一つずつお試しください.

感想

  • 夏休み子ども科学電話相談は毎年聞いています.恐竜キッズには全くついていけません.
  • もし電話して質問できるなら,ゴジラが火を吹く仕組みを教えてもらいたいです.
  • 今回の銘柄選びは,セクターが重ならないように選びました.
  • スローとファストを比べて,たしかに,スローの方が成績が良いことは確認出来ました.これは研究しがいがありそうですね.
  • SDが20%〜80%の間にあるときは,シグナルが出ても無視」は非常に重要なようです.これを外すとかなり成績が悪くなります.

免責注意事項

  • このコードに基づき投資した結果、損害が発生しても,一切責任を持ちません.
  • このコードが正しく機能する保証は一切致しません.
  • このアルゴリズムを勧めているわけではありません.あくまで QuantX / Python のサンプルコードとして掲載しているだけです.
7
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
7
3