Friday, September 30, 2011

[Text mining] Индекс настроений фондовых рынков

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

"Trading Strategies to Exploit Blog and News Sentiment" (Zhang, Skiena 2010)
"The Predictive Power of Financial Blogs" (Frisbee 2010)
"An analysis of verbs in financial news articles and their impact on stock price" (Schumaker 2010)

Но это все там, за океаном. А что же у нас, в России?

Искать правду в твиттере для российского рынка, мне показалось, бесполезным. Во-первых твиттером у нас пользуются по-прежнему единицы, а во-вторых у американцев, так или иначе, в фондовый рынок вовлечено почти все население, у нас же это развлечение для избранных. Зато в России есть раскрученная социальная сеть трейдеров comon.ru. На этом ресурсе публикуется несколько десятков статей ежедневно и, что самое главное, они по теме. Что может быть лучше для задачи анализа текста?

Итак, сказано - сделано. Я решил проверить связано ли как-то настроение блогеров comon.ru с движениями на рынке и, самое интересное, могут ли эти данные быть использованы для предсказания движений рынка. Первым делом, было выкачано около 10 тыс. статей от 100 авторов с comon.ru, вместе с датой публикации и именем автора. Потом текст статей был обработан: удалены все элементы HTML-разметки и стоп-слова а у всех оставшихся слов была выделена основа.

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

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

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

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

Далее, после усреднения данных по дням, получился некоторый индекс, назовем его индексом настроений comon.ru. Это число, которое характеризует среднее настроение блогеров comon.ru в этот день. Интересным оказался график изменения индекса настроения:

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

Следующим шагом, я проверил а сколько можно было бы заработать если покупать вечером того дня когда индекс настроений больше нуля и закрывать позицию на следующий день. И аналогично для отрицательных значений индекса настроений. Оказалось, что среднее дневное изменение индекса ММВБ в день, следующий за днем с позитивным настроением составляет: 0.13%. А в дни следующие за днями с негативным настроением -0.34%. Результат мне показался вдохновляющим. И было решено проверить математически гипотезу о том, что индекс настроения комона предсказывает значения ММВБ. Для этого, я воспользовался методом описанным в оригинальной работе, а именно, причинным тестом Грейнджера:

Model 1: MICEX ~ Lags(MICEX, 1:1) + Lags(SIGNAL, 1:1)
Model 2: MICEX ~ Lags(MICEX, 1:1)
  Res.Df Df      F  Pr(>F)  
1    178                    
2    179 -1 2.9539 0.08741 .

P-value теста составило 0.087, что меньше 0.1. Значит наша гипотеза о том что индекс настроений комона предсказывает изменения индекса ММВБ на следующий день верна с вероятностью 90%. Что является неплохим результатом, вполне сравнимым с результатом в оригинальной работе с твиттером.

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

Что использовалось для данной работы?
1. Граббер текстов с comon.ru и предварительная обработка были написан на Java
2. Вся математика, анализ и построение графиков выполнялись на R с использованием библиотек lmtest и rusquant

Какие варианты развития?
1. В отличии от твиттера, количество авторов комона которые пишут регулярно не велико. Можно ввести что-то вроде предсказательного рейтинга автора, тем самым улучшив общий прогноз.
2. Учитывать оценки других пользователей и комментарии к каждой статье.
3. Добавить анализ морфологии русского языка, учитывать время в котором написаны отдельные предложения статьи.



Tuesday, September 20, 2011

Этот безумный R


Сначала мне казалось, что это простой и примитивный язык, для небольших скриптов, с уклоном в статистику. Потом мне стало казаться, что это самый обычный язык программирования, с уклоном в статистику. Сейчас мне кажется, что это гремучая смесь классических императивных языков вроде C++ или Java и матерой функциональщины вроде Haskell или Lisp. И всё это R.

На самом деле, действительно, R многое заимствовал из Lisp. Функции в R являются полноценными сущностями. Их можно не только вызывать и определять но и передавать в качестве параметров или составлять из них сложные выражения. В R доступны замыкания и отложенные вычисления. При этом, в отличии, например, от Haskell, R не страдает от функциональной чистоты и допускает функции с побочными эффектами. Я уже не говорю о том, что в R еще и объектно-ориентированный язык. Правда, признаюсь честно, реализация объектно-ориентированного программирования в R больше похожа на помойку. В R есть несколько ООП-систем и каждая живет своей жизнью. Все это многообразие, делает работу сложней и интересней. Нередко, разобравшись в концепции, начинаешь понимать, как тот или иной код можно написать короче и эффективней. Некоторыми такими концепциями я бы и хотел сегодня поделиться.

Monday, September 19, 2011

Тиковые данные rusquant v0.3

Очередное обновление rusquant. Теперь стали доступны тиковые данные.

Как обычно, обновиться, тем у кого уже есть, или установить тем, у кого еще нет, можно командой в консоли R:
install.packages("rusquant", repos="http://R-Forge.R-project.org")

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

Для получения тиковых данных можно воспользоваться знакомой функцией getSymbols()

