機械学習でFXの予測をしてみる
この記事は、🎄GMOペパボエンジニア Advent Calendar 2022の18日目の記事です。
昨日は、june29さんの「ソフトウェアエンジニアが書いた文章をレビューするときに考えていること」でした。
はじめに
今回は、かねてから思いついて試してみたいと思っていたことをやってみます。
機械学習でFXの予測!!!
このテーマ自体は、自身の大学の卒業研究でも扱った内容なのですが、その際は以下のような内容でした。
【条件】
- データは、AUD/JPYの2010~2018の8年間の日足データを使用
- 終値、始値、高値、安値、25日平均を各値の8年分で正規化し入力データとして与える
- ネットワークは、LSTM、RNN、GRUの3つを使用しアンサンブル学習する
- 3つのネットワークを並列で予測させ、それぞれの予測結果の平均を最終的な予測値として評価する
モデルの図は下記のような感じです。
研究中に思っていたことは、エヴァのMAGIシステムっぽいなと思ってましたw
この研究の結果は、だいたい54%の正答率で予測できるという結果になりました。
その予想をもとに資産運用を1年間してみたらというシミュレーションを行ったところ、初期資産50万円から1年で56,716円プラスとなる結果になりました。
でも、このモデル学習にめちゃくちゃ時間かかるし、1年でそこまでプラスにならないのでほかにもっといいモデルやデータの準備がないかなと思っていました。
そこで今回は
値ではなく、形に着目して学習させてみたいと思います。
今まで自分がやってきた正規化は、下記のようにテストデータすべての最大最小値を使用して正規化していました。
ですが、これだと特徴が分かりにくいんではないか?
加えて、数値が違うため同じような形と判断できずに学習しているのではないかと思いました。
なので、今回は下記のように学習させるレンジで正規化して特徴をとらえやすくしてみました。また似た形の場合は数値も似るはずなので結構いい感じに学習してくれるんではないかな~と思いました。
また、今までは明日の終値がいくらか?という風に予測をさせていましたが今回は明日の終値が上がっているか下がっているかの2択で予測をするようにしました。
やってみた
条件は、下記でやってみようと思います。
- データは、AUD/JPYの2010~2021の11年間の日足データを使用
- 終値、始値、高値、安値を各値の学習レンジで正規化し入力データとして与える
- 学習レンジは3日と5日で行う(なんとなくで選定)
- ネットワークは、LSTMを使用する
- 検証は、2022年の日足データを使用する
コードは下記で確認できます。
使用したデータは下記です。学習の様子は下記のようになりました。
学習レンジ3日の場合
学習レンジ5日の場合
損失はきれいに減っていっているけど、正答率がぐちゃぐちゃですね。
しっかり学習できてなさそう。。。
とりあえず2022年のデータで予測させてみたらどうなるのか検証してみます。
検証シートは下記です。
変化率の個所を見てプラスの変化であればupと判断し、予測と比較し予測もupであれば正誤にOKと出すようにしました。
これで見てみると、3日のほうが50%の正答率5日のほうが57%の正答率となりました。
57%!?
意外と特徴とらえて予測できているのかも?
細かい設定(ロスカットなどの考慮)とかおいておいて、5日のほうで運用してたらだいたいいくらくらいになるのか雑に確かめてみました。
方法的には、10万を初期資産だとして、予想があっている場合その日の変化率を資産にかけた額を足していくというものです。
逆に予想が外れていれば、変化率をかけた金額をマイナスします。
結果は下記のとおりです。
上がり下がりしながらも、最終的には¥188,550になっているという結果がでました。
+88,550円
あまりにも出来すぎている。。。。
おかしい
どこかで、予測データの中に正解がまぎれてしまっているのではないか?
そう疑ってしまうような結果です。
ここがおかしそうだと気づいた方、ぜひコメントください。
まとめ
今回はかねてから試してみたかった方法を用いてFXの予測を行いました。
結果は疑いしかないものとなってしまいましたが、試みとしては面白かったのではないかと思います。
もっと正答率あげるために、別の活性化関数と損失関数の組み合わせを試してみたり、学習レンジを変えてみたり、入力データに平均線をいれてみたり、モデルもアンサンブル学習するように変えてみたりいろいろできることがあると思います。
また時間があれば別のパターンを試してみたいと思います。
何か意見や気付き等ありましたら是非コメントください~
また、下記記事で今回使用しているKerasで自作損失関数を実装する方法も書いているのでよかったら見てみてください~
Discussion
今更ながら記事にコメント失礼します。
初歩的な質問だったらすみません。
正解ラベルは1つなのにモデルの出力を2つにして、なぜ学習できるんですか?
少し改造してDenseの出力層を1つにして0.5以上ならup、未満ならdownという構造にしようとしたら学習が上手く進まなくなってしまいました。
LSTMの層を増やしてみたり、INPUT_LENを増やしてみたりしましたが結果は変わらず、全て1(up)を出力するだけのモデルになってしまいました。
もしかしたら初歩的な所で何か理解が間違ってるかも知れないと思って質問した次第です。
既に解決していたらすいません。
このモデルの最後のDense層の活性化関数はSoftmax関数です。
これはすごく簡単に言えばDence層の出力を合計が1になるように値を変換する役割を持っています。
例えば[0.8, 0.6]を[0.55, 0.45]に変換するような感じです。
この関数は分類問題でよく使用されます(例えばメールがスパムである確率が60%であるのであれば、逆にスパムでない確率は絶対に40%になり、合計は100%つまり1となるため)。
今回、出力を1つにしてしまった為、Softmax関数を通して以下のような処理が行われています。
[0.6] -> [1.0], [0.8] -> [1.0], [0.1] -> [1.0]
なので常に出力が1となってしまっています。
対策としては活性化関数をSoftmaxからSigmoidに変更することで、正しい結果を得られるようになると思います。
Sigmoid関数は様々な値を0~1の間に収める関数です。例は以下の通りとなります。
[1.2] -> [0.77], [0.4] -> [0.6]
この関数を使用することでDence層の出力を0~1の間に収め、期待した動作をするようになると思います。
自己解決できましたが、わざわざこんな初歩的な質問に丁寧に答えてくれてありがとうございます。
頭の中でSoftmaxとSigmoidがごっちゃになっていました。
正しくSigmoidを使って予測値をフィルターすることでこれくらいの予測精度にはなりました。
実運用はしてませんがスプレッド0.4pips入れて、ただの二値予測だけでこれくらいの利益シュミレートができるのは驚きました。