Машинное обучение: прогнозируем цены акций на фондовом рынке

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

    Машинное и глубокое обучение стали новой эффективной стратегией, которую для увеличения доходов используют многие инвестиционные фонды. В статье я объясню, как нейронные сети помогают спрогнозировать ситуацию на фондовом рынке — например, цену на акции (или индекс). В основе текста мой проект, написанный на языке Python. Полный код и гайд по программе можно найти на GitHub. Другие статьи по теме читайте в блоге на Medium.

    Нейронные сети в экономике


    Изменения в сфере финансов происходят нелинейно, и иногда может показаться, что цены на акции формируются совершенно случайным образом. Традиционные методы временных рядов, такие как модели ARIMA и GARCH эффективны, когда ряд является стационарным — его основные свойства со временем не изменяются. А для этого требуется, чтобы ряд был предварительно обработан с помощью log returns или приведён к стационарности по-другому. Однако главная проблема возникает при реализации этих моделей в реальной торговой системе, так как при добавлении новых данных стационарность не гарантируется.

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

    Обычно data science проект состоит из следующих операций:

    1. Сбор данных — обеспечивает набор необходимых свойств.
    2. Предварительная обработка данных — часто пугающий, но необходимый шаг перед использованием данных.
    3. Разработка и реализация модели — выбор типа нейронной сети и её параметров.
    4. Модели бэктестинга (тестирование на исторических данных) — ключевой шаг любой торговой стратегии.
    5. Оптимизация — поиск подходящих параметров.

    Входные данные для нашей нейронной сети — данные о ценах на акции за последние 10 дней. С их помощью мы спрогнозируем цены на следующий день.

    Сбор данных


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

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


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

    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.

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


    Для проекта я использовал две модели нейронных сетей: Многослойный перцептрон Румельхарта (Multilayer Perceptron — MLP) и модель Долгой краткосрочной памяти (Long Short Term Model — LSTM). Кратко расскажу о том, как работают эти модели. Подробнее о MLP читайте в другой статье, а о работе LSTM — в материале Джейкоба Аунгиерса.

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

    Для этого используется LSTM или Рекуррентные нейронные сети (Recurrent Neural Networks — 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 moment estimation) — более эффективный оптимизационный алгоритм по сравнению с стохастическим градиентным спуском. Есть два других расширения стохастического градиентного спуска — на их фоне сразу видны преимущества Adam:

    AdaGrad — поддерживает установленную скорость обучения, которая улучшает результаты при расхождении градиентов (например, при проблемах с естественным языком и компьютерным зрением).

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

    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.

    Модели бэктестинга


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

    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()}")

    Однако, это упрощенная версия тестирования. Для полной системы бэктестинга нужно учитывать такие факторы, как «ошибка выжившего» (survivorship bias), тенденциозность (look ahead bias), изменение ситуации на рынке и транзакционные издержки. Так как это только образовательный проект, хватает и простого бэктестинга.


    Прогноз моей модели LSTM на цены акций Apple в феврале

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

    Оптимизация гиперпараметров


    Для улучшения результатов модели после тестирования часто нужна оптимизация. Я не включил её в версию с открытым исходным кодом, чтобы читатели могли сами попробовать оптимизировать модель. Тем, кто не умеет оптимизировать, придется найти гиперпараметры, которые улучшат производительность модели. Есть несколько методов поиска гиперпараметров: от подбора параметров по сетке до стохастических методов.

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

    Вывод


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

    От редакции


    Курсы «Нетологии» по теме:

    Нетология
    49,00
    Университет интернет-профессий
    Поделиться публикацией

    Комментарии 25

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


      Это входные данные. А на выходе что? Цена на послезавтра?
        0
        Так про обучающие наборы же вроде пишут здесь
        +2
        Осталось применить NN к предсказанию лунки, в которую упадёт шарик рулетки — и все казино наши!
          0
          Недавно тут кто-то букмекеров пытался перепрогнозировать.
            +2
            Хороший пример того, как неправильно использовать NN.
              +1
              Получается зарабатывать на этом?
                +1
                Конечно получается.
                Супернейросетевые роботы, тренининги, сигналы и т.д. и т.п. расходятся на ура.
                  0
                  Во время золотой лихорадки больше всего заработали на продаже лопат, так же и тут скорее всего.
                +2

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

                  0
                  У меня вопрос. Ладно ии нельзя. но нанять профессионала можно? А что если каждый наймет себе такого?
                    +1
                    в выигрыше оказываются те, кто обладает уже информацией, а не прогнозами.
                      0
                      Инсайдеры те же мошенники и риски соответствующие.
                      0
                      Можно, если найдете. А потом вас профессионал засадит в убыток и вы начнете в нем сомневаться. Короче, если и есть профессионалы, которые регулярно (но не всегда) обыгрывают рынок, их единицы. Взять того же Баффета. Последние пару лет результаты сильно хуже SP500
                      –1
                      Небольшой доход можно получить на ошибке крупной компании или государства. Например одна компания пытается поглотить другую и тратит на это крупную сумму денег и достигает своей цели. Нейронные сети могут уловить паттерн ситуации и немного уйти в плюс. Сумма прибылей всех участников рынка нулевая, но торговый бот, на знакомых паттернах может немного заработать.
                      ИИ кстати все разные, обучены на разных примерах и разные конфигурации нейронной сети. Более удачливые конфигурации могут заработать на менее удачливых теоретически.
                      На практике прибыль может свести к нулю услуги посредника.
                      Если вы о том что сложно на обычных и доступных всем инструментах заработать, тут соглашусь. Но теоретически можно из шумоподобного сигнала выцепить ключевую информацию.
                        –1
                        Предположим, что на данный момент большинство не использует ИИ. Дальше какое доказательство?
                          0
                          ИИ сегодня — это статистический подгон модели под прошлое. Вариантов развития ситуации на фондовом рынке в миллиард раз больше чем в Го. Но написать модель, которая сделает подгон по 10000 «раскладам» можно. Она будет раюотать какое-то время, а потм непредсказуемо обрушится. И что любопытно, вы даже не поймете причинв и что сс этим делать. Если хочется более академических объяснений — рекомендую Н.Талеб «Черный лебедь»
                            0
                            Спасибо, я как раз в процессе чтения этой книжки.
                            Но стоит понимать, что обрушится — это ничего страшного, если это происходит реже 20-49% случаев (в зависимости от стратегии по стопам)
                        +1
                        Статья имеет громкий заголовок, но страдает в содержании. Об одной только подготовке данных можно приготовить отдельную серию статей. Нейронные сети применять вот так «в лоб» для прямого прогноза цены не имеет совершенно никакого смысла как минимум по причине невообразимой сложности ценообразования акции как системы со своейственной ей хаосом. Не вводите молодые умы в заблуждение.
                          +2
                          Как раз сейчас идёт соревнование на kaggle по этой теме. Возьмите чей-нибудь kernel и замените на свою модель, по времени должно занять час.

                          А потом здесь сообщите результат, интересно посмотреть как выглядит на фоне остальных.
                            +1
                            Любой, кто мало-мальски в теме, знает, что статья — туфта. Если бы можно было написать простейшую нейронку с кодом в 500 строк и хорошо (и главное стабильно) зарабатывать — сейчас бы все так делали. Не умеешь кодить сам — закажи у кого-нибудь, тебе напишут за вечер и $100. Но к сожалению или счастью, это так не работает. Многие вещи вообще не учитываются (типа новости), а даже если учитываются — одни факторы очень быстро сменяются другими, и обученная модель начинает выдавать неадекватные результаты.
                              0
                              Если посмотреть на график S&P 500 Index с 2009 года, то видно что тренд практически только вверх.

                              Поэтому с 2009 можно было хорошо и главное стабильно зарабатывать (если бы знать), вложившись в индексный фонд. Не day trading, а положив и забирать пару раз в год (или держать)

                              Есть два момента:

                              1. зарабатывать выше чем S&P 500. Например за последние 5 лет возврат S&P 500 56% (или 11% в год), Apple 194.89% (20% в год) или Амазон 368% (или 70% в год, а если бы выйти в августе 2018, то 474% или 95%)

                              2. Вовремя войти и выйти. Здесь самая большая проблема, когда начнётся новый виток спирали и ты его пропустишь, очень легко потерять всё заработанное.

                                0
                                Интересно, посмотреть на 20 лет, если бы вложился 20 лет назад в S&P 500 и забрал сегодня, то заработал бы 213%, или около 10% годовых (без учёта инфляции, в США инфляция за всё это время 55%).

                                с Apple — 25000% или 1250% или 100% в месяц.

                                А с Амазон — 110000%, или 5500% годовых или 450% в месяц.
                                  0
                                  Ну да, все верно. Я правда не совсем понимаю как ваши комментарии относятся к теме нейросетей в трейдинге )
                                    0
                                    Так что если нейросеть предсказывает повышение цены в более чем 50% случаев, то на восходящем общем тренде будет выглядить как будто она работает правильно.
                              0
                              Быстро посмотрел публикацию и у меня пропало «чувство удовлетворения». Жалко, хорошее название. К уважаемому мною «Нетологии» и переводчице это отношение не имеет. Не совсем серъезно подошел к теме товарищ из Кембриджа. Мне это напоминает старое высказывание сантехника, что он «плоскогубцами всем грыжу вылечит». Это достаточно сложная и интересная тема (Прогнозирование вперед значений динамических рядов) и неправильно так легкомысленно к этому подходить. Искусственные нейронные сети – это лишь один из инструментов, который используется для таких целей. У него есть свои достоинства, и (как и у любого метода) есть свои недостатки. Для биржевых цен акций тех или иных компаний, можно сказать, что «год на год» не приходится и «месяц на месяц» не приходится. То, что вы обучались в прошлом, совсем не означает, что вы можете прогнозировать в настоящем. Ситуация поменялась на рынке, «в мире», и динамическая кривая совсем другая. Поменялась «точка опоры».Поэтому нужен алгоритм, который обучается и накапливает знания в потоке, постоянно «впитывая новые знания». И не обязательно, что это будут нейронные сети.

                              p.s. У музыкантов плохая музыка «режет слух», график «предсказания», приведенный в статье, мне «режет зрение». Две «ломанные кривые» пляшут синхронно как трамвайные пути после землетрясения. Так не должно быть, там явное систематическое смещение.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое