この記事では、時系列モデルの代表格であるLSTMを活用したFX市場予測モデルの構築と実装について、詳細に解説します。主な内容は以下の通りです:
- LSTMネットワークの仕組みと利点
- 時系列データの前処理技術(価格正規化、時間トークン化)
- PythonによるLSTMモデルの構築と訓練
- Pythonでの予測システム実装と評価方法
- ONNXを介したMQL5への移行とエキスパートアドバイザー(EA)の開発
この記事は、AIを活用したFXトレードに興味のあるトレーダーや開発者を対象としています。Pythonでのモデル開発からMT5での実装まで、一連の流れを学ぶことができます。
LSTMネットワークの仕組みと利点
Long Short-Term Memory (LSTM) ネットワークは、従来の回帰型ニューラルネットワーク (RNN) の限界を克服するために設計された特殊なタイプのRNNです。LSTMの主な特徴は、長期的な依存関係を効果的に処理できる能力にあります。
LSTMの中核はメモリセルと呼ばれる構造です。このメモリセルは、情報を長期間保持し、必要に応じて更新や削除を行うことができます。メモリセルの動作は、以下の3つの主要なゲートによって制御されています:
- 忘却ゲート:不要な情報を選択的に忘れる
- 入力ゲート:新しい情報をメモリセルに追加する
- 出力ゲート:メモリセルの情報を出力として使用する
従来のRNNと比較して、LSTMには以下の利点があります:
- 長期的な依存関係の効果的な学習:時系列データの長期的なパターンを捉えることができる
- 選択的な情報の保持と忘却:重要な情報を長期間保持し、不要な情報を適切に忘れることができる
- 勾配問題の緩和:長い系列でも安定して学習できる
これらの特性により、LSTMは時系列データの分析や予測に特に適しており、金融市場の予測や取引戦略の開発において強力なツールとなります。例えば、過去の価格動向や市場指標の長期的なパターンを学習し、将来の価格変動を予測することができます。
学者ではないからこの辺はザックリね
時系列データの前処理
価格正規化
価格正規化の目的は、異なるスケールの価格データを統一された範囲に変換することです。これにより、モデルの学習効率が向上し、異なる通貨ペア間の比較も容易になります。
本プロジェクトでは、日次ローリング正規化という手法を採用しました。この方法の主なステップは以下の通りです:
- 日付でデータをグループ化
- 各日のローリング最高値と最安値を計算
- 価格を0から1の範囲に正規化:(price – rolling_low) / (rolling_high – rolling_low)
def normalize_daily_rolling(data):
data['date'] = data.index.date
data['rolling_high'] = data.groupby('date')['high'].transform(lambda x: x.expanding(min_periods=1).max())
data['rolling_low'] = data.groupby('date')['low'].transform(lambda x: x.expanding(min_periods=1).min())
data['norm_open'] = (data['open'] - data['rolling_low']) / (data['rolling_high'] - data['rolling_low'])
data['norm_high'] = (data['high'] - data['rolling_low']) / (data['rolling_high'] - data['rolling_low'])
data['norm_low'] = (data['low'] - data['rolling_low']) / (data['rolling_high'] - data['rolling_low'])
data['norm_close'] = (data['close'] - data['rolling_low']) / (data['rolling_high'] - data['rolling_low'])
# Replace NaNs with zeros
data.fillna(0, inplace=True)
return data
例えば、ある日のEURUSDの価格が1.1000から1.1100の間で変動した場合、1.1000が0、1.1100が1に対応し、その間の価格は比例的に0から1の間の値に変換されます。
この方法の利点は、各日の価格変動を相対的に捉えることができ、日をまたいだ大きな価格変動の影響を軽減できることです。これにより、モデルは日々の相対的な価格変動に焦点を当てることができます。
簡単に言うと、価格の絶対値ではなく、変化量にするということ。
時間トークン化
時間トークン化は、時間情報を数値表現に変換することです。これにより、LSTMモデルが時間の周期性や規則性を学習しやすくなります。
採用した時間トークン化の手法は以下の通りです:
- 各データポイントの時間を秒単位に変換
- 1日の総秒数(86400秒)で割り、0から1の範囲に正規化
例えば、午前6時は0.25、正午は0.5、午後6時は0.75に対応します。
この方法により、モデルは1日のどの時点でデータが発生したかを理解できるようになります。これは、市場の時間帯による特性(例:アジアセッション、ヨーロッパセッション、米国セッション)を学習する上で重要です。
NaN値の処理
データ前処理の過程でNaN (Not a Number) 値が発生する可能性があります。これらの値は適切に処理する必要があります。
本プロジェクトでは、NaN値をゼロに置き換える方法を採用しました。この選択には以下の理由があります:
- シンプルさ:実装が容易で、計算コストが低い
- 一貫性:データの形状を変えずに処理できる
- ONNX互換性:後のONNX変換時に問題が発生しにくい
ただし、この方法にはデータの一部を失う可能性があるというデメリットもあります。代替案として、前方補間や後方補間などの方法も検討しましたが、最終的にはゼロ置換が最も適していると判断しました。
モデル構築と訓練
データ準備とLSTMモデルの実装
モデル構築のはじめに、訓練用のデータを準備します。EURUSD通貨ペアの15分足データを取得しました。データ取得の流れは以下の通りです:
- MetaTrader 5のPythonライブラリを使用してMT5に接続
- copy_rates_from_pos関数を使用して、指定した期間のヒストリカルデータを取得
- 取得したデータをPandasデータフレームに変換し、前処理のために準備
取得したデータは、前処理を適用した後、60タイムステップのシーケンスに構造化しました。つまり、過去15時間分のデータを使用して、次の15分の価格を予測するモデルを構築しました。データは訓練セット(80%)とテストセット(20%)に分割し、モデルの汎化性能を評価できるようにしました。
class LSTMModel(nn.Module):
def __init__(self, input_size, hidden_layer_size, output_size):
super(LSTMModel, self).__init__()
self.hidden_layer_size = hidden_layer_size
self.lstm = nn.LSTM(input_size, hidden_layer_size)
self.linear = nn.Linear(hidden_layer_size, output_size)
self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
torch.zeros(1,1,self.hidden_layer_size))
def forward(self, input_seq):
lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
predictions = self.linear(lstm_out.view(len(input_seq), -1))
return predictions[-1]
LSTMモデルはPyTorchを使用して実装しました。モデルの主な構成要素は以下の通りです:
- LSTM層:時系列データの処理を担当
- 線形層:LSTM層の出力を最終的な予測値に変換
- 隠れ状態:LSTMの内部状態を保持
モデルのハイパーパラメータ(隠れ層のサイズ、学習率など)は、実験と試行錯誤を通じて最適化しました。例えば、隠れ層のサイズを64から256まで変化させ、最も良い性能を示すサイズを選択しました。
データの訓練とONNX変換
訓練は以下の手順で行いました:
- 損失関数として平均二乗誤差(MSE)を選択
- 最適化アルゴリズムとしてAdamオプティマイザを使用
- 100エポックにわたって訓練を実施
- 10エポックごとに損失を表示し、訓練の進捗を監視
- 過学習を防ぐためにearly stoppingを実装
訓練済みモデルをMQL5で使用するために、ONNX (Open Neural Network Exchange) 形式に変換しました。ONNXは、異なる深層学習フレームワーク間でモデルを交換するための開放型規格です。変換のステップは以下の通りです:
- PyTorchのonnx.export関数を使用してモデルをONNX形式に変換
- 入力と出力の名前とshapeを指定
- 変換されたモデルをファイルとして保存
ONNX形式への変換により、訓練済みモデルを異なる環境(この場合はMQL5)で容易に使用することが可能になり、Pythonで訓練したモデルをMT5で直接使用できるようになります。
Pythonでの予測システム実装と評価
予測システムの実装
LSTMモデルの訓練が完了したら、予測システムを実装します。これは、モデルの実際の性能を理解し、改善点を特定するために重要です。
予測システムは、以下の主要な機能を持つPythonスクリプトとして実装しました:
- データ読み込み:MT5から最新の市場データを取得します。これには、最新の60個の15分足データポイントが含まれます。
- データ前処理:取得したデータに対して正規化とトークン化を適用します。これにより、生のデータがモデルの入力に適した形式に変換されます。
- モデル読み込み:訓練済みのLSTMモデルを読み込みます。これはONNX形式で保存されたモデルファイルから行います。
- 予測生成:モデルを使用して将来の価格を予測します。具体的には、次の15分間の終値を予測します。
- 後処理:予測結果を元のスケールに戻します。これにより、正規化された予測値が実際の価格に変換されます。
評価方法
モデルの性能を評価するために、以下の方法を使用しました:
視覚化:
- 実際の価格と予測価格をグラフで比較します。これにより、モデルの予測がどの程度実際の価格動向を追跡しているかを視覚的に確認できます。
- 価格の変化率(パーセント変化)のプロットも作成します。これは、絶対価格ではなく価格の動きを予測する能力を評価するのに役立ちます。
数値指標:
- 平均二乗誤差(MSE):予測値と実際の値の差の二乗の平均を計算します。これは、予測の全体的な精度を評価するのに役立ちます。
- 平均絶対誤差(MAE):予測値と実際の値の絶対差の平均を計算します。これは、予測誤差の平均的な大きさを示します。
- 方向性の正確さ:価格の上昇・下降を正しく予測した割合を計算します。これは、モデルが価格の動きの方向を正確に予測できているかを評価します。
結果分析
評価の結果、以下のような洞察が得られました:
- 短期予測の精度:モデルは短期的な価格変動をある程度正確に捉えることができました。特に、次の15分から1時間程度の予測では比較的高い精度を示しました。
- 長期予測の課題:予測期間が長くなるにつれて精度が低下する傾向が見られました。これは、長期的な市場動向の予測が本質的に困難であることを示しています。
- 方向性の予測:価格の上昇・下降の方向性については比較的高い精度で予測できました。これは、モデルがトレンドを捉える能力を持っていることを示唆しています。
- ボラティリティの影響:市場のボラティリティが高い期間では予測精度が低下する傾向が見られました。これは、急激な価格変動が発生する場合、モデルが適応するのに苦労することを示しています。
- 季節性の捕捉:モデルは日内の価格パターンをある程度捉えることができました。例えば、特定の時間帯に発生する傾向のある価格変動を予測できる場合がありました。
これらの結果は、LSTMモデルがFX市場の短期予測に一定の有効性を持つことを示していますが、同時に改善の余地も明らかになりました。
改善策の検討
評価結果を基に、以下の改善策を検討しました:
- フィーチャーエンジニアリング:追加のテクニカル指標(移動平均、RSI、ボリンジャーバンドなど)や市場センチメントデータの導入
- モデルアーキテクチャの調整:層の深さやユニット数の最適化、注意機構(Attention Mechanism)の導入
- アンサンブル手法:複数のモデルを組み合わせて予測を行うアンサンブル学習の導入
- 異常値処理:極端な市場変動時のデータ処理方法の改善を検討します。例えば、異常値検出アルゴリズムを導入し、モデルの学習や予測に悪影響を与える可能性のあるデータポイントを特定・処理します。
これらの改善策を実装することで、モデルの予測精度と安定性を向上させることが期待できます。
LSTMといっても、そのハイパーパラメーター、誤差の評価方法といったアーキテキチャが無数にあるね
MQL5への移行:エキスパートアドバイザーの開発
ONNXモデルのMQL5での使用とEA基本構造
PythonでのLSTMモデルの開発と評価が完了したら、このモデルをMT5で使用可能なエキスパートアドバイザー(EA)に変換します。ONNXを介したモデルの移行、MQL5でのデータ処理の実装、そして実際のEAロジックの開発が含まれます。
まず、ONNXモデルをMQL5で読み込むために、OnnxCreateFromBuffer関数を使用しました。この関数により、ONNXファイルからモデルを読み込み、MQL5環境で使用可能な形式に変換します。
また、Pythonで作成したデータ処理パイプラインもONNX形式に変換し、MQL5で使用できるようにしました。
#resource "\\LSTM\\lstm_model.onnx" as uchar ExtModel[]
long ExtHandle = INVALID_HANDLE;
int OnInit()
{
ExtHandle = OnnxCreateFromBuffer(ExtModel, ONNX_DEFAULT);
if (ExtHandle == INVALID_HANDLE)
{
Print("Error creating model OnnxCreateFromBuffer ", GetLastError());
return(INIT_FAILED);
}
// Set input and output shapes here
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
if (ExtHandle != INVALID_HANDLE)
{
OnnxRelease(ExtHandle);
ExtHandle = INVALID_HANDLE;
}
}
取引ロジックとリスク管理
予測結果は、取引シグナルに変換されます。予測された価格変動の方向と大きさに基づいてシグナルを生成し、ノイズを減らすためのフィルタリングを適用します。
シグナル生成:
- 予測価格が現在の価格より一定以上高ければ買いシグナル
- 予測価格が現在の価格より一定以上低ければ売りシグナル
- それ以外の場合はニュートラル
フィルタリング:
- 最小変動幅の設定による誤検出の防止
- 連続したシグナルの確認による信頼性の向上
リスク管理とポジション管理も重要な要素です。以下のような機能を実装しました:
ポジションサイジング:
- アカウントバランスと予測の確信度に基づく取引量の決定
- リスクパーセンテージの動的調整
ストップロスとテイクプロフィット:
- 予測されたボラティリティに基づくストップロスの設定
- リスク・リワード比に基づくテイクプロフィットの設定
トレーリングストップ:
- 利益を確保しながらトレンドに追従するメカニズム
まとめ
このプロジェクトを通じて、多くの改善点が見つかりました。以下に焦点を当てて取り組む予定です:
改善点
- モデル精度の向上
- 追加特徴量の導入
- 異なる時間枠や通貨ペアへの適用
- リアルタイムにて運用の改善
これらの改善点を通じて、より信頼性の高いEAの開発を目指します。継続的な学習と市場変化への適応を重視し、常に進化するシステムの構築を目標としています。
課題が多すぎて永遠にかかるよね。
結局は人間がモデルを理解して適切なデータとモデルを選択する必要がある
オンラインコミュニティ
こちらのコミュニティで、AIや機械学習をトレードに活かすために日々探求しています。
興味のある方は覗いてみてください。
参考記事
記事本文のコードは、下記の記事の内容を引用しています。