Прогнозирование настроений на фондовом рынке с помощью OpenAI и Python

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

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

В этой статье будет использоваться API для получения новостей фондового и финансового рынков. Его провайдером является EODHD  —  один из ресурсов-поставщиков рыночных данных. На мой взгляд, он может похвастаться идеальным соотношением цены и качества. API предоставляет конечные точки для извлечения информации из финансовых новостей, упрощая процесс анализа рыночных настроений. Благодаря удобству использования, даже новички быстро осваивают операции по запросу и извлечению новостных статей, что позволяет динамично оценивать позитивные и негативные настроения на рынке.

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

Перейдем к исследованию рыночных настроений.

Импортирование пакетов

Начнем с импорта необходимых пакетов в среду Python. Будем использовать три основных пакета: pandas (для работы с датафреймами), eodhd (для извлечения данных) и langchain (для создания LLM-модели). Кроме них, нам понадобятся такие вспомогательные пакеты, как config и re. Импортируйте все необходимые пакеты с помощью следующего кода:

!pip install openai
!pip install langchain
!pip install eodhd
!pip install config

import re
import requests
import pandas as pd
import config as cfg
from eodhd import APIClient
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI

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

Активация ключа API

Чтобы воспользоваться всем функционалом, необходимо зарегистрировать ключ API EODHD с пакетом. Если у вас нет такого ключа, зайдите на сайт EODHD, пройдите полностью процесс регистрации для создания учетной записи, затем перейдите на страницу “Settings” (“Настройки”), где найдете свой секретный API-ключ EODHD. Важно убедиться, что этот секретный API-ключ никому не известен. Активируйте ключ API, следуя этому коду:

api_key = '<YOUR API KEY>'
api = APIClient(api_key)

Код довольно прост. В первой строке сохраняем секретный ключ API EODHD в api_key, а во второй  —  используем класс APIClient, предоставленный пакетом eodhd, для активации ключа API и сохраняем ответ в переменной client.

Обратите внимание, что вам нужно заменить <YOUR API KEY> на секретный ключ API EODHD. Помимо непосредственного хранения API-ключа в текстовом виде, существуют и другие способы повышения безопасности, например использование переменных среды и т. д.

Извлечение данных

Будем использовать API фондового рынка и финансовых новостей, обратившись к библиотеке Python, предоставленной EODHD, следующим образом:

resp = api.financial_news(s = "AAPL.US", from_date = '2024-01-01', to_date = '2024-01-30', limit = 100)
df = pd.DataFrame(resp) # Конвертация вывода json в датафрейм
df.tail()

Объяснение параметров в API:

  1. s. Строка. Обязательна, если не задан параметр ‘t’. Код тикера, для которого необходимо получить новости.
  2. t. Строка. Обязательна, если не задан параметр ‘s’. Метка для получения новостей по заданной теме (список тем вы можете найти на этой странице).
  3. api_token. Строка. Обязательна. Это api_token для доступа к API. Вы получите его после регистрации.
  4. from и to. Формат  —  ‘yyyy-mm-dd’ (год-месяц-день). Если вам нужны данные с 1 марта 2021 года по 10 марта 2021 года, используйте формат: from=2021–03–01, to=2021–03–10.
  5. limit. Количественный параметр. Опционально. Количество результатов, которое должно быть возвращено при выполнении запроса. Значение по умолчанию  —  50, минимальное  —  1, максимальное  —  1000.
  6. offset. Число. Опционально. Смещение данных. Значение по умолчанию  —  0, минимальное  —  0. Например, чтобы получить 100 символов, начиная с 200, нужно использовать limit=100 и offset=200.

Данные будут выглядеть следующим образом:

Данные о новостях AAPL (Изображение автора)

Выходные данные содержат следующие поля.

  • date: дата и время публикации статьи в формате ISO 8601.
  • title: заголовок статьи.
  • content: полный текст статьи.
  • link: ссылка на источник.
  • symbols: массив символов-тикеров, упоминаемых в статье.

Очистка данных

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

# функция очистки текстовых данных
def clean_text(text):
cleaned_text = re.sub(r'\s+', ' ', text)
return cleaned_text.strip()