> library(rusquant)
>  getSymbols("SBER", from=Sys.Date()-1, src="Finam", period="tick")
[1] "SBER"
>  SBER[1:5]
                    SBER.Close SBER.Volume
2011-09-14 09:59:59      79.24          30
2011-09-14 09:59:59      79.24          30
2011-09-14 09:59:59      79.24          10
2011-09-14 09:59:59      79.24          20
2011-09-14 09:59:59      79.24         500

Сразу отмечу, что вызов выполняется достаточно долго, т.к. объем получаемых данных очень большой. Для удобства, сохранена система именования OHLC данных. Т.е. цены можно получить всё той же функций Cl, а объем Vo.

Если же есть необходимость преобразовать тиковые данные в OHLC, то нет ничего проще, в модуле xts для этого есть ряд удобных функций типа to.minutes, to.hourly, to.minutes10 и более общая функция to.period

> to.period(SBER, "mins", k=5)
                    SBER.Open SBER.High SBER.Low SBER.Close SBER.Volume
2011-09-14 09:59:59     79.24     79.24    79.24      79.24      287520
2011-09-14 10:04:58     79.47     79.68    79.11      79.52     4042460
2011-09-14 10:09:59     79.52     79.66    79.34      79.35     3095280

Доступные значения периодов: “secs”, “seconds”, “mins”, “minutes”, “hours”, “days”, “weeks”, “months”, “quarters”, и “years”. Хотя, я сомневаюсь, что последними кто-то будет пользоваться. k=5 - показывает какое количество периодов объединять в группу. В данном примере мы получили пятиминутные данные.

Tuesday, September 13, 2011

Геомагнитные бури на фондовом рынке


Сегодняшняя тема немного несерьезная. А может быть наоборот очень серьезная. Так сложилось, что во времена моей прыщавой юности, когда рухнул совок и было не во что больше верить, люди начали слушать всяких Чумаков, Кашпировских и прочих телепузиков. Кажется именно тогда особой популярностью пользовались геомагнитные бури и бабушки у подъезда с радостью списывали очередной приступ остеохондроза на повышенную геомагнитную активность. Наверное, именно такое отношение и привело в последствии к предвзятому взгляду на прогнозы геомагнитной активности (я то её влияние никогда не чувствовал). Тем не менее, явление то существует и объективно регистрируется.

Есть масса исследований, утверждающих, что геомагнитные бури влияют на настроение людей. Люди склонны пессимистичней оценивать происходящее вокруг них во время и после бури, нежели в спокойные дни. Теперь подумаем, если люди глядят на вещи с пессимизом, причем это люди по всей земле. Значит, это должно непременно сказываться на фондовом рынке. Логично предположить, что магнитные бури должны приводить к сокращению вложений в рискованные активы, такие как акции. А раз так, то этим можно было бы воспользоваться для построения собственной торговой стратегии. И вот, в статье "Playing the Field: Geomagnetic Storms and the Stock Market" такое исследование уже проводилось и результаты мне показались достаточно интересными чтобы проверить их на практике.

Tuesday, September 6, 2011

Обновление rusquant 0.2

Небольшая библиотека для работы с Российскими фондовыми рынками в R пополнилась новыми возможностями. Теперь, помимо доступа к данным с Финама, прямо из R вы можете получить доступ к котировкам фьючерсов и опционов Forts, доступным на сайте rts.ru

Итак, для тех что еще не установил себе rusquant - ставим, для тех, кто уже установил - обновляемся командой:

install.packages("rusquant", repos="http://R-Forge.R-project.org")

Что новенького?

1. Стала доступной доска опционов:

library(rusquant)
rts <- getOptionChain("RTS-9.11", "2011-09-15", src="Forts", session = "MAIN")
В качестве параметров передается название базового инструмента, дата экспирации и источник данных src="Forts", кроме того, можно указать сессию session = "MAIN" - основную или session = "EVENING" - вечернюю. Для примера, построим улыбку волатильности. Замечу, что ожидаемая волатильность в данном примере считается биржей и точной методики расчета мне найти не удалось.
plot(cbind(rts$calls[,'Strike'], rts$calls[,'IV']), type='l', main="Implied Volatility", ylab="Volatility", xlab="Strike")
Графики открытого интереса:
plot(cbind(rts$calls[,'Strike'], rts$calls[,'OI']), type='l', col='blue', main="Open Interest", ylab="R", xlab="Strike")
lines(cbind(rts$puts[,'Strike'], rts$puts[,'OI']), type='l', col='red')
2. Стали доступны дневные исторические данные по опционам:
getSymbols("RTS-9.11M150911CA 185000", from="2011-03-21", src="Forts")
chartSeries(RTS911M150911CA185000)


Планы на будущее: добавить дивиденды, статистику и тиковые данные.

Thursday, September 1, 2011

И снова о коинтеграции временных рядов

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

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

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

Рассмотрим пример на языке программирования R:
data <- rnorm(50)
plot(data, type='l')