Python
algorithm
Trading
SmartTrade
Quantx

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

More than 1 year has passed since last update.

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つに分かれている
それぞれの下記の機能を有している

初期化

初期化では、アルゴリズムで利用する市場(日本株、中国株)、トレードする銘柄、利用する値(終値、高値など)を設定する

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のヒストグラムが
・マイナス→プラスへ転換:買い
・プラス→マイナスへ転換:売り
という簡単なアルゴリズムを作成

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)

売買実行

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

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

アルゴリズム全体

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

結果

全体の損益は下記のようなアウトプットが現れる
スクリーンショット 2017-08-27 14.13.25.png

個別の銘柄に関しての売買結果を視覚的に確認が可能
赤丸が買いシグナル、青丸が売りシグナル
スクリーンショット 2017-08-27 14.15.05.png

MACDヒストグラム単体を出力すると下記のようなアウトプットに
スクリーンショット 2017-08-27 14.15.26.png

株価のチャートと重ね合わせると、きちんとMACDヒストグラムが0と交差する点で売買できていることが確認出来る
しかし一部、0と交差しても売買をしていない箇所があり、おそらくその時の全体のポジションとの兼ね合いで売買ができなかったものと推測できるが、確認が必要
スクリーンショット 2017-08-27 14.15.47.png

今後の取り組み

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