Google Trends被廣泛使用在行銷上,公司可以利用它來觀察自家產品的搜尋熱度,也可以檢視競爭者的受歡迎程度。雖然Google Trends是個很有趣的資料,但是它本身還是存在許多限制,接下來的文章會來研究Google Trends與股票的關係,並簡單嘗試Da et al.(2011)的In Search of Attention在台灣市場奏不奏效。
在研究開始前,先回顧一下資料的取得(還沒看過可以點這),上一篇文章中,我提供日資料的取得及調整方式,但日資料在下載部分就要花費大量的時間,光是下載一年的日資料就需要送出12次的查詢(query),而Google官方為了防止全球的使用者一次性太大量的下載資料,設定了一個門檻,但是我也不知道究竟要下載多少才不會被擋。
只要使用上文的方式,就算程式本身沒有錯誤,還是會跳出error訊息,那就是因為被Google擋下來了,其實就連gtrendsR套件的作者Massicotte本人也表示不知道這個magic number是多少。因此,一方面為了下載順利,一方面也為了符合Da et al.(2011)那篇文章的資料頻率,改以週資料來使用。
# required packages
library(gtrendsR)
library(tidyquant)
# weekly data collection
trends_weekly <- function(keyword, geo) {
unadjusted <- data.frame()
# every 5 years
for (yr in c(2009,2014)) {
start <- ymd(paste(yr, "01", "01", sep = "-"))
end <- ymd(paste(yr+4, "12-31", sep = "-"))
span <- paste(start, end, sep = " ")
temp <- gtrends(keyword = keyword, geo = geo, time = span, onlyInterest = T) %>% .[[1]]
unadjusted <- rbind(unadjusted, temp)
Sys.sleep(3)
}
trends_all <- gtrends(keyword = keyword, geo = geo, time = "all", onlyInterest = T) %>% .[[1]] %>%
select(weight = hits)
end_yearmon <- paste(year(today()), formatC(nrow(trends_all)%%12, width = 2, flag = "0"), "01", sep = "-")
trends_all <- mutate(trends_all, link = format(seq(ymd("2004-01-01"), ymd(end_yearmon), by = "month"), "%Y-%m"))
trends_adjusted <- unadjusted %>%
mutate(link = format(date, "%Y-%m")) %>%
merge(trends_all, by = "link", all.x = T) %>%
mutate(SVI = hits * weight/100,
date = as.Date(date))
return(trends_adjusted)
}
函數中大部分的設定與上一篇相同,有興趣想知道細節可以參照上一篇網誌,這裡比較不同的在於時間參數,由於Google本身的設定,若要週資料,time最大必須設定5年,而資料從2004年才開始提供,所以迴圈中每5年跑一次就可以了,就是從2004、2009及2014開始跑。SVI為Search Volume Index的縮寫,就是調整後的搜尋次數。
注意:這個函數只會下載2009至2018年底的資料,有需要可以再自行擴充
Da et al.(2011)除了使用SVI、log(SVI),也使用異常的搜尋次數(Abnormal Search Volume Index, ASVI)來檢視其與未來一週的股價報酬有無預測力,在他們的結果中,ASVI可以預測下一週及下兩週的股價報酬,而第三週到一年內則沒有顯著預測力,但是有些許反轉(reversal)的現象,也就是說,在短期內(兩週內),愈高的ASVI伴隨著愈高的報酬;在長期下,愈高的ASVI伴隨著較低的報酬但沒顯著性。ASVI才能看出SVI的變動與報酬(股價的變動)之間的關係,因此ASVI也很重要。
話說回來,要怎麼計算ASVI呢?根據Da et al.(2011)的定義,每週的log(SVI)減去前八週log(SVI)的中位數,就能得到ASVI。正的ASVI被視為異常高的搜尋量,而負的SVI則表示異常低的搜尋量。計算方法如下:
trends_abnormal <- function(weekly_data) {
log_SVI <- log(weekly_data$SVI)
ASVI <- rep(NA, length(log_SVI))
for (week in 9:length(log_SVI)) {
SVI_m <- median(log_SVI[(week-8):(week-1)])
ASVI[week] <- log_SVI[week] - SVI_m
}
weekly_data <- weekly_data %>%
select(date, keyword, SVI) %>%
mutate(log_SVI = log_SVI, ASVI = ASVI)
return(weekly_data)
}
這邊我寫一個簡單的函數來直接對上一個函數下載好的資料來進行處理,接下來就可以實作看看了。
原則上我是希望能夠批次下載所有上市股票的SVI,這樣分析才會夠有可信度,只可惜Google的流量限制讓我一直無法蒐集全股票的SVI(即使只抓臺灣50也有點困難…)。但可以先用台積電來作demo,等到有足夠資料,再將寫好的程式套上去就好。以下先來實作將股價及SVI合併並且繪圖。
svi_2330 <- trends_weekly("2330", "TW")
svi_2330 <- trends_abnormal(svi_2330)
tail(svi_2330)
## date keyword SVI log_SVI ASVI
## 517 2018-11-25 2330 51.35 3.938665 -0.3547824
## 518 2018-12-02 2330 50.92 3.930256 -0.3631915
## 519 2018-12-09 2330 38.86 3.659965 -0.3698603
## 520 2018-12-16 2330 40.87 3.710396 -0.2240641
## 521 2018-12-23 2330 43.55 3.773910 -0.1205293
## 522 2018-12-30 2330 36.85 3.606856 -0.2094103
使用highcharter套件來視覺化:
library(highcharter)
hc_trends <- function(data, x = "SVI") {
hc <- highchart() %>%
hc_title(text = x) %>%
hc_chart(type = "line") %>%
hc_xAxis(categories = data$date,
title = list(text = "Time")) %>%
hc_yAxis(labels = list(format = '{value:.2f}'),
title = list(text = ifelse(x=="SVI", "Search Volume Index", "Abnormal Search Volume Index"))) %>%
hc_add_series(data[,x], showInLegend = FALSE) %>%
hc_add_theme(hc_theme_ft())
return(hc)
}
# Figure 1. SVI
hc_trends(svi_2330, x = "SVI")
# Figure 2. ASVI
hc_trends(svi_2330, x = "ASVI")
下面就不一一贅述股價資料的處理過程,基本上為了要讓兩者合併,由於是週資料,所以必須根據變數年(year)及變數週(week),這兩者都可以輕鬆透過lubridate套件來計算。而每週的股價我以週三的股價作為基準。
stock_2330 <- tq_get("2330.TW", from = "2009-01-01", to = "2018-12-31") %>%
filter(weekdays(date) == "Wednesday") %>%
mutate(year = year(date), week = week(date), ret = ROC(adjusted)) %>%
select(year, week, price = adjusted, ret)
svi_2330 <- svi_2330 %>%
mutate(year = year(date), week = week(date))
# merge
trends_2330 <- merge(stock_2330, svi_2330, by = c("year", "week"))
# Figure 3. SVI and Stock Prices of TSMC
highchart() %>%
hc_title(text = "TSMC: 2330") %>%
hc_subtitle(text = "ranging from 2009-01-01 to 2018-12-31") %>%
hc_chart(type = "line") %>%
hc_xAxis(categories = trends_2330$date.x,
title = list(text = "Time")) %>%
hc_yAxis_multiples(list(
labels = list(format = '{value:.0f}'),
title = list(text = "Search Volume Index")),
list(
labels = list(format = '{value:.0f}'),
title = list(text = "Stock Price"),
opposite = T
)) %>%
hc_add_series(trends_2330$SVI, name = "SVI(left)") %>%
hc_add_series(trends_2330$price, name = "Stock Price(right)", yAxis=1) %>%
hc_add_theme(hc_theme_ft())
以上面的結果來說股價的走勢與SVI好像有那麼一點關係,的確以相關性檢定來說,兩者有56.87%的顯著正相關性。然而,若依照Da et al.(2011)的研究,將ASVI與未來一週的週報酬做相關性檢定,相關性只有5.05%而且不顯著,其他的結果也不甚理想,所以這邊就不特別做表顯示結果了。不過也不用沮喪,我只是簡單將兩個變數做時間序列的分析,那篇文章卻是先將Russell 3000前前後後共3606檔的股票做橫斷面(cross-sectional)的分析再跑Fama-MacBeth迴歸,與我上面簡單的分析差很多,因此還不能斷言Google Trends在台灣沒有效果。
其實做到這大家應該都能發現,真正難的不是將code寫出來,也不是複製別人的實證流程,而是如何發想一個具有創造力的點子。也許在Google開放這個服務時就有人想到財金方面的應用,但真正將其發展成有影響力且有顯著結果的研究,恐怕沒有幾人,Da, Engelberg, Gao這三人辦到了,並發表在財務最有影響力的期刊The Journal of Finance。這幾位學者還有許多有趣的研究,將來有機會在撰文介紹,也許在實務上也會有所啟發!
DA, Z. , ENGELBERG, J. and GAO, P. (2011), In Search of Attention. The Journal of Finance, 66: 1461-1499. doi:10.1111/j.1540-6261.2011.01679.x