QuantX上でTa-libのローソク足のパターン分析を使ったアルゴリズムを作成する

#はじめに
Pythonのモジュールの一つである「Ta-lib」にはローソク足のパターン認識をしてくれる関数があります。詳細は別記事にてまとめてみたいと思っています。

本記事ではQuantX上にてこの関数＋αを用いたアルゴリズムを簡単に書いてみようと思います。

#QuantXとは
https://factory.quantx.io/
SmartTrade社の開発した株の取引アルゴリズム開発用のプラットフォームです。
自分で開発した取引アルゴリズムのバックテストや分析を行うことができます。

############################################################################
# サンプルコード
```code1.py
import pandas as pd
import talib as ta
import numpy as np

def initialize(ctx):
    ctx.logger.debug("initialize() called")
    ctx.configure(
      channels={          
        "jp.stock": {
          "symbols": ["jp.stock.2170",#人材関連
                      "jp.stock.2181",
                      "jp.stock.2412",
                      "jp.stock.3636",
                      "jp.stock.4716",
                      "jp.stock.6098",
                      "jp.stock.4716",
                      "jp.stock.6194",
                      "jp.stock.6550",
                      "jp.stock.1963",#プラント
                      "jp.stock.6366",
                      "jp.stock.6330",
                      "jp.stock.1357",#ダブルインバース
                      
                      ],
          "columns": ["open_price_adj",    # 始値(株式分割調整後)
                      "high_price_adj",    # 高値(株式分割調整後)
                      "low_price_adj",     # 安値(株式分割調整後)
                      "close_price_adj",   # 終値(株式分割調整後)
                      ]}})

    def _my_signal(data):
      op = data["open_price_adj"].fillna(method="ffill")
      cp = data["close_price_adj"].fillna(method="ffill")
      hp = data["high_price_adj"].fillna(method="ffill")
      lp = data["low_price_adj"].fillna(method="ffill")
      MARUBOZU = pd.DataFrame(data=0,columns=[], index=cp.index)
      TSUTSUMISEN = pd.DataFrame(data=0,columns=[], index=cp.index)
      AKASANPEI = pd.DataFrame(data=0,columns=[], index=cp.index)

      for(sym,val) in cp.items():
        MARUBOZU[sym] = ta.CDLMARUBOZU(op[sym], hp[sym], lp[sym], cp[sym])
        TSUTSUMISEN[sym] = ta.CDLENGULFING(op[sym], hp[sym], lp[sym], cp[sym])
        AKASANPEI[sym] = ta.CDL3WHITESOLDIERS(op[sym], hp[sym], lp[sym], cp[sym])
      return {
        "MARUBOZU":MARUBOZU,
        "TSUTSUMISEN":TSUTSUMISEN,
        "AKASANPEI":AKASANPEI,
        }

    # シグナル登録
    ctx.regist_signal("my_signal", _my_signal)

def handle_signals(ctx, date, current):
    '''
    current: pd.DataFrame
    '''

    done_syms = set([])
    MARUBOZU = current["MARUBOZU"].dropna()
    AKASANPEI = current["AKASANPEI"].dropna()
    TSUTSUMISEN = current["TSUTSUMISEN"].dropna()

    buy_sig1 = MARUBOZU[(MARUBOZU == 100) ] 
    sell_sig1 = MARUBOZU[(MARUBOZU == -100)]

    buy_sig2 = AKASANPEI[(AKASANPEI == 100)]
    sell_sig2 = AKASANPEI[(AKASANPEI == -100)]

    buy_sig3 = TSUTSUMISEN[(TSUTSUMISEN == 100)]
    sell_sig3 = TSUTSUMISEN[(TSUTSUMISEN == -100)]


    for (sym,val) in buy_sig1.items():
      sec = ctx.getSecurity(sym)
      sec.order_target_percent(0.0, comment="MARUBOZU BUY")

    for (sym,val) in sell_sig1.items():
      sec = ctx.getSecurity(sym)
      sec.order_target_percent(0, comment="MARUBOZU SELL")

    for (sym,val) in buy_sig2.items():
      sec = ctx.getSecurity(sym)
      sec.order_target_percent(0.10, comment="AKASANPEI BUY")

    for (sym,val) in sell_sig2.items():
      sec = ctx.getSecurity(sym)
      sec.order_target_percent(0, comment="AKASANPEI SELL")

    for (sym,val) in buy_sig3.items():
      sec = ctx.getSecurity(sym)
      sec.order_target_percent(0.10, comment= "TSUTSUMISEN BUY")

    for (sym,val) in sell_sig3.items():
      sec = ctx.getSecurity(sym)
      sec.order_target_percent(0, comment="TSUTSUMISEN SELL")

#    for (sym,val) in ctx.portfolio.positions.items():
#      returns = val["returns"]
#      if returns < -0.05:
#        sec = ctx.getSecurity(sym)
#        sec.order(-val["amount"], comment="損切り(%f)" % returns)
#        done_syms.add(sym)
  
```
#ローソク足について
今回プログラムを書くにあたって使用したローソク足の基礎知識と、そのパターンについて解説します。

