前回までRNN(LSTM)や他の識別器で為替の予測を行ってきましたが、今回はCNNで予測をしてみたいと思います。
データの準備
前回まで終値の差分を学習データとしていましたが、今回は終値そのものを学習データにしてみます。
また、今回はUSDJPYの1時間足、2008年1月1日〜2017年3月10日を利用し、前半95%を学習、後半5%をテスト(バリデーション)としました。
CNNは画像認識で高い精度を発揮していますが、画像以外でも応用することは可能です。例えば終値が以下のようなデータがあったとします。
これを画像に変換します。
このように1次元の画像と見なすことができます。
色が複数チャネルあるように見えますが実際はグレースケールです。カラーマップを以下のようにして見えやすくしています。
plt.imshow(data.reshape(1, -1), vmin=0.0, vmax=1.0,
cmap='summer', interpolation='nearest')
ラベルは前回同様に次の期間で終値が上がるか下がるかの2クラスとします。
まずは学習データのストライドを1にしてやってみます。初めの10データを表示してみます。
一つずつスライドしているのがわかりますね。これらを学習データとして使います。
ただし、このような学習データにはやや疑問があります。RNNのときは良いのですが、たった1画素スライドしただけでほぼ同じ特徴を持っているにも関わらず、クラスが上にも下にもなるからです。
(学習の過程で画像の左端ー未来に近い側ーの終値が強調される特徴抽出がされるかもしれませんが)
まずは取りあえずやってみましょう。
CNN
基本的な2層のCNNを使ってみます。今回はKerasがv2.0になったという事なのでKerasで書いてみます。
え?タイトルと違うって?backendはTensorFlowにしたのでセーフです!
input_shape = (24, 1)
model = Sequential()
model.add(Conv1D(32,
3,
activation='relu',
padding='valid',
input_shape=input_shape))
model.add(MaxPooling1D(pool_size=2))
model.add(Conv1D(64,
3,
activation='relu',
padding='valid'))
model.add(MaxPooling1D(pool_size=2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(250, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer='adam',
metrics=['accuracy'])
結果
40エポックほど回した結果です。
Epoch 40/40
54545/54545 [==============================] - 4s -
loss: 0.6905 - acc: 0.5275 - val_loss: 0.6921 - val_acc: 0.5200
正解率52%・・汎化性能は良いですが。
バックテストで利益の推移を見てみます。
Net Profit : ¥29710.00
Max Drawdown : ¥-114250.00
Number Winning Trades : 1488
Number Losing Trades : 1372
Percent Profitable : 52.03%
Avg Win Trade : ¥1071.855
Avg Los Trade : ¥-1140.824
Largest Win Trade : ¥9470.000
Largest Los Trade : ¥-14790.000
Profit Factor : 1.02
ドローダウンが酷いですが、12月からは上昇に転じています。ロットの調整でマシになりそうですがそれはまた別の話。機械学習の範囲で改善をしてみましょう。
学習データの見直し
やはり1ずつのストライドは気になるので、オーバーラップが丁度無くなる24に設定します。
オーバーラップがなくなりました。これでほぼ同じ画像(値動き)なのにラベルが異なるケースがなくなったはずです。(もちろん過去に同様の値動きがあり、その時は上下逆に動いたという場合はあります)
見直し後の結果
先ほどと同様に40エポック回しました。
Epoch 40/40
2273/2273 [==============================] - 0s -
loss: 0.6528 - acc: 0.6067 - val_loss: 0.6869 - val_acc: 0.5583
正解率55.8%
正解率が上がりました。ただし学習データが1/24になってしまったのでまだ喜べません。オーバーフィッティングの兆候も見えてきました。
バックテストの結果を見てみます。
Net Profit : ¥38620.00
Max Drawdown : ¥-11820.00
Number Winning Trades : 67
Number Losing Trades : 53
Percent Profitable : 55.83%
Avg Win Trade : ¥1677.313
Avg Los Trade : ¥-1391.698
Largest Win Trade : ¥7410.000
Largest Los Trade : ¥-9490.000
Profit Factor : 1.52
PF 1.52
いいですね。ドローダウンも少なく全体的に先ほどより安定しています。
難点を言えば取引が1日に1回しか発生しないことと、最初の1ヶ月間の長いドローダウンでしょうか。
次回以降
次は転移学習か強化学習をやってみようかと思っています。思いつきで色々脱線するかもしれませんけどね。