最終更新: 2026年06月
LSTM(Long Short-Term Memory)を使って為替を予測するコードは、Qiitaや技術ブログに大量に存在する。しかし「実装した」と「実際に使えるものを作った」の間には深い溝がある。筆者は金融時系列予測の実装を複数回試みてきたが、率直に言う。「LSTMで為替を予測してトレードに活用する」のは、コードを書くことより困難な問題が山積している。本稿では実装方法と、その限界を正直に解説する。
LSTMとは何か:FX予測との相性を考える
LSTM(Long Short-Term Memory)は1997年にHochreiterとSchmidhuberが提案した再帰型ニューラルネットワーク(RNN)の拡張だ。通常のRNNが長期依存関係の学習が苦手なのに対し、LSTMは「長期記憶」と「短期記憶」を制御するゲート機構を持つ。
時系列データに強いという特性から、為替予測への応用研究は2015年頃から活発になった。Fischer and Krauss(2018)の研究では、S&P500構成銘柄の日次リターン予測においてLSTMが他のモデル(深層ニューラルネットワーク・ランダムフォレスト・ロジスティック回帰)をアウトパフォームすることが示された。
ただし、為替(FX)は株式と異なる特性を持つ。24時間取引・マクロ経済要因の影響・中央銀行介入・市場参加者の複雑な相互作用など、「テクニカル指標だけでは捉えられない動き」が頻繁に発生する。
Pythonでの実装:ステップバイステップ
必要なライブラリ
# 標準的な構成
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
TensorFlow 2.x以降はKerasがtf.kerasとして統合されており、別途インストールは不要だ。
データの準備
GMOインターネットグループの実装事例では、2019年1月〜7月のドル円1分足データを使用し、80%を学習・各10%を検証とテストに分割している。
# データ読み込み(OHLCV形式を想定)
df = pd.read_csv('usdjpy_1min.csv', parse_dates=['datetime'], index_col='datetime')
# 終値のみ使用する場合
close = df['close'].values.reshape(-1, 1)
# 正規化(0〜1の範囲にスケーリング)
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_close = scaler.fit_transform(close)
# 訓練/テスト分割(順序を保持すること)
train_size = int(len(scaled_close) * 0.8)
train_data = scaled_close[:train_size]
test_data = scaled_close[train_size:]
注意点として、時系列データはランダムシャッフルをしてはならない。過去から未来への時間的順序を必ず保持すること。
シーケンスデータの作成
def create_sequences(data, sequence_length):
X, y = [], []
for i in range(sequence_length, len(data)):
X.append(data[i - sequence_length:i, 0])
y.append(data[i, 0])
return np.array(X), np.array(y)
# 過去60期間を入力として次の1期間を予測
sequence_length = 60
X_train, y_train = create_sequences(train_data, sequence_length)
X_test, y_test = create_sequences(test_data, sequence_length)
# LSTMに渡すための次元変換(samples, timesteps, features)
X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)
X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)
モデル構築
model = Sequential([
LSTM(units=50, return_sequences=True,
input_shape=(sequence_length, 1)),
Dropout(0.2), # 過学習防止
LSTM(units=50, return_sequences=False),
Dropout(0.2),
Dense(units=1) # 次の終値を予測
])
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
GMOの実装事例ではLSTMユニット数を40としたシンプルなモデルが使われていた。複雑なモデルが必ずしも良い結果を出すわけではなく、過学習のリスクが高まる。
学習と予測
history = model.fit(
X_train, y_train,
epochs=50,
batch_size=32,
validation_split=0.1,
shuffle=False # 時系列データはシャッフル禁止
)
# 予測と逆正規化
predictions_scaled = model.predict(X_test)
predictions = scaler.inverse_transform(predictions_scaled)
actual = scaler.inverse_transform(y_test.reshape(-1, 1))
テクニカル指標を特徴量として追加する
GMOの実験では、レートのみ(RMSE: 0.276)より、トレンド系指標(移動平均・ボリンジャーバンド・MACD)を追加した場合(RMSE: 0.108)のほうが精度が向上した。
# pandasで指標を追加する例
df['MA20'] = df['close'].rolling(20).mean()
df['MA50'] = df['close'].rolling(50).mean()
# ボリンジャーバンドの幅
rolling_std = df['close'].rolling(20).std()
df['BB_upper'] = df['MA20'] + 2 * rolling_std
df['BB_lower'] = df['MA20'] - 2 * rolling_std
# RSI
def calculate_rsi(prices, period=14):
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(period).mean()
rs = gain / loss
return 100 - (100 / (1 + rs))
df['RSI'] = calculate_rsi(df['close'])
複数特徴量を使う場合は、各特徴量を個別にスケーリングし、入力次元を(samples, timesteps, features数)に変更する。
実用上の限界:正直な評価
実装できることと「使えること」は別だ。筆者が感じた限界を正直に書く。
価格予測と方向予測の違い
LSTMで「明日の終値が109.50円になる」という価格予測を行うことは技術的に可能だが、これをトレードに直接使うのは危険だ。予測誤差が0.05円(5pips)の場合でも、方向(上昇か下落か)が当たれば利益、外れれば損失になる。
重要なのは「価格」の予測より「方向」の予測精度だ。
非定常性の問題
為替レートは非定常時系列だ。平均や分散が時間によって変化する。LSTMが学習した「パターン」は特定の期間の市場構造を反映しているに過ぎず、市場構造が変化すれば同じモデルは機能しなくなる。
定期的な再学習の必要性
この問題に対処するには、定期的(月次・週次)に最新データを使ってモデルを再学習する必要がある。「一度作ったらずっと使える」という発想は危険だ。
ハルシネーション的な学習
LSTMはトレーニングデータに過適合(過学習)しやすい。Dropoutの導入やデータ分割の工夫で緩和できるが、根本的な解決策ではない。
Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら。LSTMの予測シグナルをベースに、Claude対話でトレードロジックを設計する使い方も探索する価値がある。
評価指標の選択
from sklearn.metrics import mean_squared_error, mean_absolute_error
import numpy as np
mse = mean_squared_error(actual, predictions)
rmse = np.sqrt(mse)
mae = mean_absolute_error(actual, predictions)
# 方向予測精度(より実用的)
direction_actual = np.sign(np.diff(actual.flatten()))
direction_pred = np.sign(np.diff(predictions.flatten()))
directional_accuracy = np.mean(direction_actual == direction_pred)
print(f"RMSE: {rmse:.4f}")
print(f"MAE: {mae:.4f}")
print(f"方向予測精度: {directional_accuracy:.2%}")
方向予測精度50%はランダム(コイントス)と同等だ。55%以上が継続的に出れば、何らかの有意なシグナルが存在する可能性がある。ただし、これもデータ期間・通貨ペア・時間足によって大きく異なる。
実用的なアプローチ:予測単体に頼らない
LSTMの予測を「唯一のエントリー根拠」にするのではなく、他のシグナルと組み合わせたフィルターとして使う発想が実用的だ。
例えば:
- LSTMの上昇予測 + RSIの過売り = エントリーシグナル
- LSTMの下落予測 + 重要サポートライン付近 = 見送り
この組み合わせアプローチにより、シグナルの質を上げつつ、LSTMへの過度な依存を避けられる。
まとめ
LSTMによるFX予測の実装は、技術的な学習プロセスとして非常に価値がある。特徴量エンジニアリング・データ正規化・モデル評価の実践的スキルが身につく。
ただし「LSTMが為替を正確に予測できる」という期待は持つべきではない。為替市場には、テクニカル指標だけでは捉えられない経済・政治・心理的要因が常に影響している。LSTMはその一部を補助するツールとして位置付けるのが現実的だ。
FXには損失リスクがある。機械学習モデルのバックテスト成績が良くても、フォワードパフォーマンスが同等であるとは限らない。実運用前には十分な検証期間と小額テストを必ず実施してほしい。
よくある質問(FAQ)
Q: LSTMはTransformerやほかのアーキテクチャより為替予測に向いていますか? A: 金融時系列予測ではTransformerやTCN(Temporal Convolutional Network)との比較研究が続いている。特定のデータセット・期間では差が出ることがあるが、「どれが最強か」という一般的な答えはない。実装コストを考えると、まずLSTMで基線を確認してから他のアーキテクチャを試すのが合理的だ。
Q: 1分足より日足のほうが予測しやすいですか? A: 一般的に時間足が長いほど短期ノイズが減り、パターンが安定しやすい傾向がある。ただし日足では取引シグナルの頻度が下がる。目的に合わせて選択すること。
Q: GPUがないとLSTMの学習は難しいですか? A: FX予測の規模(数万〜数十万サンプル程度)であれば、CPUでも十分に学習できる。Google ColaboratoryのGPU環境を無料で使う方法もある。
Q: シーケンス長(sequence_length)は何が最適ですか? A: 正解はない。過去60期間・120期間・240期間など複数を試し、検証データでの方向予測精度を比較することを推奨する。
Q: LSTMで予測したシグナルをMT4/MT5で自動売買に使えますか? A: Python側でシグナルを生成し、MT4/MT5にソケット通信で送信する実装が技術的には可能だ。ただし遅延・接続安定性・MT4/MT5のカスタムインジケーター設計など、追加の実装コストがかかる。Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら。
