為替の予測をやってみた(その2 〜機械学習編〜)

この記事の概要

  • 前回の記事の続き
    • 30分後の価格帯の予測にチャレンジ
  • LSTM(Long Term Short Memory)にて予測
    • 予測精度としては今ひとつ。。
  • 売買のシステムに組込んだと仮定してバックテストを実施
    • 売買のシステムにて使用するなら非常によい結果に!

前回のおさらい

前回は予測する対象を決めるために、 3ヶ月分の為替データを分析しました。

分析内容

  1. 為替データを、移動平均線を中心とした-10〜+10の領域に区分けした。
  2. t=0と30分後(t=30)の価格の分布を確認した。

その結果、t=30の価格帯を予測するモデルを作成し、 最終的には、t=0の価格とそのモデルの予測したt=30の価格差に応じて、買い(Long)/トレードしない(NA)/売り(Short)を選択するシステムを作製することとしました。

詳しくは前回の記事を参照してください。

予測モデルの構築

さて、ここからが今回の内容になります。

モデルの選定

今回は、 LSTM(Long Term Short Memory)を選択しました。
LSTMについては、さまざまな記事がありますので、そちらをご覧ください。

私は以下などを参照にしました。

わかるLSTM ~ 最近の動向と共に - Qiita

LSTMネットワークの概要 - Qiita

KerasでLSTMを学習する手順を整理してみた | 自調自考の旅

LSTMでFX予測をやってみよう(機械学習初心者向けチュートリアル)

選定した理由:

  • 実装例など情報が豊富
  • 私自身が実際に実装したことがなかったため、勉強がてら試してみたかった

まぁ、いろいろな手法と比べてみるつもりですので、興味を持った手法を試すこととしました。

モデルの構築

モデルの概要:

  • 予測の対象:30分後(t=30)の価格帯
  • 訓練データ:予測時点での価格とそれ以前の300分の価格(t=-300〜t=0)
    • 今回は簡素化のため、インジケータは使用しませんでした
  • 訓練データは、2ヶ月分。テストデータと検証データはそれぞれ半月分
  • LSTMは1層
    • 多層にすると精度が向上するかなどは別途検証したいと思っています

実装は以下のような感じです。

def build_model(inputs, outputs, neurons, activ_func,
                dropout=0.1, loss="mean_squared_error", optimizer):
    model = Sequential()
 
    model.add(LSTM(neurons, input_shape=(inputs.shape[1], inputs.shape[2])))
    model.add(Dropout(dropout))
    #model.add(Dense(units=outputs.shape[1]))
    model.add(Dense(units=outputs.shape[1],
                kernel_initializer='random_uniform',
                bias_initializer='zeros'))
    model.add(Activation(activ_func))
    model.compile(loss="categorical_crossentropy",
              optimizer=optimizer, metrics=['categorical_accuracy'])

    return model

model = build_model(train_x_data, train_y_data, neurons = 20,activ_func="softmax",optimizer="RMSprop")

history = model.fit(train_x_data, train_y_data, 
                            epochs=100, batch_size=32, verbose=1, validation_split=0.2, callbacks=[es_cb, tb_cb, cp_cb])

学習を実行すると、以下の様に学習していきました。

f:id:MorinoKuma3:20190408205304p:plainf:id:MorinoKuma3:20190408205307p:plainf:id:MorinoKuma3:20190408205337p:plainf:id:MorinoKuma3:20190408205341p:plain

学習を実行すると、以下の様に学習していきました。

accuracyは60%を超えてきました!
これは期待できそうです。

次に混合行列を確認します。

f:id:MorinoKuma3:20190408211317p:plain

区分の上の方と下の方では上下限に張り付き気味に予測されていますが、悪くないと思います。

続けて、recall, precision, f-scoreを見ていきたいと思います。

f:id:MorinoKuma3:20190408212108p:plain

0.2...あれ?こんなもんか。。 もっといいかと思いました。

しかし、sklearnのclassification_reportが便利すぎて、地味に感動しました。

単純に予測の時点(t=0)に近い区分を、予測値(t=30)としているだけということはないだろうか...?
っと不安になったので、 t=0と、予測されたt=30とのマトリックスも確認することにしました。

f:id:MorinoKuma3:20190408212657p:plain

おや?意外にも悪くない感じで予測ができていそうです。

では、次にt=0の価格とそのモデルの予測したt=30の価格差に応じて、買い(Long)/トレードしない(NA)/売り(Short)を選択するシステムを仮定して、 買い(Long)/トレードしない(NA)/売り(Short)での混合行列を確認してみましょう。

f:id:MorinoKuma3:20190408214352p:plain

おぉ!恐ろしくいいですね!! ShortやLongのところで、逆の予想がないのがとっても素晴らしいです!!

f:id:MorinoKuma3:20190408214813p:plain

recall, precision, f-scoreも良いですね。

実際のトレードだったら、もうウハウハです(笑)

モデルを使ったバックテスト

どれくらいウハウハか確認するために簡易的ですが、今回バックテストをしてみました。

フレームワークは、pybacktestを使用しました。

その結果がこちらです。

------------------------------------------
|  Backtest(test, 2019-07-04 13:43 JST)  |
------------------------------------------

backtest:
  days: 14
  from: '2018-07-15 20:05:00'
  to: '2018-07-30 09:15:00'
  trades: 296
performance:
  PF: 48.5013
  RF: 298.4667
  averages:
    gain: 0.0007
    loss: -0.0001
    trade: 0.0006
  payoff: 4.6705
  profit: 0.1791
  winrate: 0.9122

f:id:MorinoKuma3:20190408223026p:plain

右肩上がりです!

ASKとBIDの差や滑りとかを考慮していないので、実際はもっとよくないですが、 それでも十分予測の有用性を確認できたと思います。

次回は、フォワードテストを試してみたいと思います。