QuantX에서 머신러닝을 이용한 주가 예측(특징량 공정편)

입문


안녕하십니까? 저는 재료공학 석사 1학년 학생입니다.강철 재료를 재활용한 이미지 해석 응용을 목표로 봄부터 해외 대학의 컴퓨터 과학 전공으로 교환 유학을 떠난다.
이번에는 Smart Trade에서 실습하기로 하고 주가 예측 모델을 만들어 봤습니다.

오늘의 제목.


QuantX Factory로 알고리즘을 만들어 보세요.
선인들의 기계 학습 모델(랜덤 삼림 모델)을 참고하여 특징량 공정을 추가해 보았다.완성 코드 여기 있습니다.

QuantX Factory란 무엇입니까?


스마트트레이드사가 무료로 제공하는 시스템 거래 알고리즘은 브라우저에서python이 개발한 플랫폼을 사용할 수 있다.
다음 이유로python에서 주가를 예측하고 싶은 사람에게 추천합니다.
- 웹 플랫폼의 개발 환경을 구축할 필요가 없음
- 품목별 종가와 고가 등 각종 데이터가 준비되어 있어 데이터 세트가 필요 없음
- 개발된 거래 알고리즘은 심사를 거쳐 QuantX Store에서 판매 가능
- 새로운 엔진의 이동에 따라 마감가, 개장가, 지정가의 주문 등을 선택할 수 있어 더욱 다양한 전략을 세웠다
데이터의 수집과 업데이트로 인해 많은 시간을 가졌던 시대도 이제 끝났다.
QuantX에 대한 자세한 사용 방법여기.

본론


