移動平均とRSIを組み合わせたアルゴリズム #QuantX 

## 移動平均+RSI

先日，[RSIのアルゴリズム](https://qiita.com/shinseitaro/items/6a699cf795c7254b0c84)を[QuantX](https://factory.quantx.io/)で書いてみましたが，今回はRSIに移動平均を組み合わせたアルゴリズムを書いてみます．

ストラテジーの基本方針は，
1. 複数の移動平均を使う
2. 移動平均をみて，上昇トレンドであるかどうか確認
3. 全移動平均よりも今日のロウソク足の位置が上にあることを確認
4. 短期移動平均＞中期移動平均＞長期移動平均という位置関係にあるか確認
5. 上記の条件が揃っている間はロングポジションを保持
6. ただし，RSIが90に入るような事があれば，ポジション解消
7. もしくは，RSIが60を切った場合は，ポジション解消
 

ここで，「移動平均をみて，上昇トレンドであるかどうか確認」をどのように表現するか考えてみます．図は日経平均株価の2017年10月頃のチャートに，5日25日75日の移動平均をプロットした図です．

![](https://www.tradingview.com/x/ET9Pa1Nv/)

上記図より，上昇トレンドとは，3つの移動平均線が前日よりも高い位置にあること，と定義することにします．よってここでは，**移動平均の前日比が3日連続ポジティブである**という事を上昇トレンドであるという判断に使いたいと思います．

## シグナル

上記1から5の条件が揃っている間は買い持ち．

## 手仕舞い

上記6,7が発生した時

## コード

```python
import numpy as np 
import talib as ta 

def initialize(ctx):
    # 設定
    ctx.ma_shortterm = 5 
    ctx.ma_midterm = 25
    ctx.ma_longterm = 75
    
    ctx.target = 0.10
    ctx.period = 5
    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": ["open_price_adj",    # 始値(株式分割調整後)
                      "close_price_adj",    # 終値(株式分割調整後) 
                     ]}})

    def _MYSIGNAL(data):
      
      df_open = data["open_price_adj"].fillna(method='ffill')
      df_close = data["close_price_adj"].fillna(method='ffill')
      
      # 移動平均
      df_sma_short = df_close.rolling(window=ctx.ma_shortterm).mean()
      df_sma_middle = df_close.rolling(window=ctx.ma_midterm).mean()
      df_sma_long = df_close.rolling(window=ctx.ma_longterm).mean()
      
      # 移動平均の前日比が3日連続ポジティブであるかどうか
      # memo 参照
      df_sma_short_uptrend = df_sma_short.pct_change().rolling(window=3,).min() > 0 
      df_sma_middle_uptrend = df_sma_middle.pct_change().rolling(window=3,).min() > 0 
      df_sma_long_uptrend = df_sma_long.pct_change().rolling(window=3,).min() > 0 
      df_uptrend = df_sma_short_uptrend & df_sma_middle_uptrend & df_sma_long_uptrend
      
      # 全移動平均よりも今日のロウソク足の位置が上にあることを確認
      # つまり，始値も終値も移動平均線より上に位置していることを確認
      
      df_upper_than_ma = (df_open > df_sma_short) & (df_open > df_sma_middle) & (df_open > df_sma_long) &  (df_close > df_sma_short) & (df_close > df_sma_middle) & (df_close > df_sma_long)
                         
      # 短期移動平均＞中期移動平均＞長期移動平均という位置関係にあるか確認
      df_ma_posion = (df_sma_short > df_sma_middle) &  (df_sma_middle > df_sma_long) 
      
      # RSI>90 もしくは RSI<60 であればポジションクローズ
      df_rsi = df_close.apply(lambda s: ta.RSI(s.values.astype(np.double), timeperiod=ctx.period),axis=0)
      df_position_close_condition = (df_rsi > 90) | (df_rsi < 60)
      
  
      # 買いシグナル
      buy_sig = df_uptrend & df_upper_than_ma & df_ma_posion
      sell_sig = df_position_close_condition
      
      return {

        "buy:sig": buy_sig, 
        "sell:sig": sell_sig, 
          
        }
        
    # シグナル登録
    ctx.regist_signal("MYSIGNAL", _MYSIGNAL)

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-06-13:23:40.jpg](https://qiita-image-store.s3.amazonaws.com/0/14019/359314d7-35bc-aaeb-9465-d6feae402077.jpeg)

## memo 
###移動平均の前日比が3日連続ポジティブであるかどうか
これを確認するために，過去三日間の前日比で1番小さい値がポジティブであるという確認を行いました．
`df_sma_short.pct_change().rolling(window=3,).min() > 0 ` 

## 感想

+ 今まで書いたアルゴリズムの中で今のところ一番いいですね．
+ 銘柄は前回の記事で使った銘柄をそのまま使っているだけなので，このあたりは工夫の余地はあると思います．
+ その他，移動平均の期間，RSIの閾値など，色々試してみる価値はありそうですね．
+ RSIといえば， @kozzy さんの[QuantX 上で RSI による売買アルゴリズムを開発する](https://qiita.com/kozzy/items/06692c4908659f3ca26c#_reference-ebf3bbddd516e1ee105a) が分かりやすいのでオススメです．ぜひご一読下さい．
+ 甲子園始まりましたね．自分の出身地と関係ない高校同士の試合の時は，公立高校もしくは地方の学校を応援するタイプです．

## 免責注意事項
+ このコードに基づき投資した結果、損害が発生しても，一切責任を持ちません．
+ このコードが正しく機能する保証は一切致しません．
このアルゴリズムを勧めているわけではありません．あくまで QuantX / Python のサンプルコードとして掲載しているだけです．