# применение функции замены ко всему столбцу
df['content'] = df['content'].apply(clean_text)

Теперь все данные очищены и можно продолжить работу с чат-ботом.

Большая языковая модель (LLM)

Будем использовать Langchain, чтобы сформировать LLM-цепочку с моделью OpenAI.

llm = ChatOpenAI(model = "gpt-3.5-turbo",
openai_api_key = 'YOUR OPENAI API KEY',
temperature = 0)

Примечание: чтобы код работал без ошибок, необходимо заменить YOUR OPENAI API KEY на ваш ключ API OpenAI.

Этот фрагмент кода инициализирует языковую модель (LM), инстанцируя GPT-2.5-turbo с температурой 0. Выбор температуры 0 обеспечивает детерминизм модели, не позволяя ей отвлекаться от поставленных задач и поддерживая целенаправленную и последовательную генерацию.

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

1) Промпт-инжиниринг

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

Ниже приведены часто используемые методы разработки промптов.

  1. Обучение без примеров (zero-shot prompting). Этот метод позволяет большим языковым моделям решать новые задачи даже без предварительных примеров или понимания задачи. Он работает с помощью техники, называемой “промптинг”, когда вы просто даете LLM описание желаемой задачи на естественном языке.
  2. Обучение на небольшом количестве примеров (few-shot prompting). Демонстрируя замечательные возможности промптинга, крупные языковые модели, обученные без примеров, все же не справляются с более сложными задачами. В таких случаях для повышения производительности прибегают к обучению на небольшом количестве примеров (обучению в контексте): модель получает промпт с примерами ответов. Эти примеры служат основой для выполнения моделью последующих задач.
  3. Цепочка мыслей (chain of thought prompting). Этот метод используется для систем ИИ, когда нужно упростить сложную задачу, разбив ее на управляемые этапы. Вместо того чтобы решать сложную задачу за один раз, работа модели сводится к рассуждению, позволяющему разделить решение на ряд мелких, последовательных шагов. Процесс начинается с четкого определения конечной цели, а затем рассматриваются логические предпосылки и подзадачи, необходимые для достижения этой цели.

2) Тонкая настройка

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

Существует два основных метода тонкой настройки.

1. Полная тонкая настройка.

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

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

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

2. Эффективная тонкая настройка параметров (PEFT).

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

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

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

В нашем примере будем применять методы промпт-инжиниринга, используя функциональность шаблонов Langchain, чтобы создать оптимизированный промпт для проведения анализа настроений на фондовом рынке. Задача состоит в том, чтобы создать промпт с запросом не только анализа настроений, но и объяснений выводов модели.

template = """
Identify the sentiment towards the Apple(AAPL) stocks from the news article , where the sentiment score should be from -10 to +10 where -10 being the most negative and +10 being the most positve , and 0 being neutral

Also give the proper explanation for your answers and how would it effect the prices of different stocks

Article : {statement}
"""

# Формирование промпта с помощью функциональности Langchain PromptTemplate
prompt = PromptTemplate(template = template, input_variables = ["statement"])
llm_chain = LLMChain(prompt = prompt, llm = llm)

Теперь, когда создана LLM-цепочка (LLM chain), приведу пример ее вывода.

Запуск LLM-цепочки:

print(llm_chain.run(df['content'][13]))

Вывод будет выглядеть следующим образом:

Прогноз настроений на рынке AAPL с помощью модели (изображение автора)

Анализ

Чтобы проанализировать состояние AAPL (акций Apple), исследуем 100 статей и сделаем соответствующие выводы.

Для начала убедимся, что лимит токенов модели (который составляет 4097) не превышен. Поэтому отсеем статьи с количеством токенов, превышающим 3500:

# Функция для подсчета количества токенов
def count_tokens(text):
tokens = text.split()
return len(tokens)

Подсчет токенов для всех строк в датафрейме:

# Применение функции токенизации к столбцу DataFrame
df['TokenCount'] = df['content'].apply(count_tokens)

Фильтрация датафрейма в соответствии с TokenCount:

# Определение порога количества токенов (например, сохранение строк с более чем 2 токенами).
token_count_threshold = 3500

