Поиск Alpha среди твитов финансовых изданий с NLTK, Gensim & VADER

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

Вступление

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

С точки зрения торговли, цены на медь определяются динамикой спроса и предложения на биржах металлов, в частности, на Лондонской бирже металлов (LME) и Чикагской товарной бирже (CME) COMEX. Однако цена, по которой торгуется медь, зависит от множества факторов, многие из которых очень трудно измерить одновременно:

  • Глобальный экономический рост (ВВП)
  • Страны с развивающейся рыночной экономикой
  • Экономика Китая (на Китай приходится половина мирового спроса на медь)
  • Политическая и экологическая нестабильность в странах-производителях медной руды
  • Рынок жилья США
  • Торговые санкции и тарифы
  • Многие, многие другие.

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

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

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

Проблема

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

Мы покроем:

  1. Как получить исторические твиты с GetOldTweets3.
  2. Базовые методы исследовательского анализа данных (EDA) с использованием наших данных Twitter.
  3. Методы предварительной обработки текстовых данных (стоп-слова, токенизация, n-граммы, основание и лемматизация и т. д.).
  4. Скрытое распределение Дирихле для моделирования и изучения распределения тем и их содержания в наших данных Twitter с использованием GenSim и NLTK PyLDAvis.
  5. Оценка тональности с помощью NLTK Valence Aware Dictionary и sEntiment Reasoner (VADER).

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

Стратегическая модель Spot Copper NLP

Давайте начнем со сбора наших данных.

Данные по спотовым ценам

Мы начнем с получения данных о спотовых ценах на медь. Причина, по которой мы выбрали спотовую цену на медь, а не на форвардный контракт на медь (соглашение о покупке или продаже фиксированного количества металла с поставкой в ​​согласованную фиксированную дату в будущем по согласованной сегодня цене), заключается в том, что спотовая цена наиболее реагирует на рыночные события - это предложение совершить товарную сделку немедленно. Обычно мы использовали бы терминал Bloomberg для получения этих данных, однако мы можем получить исторические данные о спотовой меди бесплатно из Business Insider:

# Imports
import glob
import GetOldTweets3 as got
import gensim as gs
import os
import keras
import matplotlib.pyplot as plt
import numpy as np
import nltk
import pandas as pd
import pyLDAvis.gensim
import re
import seaborn as sns
from keras.preprocessing.text import Tokenizer
from nltk.stem import *
from nltk.util import ngrams
from nltk.corpus import stopwords
from nltk.tokenize import TweetTokenizer
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from sklearn.feature_extraction.text import CountVectorizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
# Get Cu Spot
prices_df = pd.read_csv(
    '/content/Copper_120115_073120',
    parse_dates=True,
    index_col='Date'
)
# To lower case
cu_df.columns = cu_df.columns.str.lower()
#Plt close price
cu_df['close'].plot(figsize=(16,4))
plt.ylabel('Spot, $/Oz')
plt.title('Cu Spot Close Price, $/Oz')
plt.legend()
plt.grid()

Хотя наши данные о ценах выглядят нормально, важно отметить, что мы учитываем данные о дневных ценах. Следовательно, мы ограничиваем себя временными рамками, когда мы можем потерять информацию - любая реакция рынка на новостное событие, скорее всего, произойдет в течение нескольких минут, скорее всего, секунд после объявления о нем. В идеале мы должны использовать 1–5-минутные бары, но для целей этой статьи это подойдет.

Данные твита

Мы будем извлекать наши исторические данные о твитах с помощью библиотеки под названием GetOldTweets3 (GOT). В отличие от официального Twitter API, GOT3 позволяет пользователям получать доступ к обширной истории данных Twitter. Имея список дескрипторов Twitter, принадлежащих источникам финансовых новостей, и несколько релевантных ключевых слов, мы можем определить параметры поиска, по которым мы хотим получить данные (примечание: я опубликовал снимок экрана, а не фрагмент кода необходимой логики для выполнения этого действия ниже в целях форматирования):

