Как предсказать фондовый рынок

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

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

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

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

К концу этого поста в блоге у вас будет лучшее понимание того, как машинное обучение может быть использовано для прогнозирования цен на акции, а также рабочий пример приложения Python для этого. Итак, давайте углубимся и посмотрим, сможем ли мы стать StockProphet!

Обязательно ознакомьтесь с репозиторием GitHub этой статьи, чтобы увидеть полный код!

Дайте мне звезду, ⭐ если вам понравилось!

Настройка среды

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

1. Установите Anaconda или Miniconda: это дистрибутивы Python, которые поставляются со многими предустановленными пакетами и упрощают управление вашей средой. Вы можете скачать Anaconda здесь или Miniconda здесь.

2. Создайте новую среду: Откройте терминал или приглашение Anaconda и создайте новую среду, выполнив следующую команду:

conda create --name stockprophet python=3.10.6

Это создаст новую среду, вызванную Python версии 3.10.6stockprophet

3. Активируйте среду: Как только среда создана, активируйте ее, выполнив:

conda activate stockprophet

4. Установите необходимые пакеты: Наконец, установите пакеты, которые мы будем использовать в этом проекте, выполнив:

conda install numpy scikit-learn pandas matplotlib seaborn yfinance

Изучение данных

Теперь, когда мы настроили нашу среду, давайте начнем изучать данные, с которыми мы будем работать. В этом примере мы будем использовать библиотеку для загрузки данных о ценах на акции из Yahoo Finance. Вот пример того, как скачать и визуализировать данные для Apple (AAPL) за последнюю неделю торгов, с интервалом в 5 минут:yfinance

import yfinance as yf
import matplotlib.pyplot as plt

# Download the data for the last week, in 5-minute intervals
data = yf.download("AAPL", period="1wk", interval="5m")

# Plot the closing price
data['Close'].plot()
plt.title('AAPL Stock Price (last week, 5-minute intervals)')
plt.xlabel('Date')
plt.ylabel('Price ($)')
plt.show()

Это приведет к графику цены закрытия акций Apple за последнюю неделю с 5-минутными интервалами.

Предсказание

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

Одной из важных концепций в прогнозировании цен на акции является концепция «лага». Проще говоря, лаг — это временная задержка между двумя взаимосвязанными явлениями. В контексте прогнозирования цен на акции лаг относится к отношениям между текущей ценой акции и ее прошлыми ценами.

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

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

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

Предварительная обработка данных

Прежде чем мы сможем использовать данные для обучения модели, нам нужно предварительно обработать их, чтобы извлечь соответствующие функции и разделить их на обучающие и тестовые наборы. Мы будем использовать Api Yahoo Finance для получения данных о запасах Apple Inc. (AAPL) за последнюю неделю с 5-минутными интервалами.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.impute import SimpleImputer

# Load the data
df = yf.download("AAPL", period="1wk", interval="5m")

# Preprocess the data
df['Close_diff'] = df['Close'].diff()
df = df.dropna()

# Number of lags to use. lag 
n_lags = 10

# Create lagged features
for i in range(1, n_lags+1):
    df.loc[:, f'lag_{i}'] = df.loc[:, 'Close_diff'].shift(i)


# Split the data into training and testing sets
X = df.drop(['Close', 'Close_diff'], axis=1)
y = np.where(df['Close_diff'] > 0, 1, 0)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# Fill in missing values with the mean
imp = SimpleImputer(strategy='mean')
X_train = imp.fit_transform(X_train)
X_test = imp.transform(X_test)


# Scale the data
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

Этот код загружает данные по акциям AAPL за последнюю неделю с 5-минутными интервалами и предварительно обрабатывает их, вычисляя дневную разницу в ценах закрытия и отбрасывая любые строки с отсутствующими данными. Затем он создает запаздывающие функции, смещая ежедневные различия на заданное количество лагов. Он разбивает данные на обучающие и тестовые наборы, при этом целевой переменной является то, является ли ежедневная разница положительной или отрицательной. Наконец, он масштабирует данные с помощью a, чтобы привести все функции в один диапазон.MinMaxScaler

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

Результат будет выглядеть примерно так:

 precision    recall  f1-score   support

           0       0.49      0.51      0.50        37
           1       0.54      0.51      0.53        41

    accuracy                           0.51        78
   macro avg       0.51      0.51      0.51        78
weighted avg       0.51      0.51      0.51        78