# Создание нового датафрейма путем фильтрации на основе количества токенов
new_df = df[df['TokenCount'] < token_count_threshold]

# Удалите столбец 'TokenCount' из нового DataFrame, если он вам не нужен
new_df = new_df.drop('TokenCount', axis = 1)

# Сброс индекса
new_df = new_df.reset_index(drop = True)

Изменим шаблон промпта, чтобы получить лаконичный результат:

template_2 = """
Identify the sentiment towards the Apple(AAPL) stocks of the news article from -10 to +10 where -10 being the most negative and +10 being the most positve , and 0 being neutral

GIVE ANSWER IN ONLY ONE WORD AND THAT SHOULD BE THE SCORE

Article : {statement}
"""

# Формирование промпта с помощью функциональности Langchain PromptTemplate
prompt_2 = PromptTemplate(template = template_2, input_variables = ["statement"])

Сформируем новую LLM-цепочку:

llm_chain_2 = LLMChain(prompt = prompt_2, llm = llm)

Посмотрим на вывод:

print(new_df['content'][2])
print('')
print('News sentiment: ', llm_chain_2.run(new_df['content'][2]))
Обновленный прогноз настроений от модели (изображение автора)

Отлично, получен лаконичный результат. Теперь создадим цикл for для итерации по данным и получения настроения по каждой новости:

x = []
for i in range(0,new_df.shape[0]):
x.append(llm_chain_2.run(new_df['content'][i]))

Визуализация

Теперь построим круговые диаграммы, чтобы увидеть настроение рынка по отношению к AAPL:

import matplotlib.pyplot as plt

dt = pd.DataFrame(x) # Преобразование в Dataframe
column_name = 0 # Это название моего столбца, вы должны изменить его в соответствии с вашими данными
value_counts = dt[column_name].value_counts()

# Построение круговой диаграммы
plt.pie(value_counts, labels = value_counts.index, autopct = '%1.1f%%', startangle = 140)
plt.title(f'Pie Chart')
plt.axis('equal') # Равное соотношение сторон требуется для того, чтобы диаграмма имела вид круга.

# Демонстрация круговой диаграммы
plt.show()
Настроения на рынке AAPL (изображение автора)

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

Удаление нейтральных значений:

value_to_remove = '0'
# Удаление всех строк, в которых указанное значение встречается в столбце
dt_new = dt[dt[0] != value_to_remove]

Визуализация новых данных:

value_counts = dt_new[column_name].value_counts()

# Построение круговой диаграммы
plt.pie(value_counts, labels = value_counts.index, autopct = '%1.1f%%', startangle = 140)
plt.title(f'Pie Chart')
plt.axis('equal') # Равное соотношение сторон требуется для того, чтобы диаграмма имела вид круга.

# Демонстрация круговой диаграммы
plt.show()
Настроения на рынке AAPL за исключением нейтральных значений (изображение автора)

Наблюдая за тенденциями, можно заметить, что комбинация +5 и +7 составляет почти 40% всех данных. С учетом дополнительных значений +10, +8 и +3, суммарный процент положительных статей возрастает до 52,5%. Такая картина свидетельствует о преобладании оптимистических настроений, что подразумевает благоприятное восприятие Apple Inc. в последних статьях. Выявленный позитивный прогноз может иметь потенциальное значение для формирования общих настроений относительно рыночных показателей Apple.

Заключение

В данном исследовании были использованы: API для получения новостей фондового и финансового рынков от EODHD (для сбора новостных статей о фондовом рынке) и OpenAI-модель анализа настроений (для оценки настроений, передаваемых в этих статьях).

Для обеспечения совместимости данных и OpenAI-модели использовался инструмент обработки языка LangChain. Чтобы уточнить исходные данные для OpenAI-модели и повысить точность анализа настроений, были применены методы промпт-инжиниринга. Анализ настроений в 100 статьях позволил оценить текущее настроение рынка акций APPL.

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Nikhil Adithyan: Stock Market Sentiment Prediction with OpenAI and Python

Предыдущая статьяЛучшие практики API-авторизации
Следующая статьяПроизводительность в Jetpack Compose: стабильность и неизменяемость