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

В этой статье мы покажем, как использовать методы глубокого обучения, в частности модели LSTM, для прогнозирования будущих цен на акции с использованием Python. Мы рассмотрим два разных сценария: прогнозирование цены закрытия следующего дня для одной акции с использованием цен закрытия предыдущих девяти дней и прогнозирование цены закрытия последнего дня для всех акций в S&P 500 с использованием исторических данных.

Во-первых, мы начнем с более простого сценария прогнозирования цены закрытия следующего дня для отдельной акции, используя цены закрытия предыдущих девяти дней.

Далее мы распространим наш анализ на все акции S&P 500. Мы продемонстрируем, как загружать исторические данные о ценах для всех компонентов S&P 500 из Википедии и Yahoo Finance, предварительно обрабатывать данные, обучать модель и делать прогнозы. Мы также покажем, как сопоставить прогнозируемые цены с фактическими ценами для каждой акции, чтобы визуализировать производительность модели.

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

ЧАСТЬ 1: Прогноз для одного символа

Во-первых, мы можем загрузить исторические данные из Yahoo Finance, используя библиотеку yfinance. В следующей ячейке кода показано, как загрузить исторические данные для одного тикера.

import yfinance as yf

symbol = 'AAPL'
start_date = '2010-01-01'
end_date = '2023-02-17'
data = yf.download(symbol, start=start_date, end=end_date)

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

import matplotlib.pyplot as plt

plt.plot(data['Close'])
plt.title(symbol + ' Close Price')
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()

Теперь, когда у нас есть исторические данные, мы можем построить модель LSTM для прогнозирования будущих цен. Модель LSTM — это тип рекуррентной нейронной сети, которая может учиться на последовательностях данных, таких как данные временных рядов. В следующей ячейке кода показано, как построить модель LSTM с помощью Keras, популярной библиотеки глубокого обучения.

from keras.models import Sequential
from keras.layers import LSTM, Dense
import numpy as np

lookback = 9

def create_dataset(dataset):
    X, Y = [], []
    for i in range(len(dataset)-lookback-1):
        X.append(dataset[i:(i+lookback), 0])
        Y.append(dataset[i+lookback, 0])
    return np.array(X), np.array(Y)

