LoginSignup
5
3

More than 5 years have passed since last update.

上放れタスキのアルゴリズム #QuantX

Last updated at Posted at 2018-07-30

上放れタスキ

image.png

[出典]上放れタスキ | 銘柄・株スクリーニング | 投資顧問比較ナビ

今回は,上放れタスキというシグナルをQuantXで書いてみたいと思います.

上放れタスキとは、上昇トレンドにおいて,窓を開けて上昇した陽線が出現し、翌日に窓を開けずに安寄りした陰線が現れた状態のチャートだそうです.
チャート画像を見ると,あ〜はん:smirk:とわかった気になるのですが,DataFrameではどう表現すればいいのでしょうか?

条件

自分なりに考えてみました.

トレンド

上昇トレンドであること.
具体的には,日足の変化率を過去5日間観察し,毎日ポジティブであること.

直近3日

(以下,t-2,t-1,t0 日と表現する)

  1. t-2の高値よりt-1の安値が高い
  2. t-1の陽線が,過去100日の陽線の長さの2倍以上(必要?)
  3. t0の始値がt-1の始値を上回っいて,かつt0は陰線
  4. t0の安値がt-2の高値を上回っている

シグナル

上記の条件が発生したt2の終値でシグナルを出すことにします.ただし,過去5日間(=ホールド期間)に既にシグナルが発生していた場合は,不採用とします.

手仕舞い

シグナルが出てから5日間ホールドして、クローズすることにします。

コード

import talib as ta 
import numpy as np 


def initialize(ctx):
    # 設定
    ctx.up_trend_term = 5 
    ctx.yousen_term = 100
    ctx.yousen_threshold = 1.0 
    ctx.holding_days = 5 
    ctx.target = 0.50

    # 銘柄設定 memo参照
    ctx.codes = [6758, 8316, 2914, 7267, 7182, 8058, 8411, 4063, 7751, 5411,
                 6981, 6902, 3382, 8766, 6367, 6752, 4911, 8001, 6301, 6503, 
                 8031, 5108, 4519, 4578, 1925, 2502, 8801, 2503, 8750, 6273, 
                 7741, 7270, 6971, 4901, 8053, 6869, 6502, 8113, 8725, 8267, 
                 9843, 1605, 6723, 4612, 6702, 9021, 8308, 7309, 4188, 6762, 
                 4528, 9202, 2413, 7181, 3402, 6586, 3092, 1878, 6988, 1801, 
                 9502]

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

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

    def _TASUKI_GAP(data):

      df_open =  data["open_price_adj"].fillna(method='ffill')
      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')

      # 日足の変化率を過去5日間観察し,毎日ポジティブであることを確認
      df_is_uptrend = df_close.pct_change().rolling(window=ctx.up_trend_term,).min() > 0
      # t-2の高値よりt-1の安値が高い
      df_open_window = df_high.shift(2) < df_low.shift(1)

      # t-1の陽線が,過去100日の陽線の長さの2倍以上(必要?)
      # memo 参照
      df_intraday = df_close / df_open - 1 
      df_MA_yousen = df_intraday.where(df_intraday>0).rolling(window=ctx.yousen_term, min_periods=1).apply(np.nanmean)
      df_is_yousen_long = df_intraday.shift(1) > df_intraday.shift(2) * ctx.yousen_threshold 

      # t0の始値がt-1の始値を上回っいて,かつt0は陰線
      df_tasuki = (df_open > df_open.shift(1)) & (df_open > df_close) 
      # t0の安値がt-2の高値を上回っている
      df_is_trend_continue = df_low > df_high.shift(2)

      df_uwabure_tasuki = df_is_uptrend & df_open_window & df_is_yousen_long & df_tasuki & df_is_trend_continue

      buy_signal = (df_uwabure_tasuki) & (df_uwabure_tasuki.rolling(window=ctx.holding_days, center=False).sum() == 1)
      close_signal = buy_signal.shift(ctx.holding_days)


      return {
        "buy:sig": buy_signal,
        "close:sig": close_signal, 
        }

    # シグナル登録
    ctx.regist_signal("TASUKI_GAP", _TASUKI_GAP)


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(): 
        #ctx.logger.info(val)
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(ctx.target, comment= msg)


    # # ポジションクローズ
    df_position_close = df[df["close:sig"]]
    if not df_position_close.empty:
      for (sym, val) in df_position_close.iterrows(): 
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment= "position close")

memo

銘柄設定

ctx.codes = [6758, 8316, 2914, 7267, 7182, ...]
ctx.syms = ["jp.stock.{}".format(code) for code in ctx.codes[:50]]

format関数を使ってシンボルリストを作りました.
また,QuantXでは最大50銘柄をシミュレーションに組み込む事が出来るので,50を超えないようにctx.codes[:50]としています.

t-1の陽線が,過去100日の陽線の長さの2倍以上

本当にこれが必要かどうかわかりませんが,びよーんと伸びた陽線は気分が高まるので入れてみました.

df_intraday = df_close / df_open - 1 
df_MA_yousen = df_intraday.where(df_intraday>0).rolling(window=ctx.yousen_term, min_periods=1).apply(np.nanmean)
df_is_yousen_long = df_intraday.shift(1) > df_intraday.shift(2) * ctx.yousen_threshold 

df_intraday は始値から終値の変化率を出しています.
df_intraday.where(df_intraday>0)で,df_intradayの正の数だけを残し,負の数はNaNが入るDataFrameを作っています.
そのDataFrameに対して100日移動平均をとっているのですが,np.nanmean を渡してNaNを無視した平均値をとり,かつ min_periods=1を渡して,100日の間に一つでも数値が入っていれば平均値を返すように指示しています.つまり100日の間に99日はNaN,1日だけ0.05があれば,そこで返ってくる数値は0.05になります.

結果

2018-07-29-15:00:48.jpg

感想

  • 銘柄は東証一部上場銘柄を適当に入れました.
  • めったに出現しないと書いてありましたが,確かに出現しませんね.
  • shift を使うとだいたいの事は出来る気がしてきました.
  • 間違ってるかもしれないので,その時はぜひおしえてください:bow_tone1:

免責注意事項

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