1. 목적 및 방법

  • 기존의 랜덤 삼림 모델을 사용하는 주가 예측 모델에 대해 특징량 공정을 추가로 실시하고 정밀도를 높이려고 한다.
  • 엔진 이동과 함께 새로운 엔진이 사용할 수 있는 알고리즘을 수정한다.
    (데이터가 생명인 기계 학습의 사용에서 장시간 후진 테스트를 할 수 있는 새로운 엔진으로 이동하는 것이 중요하다.)
  • 참고 주가 예측 모델


    기계학습을 이용한 주가 예측 모델로 @sarubobo29 선생의 QuantX에서 머신러닝으로 주가를 예측하는 part1 사용을 허락해 주십시오.교사 학습을 통해 10일 후의 주가가 현재의 가격보다 더 높은지(하락 여부)를 예측하는 알고리즘하계.
    그나저나 @sarubobo29QuantX에서 머신러닝으로 주가를 예측하는 part2 도 적용을 시도했지만 이쪽은 잘 맞지 않아요.

    실시하는 특징량 공사


    기계 학습 모델의 정밀도를 높이기 위해 다음과 같은 두 가지 특징량 공정을 진행한다.

    i. 상호작용 특징량과 다항식 특징량의 생성


    이번 생성 교체 작용 특징량과 다항식 특징량은 특징량으로 추가된다.교체작용특징량은 특징량의 교체작용을 나타내는 특징량을 가리키며 특징량의 서로의 적체로 나타낸다.예를 들어 x1, x2와 같은 특징량이 있으면 x1*x2와 같은 특징량을 새로 만든다.다항식 특징량은 특징량의 다항식 표현을 새로운 특징량으로 추가하는 방법이다.예를 들어 x1, x2의 특징량의 2차 표현을 만들면 x1^2, x2^2의 특징량을 새로 만든다.

    ii. 자동 피쳐 양 선택


    훈련 데이터에 대한 과도한 학습을 방지하기 위해 자동 특징량 선택을 실시한다.자동 특징량 선택은 기계 학습을 사용하는 모델에서 모든 특징량에서 유효한 특징량 조합을 자동으로 검색하는 과정을 말한다.이번 사용에서 결정 트리 기본 모델 등 교사의 학습 모델 1개가 있는데 특징량의 중요성을 판단하는 데는 중요한 것만 남기고 모델 기본 특징량 선택을 한다.무작위 삼림 모형을 학습 모형으로 삼아 특징량 선택을 실시했다.

    2, 인코딩


    수정하다


    준비 단계의 수정점


    scikit-learn에서 특징량을 생성할 때 사용하는 다각형 nomialFeatures 함수와 특징량을 선택할 때 사용하는 SelectFromModel 함수를 새로 가져옵니다.
    from sklearn.feature_selection import SelectFromModel
    from sklearn.preprocessing import PolynomialFeatures
    

    특징량 공정을 진행할 때의 부가점(아래 단독 설명).

    # 特徴量の追加
    poly = PolynomialFeatures(degree = 3)
    poly.fit(df_x)
    df_x = poly.transform(df_x)
    
    # ここから手順3
    # 学習データとテストデータに分割(前半5割を学習データ,後半5割をテストデータ)
    X_train, X_test, y_train, y_test = train_test_split(df_x, y, train_size=0.5, shuffle = False)
    
    # 特徴量の選択(モデルはランダムフォレスト)
    select = SelectFromModel(RandomForestClassifier(n_estimators = 300, random_state = 1), threshold = "1.40*median")
    select.fit(X_train, y_train)
    X_train = select.transform(X_train)
    X_test = select.transform(X_test)
    
    # 学習データを使って学習(モデルはランダムフォレスト)
    clf = RandomForestClassifier(random_state=1, n_estimators = 100, 
    max_leaf_nodes = 10, max_depth=6, max_features=None)
    clf = clf.fit(X_train, y_train)
    
    우선 이번에는 PolynomialFeatures 함수를 사용하여 3회 이하의 교체작용특징량과 다항식특징량을 새로운 특징량으로 추가한다.degree 값을 설정하면 이 값 이하의 비트의 교체 작용 특징량과 다항식 특징량을 생성할 수 있습니다.
    # 特徴量の追加
    poly = PolynomialFeatures(degree = 3)
    poly.fit(df_x)
    df_x = poly.transform(df_x)
    
    그런 다음 피쳐 양을 선택합니다.SelectFromModel을 사용하여 피쳐 양을 선택합니다.이번에는 특징량의 중요성을 판단하는 모델로 RandomForest Classifier를 사용했다.특징량 선택에서 어떤 기준을 설정하고 더 큰 중요성을 가진 특징량만 선택한다.이번에는 이 특징량 선택의 기준으로median(중앙값),threshold="1.40*median"을 사용합니다.
    # 特徴量の選択(モデルはランダムフォレスト)
    select = SelectFromModel(RandomForestClassifier(n_estimators = 300, random_state = 1), threshold = "1.40*median")
    select.fit(X_train, y_train)
    X_train = select.transform(X_train)
    X_test = select.transform(X_test)
    

    새 엔진에 사용되는 수정점


    신호 이름을'market:sig'로 수정하여 새 엔진에서도 사용할 수 있도록 합니다.
    return {
      "market:sig": market_sig,
    }
    

    디버깅 훈련 데이터, 테스트 데이터 득점 코드 추가


    특징량의 추가와 선택으로 인해 과잉 적합과 적합 부족이 발생하는 것을 방지하기 위해 디버깅은 훈련 데이터, 테스트 데이터의 정밀도를 나타낸다.
    ctx.logger.debug("Training score: {:.3f}".format(clf.score(X_train, y_train)))
    ctx.logger.debug("Test score: {:.3f}".format(clf.score(X_test, y_test)))
    

    모든 코드

    # Sample Algorithm
    # ライブラリーのimport
    # 必要ライブラリー
    import maron
    import maron.signalfunc as sf
    import maron.execfunc as ef
    # 追加ライブラリー
    # 使用可能なライブラリに関しましては右画面のノートをご覧ください①
    import pandas as pd
    import numpy as np
    import talib as ta
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.feature_selection import SelectFromModel
    from sklearn.preprocessing import PolynomialFeatures
    
    # オーダ方法(目的の注文方法に合わせて以下の2つの中から一つだけコメントアウトを外してください)
    # オーダー方法に関しましては右画面のノートをご覧ください②
    #ot = maron.OrderType.MARKET_CLOSE # シグナルがでた翌日の終値のタイミングでオーダー
    ot = maron.OrderType.MARKET_OPEN   # シグナルがでた翌日の始値のタイミングでオーダー
    #ot = maron.OrderType.LIMIT        # 指値によるオーダー
    
    # 銘柄、columnsの取得
    # 銘柄の指定に関しては右画面のノートをご覧ください③
    # columnsの取得に関しては右画面のノートをご覧ください④
    def initialize(ctx):
      # 設定
      ctx.logger.debug("initialize() called")
      ctx.configure(
        channels={               # 利用チャンネル
          "jp.stock": {
            "symbols": [
              "jp.stock.1321", #日経225連動型上場投資信託
            ],
            "columns": [
              #"close_price",     # 終値
              "close_price_adj", # 終値(株式分割調整後)
              #"volume_adj",     # 出来高
              #"txn_volume",     # 売買代金
            ]
          }
        }
      )
    
      # シグナル定義
      def _my_signal(data):
        # 欠損値補間
        cp = data["close_price_adj"].fillna(method='ffill')
    
        # ctx.logger.debug(cp)
    
        # ここから手順1(教師データの生成)
        # 教師データを入れる型を用意
        y = pd.DataFrame(0, index = cp.index, columns = cp.columns)
        y = cp.diff(-10)    # ここで何日後を予測するかを決めれる
        y = y['jp.stock.1321']<0    # True, Falseに変換
    
        # ここから手順2(株価データから特徴抽出)
        # 特徴量を入れるための準備
        rsi7 = pd.DataFrame(0, index=cp.index, columns=["rsi7"])
        sma14 = pd.DataFrame(0,index=cp.index, columns=["sma14"])
        sma7 = pd.DataFrame(0,index=cp.index, columns=["sma7"])
        sma7_diff = pd.DataFrame(0,index=cp.index, columns=["sma7_diff"])
        sma14_diff = pd.DataFrame(0,index=cp.index, columns=["sma14_diff"])
        sma_diff = pd.DataFrame(0,index=cp.index, columns=["sma_diff"])
        bb_mid = pd.DataFrame(0,index=cp.index, columns=["bb_mid"])
        bb_up = pd.DataFrame(0,index=cp.index, columns=["bb_up"])
        bb_low = pd.DataFrame(0,index=cp.index, columns=["bb_low"])
        bb_diff = pd.DataFrame(0,index=cp.index, columns=["bb_diff"])
        mom = pd.DataFrame(0,index=cp.index, columns=["mom"])
    
        for (sym,val) in cp.items():
          rsi7['rsi7'] = ta.RSI(cp[sym].values.astype(np.double), timeperiod=7)
          sma14['sma14'] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=14)
          sma7['sma7'] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=7)
          bb_up['bb_up'], bb_mid['bb_mid'], bb_low['bb_low'] = ta.BBANDS(cp[sym].values.astype(np.double), timeperiod=14)
          mom['mom'] = ta.MOM(cp[sym].values.astype(np.double), timeperiod=14)
    
        sma7_diff['sma7_diff'] = sma7.diff()
        sma14_diff['sma14_diff'] = sma14.diff()
        sma_diff['sma_diff'] = sma7['sma7'] - sma14['sma14']
        bb_diff['bb_diff'] = bb_mid['bb_mid'] - bb_up['bb_up']
    
        # 特徴量の結合
        df_x = pd.concat([rsi7, sma7_diff, sma14_diff, sma_diff, 
        bb_diff, mom], axis = 1)
        ctx.logger.debug(df_x)
    
        # はじめのNAN削除
        df_x = df_x[14:]
        y = y[14:]
    
        # 特徴量の追加
        poly = PolynomialFeatures(degree = 3)
        poly.fit(df_x)
        df_x = poly.transform(df_x)
    
        # ここから手順3
        # 学習データとテストデータに分割(前半5割を学習データ,後半5割をテストデータ)
        X_train, X_test, y_train, y_test = train_test_split(df_x, y, train_size=0.5, shuffle = False)
    
        # 特徴量の選択(モデルはランダムフォレスト)
        select = SelectFromModel(RandomForestClassifier(n_estimators = 300, random_state = 1), threshold = "1.40*median")
        select.fit(X_train, y_train)
        X_train = select.transform(X_train)
        X_test = select.transform(X_test)
    
        # 学習データを使って学習(モデルはランダムフォレスト)
        clf = RandomForestClassifier(random_state=1, n_estimators = 100, 
        max_leaf_nodes = 10, max_depth=6, max_features=None)
        clf = clf.fit(X_train, y_train)
    
        # ここから手順4
        # テストデータを使って予測
        pred = clf.predict(X_test)
    
        # market_sigのインデックスを合わせる
        test = np.ones(len(X_train)+14, dtype=np.bool) * False
        market_sig = np.hstack((test, pred))
        market_sig = pd.DataFrame(data = market_sig, columns=cp.columns, index=cp.index)
    
        # ctx.logger.debug(market_sig)feature = clf.feature_importances_
        # ctx.logger.debug(feature)
    
        feature = clf.feature_importances_
        ctx.logger.debug(market_sig)
    
        # normalize signals
        market_sig[market_sig == True] = 1.0
        market_sig[market_sig == False] = 0.0
        ctx.logger.debug(market_sig)
    
        # スコア表示
        ctx.logger.debug("Training score: {:.3f}".format(clf.score(X_train, y_train)))
        ctx.logger.debug("Test score: {:.3f}".format(clf.score(X_test, y_test)))
    
    
        return {
          "market:sig": market_sig,
        }
    
      # シグナル登録
      ctx.regist_signal("my_signal", _my_signal)
    
    def handle_signals(ctx, date, current):
      '''
      current: pd.DataFrame
      '''
      # 1321を取引するため
      bull = ctx.getSecurity("jp.stock.1321")
    
      # シグナルを取得
      market_signal = current["market:sig"][0]
    
      if market_signal == 1.0:
        bull.order_target_percent(0.5, comment="BULL BUY")
      else:
        bull.order_target_percent(0, comment="BULL SELL")
    

    3. 테스트 결과



    손익률을 보면 같은 기간 역방향 테스트에서 14.60%→22.60%로 올라갈 수 있다.SharpeRatio 등도 개선되었다.

    훈련 데이터, 테스트 데이터의 점수를 보면 훈련 데이터에 너무 적합하고 과도한 학습이 발생했다는 것을 알 수 있다.추가 특징량의 수량과 원래의 무작위 삼림 모델의 변수 등을 조작했지만 개선할 수밖에 없는 것이 앞으로의 과제다.

    4. 개선 방안

  • 모형면
    과도한 학습을 방지하기 위해 각 모델의 매개 변수 조정
    다른 모델 또는 여러 모델의 컬렉션 사용
  • 특징량
    기본 지표를 특징량으로 추가
  • 기타
    새 엔진에서 더욱 장기적인 역방향 테스트를 실시하여train 데이터 증가
  • 마지막


    기사 읽어줘서 고마워요.지식이 아직 부족하니 잘못이 있으면 반드시 지적해 주십시오.더 좋은 알고리즘을 만들기 위해 최선을 다하겠습니다!

    좋은 웹페이지 즐겨찾기