深層学習 Day 4 - 為替データの扱い のまとめ


この記事は個人的なお勉強用のメモです。

# 講義

講義なし。
完全な自習。
それどころか、「為替データの扱い」というものが
シラバスでいうどれに相当するのかもわかっていない。

# 実装演習

### 実装方針

以下のページを参考にしてして実行してみた。

単純なディープラーニングで為替を予想する
`https://www.tcom242242.net/entry/fx-begin/%E3%80%90fx-ai%E3%80%91%E5%8D%98%E7%B4%94%E3%81%AA%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%A7%E7%82%BA%E6%9B%BF%E3%82%92%E4%BA%88%E6%83%B3%E3%81%99/`


ただし、以下の部分のみ変更
・ソースコードの先頭に oandapyV20 をインストールする行（!pip install oandapyV20）を追加
・自ら発行したアクセストークンを指定
・グラフにラベルを表示するための行（plt.legend()）の行を追加
　（コピー元のソースにはこの行が存在しないが、どうしてラベルを表示できているのだろううか）

### サンプルコード

```python
!pip install oandapyV20

import numpy as np
import pandas as pd
from oandapyV20 import API
import oandapyV20.endpoints.instruments as instruments
import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation, Flatten
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error

COUNT = 5000        # 一度に取得するデータ数(max:5000)
NB_ITR = 10         # count * NB_ITR 分データを取得
GRANULARITY = "M5"   # 足の種類。今回は５分足
INSTRUMENT = "USD_JPY"    # USD/JPY
INPUT_LEN = 10            # 入力の長さ。現時点から10足前までのデータを入力とする。
EPOCHS = 100              # ニューラルネットワークの学習EPOCH
BATCH_SIZE = 32           # ニューラルネットワークのバッチサイズ
ACCESS_TOKEN = "************"    # OANDA APIのアクセストークン（この部分は自分で取得したトークンを指定）
api = API(access_token=ACCESS_TOKEN, environment="practice")

params = {
    "granularity": GRANULARITY,
    "count": COUNT,
    "price": "B",
}

def get_candles(instrument="USD_JPY", params=None, api=None):
    """
        足データを取得してDataFrameに変換
    """
    instruments_candles = instruments.InstrumentsCandles(
        instrument=instrument, params=params)

    api.request(instruments_candles)
    response = instruments_candles.response

    df = pd.DataFrame(response["candles"])

    return df

# 足データの取得
candles = None
for i in range(NB_ITR):
    print(i)
    new_candles = get_candles(instrument=INSTRUMENT, params=params, api=api)
    params["to"] = new_candles["time"].iloc[0]
    print(params["to"])
    candles = pd.concat([new_candles, candles])


prices = np.array([x["c"] for x in candles["bid"].values])
prices = prices.astype(np.float64)
prices = prices.reshape(-1, 1)

sc = MinMaxScaler(feature_range=(0, 1))
prices = sc.fit_transform(prices)

X, Y = [], []
for i, _ in enumerate(prices):
    if (i+INPUT_LEN+1 >= len(prices)):
        break
    X.append(prices[i:i+INPUT_LEN])
    Y.append(prices[i+INPUT_LEN+1])

X = np.array(X)
Y = np.array(Y)

# 学習用・テスト用に分割
split_index = int(len(prices)*0.7)
X_train = X[:split_index]
Y_train = Y[:split_index]
X_test = X[split_index:]
Y_test = Y[split_index:]

# モデルの作成
model = Sequential()
model.add(Flatten(input_shape=[INPUT_LEN, 1]))
model.add(Dense(32))
model.add(Activation("relu"))
model.add(Dense(32))
model.add(Activation("relu"))
model.add(Dense(1))
model.add(Activation("linear"))

model.compile(loss="mse",   # 誤差関数
              optimizer="adam",     # 最適化手法
              metrics=["accuracy"])

model.fit(X_train, Y_train, batch_size=BATCH_SIZE, epochs=EPOCHS)

print(model.evaluate(X_test, Y_test))

# 実際の値と評価値を比較する
predicted_y = model.predict(X_test)
fig, ax = plt.subplots()

# 実際の値のプロット
Y_test = sc.inverse_transform(Y_test)
ax.plot(np.arange(len(Y_test)), Y_test, label="real")

# 予測値のプロット
predicted_y = sc.inverse_transform(predicted_y)
ax.plot(np.arange(len(predicted_y)), predicted_y, label="predicted_value")
plt.legend()
plt.show()
```

### サンプルコードの概要（深層学習の部分）

- Keras を利用（TensorFlow バージョン2）
- 中間層は2層、いずれの層もノードの数は32、活性化関数は ReLU
- 誤差関数は MSE（二乗誤差）
- 最適化手法は Adam


### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810819/f1ae356a-80d6-c3ca-1f2b-84ddc5d48129.png)

（中略）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810819/b8c223e3-256f-c118-01ac-564187b1dbe2.png)

部分的に予測が少し外れているが、ほぼ正しい予測が出力されている。
筆者が言うように、直前のデータを使って予測しているため、
外れが少ないのだろう。