QuantXでDMIの実装　#QuantX

#DMIとは何か?
DMIは、終値の比較ではなく、当日の高値安値が前日の高値安値に比べてどちらが大きいかということを基準に相場の強弱を判断します。株価が上昇トレンドの場合は、前日の高値を当日の高値が更新することが多いことや、株価が下降トレンドの場合は、前日の安値を当日の安値が更新することが多いことなどによりトレンドが変化することを利用したものです。

##DMIで使う指標は？
・＋DI（プラスの方向性指数）
・－DI（マイナスの方向性指数）
・ADX（トレンドの強弱を測る指数）
・ADX-R（トレンドの強弱を測る指数 ADXの期間を変えたもの）

##指標の計算方法
###+DI
```
＋DI ＝ ＋DM ÷ TR

＋DM ＝ 当日の高値 – 前日の高値

TR ＝
・当日の高値 – 当日の安値
・当日の高値 – 前日の終値
・前日の終値 – 当日の安値
の中から最大となるものを使う。
```

###-DI
```
－DI ＝ －DM ÷ TR

－DM ＝ 前日の安値 – 当日の安値

TR ＝
・当日の高値 – 当日の安値
・当日の高値 – 前日の終値
・前日の終値 – 当日の安値
の中から最大となるものを使う。
```

###ADX
```
ADX ＝ DXの平均値

DX ＝ ｛（＋DI）－（－DI）｝ ÷ DIの合計

※ADXの計算期間が14日の場合は、14日分のDXを足して14で割る
```

###ADX-R
```
ADX ＝ DXの平均値

DX ＝ ｛（＋DI）－（－DI）｝ ÷ DIの合計

※ADXと計算方法は基本的に同じ、期間を28日など長めに設定する
```
TA-Libに全部あるので計算はそっちに任せましょう。

##売買シグナル
上昇トレンドと下落トレンドを見極める場合は「＋DIと－DIの２本の線」を使います。

＋DIが－DIを下から上に上抜いたら買いシグナル、逆に＋DIが－DIを上から下に下抜いたら売りシグナルとなります。

補助的な意味でADXとADX-Rを使います。
トレンドが強い・・・ADXがADX-Rを下から上抜いた時。
トレンドが弱い・・・ADXがADX-Rを上から下抜いた時。

ADX単体でもトレンド判定はできます。

##コードの実装
https://factory.quantx.io/developer/977a1020c4784e1aa6e8a3f204de9561

```python:dmi.py
import talib as ta 
import pandas as pd 
import numpy as np 

#関数の初期化
def initialize(ctx):
  #設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          #銘柄選択
        "jp.stock": {
          "symbols": [
            "jp.stock.2317", 
            "jp.stock.3150", 
            "jp.stock.3665", 
            "jp.stock.3687",
            "jp.stock.3836", 
            "jp.stock.3923", 
            "jp.stock.3962",
            "jp.stock.6035",
            "jp.stock.6046", 
            "jp.stock.6050",
            "jp.stock.6055", 
            "jp.stock.6067",
            "jp.stock.6200", 
            "jp.stock.6920",
          ],
          "columns": [
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

    #シグナル定義
    def _mysignal(data):
      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      hp = data["high_price_adj"].fillna(method='ffill')
      lp = data["low_price_adj"].fillna(method='ffill')
      cp = data["close_price_adj"].fillna(method='ffill')

      #データの入れ物を用意
      ADX = pd.DataFrame(data=0,columns=[], index=cp.index)
      ADXR = pd.DataFrame(data=0,columns=[], index=cp.index)
      DIp = pd.DataFrame(data=0,columns=[], index=cp.index)
      DIm = pd.DataFrame(data=0,columns=[], index=cp.index)
      
      #TA-Libによる計算
      for (sym,val) in cp.items():
        ADX[sym] = ta.ADX(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), timeperiod=14)
        ADXR[sym] = ta.ADXR(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), timeperiod=28)
        DIp[sym] = ta.PLUS_DI(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), timeperiod=14)
        DIm[sym] = ta.MINUS_DI(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), timeperiod=14)
      
      #売買シグナル
      buy_sig = ((DIp > DIm) & (DIp.shift(1) < DIm.shift(1))) | ((ADX > ADXR) & (ADX.shift(1) < ADXR.shift(1))) 
      sell_sig = ((DIp < DIm) & (DIp.shift(1) > DIm.shift(1))) | ((ADX > ADXR) & (ADX.shift(1) < ADXR.shift(1)))

                                
      return {
        "ADX":ADX, 
        "ADX-R": ADXR, 
        "DIp":DIp, 
        "DIm": DIm, 
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,    
        }

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

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

    # 買いシグナル
    df_buy = df[df["buy:sig"]]
    if not df_buy.empty:
      for (sym, val) in df_buy.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(0.15, 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)
        
    # #利益確定売り　損切り
    # done_syms = set([])
    # for (sym,val) in ctx.portfolio.positions.items():
    #     returns = val["returns"]
    #     #ctx.logger.debug("%s %f" % (sym, returns))
    #     if returns < -0.03:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="損切り(%f)" % returns)
    #       done_syms.add(sym)
    #     elif returns > 0.10:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
    #       done_syms.add(sym)
   
```
今回のコードのポイントとしては
銘柄を前回成績の良かったものを使う
手仕舞いをシグナルのみに任せる

基本的なコードの解説は
https://qiita.com/katakyo/items/4c8cbf2125da548f3f11
などに記載しているのでそちらを参考にしていただけるといいと思います。


##バックテスト結果
<img width="815" alt="スクリーンショット 2019-02-01 10.14.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/9945e92e-80fc-702d-d486-d18ad44344b4.png">

3年だと相当な損益率が出ました!!
銘柄直近で結果が出る銘柄を探しておきたいところですね。

##金融用語まとめ
バックテスト後の上にある金融指標が損益率意外よくわからないなあという方向けです。

[ドローダウン](https://www.nomura.co.jp/terms/japan/to/A01914.html)
[ボラティリティ](https://www.nomura.co.jp/terms/japan/ho/volatility.html)
[アルファ](https://www.nomura.co.jp/terms/japan/a/alpha.html)
[ベータ](https://www.nomura.co.jp/terms/japan/he/beta.html)

##予告
2/16日に大学生向けのイベントを開きます。
http://algorithms-contest.quantx.io/

##宣伝
勉強会やってます！
日時：毎週金曜日19時〜
場所：神田　千代田共同ビル４階　SmartTrade社オフィス
内容：初心者(プログラミングってものを知らなくてもOK)向けに初心者(私とか)がこんな内容をハンズオン(一緒にやる事)で解説しています
備考：猛者の方も是非御鞭撻にいらして下さい、そして開発・伝導者になりましょう！

もくもく会もやってます！
日時：毎週水曜日18時〜
場所：神田　千代田共同ビル４階　SmartTrade社オフィス
内容：基本黙々と自習しながら猛者の方に質問して強くなっていく会
備考：お菓子と終わりにお酒を飲みながら参加者と歓談できます！

詳細はこちらだよ
Pythonアルゴリズム勉強会HP：https://python-algo.connpass.com/
(connpassって言うイベントサイトに飛びます）

インターンブログも書いてます！！
インターン活動期や神田メシ（？）なども書いたりしてます！
興味あれば是非みてください！！
http://intern.quantx.io/


##免責注意事項
このコードや知識を使った実際の取引で生じた損益に関しては一切の責任を負いかねません。