Метод .setQuerySearch() принимает один поисковый запрос, поэтому мы не можем извлекать твиты по нескольким критериям поиска. Мы можем легко решить это ограничение с помощью цикла. Например, можно просто назначить имена переменных для каждого выполнения уникального запроса, например, «спотовая медь», «цены на медь» и т. Д., Но для целей этой статьи мы можем ограничиться одним запросом:

# Define handles
commodity_sources = ['reuters','wsj','financialtimes', 'bloomberg']
# Query 
search_terms = 'spot copper'
# Get twitter data
tweets_df = get_tweets(
  commodity_sources,
  search_term = search_terms,
  top_only = False,
  start_date = '2015-01-01',
  end_date = '2020-01-01'
).sort_values('date', ascending=False).set_index('date')
tweets_df.head(10)

Все идет нормально.

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

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

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

Во-первых, удалим лишнюю информацию в виде тегов и URL-адресов, т.е.

Мы определяем пару однострочных функций Lambda, которые используют Regex для удаления букв и символов, соответствующих выражениям, которые мы хотим удалить:

#@title Strip chars & urls
remove_handles = lambda x: re.sub(‘@[^\s]+’,’’, x)
remove_urls = lambda x: re.sub(‘http[^\s]+’,’’, x)
remove_hashtags = lambda x: re.sub('#[^\s]*','',x)
tweets_df[‘text’] = tweets_df[‘text’].apply(remove_handles)
tweets_df[‘text’] = tweets_df[‘text’].apply(remove_urls)
tweets_df[‘text’] = tweets_df[‘text’].apply(remove_hashtags)

Затем мы проводим фундаментальный анализ данных нашего твиттера, исследуя состав твита, такой как длина отдельного твита (слов в твите), количество символов и т. Д.

Стоп-слова

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

Первоначально этот эксперимент был опробован с удалением всех стоп-слов из твитов с использованием очень удобного стандартного списка стоп-слов NLTK:

# Standard tweet sw
stop_words_nltk = set(stopwords.words('english'))
# custom stop words
stop_words = get_top_ngram(tweets_df['text'], 1)
stop_words_split = [
    w[0] for w in stop_words
    if w[0] not in [
        'price', 'prices',
        'china', 'copper',
        'spot', 'other_stop_words_etc'
    ] # Keep SW with hypothesised importance
]
stop_words_all = list(stop_words_nltk) + stop_words_split

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

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

N-граммы

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

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

NLTK имеет очень удобный (и очень эффективный) n-граммовый токенизатор: from nltk.util import ngram. Функция n-грамм возвращает генератор, который выдает верхние n-грамм в виде кортежей. Мы, однако, заинтересованы в изучении того, что на самом деле представляют собой эти n-граммы, так что в первую очередь будем использовать Scikit-learn CountVectorizer для анализа данных наших твитов:

def get_ngrams(doc, n=None):
  """
  Get matrix of individual token counts for a given text document.
    Args:
      corpus: String, the text document to be vectorized into its  constituent tokens.
    n: Int, the number of contiguous words (n-grams) to return.      
    Returns:
      word_counts: A list of word:word frequency tuples.
  """
  # Instantiate CountVectorizer class
  vectorizer = CountVectorizer(ngram_range=
  (n,n)).fit(doc)
  bag_of_words = vectorizer.transform(doc)
  sum_of_words = bag_of_words.sum(axis=0)
  # Get word frequencies
  word_counts = [(word, sum_of_words[0, index])
      for word, index in vectorizer.vocabulary_.items()
  ]
  word_counts = sorted(word_counts, key=lambda x:x[1], reverse=True)
  return word_counts
# Get n-grams
top_bigrams = get_ngrams(tweets_df['text'], 2)[:20]
top_trigrams = get_ngrams(tweets_df['text'], 3)[:20]

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

Токенизация и лемматизация.

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

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

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

Вместо этого мы реализуем лемматизатор, WordNetLemmatizer, чтобы нормализовать слова в данных нашего твита. Лемматизация, возможно, более точна, чем определение корней для нашего приложения, поскольку она учитывает значение слова. WordNetLemmatizer также может помочь повысить точность нашей тематической модели, поскольку в ней используется тегирование части речи (POS). Тег POS для слова указывает его роль в грамматике предложения, например проводит различие между существительным POS и прилагательным POS, например Медь и Цена на медь.