# Scale data
data = np.array(data['Close']).reshape(-1, 1)
scaler = MinMaxScaler(feature_range=(0, 1))
data = scaler.fit_transform(data)
# Train and test split
train_size = int(len(data) * 0.8)
train_data = data[:train_size]
test_data = data[train_size:]
train_X, train_Y = create_dataset(train_data)
test_X, test_Y = create_dataset(test_data)
train_X = np.reshape(train_X, (train_X.shape[0], train_X.shape[1], 1))
test_X = np.reshape(test_X, (test_X.shape[0], test_X.shape[1], 1))
# Create model
model = Sequential()
model.add(LSTM(50, input_shape=(lookback, 1)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(train_X, train_Y, epochs=50, batch_size=64, verbose=2)

Мы разделяем данные на обучающий набор и тестовый набор и создаем последовательности прошлых цен и соответствующих им будущих цен с помощью функции create_dataset. Затем мы нормализуем данные с помощью MinMaxScaler и изменяем их форму, чтобы они соответствовали входному формату модели LSTM.

Модель LSTM состоит из входного слоя, слоя LSTM с 50 единицами и плотного выходного слоя. Мы компилируем модель с функцией потери среднеквадратичной ошибки и оптимизатором Адама и подгоняем ее к обучающим данным.

Как только модель обучена, мы можем использовать ее для прогнозирования тестовых данных. В следующей ячейке кода показано, как использовать модель для прогнозирования 10-й цены на основе 9 прошлых цен.

test_X = test_X.reshape((test_X.shape[0], lookback, 1))
predictions = model.predict(test_X)
predictions = scaler.inverse_transform(predictions)
actuals = scaler.inverse_transform(test_Y.reshape(-1, 1))
for i in range(10):
    print('Predicted:', predictions[i][0], 'Actual:', actuals[i][0])

Сначала мы изменяем тестовые данные, чтобы они соответствовали входному формату модели LSTM. Затем мы используем функцию прогнозирования, чтобы делать прогнозы, и инвертируем масштабирование, чтобы получить фактические цены. Мы печатаем первые 10 прогнозируемых цен и соответствующие им фактические цены.

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

plt.plot(actuals, label='Actual')
plt.plot(predictions, label='Predicted')
plt.title(symbol + ' Close Price')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.show()

На графике прогнозируемые цены показаны оранжевым цветом, а фактические цены — синим. Мы видим, что модель способна уловить общую тенденцию цены акций, но имеет некоторую ошибку в предсказании точной цены.

ЧАСТЬ 2: Прогноз для всех символов

В предыдущем разделе мы показали, как использовать модель LSTM для прогнозирования будущей цены отдельной акции. В этом разделе мы распространим наш анализ на все акции S&P 500.

Во-первых, нам нужно загрузить исторические данные для всех компонентов S&P 500 из Yahoo Finance. Мы будем использовать те же даты начала и окончания, что и раньше.

import yfinance as yf
import pandas as pd

# Download S&P 500 components from Wikipedia
url = 'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies'
table = pd.read_html(url, header=0)[0]
symbols = list(table.Symbol)
# Download historical data for all S&P 500 components
start_date = '2010-01-01'
end_date = '2023-02-17'
dfs = {}
for symbol in symbols:
    print('Downloading', symbol)
    df = yf.download(symbol, start=start_date, end=end_date)
    if len(df) >= 50:
        dfs[symbol] = df

Приведенный выше код загружает исторические данные для всех компонентов S&P 500 и сохраняет их в словаре фреймов данных, где ключи — это символы, а значения — фреймы данных. Он сохраняет данные символа только в том случае, если его длина составляет 50 или более.

Теперь мы можем использовать те же функции create_dataset и train_test_split, что и раньше, для подготовки данных для каждого символа. Однако на этот раз мы будем обучать модель LSTM на всех данных, кроме последнего дня, и использовать ее для прогнозирования цены каждого символа в последний день.

from sklearn.preprocessing import MinMaxScaler
import numpy as np

def create_dataset(data, lookback=9):
    X, Y = [], []
    for i in range(lookback, len(data)):
        X.append(data[i-lookback:i, 0])
        Y.append(data[i, 0])
    return np.array(X), np.array(Y)

def train_test_split(data, test_size=0.2, lookback=9):
    train_size = int(len(data) * (1 - test_size))
    train, test = data[:train_size], data[train_size-lookback:]
    return train, test


lookback = 9
test_size = 0.2
results = []

for symbol, df in dfs.items():
    # Prepare data
    data = df['Close'].values.reshape(-1, 1)
    scaler = MinMaxScaler(feature_range=(0, 1))
    data = scaler.fit_transform(data)
    train, test = train_test_split(data, test_size=test_size, lookback=lookback)
    train_X, train_Y = create_dataset(train, lookback=lookback)
    test_X, test_Y = create_dataset(test, lookback=lookback)
    # Train model
    train_X = train_X.reshape((train_X.shape[0], train_X.shape[1], 1))
    test_X = test_X.reshape((test_X.shape[0], test_X.shape[1], 1))
    model = keras.models.Sequential([
        keras.layers.LSTM(50, input_shape=(lookback, 1)),
        keras.layers.Dense(1)
    ])
    model.compile(loss='mse', optimizer='adam')
    model.fit(train_X, train_Y, epochs=100, batch_size=32, verbose=0)
    # Make predictions
    test_X = test_X.reshape((test_X.shape[0], lookback, 1))
    predictions = model.predict(test_X)[-1]
    predictions = scaler.inverse_transform(predictions.reshape(-1, 1))[0]
    actual = df['Close'][-1]
    results.append((symbol, actual, predictions))

Приведенный выше код перебирает все компоненты S&P 500 и обучает модель LSTM на исторических данных для каждой акции. Затем модель используется для прогнозирования цены закрытия для каждой акции в последний день доступных данных.

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

import matplotlib.pyplot as plt

plt.figure(figsize=(16, 12))
for symbol, actual, predicted in results:
    plt.plot([symbol]*2, [actual, predicted], 'o-', label=symbol)
# plt.legend()
plt.title('Predicted vs Actual Prices for S&P 500 Stocks')
plt.ylabel('Price ($)')
plt.show()

Приведенный выше код отображает прогнозируемые цены и фактические цены для каждой акции в последний день доступных данных. Ось X представляет символ, а ось Y представляет цену. Фактическая цена показана синей точкой, а прогнозируемая цена показана оранжевой линией.

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

В этой статье мы показали, как использовать глубокое обучение, в частности модели LSTM, для прогнозирования будущей цены акций с использованием Python. Мы также продемонстрировали, как распространить этот анализ на все акции S&P 500 и как сопоставить прогнозируемые цены с фактическими ценами для каждой акции.

Станьте участником Medium сегодня и получите неограниченный доступ к тысячам руководств по Python и статьям по науке о данных! Всего за 5 долларов в месяц вы получите доступ к эксклюзивному контенту и поддержите меня как писателя. Зарегистрируйтесь сейчас, используя мою ссылку, и я получу небольшую комиссию без каких-либо дополнительных затрат для вас.

Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .

Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.