3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

QuantXでシンプルな機械学習を実装する

Posted at

現状のQuantXってどこまでのライブラリがサポートされてるの?って思っていたところ、どうやらscikit-learnは使えるっぽいので、シンプルな機械学習を実装してみました。

#今回書いたコード

from sklearn.ensemble import RandomForestClassifier
import numpy as np 
import pandas as pd

def initialize(ctx):
    # 設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      channels={          # 利用チャンネル
        "jp.stock": {
          "symbols": [
            "jp.stock.6942",
            "jp.stock.2721",
            "jp.stock.9263",
            "jp.stock.6556",
            "jp.stock.3092",
            "jp.stock.4380",
            "jp.stock.3856",
            "jp.stock.2930",
            "jp.stock.2146",
            "jp.stock.3445",
            "jp.stock.6065",
            "jp.stock.8927",
            "jp.stock.2371",
            "jp.stock.3765",
            "jp.stock.3932",
            "jp.stock.5542",
            "jp.stock.3779",
            "jp.stock.2127",
            "jp.stock.2211",
            "jp.stock.8167",
            "jp.stock.3064",
            "jp.stock.3276",
            "jp.stock.8918",
            "jp.stock.2928",
            "jp.stock.6071",
            "jp.stock.1434",
            "jp.stock.3676",
            "jp.stock.3825",
            "jp.stock.6067",
            "jp.stock.1333", 
            "jp.stock.3267",
            "jp.stock.1814", 
            "jp.stock.4521", 
            "jp.stock.4503", 
            "jp.stock.5194", 
            "jp.stock.5391", 
            "jp.stock.5940", 
            "jp.stock.7226", 
            "jp.stock.7956", 
            "jp.stock.3092", 
            "jp.stock.7148", 
            "jp.stock.9115", 
            "jp.stock.9508", 
            "jp.stock.2371", 
            "jp.stock.3765", 
            "jp.stock.6533", 
            "jp.stock.4587", 
            "jp.stock.4536", 
            "jp.stock.3064", 
            "jp.stock.1808", 
          ],
          "columns": [
            #"open_price_adj",    # 始値(株式分割調整後)
            #"high_price_adj",    # 高値(株式分割調整後)
            #"low_price_adj",     # 安値(株式分割調整後)
            #"volume_adj",         # 出来高
            #"txn_volume",         # 売買代金
            "close_price",        # 終値
            "close_price_adj",    # 終値(株式分割調整後) 
          ]
        }
      }
    )

    def _my_signal(data):
      cp=data["close_price_adj"].fillna(method='ffill')
      window_length = 10
      train_data = cp.ix[:,:int(len(cp.columns)/2)]
      test_data = cp.ix[:,int(len(cp.columns)/2):]
      classifier = RandomForestClassifier()
      X = []
      Y = []
      for (sym,val) in train_data.items():
        for i in range(len(train_data[sym]) - (window_length)):
          recent_prices_train = train_data[sym].iloc[i:(i + window_length +1)]
          recent_prices_train = recent_prices_train.values.astype(np.float)
          recent_prices_train = recent_prices_train.reshape(-1,)
          changes_train = (np.diff(recent_prices_train) > 0)
          X.append(changes_train[:-1])
          Y.append(changes_train[-1])
      X = np.array(X)
      Y = np.array(Y)
      Y = Y.reshape(-1,1)
      
      if len(Y) >= 100:
        model = classifier.fit(X, Y)
      
      
      tmp = pd.DataFrame(None, index=cp.index, columns=cp.columns)
      prediction = pd.Series(None, index=test_data.index)
      
      for (sym,val) in test_data.items():
        x = []
        for i in range(len(test_data[sym]) - (window_length)):
          recent_prices_test = test_data[sym].iloc[i:(i + window_length +1)]
          recent_prices_test = recent_prices_test.values.astype(np.float)
          recent_prices_test = recent_prices_test.reshape(-1,)
          changes_test = (np.diff(recent_prices_test) > 0)
          x.append(changes_test[:-1])
          
        prediction_tmp = model.predict(x)
        prediction[window_length:] = prediction_tmp
        tmp[sym] = prediction
      
      buy_sig = tmp[tmp.ix[:,int(len(cp.columns)/2):] == True]
      sell_sig = tmp[tmp.ix[:,int(len(cp.columns)/2):] == False]
      
      
      return {
        "buy:sig":buy_sig,
        "sell:sig":sell_sig
      }

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

def handle_signals(ctx, date, current):
    '''
    current: pd.DataFrame
    '''
    
    done_syms = set([])
    for (sym,val) in ctx.portfolio.positions.items():
        returns = val["returns"]
        if returns < -0.03:
          sec = ctx.getSecurity(sym)
          sec.order_target_percent(0, comment="損切り(%f)" % returns)
          done_syms.add(sym)
        elif returns > 0.05:
          sec = ctx.getSecurity(sym)
          sec.order_target_percent(0, comment="利益確定売(%f)" % returns)
          done_syms.add(sym)

    buy = current["buy:sig"].dropna()
    for (sym,val) in buy.items():
        if sym in done_syms:
          continue
        
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0.1, comment="SIGNAL BUY")
        pass

    sell = current["sell:sig"].dropna()
    for (sym,val) in sell.items():
        if sym in done_syms:
          continue
    
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment="SIGNAL SELL")
        pass

#やったこと

qiita用画像.png

まず、学習用の銘柄データと実際に売買する銘柄データに分けます。
次に、学習用のデータに対して、各銘柄の終値を算出し、前日と比べて株価が上昇したか下落したかの真偽値判定を行います。
そうして得られた真偽値データを一定期間ずつ切り出し(今回はwindow_length=10日間で検証)、9日間の入力データと10日目の正解ラベルを大量に用意します。
あとは、ランダムフォレストで分類器を作成し、実際に売買を実行するデータで予測値を算出した後、その予測値を元に売買シグナルを作成しました。

#バックテスト結果
スクリーンショット 2019-01-24 15.01.28.png

直近3年でこのくらいの値です。
いやシグナル回数多すぎな。

#まとめ
機械学習素人すぎてこれでうまくいってるか全く自信がないですが、一応QuantXでscikit-learnってどうやって使うんだ?ってところでサンプル例として作ってみました。
そろそろ金融指標をいじいじするのにも限界が見えてきたので、ここらへんで機械学習×システムトレードの領域の勉強を深めていきたいなあと思う次第です。
オススメの本やサイトなどあれば教えていただきたいです、、

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?