Примечание. Теги POS необходимо настроить вручную в WordNetLemmatizer. Без тега POS предполагается, что все, что вы его кормите, является существительным.

def preprocess_tweet(df: pd.DataFrame, stop_words: None):
  """
  Tokenize and Lemmatize raw tweets in a given DataFrame.
    Args:
      df: A Pandas DataFrame of raw tweets indexed by index of type       DateTime.
      stop_words: Optional. A list of Strings containing stop words         to be removed.
    Returns:
      processed_tweets: A list of preprocessed tokens of type          String.
  """
  processed_tweets = []
  tokenizer = TweetTokenizer()
  lemmatizer = WordNetLemmatizer()
  for text in df['text']:
    words = [w for w in tokenizer.tokenize(text) if (w not in    stop_words)]
    words = [lemmatizer.lemmatize(w) for w in words if len(w) > 2]    
    processed_tweets.append(words)
    return processed_tweets
# Tokenize & normalise tweets
tweets_preprocessed = preprocess_tweet(tweets_df, stop_words_all)

В целях демонстрации полезности вышеупомянутой функции мы также передали в функцию список стоп-слов.

Векторизация и непрерывный набор слов

Теперь нам нужно преобразовать наши токенизированные твиты в векторы, используя метод представления документа, известный как B ag Of Words (BOW). Чтобы выполнить это сопоставление, мы будем использовать Класс Gensim’s Dictionary:

tweets_dict = gs.corpora.Dictionary(tweets_preprocessed)

Передавая список обработанных твитов в качестве аргумента, словарь Gensim’s Dictionary создает отображение уникальных целочисленных идентификаторов для каждого уникального нормализованного слова (аналогично Hash Map). Мы можем просмотреть сопоставление word: id, вызвав .token2id() в нашем tweets_dict. Затем мы подсчитываем количество вхождений каждого отдельного слова, преобразуем слово в его целочисленный идентификатор слова и возвращаем результат в виде разреженного вектора:

cbow_tweets = [tweets_dict.doc2bow(doc) for doc in tweets_preprocessed]

Тематическое моделирование LDA

Теперь самое интересное.

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

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

Чтобы исследовать различные темы (и темы указанных тем) в нашем корпусе твитов, мы будем использовать модель Gensim Скрытое распределение Дирихле. LDA - это генеративная вероятностная модель, применимая к коллекциям дискретных данных, таких как текст. LDA функционирует как иерархическая байесовская модель, в которой каждый элемент в коллекции моделируется как конечная смесь по базовому набору тем. Каждая тема, в свою очередь, моделируется как бесконечное сочетание базового набора вероятностей темы (Blei, Ng et al 2003).

Мы передаем наши недавно векторизованные твиты cbow_tweets и словарь, сопоставляющий каждое слово с идентификатором tweets_dict в класс модели LDA Gensim:

# Instantiate model 
model = gs.models.LdaMulticore(
  cbow_tweets,
  num_topics = 4,
  id2word = tweets_dict,
  passes = 10,
  workers = 2)
# Display topics 
model.show_topics()

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

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

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

  • Цена на медь (естественно)
  • Торговая война США и Китая
  • Президент США Дональд Трамп
  • Крупнейшие добытчики меди
  • Макроэкономические сообщения
  • Гражданские / политические волнения в стране-производителе

Помимо этого, при определении этого гиперпараметра следует руководствоваться собственными суждениями.

Стоит отметить, что существует целый набор других гиперпараметров. Такая гибкость делает модель LDA Gensim чрезвычайно мощной. Например, в качестве байесовской модели, если бы у нас была априорная вера в вероятность темы / слова, наша модель LDA позволяет нам кодировать эти априорные значения для распределения Дирихле с помощью метода init_dir_prior или аналогичным образом с помощью гиперпараметра eta.

Возвращаясь к нашей модели, вы заметите, что мы использовали многоядерный вариант Gensim's LdaModel, который обеспечивает более быструю реализацию (операции распараллелены для многоядерных машин):

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

