Smart Tradeで基本的なアルゴリズムを作成

#Smart Tradeとは
Smart Tradeとは株式会社Smart Tradeが提供する、株式投資アルゴリズムの開発プラットフォームサービスの名称
~~現在はβ版だが、近々正式版がリリースされるとの事~~
（2017/11/25追記：2017/11/20に正式版リリース完了、サービス名称も「QuantX」に）

Pythonを用いてトレーディングアルゴリズムを記述することができ、バックテストも簡便に行うことができる機能を備えている

下記がHPからサービスを利用する事が可能
https://smarttrade.co.jp


#参考にしたリンク
下記のQiita投稿を参考にアルゴリズムを作成
HPにはサンプルアルゴリズムもあるのでそちらを参考にする事も可能
チュートリアルの充実が待たれる

Pythonで投資アルゴリズムを開発してみる1
http://qiita.com/hiroshimoda/items/e89444729fe7d25c0275

Building Algorithmic Strategies on SmartTrade
http://qiita.com/vinyip918/items/8623c5e902b113becd38

#アルゴリズムの書き方

##チュートリアル
下記に簡易なチュートリアルがある
https://beta.smarttrade.co.jp/handbook/ja/

##アルゴリズムの構成
Smart Trade上でのアルゴリズムは大きく3つに分かれている
それぞれの下記の機能を有している
###初期化
初期化では、アルゴリズムで利用する市場（日本株、中国株）、トレードする銘柄、利用する値（終値、高値など）を設定する

```python:initialize.py
def initialize(ctx):
 ctx.configure(
  target="jp.stock.daily",
  channels={# 利用チャンネル
            "jp.stock": {"symbols": ["jp.stock.7203"],
                         "columns": [ "high_price_adj",       
                                      "low_price_adj","close_price",
                                      "close_price_adj","volume_adj",]
                        }})
```
###シグナル定義
シグナル定義の箇所で、売買のシグナルを出すアルゴリズムを記述する
今回はMACDを用いて、MACDのヒストグラムが
・マイナス→プラスへ転換：買い
・プラス→マイナスへ転換：売り
という簡単なアルゴリズムを作成

```python:algorism.py
def _TALIB_CALL(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")

　　　 #変数を定義
      result_macd = {}
      result_macdsignal = {}
      result_macdhist = {}
      result = pd.DataFrame(data=0,columns=cp.columns, index=cp.index)

      for (sym,val) in cp.items():#各銘柄に対してMACD,MACDシグナル,MACDヒストグラムを計算
        
        result_macd[sym], result_macdsignal[sym], result_macdhist[sym] = ta.MACD(cp[sym].values.astype(np.double),
                                     fastperiod=12, slowperiod=26, signalperiod=9)

        macd = pd.DataFrame(data=result_macd,columns=cp.columns, index=cp.index)
        macdsignal = pd.DataFrame(data=result_macdsignal,columns=cp.columns, index=cp.index)
        macdhist = pd.DataFrame(data=result_macdhist,columns=cp.columns, index=cp.index)

        #交差判定
        test = np.sign( macdhist[sym].values[1:]) - np.sign(macdhist[sym].values[:-1])
        n = len(test)
        for i, row in enumerate(test):
          result[sym][i+1] = 0 if isNaN(test[i]) else test[i]
      
      
      #売買シグナルを定義
      buy_sig = result[result >= 2]
      sell_sig = result[result <= -2]
      
      return {
            "macd": macd,
            "macdsignal": macdsignal,
            "macdhist": macdhist,
            "buy:sig": buy_sig,
            "sell:sig": sell_sig,
      }
    # シグナル登録
    ctx.regist_signal("TALIB_CALL", _TALIB_CALL)

```

###売買実行
売買実行の箇所で、シグナル定義で記述したアルゴリズムに基づき、売買する数量や利確、損切りの基準を記載する

```python:handle_signals.py
def handle_signals(ctx, date, current):
    
    #買いシグナルが出た場合の処理
    buy = current["buy:sig"].dropna()
    for (sym, val) in buy.items():

        sec = ctx.getSecurity(sym)
        sec.order(sec.unit()*1, comment="シグナル買(%f)" % val)
        pass
      
　　 #売りシグナルが出た場合の処理
    sell = current["sell:sig"].dropna()
    for (sym, val) in sell.items():

        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment="シグナル売(%f)" % val)
        pass

    pass
```

###アルゴリズム全体

