分析數據還是以數據「作」分析呢?
https://htmichael.blogspot.hk/2017/08/blog-post.html
【EJFQ信析】港股未脫超買 不離三種下場
http://www2.hkej.com/instantnews/market/article/1636469
今次關心的他如何用200天移動平均線去作為後市預測,甚至作為買賣指標。想到的第一個問題,先是「偏離200天移動平均線的程度,與未來20天的平均回報是否負相關?」所以整個步驟分為:
1. 提取股價和求取200天移動平均數值
2. 製作紀錄200天移動平均線偏離度、和未來20天的平均回報的數據列
3. 製作Scatter plot,Correlation、r^2 等用作觀察
4. 製作迴歸線Regression Line、預測值區間Prediction Intervals.
今次數據整理的過程中經常使用Tidyverse中的 mutate()方法-(見:R User Group 的 Machine Learning for Beginners)。R的金融套件以往是quantmod, TTR, 等,但套件一多而各自對資料有不同格式風格的要求,就會混亂和不便,Tidyquant 是一個為了讓 Quants 們也可以融入到 Tidyverse 的格式環境中,今次就用到當中的 tq_get()、tq_mutate()、tq_performance()。tq_get()是用來提取股價的,好比getsymbols()、get.hist.quote();tq_mutate() 整作指標等的新數據列;tq_performance() 用作分析股票/組合的表現。後面兩個都是調用 TTR、quantmod、tseries 等底層套件的功能,兩者可用的功能可以用 tq_mutate_fun_options()、tq_performance_fun_options() 查詢。
tq_mutate_fun_options() 查看可以進行的數據操作 |
tq_performance_fun_options() 查看可以進行的表現分析 |
先看2010年至今的 "偏離200天移動平均線" 和 "隨後20個交易日的平均表現" 的比較。[dSMA] 的是顯著不等於零的( 當 Pr ( > | t | ) 足夠細小)。每比SMA.200 高 1% ,回報就低0.0884% (雖然還是太小了吧?但你不會認為這麼容易可以明顯地賺大錢吧?)。以 31Aug 高約14%為例,預測回報為 -0.884 %,95%區間在大約 +9%至-11% 之間。 區間之闊就是一個簡單線性模型所未考慮的一切因素和隨機誤差。這是否值搏就見仁見智,和你如何控制注碼了。
2010年1月1日 - 2017年8月31日 |
但另一篇提出一個數據的自我閹割問題,如果用更多數據,加入2010年之前的股價資料,又是否成立呢?改一改開始日期變成2000年,就可以看到下圖,基本上就是一條平線,再沒有斜度的顯著性。Why ?
2000年1月1日 - 2017年8月31日 |
如果當偏離200天線後,就會回歸200天線。這就會表現為Scatter plot上的負數斜率;如果愈升(跌)愈高(低)的話,這應該會表現為Scatter plot上的正數斜率,如下圖。
2000年1月1日 - 2010年1月1日 |
回到 Tidyquant 的試驗,希望最終是可以建立到買賣紀錄和測試投資組合表現的方式。要以投資組合的角度做比較,而不單是大量個別交易的回報統計,但這個就跟注碼控制有關,每個交易機會時應該把多少資金從Cash轉到Stock? 雖然這方面要另外測試,但我猜想之下應該會是需要記錄以下資料。
新增說明文字 |
另一方面,只統計大量單筆交易的結果還算容易,只要看每次從觸發交易到退出期間的回報做個總結。以下可見平均是有約3.6%的回報:
## Example of 200 Day Testing ## library(tidyquant) # 引入 tidyquant library dateStart <- as_date("2010-01-01") # 設定觀察期初 dateEnd <- as_date("2017-08-31") # 設定觀察期尾 # 用tidyquant的 tq_get 取得 tibble 格式的股價資料 StockHSI <- c("^HSI") %>% tq_get(get = "stock.price", from = dateStart, to = dateEnd) myData <- StockHSI %>% filter(!is.na(close)) # 觀察過資料後,留意到幾筆 NA 資料 (例如23/08的颱風停市),直接刪除 # 用 geom_ma 製作 一個 20天 和 200天 移動平均線 的圖 p1 <- myData %>% ggplot(aes(x = date, y = close)) + geom_barchart(aes(open = open, high = high, low = low, close = close), color_up = "darkgreen", color_down = "darkred") + geom_ma(ma_fun = SMA, n = 200, col = "darkblue", size = 0.5) + geom_ma(ma_fun = SMA, n = 20, col = "blue", size = 0.5) p1 # 自定一個函數,計算未來20天的平均回報 avgReturn <- function(x, p=1, ... ){ V <- matrix(NA, ncol=p, nrow=NROW(x)) for (i in 1:p) { V[,i] <- lead(x, n=p)/x } avgReturn <- apply(V,1,function(x) sum(x)) / p return(avgReturn) } # 用 tq_mutate、mutate 的製作紀錄200天移動平均線偏離度、和20天內平均回報 的數據列 myData <- myData %>% tq_mutate(select=close, mutate_fun = SMA, n = 200) %>% rename(SMA200 = SMA) myData <- myData %>% mutate(dSMA = close / SMA200 -1, avgRet = avgReturn(close,20) - 1) # 記下當日的偏離度,之後去除NA資料 todayData <- myData %>% filter(date==dateEnd) myData <- myData %>% filter(!is.na(avgRet) & !is.na(dSMA)) # 製作 200天移動平均線偏離度 的圖 p2 <- myData %>% ggplot(aes(x = date, y = dSMA)) + geom_line() p2 # 將數據用作線性回歸模型 lm1 <- lm(avgRet ~ dSMA, data = myData) summary(lm1) pAvgRet <- predict(lm1, interval="prediction") myData <- cbind(myData, pAvgRet) # 製作 Scatter Plot,加上regression line、 預測區間、最近的200天偏離度。 ggplot(myData, aes(x = dSMA, y = avgRet)) + geom_point(size=0.5) + geom_vline(xintercept=todayData$dSMA, col="grey", size=0.5, linetype="dashed") + stat_smooth(method = "lm", col = "red", size=0.75) + geom_line(aes(y=lwr), color = "red", size=0.5, linetype = "dashed") + geom_line(aes(y=upr), color = "red", size=0.5, linetype = "dashed") + labs(x = "Deviation from SMA.200", y = "Average Return.20") # 紀錄觸發點 myData <- myData %>% mutate(trigger = ifelse(dSMA>0.15, -1, ifelse(dSMA < (-0.15), 1, 0) )) # 每個機會出現後20天的回報總結: myData %>% filter(trigger == 1) %>% select(avgRet) %>% summary() # 買入信號 myData %>% filter(trigger == -1) %>% select(avgRet) %>% summary()
# 賣入信號
# 自定一個函數,將交易紀錄轉變成投資組合的價值 trade2Hold <- function(price, trade, initCash=100, initStock=0, ... ){ V <- matrix(NA, nrow=length(trade), ncol=6) V[1,1] = price[1]; # price V[1,2] = trade[1]; # trade V[1,3] = initStock + trade[1]; # Holding Stock Number V[1,4] = V[1,1] * V[1,3]; # Holding Stock Value V[1,5] = initCash - V[1,1] * V[1,2]; # Holding Cash Value V[1,6] = V[1,4] + V[1,5] for (i in 2:length(trade)) { V[i,1] = price[i]; # price V[i,2] = trade[i]; # trade V[i,3] = V[i-1,3] + trade[i]; # Holding Stock Number V[i,4] = V[i,1] * V[i,3]; # Holding Stock Value V[i,5] = V[i-1,5] - V[i,1] * V[i,2]; # Holding Cash Value V[i,6] = V[i,4] + V[i,5] } return(V[,6]) } # 製作買賣紀錄 和 投資組合價值 的數據列 initialCash = myData$close[1] # 將開始的現金定為恆指的期初點數,方便繪圖比較
myData <- myData %>% mutate(trade = 0.1*(trigger - lag(myData$trigger, n=10, default=0)))
myData <- myData %>% mutate(pfValue = trade2Hold(close, trade, initCash= initialCash)) # 組合價值 myData <- myData %>% tq_mutate(select=close, mutate_fun=dailyReturn, col_rename="bmRet") %>% tq_mutate(select=pfValue, mutate_fun=dailyReturn, col_rename="pfRet") # 組合和基準的回報 #
製作 組合 和 基準 的圖
p3 <- myData %>% ggplot(aes(x = date)) + geom_line(aes(y = pfValue), col = "blue", size = 0.5) + geom_line(aes(y = close), col = "black", size = 0.5) + geom_line(aes(y = SMA200), col = "black", size = 0.1, linetype = "dotdash") p3 # CAPM's Alpha, Beta; Sharpe Ratio myData %>% tq_performance(Ra = pfRet, Rb = bmRet, performance_fun = table.CAPM) myData %>% tq_performance(Ra = pfRet, Rb = NULL, performance_fun = SharpeRatio, Rf=0.03/365, p=0.99)
沒有留言:
張貼留言