Чтобы понять распределение тем и их ключевых слов, мы будем использовать pyLDAvis, который запускает интерактивный виджет, что делает его идеальным для использования в записных книжках Jupyter / Colab:

pyLDAvis.enable_notebook()
topic_vis = pyLDAvis.gensim.prepare(model, cbow_tweets, tweets_dict)
topic_vis

Результаты модели LDA

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

Что обеспечивает надежную тематическую модель?

Хорошая тематическая модель обычно представляет собой большие отдельные темы (кружки) без пересечения. Площадь указанных кругов пропорциональна пропорциям тем в общем количестве N токенов в корпусе (а именно, наших данных Twitter). Центры каждого тематического круга задаются в двух измерениях: ПК1 и ПК2, а расстояние между ними задается выходными данными модели уменьшения размерности (точнее, многомерного масштабирования), которая запускается на матрице межтематических расстояний. Полное объяснение математических деталей визуального оформления темы pyLDAvis можно найти здесь.

Интерпретация наших результатов

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

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

Номер темы:

  1. Добыча меди и страны-экспортеры меди

Первые слова включают в себя основных добытчиков меди (BHP Billiton, Antofagasta, Anglo American и Rio Tinto), а также упоминания основных стран-экспортеров меди, таких как Перу, Чили, Монголия и т. Д.

2. Торговля и производство в Китае

Популярные слова включают «Медь», «Цена на медь», «Китай», «Фрипорт» и «Шанхай».

3. США / Китайская торговая война

Популярные слова включают «Медь», «Цена», «Китай», «Трамп», «Доллар» и «ФРС», а также некоторые необычные термины, такие как «Чили» и «Видео».

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

Проверить модель LDA

Как специалисты по данным, мы знаем, что должны проверять целостность и надежность любой модели. Наша модель LDA ничем не отличается. Мы можем сделать это, проверив когерентность (упомянутую выше) нашей модели. Проще говоря, Coherence измеряет относительное расстояние между словами в теме. Математические подробности математики, лежащие в основе того, как рассчитывается этот балл, можно найти в этой статье. Я не стал повторять различные выражения для краткости.

Вообще говоря, оценка от 0,55 до 0,70 указывает на умелую тематическую модель:

# Compute Coherence Score
coherence_model = gs.models.CoherenceModel(
    model=model,
    texts=tweets_preprocessed,
    dictionary=tweets_dict,
    coherence='c_v')
coherence_score = coherence_model.get_coherence()
print(f'Coherence Score: {coherence_score}')

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

Наш выбор меры оценки, наблюдаемой в подписи вышеупомянутой логики модели когерентности, мотивирован результатами в статье Roder, Both & Hindeburg. Как видите, мы выбрали для оценки нашей модели показатель coherence = 'c_v, а не u_mass, c_v, c_uci. и т. д. Показатель c_v показал лучшие результаты по сравнению с другими показателями, особенно в случае небольших наборов слов, определяющих наш выбор.

Оценка настроения: VADER

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

Мы будем использовать словарь Valence Aware Dictionary и SEntiment Reasoner (VADER) для анализа наших твитов и на основе суммы основной интенсивности каждого слова в каждом твите сгенерировать оценку тональности от -1 до 1.

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

VADER - это популярная эвристическая модель анализа настроений, основанная на правилах (составленная людьми) от Hutto and Gilbert. Он особенно точен (и был разработан специально для этого приложения) для использования в текстах социальных сетей. Поэтому кажется рациональным использовать его в нашем проекте.

Реализация VADER очень проста:

# Instantiate SIA class
analyser = SentimentIntensityAnalyzer()
sentiment_score = []
for tweet in tweets_df[‘text’]:
  sentiment_score.append(analyser.polarity_scores(tweet))

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

  • Отрицательная пропорция текста
  • Положительная пропорция текста
  • Нейтральная пропорция текста &
  • Комбинированная интенсивность полярности настроений в приведенном выше, «сложном» балле.