```python:MACD.py

import pandas as pd
import talib as ta
import numpy as np
def isNaN(num):
    return num != num


def initialize(ctx):
    #pp.pprint(vars(ctx))
    # print(ctx.positions)

    # 設定
    ctx.configure(
        target="jp.stock.daily",
        channels={          # 利用チャンネル
            "jp.stock": {
              "symbols": [
                "jp.stock.7203",  "jp.stock.7267",
                "jp.stock.7270",  "jp.stock.7269",
                "jp.stock.7259",  "jp.stock.7202",
                "jp.stock.7203",  "jp.stock.7205",
                "jp.stock.7208",  "jp.stock.7211",
                "jp.stock.7211",  "jp.stock.7276",
                "jp.stock.7272",  "jp.stock.7240",
                "jp.stock.3116",  "jp.stock.7282",
                "jp.stock.7248",  "jp.stock.7313",
                "jp.stock.6995",  "jp.stock.7222",
                "jp.stock.7278",  "jp.stock.7242",
                "jp.stock.7287",  "jp.stock.7251",
                "jp.stock.7230",  "jp.stock.5949",
                "jp.stock.7296",  "jp.stock.7279",
                "jp.stock.7250",  "jp.stock.5970",
                "jp.stock.7220",
              ],
              "columns": [ "high_price_adj", "low_price_adj","close_price",        # 終値
            "close_price_adj",    # 終値(株式分割調整後) 
            "volume_adj",         # 出来高
      ]
      }
      }
    )
    
    # talib sample...
    def _TALIB_CALL(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")


      result_macd = {}
      result_macdsignal = {}
      result_macdhist = {}
      result = pd.DataFrame(data=0,columns=cp.columns, index=cp.index)

      for (sym,val) in cp.items():
        
        result_macd[sym], result_macdsignal[sym], result_macdhist[sym] = ta.MACD(cp[sym].values.astype(np.double),
                                     fastperiod=12, slowperiod=26, signalperiod=9)

        macd = pd.DataFrame(data=result_macd,columns=cp.columns, index=cp.index)
        macdsignal = pd.DataFrame(data=result_macdsignal,columns=cp.columns, index=cp.index)
        macdhist = pd.DataFrame(data=result_macdhist,columns=cp.columns, index=cp.index)

      
        test = np.sign( macdhist[sym].values[1:]) - np.sign(macdhist[sym].values[:-1])
        n = len(test)
        for i, row in enumerate(test):
          result[sym][i+1] = 0 if isNaN(test[i]) else test[i]
      
      
      
      buy_sig = result[result >= 2]
      sell_sig = result[result <= -2]
      
      return {
            "macd": macd,
            "macdsignal": macdsignal,
            "macdhist": macdhist,
            "buy:sig": buy_sig,
            "sell:sig": sell_sig,
      }

    
    # シグナル登録
    ctx.regist_signal("TALIB_CALL", _TALIB_CALL)

def handle_signals(ctx, date, current):
    
    buy = current["buy:sig"].dropna()
    for (sym, val) in buy.items():

        sec = ctx.getSecurity(sym)
        sec.order(sec.unit()*1, comment="シグナル買(%f)" % val)
        pass
      
    sell = current["sell:sig"].dropna()
    for (sym, val) in sell.items():

        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment="シグナル売(%f)" % val)
        pass

    pass
```
#結果

全体の損益は下記のようなアウトプットが現れる
<img width="1004" alt="スクリーンショット 2017-08-27 14.13.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/191566/8bc705b0-4c29-42ab-9721-14322749e7e8.png">

個別の銘柄に関しての売買結果を視覚的に確認が可能
赤丸が買いシグナル、青丸が売りシグナル
<img width="1004" alt="スクリーンショット 2017-08-27 14.15.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/191566/415cfb86-c322-d596-7deb-c05a8a54f80b.png">

MACDヒストグラム単体を出力すると下記のようなアウトプットに
<img width="1003" alt="スクリーンショット 2017-08-27 14.15.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/191566/109ef448-6043-99c0-4fb4-78f1bc29e5b6.png">

株価のチャートと重ね合わせると、きちんとMACDヒストグラムが0と交差する点で売買できていることが確認出来る
しかし一部、0と交差しても売買をしていない箇所があり、おそらくその時の全体のポジションとの兼ね合いで売買ができなかったものと推測できるが、確認が必要
<img width="1004" alt="スクリーンショット 2017-08-27 14.15.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/191566/0c7c4d14-20a8-1c7d-083a-3e8eeed84ed7.png">


#今後の取り組み

時系列でのデータ解析手法を学習して、いわゆる「二番底」や「弱気、強気の乖離」などを捉えられるようなアルゴリズムを作成したい