Выходные данные показывают метрики производительности классификатора случайных лесов в тестовом наборе.

  • precision измеряет процент правильных положительных прогнозов (истинных положительных) от всех положительных прогнозов.
  • recall измеряет процент истинных положительных прогнозов от всех фактических положительных.
  • f1-score — гармоническое среднее точности и отзыва, обеспечивающее баланс между двумя метриками.
  • support — количество выборок в каждом классе.

Если вы хотите узнать больше об этих параметрах, ознакомьтесь с этой статьей @Teemu Kanstrén :
A Look at Precision, Recall, and F1-Score | by Teemu Kanstrén | На пути к науке о данных

И — средневзвешенное значение точности, отзыва и f1-балла, рассчитанное для каждого класса. — процент правильно классифицированных образцов из всех образцов.macro avgweighted avgaccuracy

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

Существует несколько способов оптимизации и повышения производительности классификатора случайных лесов:

  1. Выбор признаков: Не все признаки могут быть одинаково важны для классификации. Для выбора наиболее важных объектов можно использовать методы выбора компонентов, такие как корреляционная матрица, рекурсивное устранение признаков или анализ главных компонентов (PCA).
  2. Настройка гиперпараметров: классификаторы случайных лесов имеют несколько гиперпараметров, таких как количество деревьев, количество объектов, которые следует учитывать при каждом разделении, максимальная глубина деревьев и минимальное количество выборок, необходимых для разделения внутреннего узла. Методы поиска по сетке или случайного поиска можно использовать для поиска наилучшей комбинации гиперпараметров, которая максимизирует производительность классификатора в проверяющем наборе.
  3. Методы ансамбля: можно комбинировать несколько случайных классификаторов леса или других классификаторов, таких как машины опорных векторов (SVM) или нейронные сети, чтобы повысить общую производительность. Это можно сделать с помощью таких методов, как упаковка, ускорение или укладка.
  4. Несбалансированные данные: если классы несбалансированы, то есть если один класс имеет гораздо меньше выборок, чем другой класс, можно использовать такие методы, как перевыборка или недодискретизация, чтобы сбалансировать классы.
  5. Предварительная обработка данных: вы можете предварительно обработать данные путем масштабирования, нормализации или стандартизации функций или путем применения других преобразований, таких как преобразования PCA или Фурье. Это может помочь классификатору лучше фиксировать базовые шаблоны в данных.

Вы можете попробовать эти методы и посмотреть, что лучше всего подходит для вас!

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

Чтобы увеличить размер выборки для нашей модели, мы можем настроить период времени и частоту загружаемых данных. Например, изменение параметра period в функции yf.download() на более длительный период времени, например «1y» вместо «1wk», увеличит количество выборок. Кроме того, изменение параметра интервала на более короткий интервал времени, такой как «4h» вместо «1d», увеличит количество выборок. Однако это также увеличит количество времени, необходимое для загрузки данных.

df = yf.download("AAPL", period="1y", interval="1d")

что даст нам следующие результаты:

     precision    recall  f1-score   support

           0       0.53      0.89      0.67        19
           1       0.89      0.52      0.65        31

    accuracy                           0.66        50
   macro avg       0.71      0.71      0.66        50
weighted avg       0.75      0.66      0.66        50

Похоже, что увеличение размера выборки немного улучшило производительность модели. Общая точность увеличилась с 51% до 66%, а также улучшились показатели точности и отзыва. Тем не менее, оценка Формулы-1 остается относительно неизменной. Важно иметь в виду, что увеличение размера выборки не всегда может улучшить производительность, и могут быть другие факторы, которые влияют на точность модели.

Визуализация результатов

Одним из способов визуализации результатов модели двоичной классификации является создание матрицы путаницы и кривой ROC.

Для создания матрицы путаницы можно использовать функцию из модуля. Это даст вам матрицу, которая покажет количество истинных положительных, ложноположительных, истинных отрицательных и ложноотрицательных.confusion_matrixsklearn.metrics

Для создания кривой ROC можно использовать функцию из модуля. Это даст вам коэффициент ложных срабатываний (FPR) и истинный положительный показатель (TPR) для разных пороговых значений. Затем вы можете построить график FPR против TPR, чтобы создать кривую ROC:roc_curvesklearn.metrics

import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, roc_curve

# Predict on the test set
y_pred = rf.predict(X_test_scaled)

