Привет, это моя первая статья о среде, и спасибо, что решили ее прочитать. Меня зовут Виктор, и я энтузиаст в мире машинного обучения и глубокого обучения. Весь код, использованный в статье, будет находиться в репозитории гитхаб. Подробно описывать не буду, приведу только основные сокращения кода с небольшими комментариями, чтобы он был быстрее и понятнее. Так как код лучше.

Статья носит исключительно ознакомительный характер и категорически не способствует применению в реальной торговле!

Сегодня мы рассмотрим, как применять двунаправленный LSTM для прогнозирования направления цены закрытия следующего дня акций Microsoft (MSFT).

Я предпочитаю использовать env-файл anaconda и yml со всеми зависимостями. Вы можете найти этот файл в репозитории.

Сначала нам нужно загрузить данные из файла csv и нормализовать цену открытия и закрытия с помощью MinMaxScaler.

Хотелось бы посмотреть, как выглядит разница между логарифмами цен закрытия. Мы не будем использовать эти данные в этой статье, но они могут быть очень полезны при классификации прогнозных данных для более чистых сигналов.

давайте посмотрим на наш тестовый сплит:

Накапливайте каждые 50 дневных баров и функцию подготовки данных с помощью вычислителя ema.

Следующим шагом делаем модель. Я предпочитаю разбивать данные разной природы и объединять на последних этапах

Параметры для наших моделей

len = 50
test_size = 0.2
neurons = 100
epochs = 10
batch_size = 32
loss = 'mse'
dropout = 0.2
optimizer = 'adam'

Постепенно получайте данные для обучения и тестирования и тренируйте нашу модель

_train, x_test, x_open_train, x_open_test, y_train, y_test, x_tech_train, x_tech_test = prepare_data(df.values, target_col, len, test_size)

print(x_train.shape) # (3988, 50, 5)
print(x_test.shape) # (996, 50, 5)
print(x_open_train.shape) # (3988, 1)
print(x_open_test.shape) # (996, 1)
print(x_tech_train.shape) # (3988, 5)
print(x_tech_test.shape) # (996, 5)
y_train = np.array(y_train).reshape(1, -1).squeeze()
y_test = np.array(y_test).reshape(1, -1).squeeze()

print(y_train.shape) # (3988,)
print(y_test.shape) # (996,)

Обучение…

model = build_lstm_model(x_train, x_tech_train, x_open_train, output_size=1, neurons=neurons, dropout=dropout, loss=loss, optimizer=optimizer)
history = model.fit(x=[x_train, x_tech_train, x_open_train], y=y_train, epochs=epochs, batch_size=batch_size, verbose=1, shuffle=True, validation_split=0.05)
Train on 3788 samples, validate on 200 samples
Epoch 1/10
3788/3788 [==============================] - 26s 7ms/step - loss: 0.0145 - val_loss: 6.3099e-04
Epoch 2/10
3788/3788 [==============================] - 23s 6ms/step - loss: 4.3845e-04 - val_loss: 1.8132e-04
Epoch 3/10
3788/3788 [==============================] - 23s 6ms/step - loss: 3.4634e-04 - val_loss: 1.5705e-04
Epoch 4/10
3788/3788 [==============================] - 27s 7ms/step - loss: 2.8954e-04 - val_loss: 1.1994e-04
Epoch 5/10
3788/3788 [==============================] - 29s 8ms/step - loss: 2.4499e-04 - val_loss: 1.1416e-04
Epoch 6/10
3788/3788 [==============================] - 37s 10ms/step - loss: 2.2312e-04 - val_loss: 1.0454e-04
Epoch 7/10
3788/3788 [==============================] - 26s 7ms/step - loss: 1.9670e-04 - val_loss: 1.3416e-04
Epoch 8/10
3788/3788 [==============================] - 25s 7ms/step - loss: 1.9615e-04 - val_loss: 1.2558e-04
Epoch 9/10
3788/3788 [==============================] - 28s 7ms/step - loss: 1.8774e-04 - val_loss: 8.5019e-05
Epoch 10/10
3788/3788 [==============================] - 25s 7ms/step - loss: 1.8120e-04 - val_loss: 8.2655e-05

Рассчитать ошибку

preds = model.predict([x_test, x_tech_test, x_open_test]).squeeze()
mean_absolute_error(preds, y_test)
0.011188932196784048

позволяет увидеть реальную цену закрытия с прогнозируемыми ценами

close_real_normallized = close_price_scaller.inverse_transform(y_test.reshape(-1, 1))
close_pred_normallized = close_price_scaller.inverse_transform(preds.reshape(-1, 1))
fig, ax = plt.subplots(1, figsize=(70, 15))
ax.plot(close_real_normallized, label='actual', linewidth=2)
ax.plot(close_pred_normallized, label='prediction', linewidth=2)
ax.set_ylabel('price', fontsize=14)
ax.set_title('title', fontsize=16)
ax.legend(loc='best', fontsize=16);

давай пофантазируем немного

Теперь мы можем посчитать, сколько денег принесет нам наша модель.

pred_bi_direct =[0]
for index in range(1, len(close_pred_normallized)):
    prev_pred = close_pred_normallized[index-1]
    pred = close_pred_normallized[index]
    delta_pred = prev_pred - pred
    pred_bi_direct.append(1 if delta_pred < 0 else -1)
balance_story = calculate_profit()

Ой ... Но давайте посмотрим на это под другим углом. На этом графике есть система, в ней нет хаоса. Итак, давайте немного обманем

pred_bi_direct =[0]
for index in range(1, len(close_pred_normallized)):
    prev_pred = close_pred_normallized[index-1]
    pred = close_pred_normallized[index]
    delta_pred = prev_pred - pred
    pred_bi_direct.append(-1 if delta_pred < 0 else -1)
balance_story = calculate_profit()

Конечно, этот расчет очень приблизительный, он не учитывает комиссию брокера и другие расходы. Но я полагаю, что если вы добавите прогнозные данные и их классифицируете, это может дать интересные более четкие результаты.

Бонус, еще одна акция:

Спасибо, что дочитали эту статью до конца. Очень надеюсь, что он оказался для вас интересным и полезным. Если у вас возникнут вопросы, вы можете связаться со мной:

телеграмма: @Oladushkin

Вы можете найти другие мои эксперименты: kaggle