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

Цель этой статьи — продемонстрировать, как использовать методы глубокого обучения, в частности модели 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 — это рекуррентные нейронные сети, способные учиться на последовательных данных, таких как данные временных рядов. Используя Keras, широко используемую библиотеку глубокого обучения, следующая ячейка кода создает модель LSTM.

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

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 мы генерируем последовательности предыдущих цен вместе с соответствующими им будущими ценами на основе данных, разделенных на наборы для обучения и тестирования. После нормализации данных мы изменяем их форму, чтобы они соответствовали входному формату модели LSTM, используя MinMaxScaler.

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

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

# Reshape the test data
test_X = test_X.reshape((test_X.shape[0], lookback, 1))

# Use the trained model to make predictions on the test data
predictions = model.predict(test_X)
# Convert the predicted values back to their original scale
predictions = scaler.inverse_transform(predictions)
# Convert the actual values back to their original scale
actuals = scaler.inverse_transform(test_Y.reshape(-1, 1))
# Print the first 10 predicted and actual values
for i in range(10):
    print(f"Predicted: {predictions[i][0]:.2f} Actual: {actuals[i][0]:.2f}")

В качестве первого шага мы изменяем тестовые данные в соответствии с входным форматом модели 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 будет расширен в этом разделе.

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

# Import necessary libraries
import yfinance as yf
import pandas as pd

# Download the list of 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)
# Define the start and end dates for the historical data
start_date = '2010-01-01'
end_date = '2023-02-17'
# Download historical data for all S&P 500 components
data = {}
for symbol in symbols:
    print(f"Downloading data for {symbol}")
    df = yf.download(symbol, start=start_date, end=end_date)
    if len(df) >= 50:
        data[symbol] = df

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

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

# Import necessary libraries
from sklearn.preprocessing import MinMaxScaler
import numpy as np
from tensorflow import keras

# Define functions to create and split the dataset
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
# Define the lookback and test size
lookback = 9
test_size = 0.2
# Create an empty list to store the results
results = []
# Iterate through each symbol and its corresponding data
for symbol, df in dfs.items():
    print(f"Processing {symbol}")
    # Prepare the 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 the 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 on the test data
    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]
    # Append the results to the list
    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, а прогнозируемые цены можно сравнить с фактическими ценами.