ローソク足を複数組み合わせたアルゴリズムを作る

#はじめに
[QuantX Factory]()では、talibを用いて、ローソク足を用いた株売買アルゴリズムを作ることが出来ます。
[こちら]()の記事では、ローソク足とテクニカル指標を組み合わせたアルゴリズムを紹介しています。
今回は、複数のローソク足を使って売買シグナルを出すアルゴリズムを紹介したいと思います。

#アルゴリズム
このアルゴリズムでは、赤三兵、黒三兵をアレンジしたいと思います。

```python
# 必要なライブラリーをimportする
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
import pandas as pd
import talib as ta
import numpy as np

# オーダ方法を決定する
ot = maron.OrderType.MARKET_OPEN   # シグナルがでた翌日の始値のタイミングでオーダー

# 銘柄、columnsの取得を行う
# 初期化を行う
def initialize(ctx):
  ctx.configure(
    channels={               # 利用チャンネル
      "jp.stock": {
        "symbols": [
          "jp.stock.2914", #JT(日本たばこ産業)
          "jp.stock.8766", #東京海上ホールディングス
          "jp.stock.8031", #三井物産
          "jp.stock.8316", #三井住友フィナンシャルグループ
          "jp.stock.8411", #みずほフィナンシャルグループ
          "jp.stock.9437", #NTTドコモ
          "jp.stock.4502", #武田薬品工業
          "jp.stock.8058", #三菱商事
          "jp.stock.9433", #KDDI
          "jp.stock.9432", #日本電信電話
          "jp.stock.7267", #ホンダ（本田技研工業）
          "jp.stock.8306", #三菱ＵＦＪフィナンシャル・グループ
          "jp.stock.4503", #アステラス製薬
          "jp.stock.4063", #信越化学工業
          "jp.stock.7974", #任天堂
          "jp.stock.6981", #村田製作所
          "jp.stock.3382", #セブン＆アイ・ホールディングス
          "jp.stock.9020", #東日本旅客鉄道
          "jp.stock.8802", #三菱地所
          "jp.stock.9022", #東海旅客鉄道
          "jp.stock.9984", #ソフトバンクグループ
          "jp.stock.6861", #キーエンス
          "jp.stock.6501", #日立製作所
          "jp.stock.6752", #パナソニック
          "jp.stock.6758", #ソニー
          "jp.stock.6954", #ファナック
          "jp.stock.7203", #トヨタ自動車
          "jp.stock.7751", #キヤノン
          "jp.stock.4452", #花王
          "jp.stock.6098", #リクルートホールディングス
        ],
        "columns": [
          "open_price_adj",    # 始値(株式分割調整後)
          "high_price_adj",    # 高値(株式分割調整後)
          "low_price_adj",     # 安値(株式分割調整後)
          "close_price",     # 終値
          "close_price_adj", # 終値(株式分割調整後)
          #"volume_adj",     # 出来高
          #"txn_volume",     # 売買代金
        ]
      }
    }
  )
  
  # シグナル定義
  def _my_signal(data):
    # 終値等の取得を行い、欠損値補完を行う。
    cp =  data["close_price_adj"].fillna(method='ffill')
    op =  data["open_price_adj"].fillna(method= 'ffill')
    hp = data["high_price_adj"].fillna(method="ffill")
    lp = data["low_price_adj"].fillna(method="ffill")
    
    # ローソク足についてを計算
    candle_1 = pd.DataFrame(data=0,columns=[], index=cp.index)
    for(sym,val) in cp.items():
      candle_1[sym] = ta.CDLMARUBOZU(op[sym],hp[sym],lp[sym],cp[sym])
      
    # true,falseのbool型にする
    candle_1_buy = candle_1[(candle_1 == 100)]
    candle_1_sell = candle_1[(candle_1 == -100)]
    candle_1_buy[(candle_1 == 100)] = True
    candle_1_sell[(candle_1 == -100)] = False

    # 売買シグナルを定義(bool値で返す)
    buy_sig = candle_1_buy & candle_1_buy.shift(1)
    sell_sig = candle_1_sell 

    # market_sigという全て0が格納されているデータフレームを作成
    market_sig = pd.DataFrame(data=0.0, columns=cp.columns, index=cp.index)
    
    # buy_sigがTrueのとき1.0、sell_sigがTrueのとき-1.0とおく
    market_sig[buy_sig == True] = 1.0
    market_sig[sell_sig == True] = -1.0
    market_sig[(buy_sig == True) & (sell_sig == True)] = 0.0

    return {
      "market:sig": market_sig,
      "candle:1":candle_1
    }
      
  # シグナル登録
  ctx.regist_signal("my_signal", _my_signal)

def handle_signals(ctx, date, current):
  '''
  current: pd.DataFrame
  '''
  market_sig = current["market:sig"]

  done_syms = set([])
  
  # 損切り、利確の設定
  for (sym, val) in ctx.portfolio.positions.items():
    returns = val["returns"]
    if returns < -0.03:
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="損切り(%f)" % returns)
      done_syms.add(sym)
    elif returns > 0.05:
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
      done_syms.add(sym)
      

  # 買シグナルについて注文方法を設定する
  buy = market_sig[market_sig > 0.0]
  for (sym, val) in buy.items():
    if sym in done_syms:
      continue
    
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
    #ctx.logger.debug("BUY: %s,  %f" % (sec.code(), val))
    pass
    
  # 売シグナルも同様に行う
  sell = market_sig[market_sig < 0.0]
  for (sym, val) in sell.items():
    if sym in done_syms:
      continue
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")
    #ctx.logger.debug("SELL: %s,  %f" % (sec.code(), val))
    pass
```


