рекомендации

четверг, 23 июля 2020 г.

Введение в нейронные сети для финансовых рынков


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

Эта статья будет введением в то, как использовать нейронные сети для прогнозирования движений фондового рынка, в частности, цены акции (или индекса). Этот пост основан на моем проекте IntroNeuralNetworks. Целью этого проекта является прогнозирование котировок акций выбранной компании с использованием методов машинного обучения и нейронных сетей.


Для второй, более продвинутой реализации нейронных сетей для прогнозирования акций, ознакомьтесь с моей следующей статьей или посетите репозиторий GitHub. Для получения дополнительной информации, проверьте мою страницу: Engineer Quant.

Потребность в нейронных сетях в финансах

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

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

Типичный научный проект с полным стеком имеет следующую структуру:

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

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

1. Сбор данных.

К счастью, данные о ценах на акции, необходимые для этого проекта, легко доступны в Yahoo Finance. Данные могут быть получены с помощью их Python API, pdr.get_yahoo_data(ticker, start_date, end_date) или непосредственно с их веб-сайта.

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

В нашем случае нам нужно разбить данные на обучающие наборы из десяти цен и цены следующего дня. Я сделал это, определив класс Preprocessing, разбив данные на обучающие и тестовые данные и определив метод get_train(self, seq_len), который возвращает обучающие данные (входные и выходные данные) в виде массивов numpy, учитывая конкретную длину окна (десять в нашем случае). Полный код выглядит следующим образом:

def gen_train(self, seq_len):
    """
    Generates training data
    :param seq_len: length of window
    :return: X_train and Y_train
    """
    for i in range((len(self.stock_train)//seq_len)*seq_len - seq_len - 1):
        x = np.array(self.stock_train.iloc[i: i + seq_len, 1])
        y = np.array([self.stock_train.iloc[i + seq_len + 1, 1]], np.float64)
        self.input_train.append(x)
        self.output_train.append(y)
    self.X_train = np.array(self.input_train)
    self.Y_train = np.array(self.output_train)

Аналогично, для тестовых данных я определил метод, который возвращает тестовые данные X_test и Y_test.

3. Разработка и внедрение модели

Модели нейронной сети

Для этого проекта я использовал две модели нейронной сети: многослойный персептрон (MLP) и долгая краткосрочная память (LSTM). Я кратко расскажу о том, как работают эти модели, но чтобы разобраться, как работает MLP, ознакомьтесь с этой статьей. Для LSTM, посмотрите эту превосходную статью от Jakob Aungiers.

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

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

Реализация моделей

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

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

Давайте начнем с более простого MLP. В keras это делается путем создания последовательной модели и добавления поверх нее слоев. Полный код выглядит следующим образом:

model = tf.keras.models.Sequential()model.add(tf.keras.layers.Dense(100, activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(100, activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(1, activation=tf.nn.relu))model.compile(optimizer="adam", loss="mean_squared_error")

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

Adaptive Gradient Algorithm (AdaGrad), который поддерживает скорость обучения по параметру, которая повышает производительность при проблемах с разреженными градиентами (например, проблемы с естественным языком и компьютерным зрением).
Root Mean Square Propagation (RMSProp), который также поддерживает скорости обучения по каждому параметру, которые адаптированы на основе среднего значения последних градиентов для веса (например, как быстро оно изменяется). Это означает, что алгоритм хорошо справляется с онлайн и нестационарными задачами (например, с шумом).

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

Теперь нам нужно согласовать модель с нашими данными обучения. Опять же, keras упрощает задачу, требуя только следующий код:

model.fit(X_train, Y_train, epochs=100)

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

model.evaluate(X_test, Y_test)

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

Для модели LSTM процедура аналогична, поэтому я опубликую код ниже, оставив объяснение для вас:

model = tf.keras.Sequential()
model.add(tf.keras.layers.LSTM(20, input_shape=(10, 1), return_sequences=True))
model.add(tf.keras.layers.LSTM(20))
model.add(tf.keras.layers.Dense(1, activation=tf.nn.relu))model.compile(optimizer="adam", loss="mean_squared_error")model.fit(X_train, Y_train, epochs=50)model.evaluate(X_test, Y_test)

Важно отметить, что keras требует от входных данных определенной размерности, определенной вашей моделью. Крайне важно, чтобы вы переформатировали свои данные, используя NumPy.

4. Тестирование модели на исторических данных

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

def back_test(strategy, seq_len, ticker, start_date, end_date, dim):
    """
    A simple back test for a given date period
    :param strategy: the chosen strategy. Note to have already formed the model, and fitted with training data.
    :param seq_len: length of the days used for prediction
    :param ticker: company ticker
    :param start_date: starting date
    :type start_date: "YYYY-mm-dd"
    :param end_date: ending date
    :type end_date: "YYYY-mm-dd"
    :param dim: dimension required for strategy: 3dim for LSTM and 2dim for MLP
    :type dim: tuple
    :return: Percentage errors array that gives the errors for every test in the given date range
    """
    data = pdr.get_data_yahoo(ticker, start_date, end_date)
    stock_data = data["Adj Close"]
    errors = []
    for i in range((len(stock_data)//10)*10 - seq_len - 1):
        x = np.array(stock_data.iloc[i: i + seq_len, 1]).reshape(dim) / 200
        y = np.array(stock_data.iloc[i + seq_len + 1, 1]) / 200
        predict = strategy.predict(x)
        while predict == 0:
            predict = strategy.predict(x)
        error = (predict - y) / 100
        errors.append(error)
        total_error = np.array(errors)
    print(f"Average error = {total_error.mean()}")

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

Ниже показано, как работала моя модель LSTM при прогнозировании цены акций Apple в феврале.



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

5. Оптимизация - настройка гиперпараметров

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

Заключение

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

Комментариев нет:

Отправить комментарий