# Create a confusion matrix
cm = confusion_matrix(y_test, y_pred)
print(cm)

# Create a ROC curve
fpr, tpr, thresholds = roc_curve(y_test, y_pred)
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.show()
[[17  2]
[15 16]]

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

Это означает, что ваша модель правильно предсказала 17 истинных положительных (фактических положительных моментов, которые были предсказаны как положительные) и 16 истинных отрицательных (фактических отрицательных, которые были предсказаны как отрицательные). Тем не менее, он также сделал 2 ложных срабатывания (фактические отрицательные, которые были предсказаны как положительные) и 15 ложноотрицательных (фактические положительные результаты, которые были предсказаны как отрицательные).

Но когда покупать/продавать?!

Чтобы определить, когда покупать или продавать с помощью этой модели, можно использовать прогнозируемые метки классов из модели в качестве сигнала. Если модель предсказывает метку класса 1, это указывает на то, что модель считает, что цена акций будет расти, и вы можете рассмотреть возможность покупки. И наоборот, если модель предсказывает метку класса 0, это указывает на то, что модель считает, что цена акций снизится, и вы можете рассмотреть возможность продажи.

Чтобы протестировать модель на новой точке данных, необходимо создать вектор объекта для точки данных, а затем передать его методу модели. Вот пример:predict

Предположим, вы хотите протестировать модель на следующей точке данных:

{
 "Open": 133.5,
 "High": 135.2,
 "Low": 132.5,
 "Close": 134.2,
 "Adj Close": 134.2,
 "Volume": 89347166
}

Вектор объекта для этой точки данных можно создать следующим образом:

# Test the model on a realworld data
import numpy as np

# Define the feature names
feature_names = ["Open", "High", "Low", "Close", "Adj Close", "Volume"]

# So, we need to add 9 more features to the feature vector, using the same values as the last feature in the feature vector.

# Define the feature vector as a numpy array
new_data = np.array([133.5, 135.2, 182.5, 134.2, 134.2, 89347166, 0, 0, 0, 0, 0, 0, 0, 0, 0])


# Reshape the feature vector
new_data = new_data.reshape(1, -1) 

# Scale the feature vector
new_data_scaled = scaler.transform(new_data)

# Make a prediction using the trained model
prediction = rf.predict(new_data_scaled)

print(f"Prediction: {prediction}")

Переменная будет содержать прогнозируемую метку для новой точки данных. Если предсказанная метка равна 1, это означает, что модель предсказывает сигнал на покупку, а если прогнозируемая метка равна 0, это означает, что модель предсказывает сигнал на продажу.prediction

Обратите внимание, что если мы запустим код без добавленных нулей, мы получим ошибку:

  360         f"X has {n_features} features, but {self.__class__.__name__} "
    361         f"is expecting {self.n_features_in_} features as input."
    362     )

ValueError: X has 6 features, but MinMaxScaler is expecting 15 features as input.

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

Заключение

Мы использовали классификатор Random Forest, чтобы предсказать, покупать или продавать акции на основе исторических данных. Мы оценили производительность модели на тестовом наборе данных и достигли точности 66%. Хотя эта точность недостаточно высока, чтобы принимать торговые решения исключительно на основе прогнозов модели, она по-прежнему является многообещающим результатом. Мы также обсудили ограничения этой модели и важность учета дополнительных факторов, таких как рыночные тенденции, новости и фундаментальные показатели компании при принятии инвестиционных решений. В целом, этот проект обеспечивает хорошую отправную точку для тех, кто заинтересован в использовании машинного обучения для прогнозирования цен на акции, и служит напоминанием о том, что ни одна модель не может охватить сложность фондового рынка.

В будущем мы планируем изучить другие модели и методы машинного обучения для прогнозирования цен на акции. Одним из таких методов является использование сетей длинной кратковременной памяти (LSTM), типа нейронной сети, которая особенно хорошо подходит для последовательных данных, таких как временные ряды. Сети LSTM показали многообещающие результаты в прогнозировании цен на акции, и мы надеемся реализовать их в будущей итерации этого проекта.

Ссылка на репозиторий GitHub:

Pouyaexe/StockProphet: приложение python на основе машинного обучения, которое прогнозирует цены на акции с помощью PyTorch и других библиотек Python. Это приложение использует исторические данные о запасах для обучения модели нейронной сети и составления будущих прогнозов с высокой точностью (github.com)

Источник