PyTorchを初めて使い、USDJPYの価格予測をしてみました.
色々、試行錯誤しましたが、損失があまり変わらないです.
移動平均線みたいな予測になってますね.
過学習かどうかの判断が難しいな...
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
pd.set_option('display.max_columns', None)
df = pd.read_csv('candle_d_dmi_close_5.csv')
df.head()
time | volume | open | high | low | close | spread | tr | plus_dm | minus_dm | smoothed_tr | smoothed_plus_dm | smoothed_minus_dm | plus_di | minus_di | dx | adx | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2016-09-01 | 0.0 | 103.409 | 103.996 | 103.058 | 103.230 | 0.017 | 0.938 | 0.508 | 0.000 | 0.938 | 0.169 | 0.000 | 18.053 | 0.000 | 100.000 | 100.000 |
1 | 2016-09-02 | 0.0 | 103.238 | 104.319 | 102.799 | 103.761 | 0.265 | 1.520 | 0.323 | 0.000 | 1.132 | 0.221 | 0.000 | 19.484 | 0.000 | 100.000 | 100.000 |
2 | 2016-09-05 | 0.0 | 104.047 | 104.107 | 103.144 | 103.405 | 0.044 | 0.963 | 0.000 | 0.000 | 1.076 | 0.147 | 0.000 | 13.669 | 0.000 | 100.000 | 100.000 |
3 | 2016-09-06 | 0.0 | 103.398 | 103.805 | 101.929 | 102.011 | 0.014 | 1.876 | 0.000 | 1.215 | 1.342 | 0.098 | 0.405 | 7.302 | 30.169 | 61.026 | 87.009 |
4 | 2016-09-07 | 0.0 | 101.996 | 102.128 | 101.205 | 101.737 | 0.010 | 0.923 | 0.000 | 0.724 | 1.203 | 0.065 | 0.511 | 5.434 | 42.518 | 77.336 | 83.784 |
# import
%matplotlib inline
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.preprocessing import MinMaxScaler, StandardScaler
import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
from sklearn.model_selection import train_test_split
# Dataset
class TimeSeriesDataset(Dataset):
def __init__(self, X, y):
self.X = torch.tensor(X, dtype=torch.float32)
self.y = torch.tensor(y, dtype=torch.float32)
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
# Model
class LSTMModel(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size):
super(LSTMModel, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
# LSTMの初期状態を初期化
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
# LSTM出力
out, _ = self.lstm(x, (h0, c0))
# 最後のタイムステップの出力を使用
out = self.fc(out[:, -1, :])
return out
# Sequence
def create_sequences(X, y, seq_length):
X_seq, y_seq = [], []
for i in range(len(X) - seq_length):
X_seq.append(X[i:i+seq_length])
y_seq.append(y[i+seq_length]) # t+1の予測
return np.array(X_seq), np.array(y_seq)
# Main
feature_columns = ['close', 'plus_di', 'minus_di']
target_column = 'close'
sequence_lens = range(200, 201, 10)
split_ratio = 0.8
batch_size = 1000
hidden_sizes = range(200, 201, 10)
num_layers = 3
output_size = 1
num_epochs = 100
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# データ読み込み
# df = pd.read_csv('your_data.csv')
X = df[feature_columns].values
y = df[target_column].values.reshape(-1, 1)
# データの前処理(スケーリング)
X_scaler = StandardScaler()
y_scaler = StandardScaler()
X_scaled = X_scaler.fit_transform(X)
y_scaled = y_scaler.fit_transform(y)
for sequence_len in sequence_lens:
# シーケンスデータの作成
X_seq, y_seq = create_sequences(X_scaled, y_scaled, sequence_len)
# トレーニングデータとテストデータに分割
split_idx = int(len(X_seq) * split_ratio)
X_train, X_test = X_seq[:split_idx], X_seq[split_idx:]
y_train, y_test = y_seq[:split_idx], y_seq[split_idx:]
# データローダーの作成
train_dataset = TimeSeriesDataset(X_train, y_train)
test_dataset = TimeSeriesDataset(X_test, y_test)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
for hidden_size in hidden_sizes:
print(f"Sequence length: {sequence_len}, Hidden size: {hidden_size}")
# モデルの定義
model = LSTMModel(X_train.shape[2], hidden_size, num_layers, output_size).to(device)
# 損失関数
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 訓練・テスト
train_losses, test_losses = [], []
for epoch in range(num_epochs):
# 訓練
model.train()
train_loss = 0
for X_batch, y_batch in train_loader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
# フォワードパス
outputs = model(X_batch)
# 損失
loss = criterion(outputs, y_batch)
# バックワードパスと最適化
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
# テスト
model.eval()
test_loss = 0
with torch.no_grad():
for X_batch, y_batch in test_loader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
outputs = model(X_batch)
# 損失
loss = criterion(outputs, y_batch)
test_loss += loss.item()
# 損失
train_losses.append(train_loss / len(train_loader))
test_losses.append(test_loss / len(test_loader))
if (epoch+1) % 10 == 0:
print(
f'Epoch [{epoch+1:03}/{num_epochs:03}], '
f'Train Loss: {train_losses[-1]:.4f}, '
f'Test Loss: {test_losses[-1]:.4f}'
)
# 予測・評価
model.eval()
predictions, actuals = [], []
# 予測
with torch.no_grad():
for X_batch, y_batch in test_loader:
X_batch = X_batch.to(device)
outputs = model(X_batch)
predictions.extend(outputs.cpu().numpy())
actuals.extend(y_batch.cpu().numpy())
# スケールを元に戻す
predictions = y_scaler.inverse_transform(np.array(predictions))
actuals = y_scaler.inverse_transform(np.array(actuals))
# 評価
mse = np.mean((predictions - actuals) ** 2)
rmse = np.sqrt(mse)
mae = np.mean(np.abs(predictions - actuals))
print(f'Mean Squared Error : {mse:.4f}')
print(f'Root Mean Squared Error: {rmse:.4f}')
print(f'Mean Absolute Error : {mae:.4f}')
# 可視化
plt.figure(figsize=(20, 12))
# 訓練・テストの損失
plt.subplot(2, 1, 1)
plt.plot(train_losses, label='Training Loss')
plt.plot(test_losses, label='Testing Loss')
plt.title('Model Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
# 実績・予測
plt.subplot(2, 1, 2)
plt.plot(actuals, label='Actual Price')
plt.plot(predictions, label='Predicted Price')
plt.title('Price Prediction')
plt.xlabel('Time Steps')
plt.ylabel('Price')
plt.legend()
plt.tight_layout()
plt.show()
Sequence length: 200, Hidden size: 200
Epoch [010/100], Train Loss: 0.0606, Test Loss: 0.1134
Epoch [020/100], Train Loss: 0.0379, Test Loss: 0.1359
Epoch [030/100], Train Loss: 0.0118, Test Loss: 0.0716
Epoch [040/100], Train Loss: 0.0069, Test Loss: 0.0334
Epoch [050/100], Train Loss: 0.0047, Test Loss: 0.0221
Epoch [060/100], Train Loss: 0.0036, Test Loss: 0.0162
Epoch [070/100], Train Loss: 0.0035, Test Loss: 0.0160
Epoch [080/100], Train Loss: 0.0034, Test Loss: 0.0162
Epoch [090/100], Train Loss: 0.0033, Test Loss: 0.0156
Epoch [100/100], Train Loss: 0.0033, Test Loss: 0.0152
Mean Squared Error : 2.8465
Root Mean Squared Error: 1.6871
Mean Absolute Error : 1.2243