TensorFlow (ディープラーニング)で為替(FX)の予測をしてみる

機械学習で何ができるの？深層学習（ディープラーニング）だと何が違うの？ というのは他の方に任せるとして、やっぱりMNIST以外のデータで色々試してみたいですよね。
**というわけで為替(FX)の予測でもやってみます**

**関連シリーズ**
- 第１回 TensorFlow (ディープラーニング)で為替(FX)の予測をしてみる
- [第２回 ディープじゃない機械学習で為替(FX)の予測をしてみる](http://qiita.com/hayatoy/items/61042af42688464250f9)
- [第３回 TensorFlow (ディープラーニング)で為替(FX)の予測をしてみる CNN編](http://qiita.com/hayatoy/items/0ec3f3da680ae192ddc7)

# 他の方の研究、記事など

調べてみると色んな方がやっています。[この辺](https://github.com/corrieelston/datalab/blob/master/FinancialTimeSeriesTensorFlow.ipynb)とか、Qiitaだと以下が有名なようです。

- [[TensorFlowで株価予想] 0 - Google のサンプルコードを動かしてみる](http://qiita.com/akiraak/items/b27a5616a94cd64a8653)
- [TensorFlowを使った為替(FX)のトレードシステムを作るチュートリアル](http://qiita.com/jiji_platform/items/268377c542706e6f44b1)

学習に用いるデータを大きく分けると以下で、`特徴量`と`ラベル`はそれぞれ組み合わせが入れ替わるのもあります。

| 特徴量 | ラベル |
| --- | --- |
| 過去の値動き（終値） | 次の終値 |
| テクニカルインジケータ | 取引有無 | 

今回は以下の論文を参考に、過去の値動きの変動量を学習させてみます。
終値の変動値を特徴量として、次に**上がるか** or **下がるか**を予測する2クラス問題です。
[Artificial neural networks approach to the forecast of stock market price movements](https://www.researchgate.net/publication/307639575_Artificial_neural_networks_approach_to_the_forecast_of_stock_market_price_movements)
(精度が平均8割もあるけど…ホントかなぁ）

# ヒストリカルデータの取得
フリーでデータをダウンロードできるところはたくさんありますが、細かい時間単位（５分足とか１分足）になると数が限られます。有名どころだと

- [FXDD](http://www.fxdd.com/us/en/forex-resources/forex-trading-tools/metatrader-1-minute-data/)
- [OANDA (API)](http://developer.oanda.com/rest-live/rates/)
- [Dukascopy](https://www.dukascopy.com/swiss/english/marketwatch/historical/)

この辺りでしょうか。ただ注意しなければならないのは、どこでダウンロードしても**同じデータであるとは限らない**点です。
> な… 何を言っているのか わからねーと思うが、俺も何をされたのかわからなかった……… 恐ろしいものの片鱗を 味わったぜ………

つまり**大人の事情**でちょっと値が違うんですけど、それは今回無視しますw
また、データ欠損もそこそこあります。

# 動作環境の構築
今回必要なのは`Python`、`TensorFlow`、`Pandas`と`numpy`位です。`pip`で大体インストール可能ですが、めんどくさければ`Google Cloud Platform`の`Datalab`を使えばプリインストールされている環境が利用できます。
[Cloud Datalab](https://cloud.google.com/datalab/)
`Compute Engine`上で動いているので、ちょっと重めの計算したいなぁという時はCPU数を32に増やしたり、ただデータを眺めるだけの時はリソースを制限したりと、柔軟に調整できます。

また[Dataflow](https://cloud.google.com/dataflow/)にもTensorFlowは入っているので、学習の時だけクラウドで実行することもできます。
詳しいやり方は以下の記事を参照してください。
http://qiita.com/hayatoy/items/2eb2bc9223dd6f5c91e0

# トレーニングデータの作成
ヒストリカルデータからトレーニング用にデータを作成します。
今回はEUR/USDの2011年から2015年までの1時間足を使います。

## Pandas Dataframeに読み込む
データの提供先によってフォーマットは異なりますが、`Open`, `High`, `Low`, `Close`, `Volume`と日付データが揃っているのが一般的です。
今回は以下のようにCSVから読み込みをしています。

```py
dateparse = lambda x: pd.datetime.strptime(x, '%d.%m.%Y %H:%M:%S.000')
df = pd.read_csv(filename, index_col = 0, parse_dates=True, date_parser=dateparse)
```
試しに`df.tail()`してみるとこんな感じ

|   | High | Close | Volume | Open | Low |
| --- | --- | --- | --- | --- | --- |
| Gmt time |		
| 2015-12-31 17:00:00 | 1.08673 | 1.08655 | 6267.45 | 1.08582 | 1.08530 |
| 2015-12-31 18:00:00 | 1.08803 | 1.08693 | 5447.33 | 1.08654 | 1.08611 |
| 2015-12-31 19:00:00 | 1.08743 | 1.08574 | 2827.16 | 1.08693 | 1.08567 |
| 2015-12-31 20:00:00 | 1.08768 | 1.08660 | 5481.39 | 1.08577 | 1.08572 |
| 2015-12-31 21:00:00 | 1.08692 | 1.08564 | 2532.77 | 1.08660 | 1.08529 |

終値をプロットしてみる

```py
df['Close'].plot(figsize=(10,5), linewidth=0.5)
```
![Close Price](https://qiita-image-store.s3.amazonaws.com/0/162369/99a80e70-dea5-fdf3-1f7b-ff89b64009a6.png)
この区間の長期レンジは下降(ドル高ユーロ安）ですね。

## 終値の差分を求める
`Pandas`を使うと簡単です。

```py
# 一つ前の終値と現在の終値の差分
df['Close_Diff'] = df['Close'] - df['Close'].shift(1)
```

### 正規化する
分散はどうするの？とか色々ツッコミはあるかと思いますが、学習させる上ではどれが正解とも言い難いのでとりあえず最大最小値の差を1.0に合わせるだけにします。
*（今気がついたけど中央値を平均にしちゃうと差分の意味が変わっちゃうな…まぁいいか）*

```py
df = pd.DataFrame((df['Close_Diff']-df['Close_Diff'].mean()) / (df['Close_Diff'].max() - df['Close_Diff'].min()), columns=['Close_Diff'])
```
プロットして確認してみます。

![close_diff.png](https://qiita-image-store.s3.amazonaws.com/0/162369/06f4183c-30a2-6c3b-e471-fb66236ecc3c.png)

これを26期間にスライス、1期間毎にストライドさせています。

# RNN (LSTM)で学習
LSTMの実装は[これ](https://github.com/aymericdamien/TensorFlow-Examples/blob/master/notebooks/3_NeuralNetworks/bidirectional_rnn.ipynb)ほぼそのままで、入力の部分だけshapeを今回のデータに合わせました。するとこんな感じにBi-Directionalなモデルが出来上がります。
![rnn.png](https://qiita-image-store.s3.amazonaws.com/0/162369/dbe13bcf-9444-95f7-de90-6ea2764d8e00.png)
Bi-Directionalにすると過去から未来への時系列と未来から過去への時系列を追って学習してくれるのですが、これが今回のデータに合っているかどうかは再考が必要です。

設定はこんな感じ。

```py
learning_rate = 0.0001
training_iters = 500000
batch_size = 128
```

ちなみにトレーニングデータの多い方のクラス割合は`0.502118`なので、これを超えないとランダムに選択するより精度悪いじゃん！ってなります。
では学習の結果は・・・

`0.528883`

う〜ん・・・**2%ちょっと**ランダムよりマシですね。
試しにステップ数を上げてぶん回してもほとんど変わりませんでした。
**追記**
スライスする期間を104に上げ、ステップ数を80万位にしてみました。
8コア(CPU only)で15時間ほど。

![35.187.203.56-6006-(iPad).png](https://qiita-image-store.s3.amazonaws.com/0/162369/5371f06e-c42a-bccb-ba19-cd207b2b528b.png)
...oh... オーバーフィッティングしちゃった。

# 次回以降
CNNを使ったり、別の通貨ペアでも試してみようかなと思います。

**追記　→やってみました。**
[TensorFlow (ディープラーニング)で為替(FX)の予測をしてみる CNN編](http://qiita.com/hayatoy/items/0ec3f3da680ae192ddc7)

**DISCLAIMER**
この記事は個人的な趣味による実験です。真似して損害を被っても当方は責任を負いません。。というか絶対損しますw