#アルゴリズムの解説
基本的なアルゴリズムの仕組みは[公式ドキュメント](https://factory.quantx.io/handbook/ja/api.html)や[前回の記事](https://qiita.com/Miku_F/items/c7edef3b03c2048ffe2a)と同じなので、今回はこのアルゴリズムの特徴的なところを紹介したいと思います。


今回作りたいのは、
![赤三兵 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378059/b87db82f-36f4-8b6a-4b89-3ee74187ab29.png)
になります。(https://ottopilotmedia.com/chart/rousoku-pattern)

talib には、複数本のローソク足を組み合わせてセットになったものがいくつかありますが、今回は練習のためと、赤三兵はtalibには、用意されていなかったので、このセットを作ってみたいと思います。

使ったローソク足は[こちら](https://qiita.com/Mea/items/e0f091367e2ce32144c0)にて紹介されている、丸坊主のローソク足組み合わせました。

今回のアルゴリズムは基本的な形をしていますが、他のアルゴリズムと比べて特徴的なところは以下になります。

```python
  def _my_signal(data):
    # 終値等の取得を行い、欠損値補完を行う。
    cp =  data["close_price_adj"].fillna(method='ffill')
    op =  data["open_price_adj"].fillna(method= 'ffill')
    hp = data["high_price_adj"].fillna(method="ffill")
    lp = data["low_price_adj"].fillna(method="ffill")
    
    # ローソク足についてを計算
    candle_1 = pd.DataFrame(data=0,columns=[], index=cp.index)
    for(sym,val) in cp.items():
      candle_1[sym] = ta.CDLMARUBOZU(op[sym],hp[sym],lp[sym],cp[sym])
      
    # true,falseのbool型にする
    candle_1_buy = candle_1[(candle_1 == 100)]
    candle_1_sell = candle_1[(candle_1 == -100)]
    candle_1_buy[(candle_1 == 100)] = True
    candle_1_sell[(candle_1 == -100)] = False

    # 売買シグナルを定義(bool値で返す)
    buy_sig = candle_1_buy & candle_1_buy.shift(1)
    sell_sig = candle_1_sell & candle_1_sell.shift(1)
```

赤三兵では買シグナルを出します。
今回は、使用しているローソク足の種類も同じなので、新たに candle_2 を定義することなく、candle_1を組み合わせて、buy_signalを出していきます。
実際には、

```python
    # 売買シグナルを定義(bool値で返す)
    buy_sig = candle_1_buy & candle_1_buy.shift(1)
    sell_sig = candle_1_sell & candle_1_sell.shift(1)
```

というコードになります。
pandas のメソッドを使って、2日連続で、丸坊主が出ているときに買うというシグナル生成いたしました。
写真上では3つ連続の時になっていますが、3つにすると制約的に厳しくなり、シグナルが出にくくなるので、今回は2つにしました。

売シグナルも同様の操作を行います。


#まとめ
このアルゴリズムをTOPIX Core 30で行ったものが以下になります。

![赤三兵損益率 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378059/adf0e521-70d0-7f58-2447-13aff3f0203c.png)

あまりシグナルが出ず、取引が行われませんでした。
次回は色々な指標を組み合わせて、複数のものから判断できるアルゴリズムを検討してみたいと思います！