【FX, AI】単純なディープラーニングで為替を予想する

English version

前回までで簡単なチャートの表示やテクニカル分析を行いました。

今回はとうとうニューラルネットワーク(ディープラーニング)でFXの予想をしてみます。

具体的には、現時点から過去n日分の情報を入力して次の日(n+1)の値を予想させます。

ニューラルネットワークとは

(人工)ニューラルネットワークとは簡単に言ってしまえば、人間の脳の神経回路網を簡易的にモデル化したものです。

以下はニューラルネットワークの1例です。

ニューラルネットワークのイメージ図

このネットワークは左から値を入力して、そこから右方向に伝搬していくようなモデルです。
今回の為替の例で言えば、過去n日分のチャートのデータを左から入力して、次の日n+1日の為替の予想値を右から出力させます。
このネットワークの層を増やしたもの(ディープにしたもの)をディープラーニングと言います。

ニューラルネットワークの処理は主に学習フェーズと推論フェーズに分かれています。
学習フェーズはニューラルネットワークにデータを入力し学習させます。
推論フェーズでは、実際に未知の情報を入力して、予想させます。

実装

今回はニューラルネットワークを構築するためのライブラリとしてTensorFlowを用います。
インストールしていない人は以下のコマンドでインストールしてください。

pip install tensorflow


また、TensorFlowのバージョン2.0を使うのでバージョンが古い人は更新しておいてください。

では実装していきます。
ソースコードは主に

  • 生の為替データの取得
  • 生データから学習データへの加工
  • ニューラルネットワークの学習
  • ニューラルネットワークを使った予測

のようなフェーズがあります。
順番に実装していきます。

いつものように必要なモジュール等をimportしておきます。
Tensorflowやoanda関連のライブラリです。

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"   # 足の種類。今回は5分足
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",
}

生のデータの取得

為替データの取得を行います。

今回はUSD/JPYの5分足のデータを用います。
先に足データを取得して、pandasのDataFrame型にして返すメソッドを用意します。
通常のOANDA APIの操作では1度に5000件のデータしか取れないため、メソッド作って何回もこの処理を行うことで5000件以上のデータを取得します。

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])

ここでは、NB_ITR分get_candlesメソッドを呼び出してデータを取得してます。
細かい説明は省きますが、データを取ってきてはすでにあるデータに追加しています。
これで生データの取得は完了です。

生データから学習データへの加工

今回は取得した足データの中でもCloseのデータだけを使うので、Closeだけを取り出していきます。

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

次に、取得したデータを標準化しておきます。つまり、すべてのデータを0〜1の間の値に変化しています。
(標準化することで学習効率が上がるため)
ここでは、scikit-learnという機械学習用のライブラリを用います。MinMaxScalerが標準化に用いるクラスです。fit_transformとすることで標準化しています。

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

ニューラルネットワークに読み込めるようなデータ(X,Y)を生成します。
各データはX[0]=[t1, t2, …, tn], Y[0]=tn+1となるようになります。

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:]

ニューラルネットワークの構築と学習

では、ニューラルネットワークの構築と学習を行っていきます。

TensorFlowのKerasではニューラルネットワークの構築は簡単です。以下のコードで構築は完了です。

# モデルの作成
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のaddメソッドを使うことで層を順に追加していきます。
今回は値の予測(回帰)をするので、出力は1つになります。

次に構築したニューラルネットワークを学習していきます。

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

modelのfit関数を使えば簡単に学習できます。先程作成した学習用のデータ(X_train, Y_train)を使って学習していきます。

ニューラルネットワークを使った評価と予測

ここまでで学習は終わりました。
次に学習したモデルの評価を行っていきます。
まず、テスト用に用意したデータ(X_test, Y_test)を使って評価してみます。
これもmodelについてevaluateメソッドを使えば簡単です。

print(model.evaluate(X_test, Y_test))

すると次のように出力します。

[5.802867302361515e-05, 0.00013352917612498332]

今回は左の要素(loss)だけ見れば良いです。左の要素はテストデータに対する二乗誤差です。

誤差を小さくできていることがわかります。

では、どのように予測しているか実際にプロットして確認します。

# 実際の値と評価値を比較する
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)

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

先程データ標準化したりしたので元の値に戻す作業もしています。
以下が上記のコードを実行した後の出力です。

単純なニューラルネットワークによる予想


単純なニューラルネットワークでもある程度うまく予測できているように見えますね!
ただ、今回は予測したい時点から1時点前のデータを見てるので、1時点前の値に近い値を出力していればだいたい当たってしまう設定になっているかもしれません(笑)

終わりに

今回は単純なニューラルネットワークを使って為替の予測をしてみました。
単純なニューラルネットワークでもまともな結果が出ているような気がします。

次は時系列データをうまく扱えるリカレントニューラルネットワークを使って学習してみようと思います。

タイトルとURLをコピーしました