В частности, я хочу взять данные за первые пять дней, чтобы спрогнозировать цену закрытия шестого дня. .
Прежде всего, в качестве экономических данных у меня есть цены открытия, максимума, минимума и закрытия; В качестве данных о настроениях у меня есть среднее значение показателя полярности, агрегированное по дням заголовков, опубликованных для каждого тикера.
Прежде всего я изучил матрицу корреляции. Поскольку я увидел, что существует огромная корреляция между ценами открытия, максимума, минимальной и закрытия, я решил сохранить только цену закрытия в данных своих функций, которые будут использоваться в моей модели.
У меня есть 50 тикеров в моем фрейме данных, поэтому, чтобы создать данные последовательности для моей модели, я определил следующие функции:
Код: Выделить всё
def create_sequences(data, seq_length, feature_cols, target_col):
features = feature_cols.copy()
features.remove('ticker')
ticker_list = []
X = []
y = []
for ticker in data["ticker"].unique():
ticker_data = data[data["ticker"] == ticker].reset_index(drop=True)
ticker_data = ticker_data.drop('ticker', axis=1)
for i in range(seq_length, len(ticker_data)):
X.append(ticker_data.loc[i - seq_length: i - 1, features].values)
y.append(ticker_data.loc[i, target_col])
ticker_list.append(ticker)
return ticker_list, np.asarray(X), np.asarray(y)
Затем я определил следующие функции для масштабирования и создания набора данных:
Код: Выделить всё
def define_scalers_per_ticker(dataframe_train):
price_column = "close"
scaler = {}
for ticker in dataframe_train["ticker"].unique():
ticker_data = dataframe_train[dataframe_train["ticker"] == ticker]
scaler[ticker] = {}
price_scaler = MinMaxScaler(feature_range = (0,1))
price_scaler.fit(ticker_data[[price_column]])
scaler[ticker][price_column] = price_scaler
volume_scaler = MinMaxScaler(feature_range = (0,1))
volume_scaler.fit(ticker_data[["volume"]])
scaler[ticker]["volume"] = volume_scaler
return scaler
def scale_ticker_data(scaler, dataframe):
scaled_dataframe = dataframe.copy()
numeric_columns = ["close", "volume"]
scaled_dataframe[numeric_columns] = scaled_dataframe[numeric_columns].astype("float32")
for ticker in dataframe["ticker"].unique():
ticker_mask = dataframe["ticker"] == ticker
for column in numeric_columns:
scaled_values = scaler[ticker][column].transform(
scaled_dataframe.loc[ticker_mask, [column]]
)
scaled_dataframe.loc[ticker_mask, [column]] = scaled_values
return scaled_dataframe
def scale_dataframe(train_dataframe: pd.DataFrame, test_dataframe: pd.DataFrame):
scaler = define_scalers_per_ticker(train_dataframe)
df_train_trs = scale_ticker_data(scaler, train_dataframe)
df_test_trs = scale_ticker_data(scaler, test_dataframe)
return scaler, df_train_trs, df_test_trs
Код: Выделить всё
class TemporalDataset(Dataset):
def __init__(self, tickers, sequence_data, labels):
self.data = sequence_data
self.tickers = tickers
self.labels = labels
def __len__(self):
return len(self.data)
def __getitem__(self, idx)->Dict:
ticker = self.tickers[idx]
data = torch.tensor(self.data[idx], dtype=torch.float32)
labels = torch.tensor(self.labels[idx], dtype=torch.float32)
sample = {'ticker': ticker, 'data': data, 'labels': labels}
return sample
class BaseLstmVar(nn.Module):
def __init__(self, input_size, hidden_size, num_lstm_layers, lstm_dropout, dropout, output_size):
super(BaseLstmVar, self).__init__()
self.name = "BaseLSTMVar"
self.lstm =nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=num_lstm_layers,
batch_first=True,
bidirectional=True,
dropout=lstm_dropout if num_lstm_layers > 1 else 0
)
self.fc1 = nn.Linear(2*hidden_size, 50)
self.dropout = nn.Dropout(dropout)
self.fc2 = nn.Linear(50, output_size)
self.leaky_relu = nn.LeakyReLU()
def forward(self, x):
lstm_out, (hn, cn) = self.lstm(x)
target = torch.mean(lstm_out, dim=1)
out = self.fc1(target)
out = self.leaky_relu(out)
out = self.dropout(out)
out = self.fc2(out)
return out
Код: Выделить всё
ticker_list_train, x_train, y_train = create_sequences(
df_train_model, sequence_length, feature, 'close', True
)
ticker_list_test, x_test, y_test = create_sequences(
df_test_model, sequence_length, feature, 'close', True
)
train_dataset = TemporalDataset(
ticker_list_train, x_train, y_train
)
test_dataset = TemporalDataset(
ticker_list_test, x_test, y_test
)
batch_size = 32
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
net = BaseLstmVar(
input_dim, hidden_lstm_size, lstm_num_layers, lstm_drp, dropout_rate, output_size
)
print(net)
epochs = 2
learning_rate = 1e-3
criterion = nn.MSELoss()
optimizer = optim.AdamW(net.parameters(), lr=learning_rate)
device = detect_device()
train_logger = instantiate_logger(f"{model}_{net.name}_train_logger_pkl")
net = net.to(device)
# training
losses = []
for epoch in range(epochs):
net.train()
epoch_loss = 0
train_logger.info(
f"Starting epoch {epoch + 1}/{epochs}"
)
for idx_batch, batch in enumerate(train_dataloader):
optimizer.zero_grad()
batch_x, batch_y = batch['data'].to(device), batch['labels'].to(device)
outputs = net(batch_x)
loss = criterion(outputs, batch_y.reshape(-1, 1))
loss.backward()
optimizer.step()
loss_rnd = round(loss.item(), 4)
epoch_loss += loss_rnd
train_logger.info(
f"Batch [{idx_batch + 1}/{len(train_dataloader)}], \t Loss: {loss_rnd: .4f}"
)
avg_epoch = epoch_loss / len(train_dataloader)
losses.append(avg_epoch)
train_logger.info(
f"Avg epoch loss in {epoch + 1} epoch: {avg_epoch:.4f}"
)
Код: Выделить всё
batch = next(iter(test_dataloader))
tickers, data, labels = batch['ticker'], batch['data'].to(device), batch['labels'].to(device)
output_test = net(data).detach().cpu().numpy()
output_real = labels.cpu().numpy()
unsc_out_test = []
unsc_out_real = []
for idx, ticker in enumerate(tickers):
unsc_out_test.append(scaler[ticker]['close'].inverse_transform(output_test[idx].reshape(-1, 1)).item())
unsc_out_real.append(scaler[ticker]['close'].inverse_transform(output_real[idx].reshape(-1, 1)).item())
Подробнее здесь: https://stackoverflow.com/questions/791 ... same-value
Мобильная версия