#@title Extract Sentiment Score Elements
sentiment_prop_negative = []
sentiment_prop_positive = []
sentiment_prop_neutral = []
sentiment_score_compound = []
for item in sentiment_score:
  sentiment_prop_negative.append(item['neg'])
  sentiment_prop_positive.append(item['neu'])
  sentiment_prop_neutral.append(item['pos'])
  sentiment_score_compound.append(item['compound'])
# Append to tweets DataFrame
tweets_df['sentiment_prop_negative'] = sentiment_prop_negative
tweets_df['sentiment_prop_positive'] = sentiment_prop_positive
tweets_df['sentiment_prop_neutral'] = sentiment_prop_neutral
tweets_df['sentiment_score_compound'] = sentiment_score_compound

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

  • Очевидно, что оценка настроения очень шумная / непостоянная - наши данные Twitter могут просто содержать избыточную информацию, а некоторые из них вызывают большие всплески оценок. Однако такова природа обнаружения сигналов - нам нужна только эта важная информация.
  • Наши данные Twitter, по-видимому, преимущественно положительные: средний отрицательный балл составляет 0,09, а средний положительный балл - 0,83.

Оценка настроений VS спотовая цена на медь

Теперь мы должны оценить, окупились ли наши упорные усилия: Предсказывает ли наша оценка настроений спотовую цену на медь!

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

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

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

Заключение

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

Следуя принципу бритвы Оккама, мы реализовали готовое решение для анализа основных настроений в наших данных твиттера. Помимо изучения некоторых известных методов EDA и предварительной обработки в качестве предварительного условия, мы использовали Словарь с пониманием валентности NLTK и sEntiment Reasoner (VADER), чтобы сгенерировать соответствующую оценку тональности для каждого твита, и исследовали корреляцию указанного балла по сравнению с простыми соответствующими движениями спотовых цен на медь.

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

Наблюдения, критика и дальнейший анализ

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

Возможности для очень интересной дальнейшей работы и анализа существуют в изобилии в отношении нашей проблемы:

  1. Встраивание нейронной сети. В качестве примера, чтобы лучше понять, как модель НЛП со связанной меткой (или метками) принимает торговое решение, мы бы посмотрим, чтобы обучить нейронную сеть с встраиванием Слой". Затем мы могли бы изучить обученный уровень внедрения, чтобы понять, как модель обрабатывает различные токены внутри уровня по сравнению с токенами с аналогичной кодировкой и метками. Затем мы могли бы визуализировать, как модель группирует слова по их влиянию на класс, который мы хотим предсказать, то есть 0 для отрицательного движения цены, 1 для положительного движения цены. Например, Embedding Projector от TensorFlow - бесценный инструмент для визуализации таких вложений:

2. Полиномиальный наивный байесовский анализ

Мы использовали VADER для анализа и интерпретации основного настроения наших данных Twitter, и он проделал разумную работу. Однако недостатком использования VADER является то, что он учитывает не все слова в документе, а фактически около 7500 слов. Учитывая сложность торговли сырьевыми товарами и связанной с ней терминологии, мы можем упустить важную информацию.

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

3. Данные за день

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

Спасибо, что нашли время прочитать мою статью, надеюсь, вам было интересно.

Пожалуйста, не стесняйтесь обращаться - я очень приветствую комментарии и конструктивную критику.

использованная литература

  1. Хатто, Си Джей и Гилберт, Э. Э. (2014). VADER: Экономичная основанная на правилах модель для анализа настроений в тексте социальных сетей. Восьмая международная конференция по блогам и социальным сетям (ICWSM-14). Анн-Арбор, Мичиган, июнь 2014 г.
  2. Лейн, Ховард, Хапке (2019): Обработка естественного языка в действии.
  3. Moneyweek (2019): Циклы на рынке металлов: когда будут сиять цинк и медь.
  4. Nikkei, азиатский обзор (2020 г.):‘ Dr. Медь неправильно диагностирует мировую экономику .
  5. Kitco 2020: медь падает из-за фиксации прибыли из-за напряженности между США и Китаем.
  6. Metal Miner, (2020): что означает китайское теневое финансирование металлов для рынков.