ローソク足には、ある期間で区切った時の「始値」「終値」「高値」「安値」の4つの情報が含まれています。
それを図示したものがこちらです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/296633/720bfaab-6726-f69a-5ab0-5817f6ae9021.png)


始値より終値が高いものを陽線、その逆を陰線と呼びます。
上下に飛び出たものをひげと呼びます。4つの値の内一致するものがあれば、ひげや実体がなくなることもあります。

これらを時系列で並べると、上昇シグナルや下降シグナルを発見することができます。

#赤三兵
実体の重なった陽線が3本連続で並んだ状態です。始値、終値が共に切りあがっています。強気の相場で現れることが多いですが、高値圏で現れると天井を示す場合もあります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/296633/0d9ecefe-7a6f-842a-3018-6585cf7018d5.png)


#丸坊主
ひげがほとんどない陽線、もしくは陰線です。陽線の場合は強い買いシグナル、陰線の場合は売りシグナルを示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/296633/5bd6d320-41e6-9cca-c428-c93f4129a465.png)

#包み線(抱き線)
前日の陰線を完全に包み込む形で現れた陽線です。強い買いシグナルといわれており、特に安値圏で発生した場合は相場の転換点となる場合もあります。一方陽線を陰線が包み込んでいる場合は売りシグナルとなります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/296633/c220db8f-49b1-81df-0755-e331eb7c3ee1.png)



#プログラムの解説
Ta-libの関数の中にはCDL~で始まるものがあります。
(Ta-libの関数の一覧は[こちら](http://ta-lib.org/function.html))
これらはローソク足にパターンを認識する関数で、以下のように記述します。

```example.py
import talib as ta
integer = ta.CDLxxx([始値], [高値], [安値], [終値])
```
帰り値はそのパターンが陽線で検出された場合は100,
陰線の場合は-100となります。

今回検出した3パターンのローソク足の配列は以下の関数で検出しています。
      
```example.py
        MARUBOZU[sym] = ta.CDLMARUBOZU(op[sym], hp[sym], lp[sym], cp[sym])        #丸坊主
        AKASANPEI[sym] = ta.CDL3WHITESOLDIERS(op[sym], hp[sym], lp[sym], cp[sym]) #赤三兵
        TSUTSUMISEN[sym] = ta.CDLENGULFING(op[sym], hp[sym], lp[sym], cp[sym])    #包み線
```

さて、まずは陽線でこれらが検出された時に買い、陰線で検出された時に売り、としてバックテストを行ってみましょう。

#結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/296633/dada997f-1db1-3a05-62f1-f0af6320b03d.png)

日経の下げの影響を受けにくいが、利益も大きくなりにくい。

#戦略
・丸坊主で買うと高値掴みになるのでは？(逆に売ると安値で売らされているのでは？)
→丸坊主に関するシグナルをなくしてみる。

#結果2
![image.png](https://qiita-image-store.s3.amazonaws.com/0/296633/b07addb1-c18f-c1e3-3a33-034517cb6eea.png)
利益は大きくなったが、ドローダウンも大きくなった。




#考察
今回は3種類のローソク足しか使っていませんが、Ta-libにはほかにも多くのローソク足を認識できる関数があります。それらの組み合わせにより、結果はさらに改良することができると思います。