################################################# # T02: R程式-金融科技 # # 吳漢銘 國立臺北大學統計學系 # # http://www.hmwu.idv.tw/ # ################################################# # install.packages("quantmod") library(quantmod) getSymbols("AAPL", src="yahoo") # getSymbols("BABA") #default src="yahoo" dim(AAPL) class(AAPL) head(AAPL, 3) tail(AAPL, 3) head(AAPL$AAPL.Open, 3) # myApple <- get(getSymbols("AAPL", src="google")) myApple <- get(getSymbols("AAPL")) head(myApple, 3) tail(myApple, 3) class(myApple) myApple.df <- as.data.frame(myApple) class(myApple.df) AAPL.df <- as.data.frame(AAPL) class(AAPL.df) # chartSeries(AAPL) chartSeries(AAPL, subset="2016") chartSeries(AAPL, subset="2016-09::2016-12") chartSeries(AAPL, subset="2016-09::2016-12", type = "line", theme = "white") # chartSeries(AAPL["2016"]) chartSeries(AAPL["2016-01"]) chartSeries(AAPL["2016-01/2016-03"]) chartSeries(AAPL["2016-01-01/2016-03-15"]) # candleChart(AAPL["2016-01/2016-03"]) barChart(AAPL["2016-01::2016-03"]) # start.date <- as.Date("2012-02-01") end.date <- as.Date("2012-02-28") APPL.201202 <- AAPL[index(AAPL) > start.date & index(AAPL) < end.date] head(APPL.201202, 3) tail(APPL.201202, 3) AAPL.201604 <- get(getSymbols("AAPL", from = as.Date("2016-04-01"), to = as.Date("2016-04-30"), src="yahoo")) index(AAPL.201604) # multiple stocks getSymbols(c("VZ", "AAPL", "MMM", "IBM")) head(MMM, 3) # getwd() # 儲存資料(Rdata格式) saveSymbols(c("AAPL", "MMM"), file.path=".") list.files() removeSymbols("AAPL") load("AAPL.RData") write.zoo(IBM, "IBM.csv", sep = ",", qmethod = "double") # or removeSymbols("IBM") # > showSymbols() getSymbols.csv("IBM", env=globalenv()) head(IBM, 3) write.csv(as.data.frame(IBM), "IBM_2.csv") getSymbols.csv('IBM_2', env=globalenv()) # symbols <- stockSymbols() head(symbols) # TSMC <- getSymbols("2330.TW", auto.assign = FALSE) head(TSMC) getSymbols(c("2330.TW", "2303.TW", "2337.TW")) head(2330.TW) # error head("2330.TW") # wrong head('2330.TW') # wrong, Enter鍵旁的「'」 head(`2330.TW`) # correct, Tab 鍵上方的「`」 TSMC <- get("2330.TW") # or TSMC <- `2330.TW` UMC <- get("2303.TW") MXIC <- get("2337.TW") head(UMC) # View(UMC) # chartSeries(TSMC) chartSeries(UMC) getSymbols("^DJI") chartSeries(DJI) # class(TSMC) dim(TSMC) head(TSMC, 3) tail(TSMC, 3) TSMC.m <- to.monthly(TSMC) head(TSMC.m, 3) TSMC.q <- to.quarterly(TSMC) head(TSMC.q, 3) TSMC.y <- to.yearly(TSMC) head(TSMC.y, 3) TSMC.2012 <- TSMC["2012"] TSMC.2012w <- to.weekly(TSMC.2012) # chartSeries(TSMC.2012w) chartSeries(TSMC.2012w, theme="white", grid=T, up.col="red", dn.col="green") chartSeries(TSMC.2012w, TA=NULL) #no volume chartSeries(TSMC.2012w,TA=c(addVo(), addBBands())) #add volume and Bollinger Bands from TTR myTheme <- chartTheme("white", up.col="red", dn.col="green") chartSeries(TSMC.2012w, theme=myTheme, grid=T) # # install.packages("TTR") library(TTR) data(ttrc) dim(ttrc) head(ttrc) t <- 1:100 sma.20 <- SMA(ttrc[t, "Close"], 20) ema.20 <- EMA(ttrc[t, "Close"], 20) wma.20 <- WMA(ttrc[t, "Close"], 20) plot(ttrc[t,"Close"], type="l", main="ttrc") lines(sma.20, col="red", lwd=2) lines(ema.20, col="blue", lwd=2) lines(wma.20, col="green", lwd=2) legend("topright", legend=c("sma.20", "ema.20", "wma.20"), col=c("red", "blue", "green"), lty=1, lwd=2) # getSymbols("BABA") head(BABA) chartSeries(BABA["2014-10-01/2015-03-31"], theme=chartTheme("white", up.col="red", dn.col="green"), name="Ali BABA K-line", show.grid=TRUE) addSMA(10) #10日簡單移動平均線 # 策略: 當快線(成交價)向上穿過慢線(MA值),可買進。 # 當慢線穿過快線,可出場。 # 移動平均線(MA) addEMA(24, col="blue") # 指數平滑異同移動平均線(MACD) # 用於判斷股票的價格變化 # 計算方式=兩條EMA計算差值(DIF),再對差值進行移動平均計算 addMACD() ################################################################################ ## # ## K線圖分析: 上海證券交易所綜合股價指數 # ## # ################################################################################ # install.packages("quantmod") library(quantmod) # 定義K線圖佈景主題 myTheme <- chartTheme("white", up.col="red", dn.col="green") # 讀入上証綜指2015年日資料 SSEC2015 <- read.csv("data/SSEC2015.csv", header=TRUE) head(SSEC2015, 3) # 將資料框轉成xts時序類別 SSEC2015 <- xts(SSEC2015[, -c(1,2)], order.by=as.Date(SSEC2015$Date)) class(SSEC2015) head(SSEC2015, 3) tail(SSEC2015, 3) # 繪製K線圖(預設值) chartSeries(SSEC2015) # 繪製K線圖(設定佈景主題,標題名稱) chartSeries(SSEC2015, theme=myTheme, name="上證綜指2015年3月份,日K線圖") # 讀入上証綜指2014年日資料 SSEC2014 <- read.csv("data/SSEC2014.csv", header=TRUE) SSEC2014 <- xts(SSEC2014[, -c(1,2)], order.by=as.Date(SSEC2014$Date)) head(SSEC2014, 3) # 將日資料轉成周資料 SSEC2014W <- to.weekly(SSEC2014) head(SSEC2014W) chartSeries(SSEC2014W, theme=myTheme, name="上證綜指2014年8-12月份,週K線圖") ###################################### # R語言捕捉「早晨之星」型態 # ###################################### # 刪除所有物件 rm(list=ls()) myTheme <- chartTheme("white", up.col="red", dn.col="green") # 讀入上證綜指2012年日交易資料 SSEC2012 <- read.csv("data/SSEC2012.csv", header=TRUE) # 轉為xts時序資料類別 SSEC2012 <- xts(SSEC2012[, -c(1,2)], order.by=as.Date(SSEC2012$Date)) head(SSEC2012, 3) tail(SSEC2012, 3) # 取收盤價與開盤價 Close <- SSEC2012$Close Open <- SSEC2012$Open # 計算每一個交易日的收盤價與開盤價的差值 CL_OP <- Close - Open names(CL_OP) <- "CL_OP" head(CL_OP) # 摘要差值分佈情況 summary(CL_OP) # 取前期值(lag) head(CL_OP) head(lag(CL_OP, 1)) head(lag(CL_OP, 2)) # 結合三期資料: 本期差值、前一期差值、前二期差值 dataCL_OP <- merge(CL_OP, lag(CL_OP, 1), lag(CL_OP, 2)) class(dataCL_OP) head(dataCL_OP, 3) # 判斷「早晨之星」型態: 0: 不是。1: 是 # 補捉綠色實體(up:high-open, lower:close-low)、 # 十字星(open~close) # 紅色實體(up:high-close, lower:open-low) candle <- apply(dataCL_OP, 1, function(x) { ifelse(x[3] < (-11) & abs(x[2]) < 2 & x[1] > 6 & abs(x[1]) > 0.5 * abs(x[3]), 1, 0) }) # 轉換成xts時間序列類別 candle <- xts(as.numeric(candle), order.by = index(dataCL_OP)) names(candle) <- "candle" head(candle, 3) # 定義十字星實體位置所需要的資料 dataCOP <- merge(Open, lag(Open, 1), lag(Close, 1), lag(Close, 2)) tail(dataCOP, 3) # 定義十字星實體位置,要在其前後綠色實體和紅色實體下方 # 捕捉符合十字星實體位置的K線圖 Doji <- apply(dataCOP, 1, function(x) { ifelse(x[2] < x[4] & x[2] < x[1] & x[3] < x[4] & x[3] < x[1], 1, 0) }) # 轉換成xts時間序列類別 Doji <- xts(as.numeric(Doji), order.by = index(dataCOP)) names(Doji) <- "Doji" head(Doji, 3) # 定義下跌趨勢 # 計算收益率 ret <- ROC(Close, type = "discrete") names(ret) <- "SSEC2012.ret" head(ret) # 結合「尋找向下趨勢所需資料」,前一期收益、前二期收益 dataret <- merge(lag(ret, 2), lag(ret, 1)) # 尋找向下趨勢 trend <- apply(dataret, 1, function(x) { ifelse(x[1] < 0 & x[2] < 0, 1, 0) }) trend <- xts(as.numeric(trend), order.by = index(dataret)) names(trend) <- "trend" head(trend) # 定義「早晨之星」捕捉函數 MorningStar <- function(candle, Doji, trend) { star <- na.omit(merge(candle, Doji, trend)) signal <- apply(star, 1, function(x) { ifelse(all(x == 1), 1, 0) }) signal <- xts(as.numeric(signal), order.by = index(star)) return(index(signal[signal == 1])) } # 捕捉上証縩指2012年出現「早晨之星」的日期 MorningStar(candle, Doji, trend) # 繪製2012/09/06附近的K線圖 SSEC201209 <- SSEC2012["2012-08-21/2012-09-30"] chartSeries(SSEC201209, theme = myTheme) ###################################### # R語言捕捉「烏雲蓋頂」型態 # ###################################### rm(list=ls()) myTheme <- chartTheme("white", up.col="red", dn.col="green") # 讀入上證綜指2011年日交易資料 SSEC2011 <- read.csv("data/SSEC2011.csv", header = TRUE) SSEC2011 <- xts(SSEC2011[, -c(1, 2)], order.by = as.Date(SSEC2011$Date)) Close <- SSEC2011$Close Open <- SSEC2011$Open CL_OP <- Close - Open names(CL_OP) <- "CL_OP" dataCL_OP <- na.omit(merge(CL_OP, lag(CL_OP))) head(dataCL_OP, 3) # 捕捉連續2期的不同顏色的蠟燭實體 cloudColor <- apply(dataCL_OP, 1, function(x) { ifelse(x[2] > 0 & x[1] < 0, 1, 0) }) cloudColor <- xts(as.numeric(cloudColor), order.by = index(dataCL_OP)) head(cloudColor, 3) # 描述「烏雲蓋頂」形態收盤價、開盤價的位置條件 dataCOP <- merge(Close, Open, lag(Close), lag(Open)) cloud <- apply(dataCOP, 1, function(x) { ifelse(x[2] > x[3] & x[1] < 0.5 * (x[3] + x[4]) & x[1] > x[4], 1, 0) }) cloud <- xts(as.numeric(cloud), order.by = index(dataCOP)) head(cloud, 3) # 定義向上趨勢 # 計算收益率 ret <- ROC(Close, type = "discrete") names(ret) <- "SSEC2011.ret" head(ret, 3) dataret <- merge(lag(ret, 2), lag(ret, 1)) Uptrend <- apply(dataret, 1, function(x) { ifelse(x[1] > 0 & x[2] > 0, 1, 0) }) Uptrend <- xts(as.numeric(Uptrend), order.by = index(dataret)) head(Uptrend, 3) # 尋找「烏雲蓋頂」形態 darkCloud <- cloudColor + Uptrend + cloud names(darkCloud) <- "darkCloud" darkCloud[darkCloud == 3] # 繪製2011/05/19附近的K線圖 SSEC201105 <- SSEC2011["2011-05-01/2011-05-30"] chartSeries(SSEC201105, theme = myTheme) # 繪製2011/08/16附近的K線圖 SSEC201108 <- SSEC2011["2011-08-01/2011-08-30"] chartSeries(SSEC201108, theme = myTheme) ################################################################################ ## # ## 動量交易策略: 萬科(Vanke)集團股票 # ## # ################################################################################ ###################################### # 價格動量計算公式 # ###################################### rm(list=ls()) myTheme <- chartTheme("white", up.col="red", dn.col="green") # 讀取萬科股票2014~20150428,日資料 Vanke <- read.csv("data/Vanke.csv", header = TRUE) Vanke <- xts(Vanke[, -c(1, 2)], order.by = as.Date(Vanke$Date)) head(Vanke, 3) tail(Vanke, 3) Close <- Vanke$Close names(Close) <- "vanke.Close" tail(Close, 3) summary(Close) # 計算滯後5期(前5期)收盤價 lagClose <- lag(Close, 5) names(lagClose) <- "lagClose" vankeClose <- merge(Close, lagClose) vankeClose <- na.omit(vankeClose) head(vankeClose) # 計算5日(作差法)動量 momentum5 <- vankeClose$vanke.Close - vankeClose$lagClose names(momentum5) <- "vanke.Momentum" tail(momentum5, 3) # 繪製收盤價曲線和5日動量曲線 plot.zoo(merge(Close, momentum5), col = c("black", "blue"), main = "萬科股價與5日動量圖") # 計算5日(作除法)動量 Momentum <- (Close - lagClose) / lagClose Momentum <- Momentum[-5:-1, ] names(Momentum) <- "vanke.roc5" head(Momentum) ###################################### # 動量相關函數 # ###################################### library(TTR) # 以 momentum {TTR} 計算5日動量(作差法) # na.pad = TRUE: 資料包含NA的日期 Momentum1 <- momentum(Close, n = 5, na.pad = TRUE) head(Momentum1) tail(Momentum1) # 計算股價的5期收益率(離散變化率) ROCDis <- ROC(Close, n = 5, type = "discrete", na.pad = TRUE) ROCDis <- na.omit(ROCDis) names(ROCDis) <- "vanke.ROCDis" head(ROCDis) ###################################### # 股價年走勢及動量線 # ###################################### # 2015年萬科股價走勢K線圖 Vanke2015 <- Vanke["2015"] chartSeries(Vanke2015, theme = myTheme, name = "萬科2015年K線圖") # 在K線圖上,繪製收盤價線(technical analysis) addTA(Cl(Vanke2015), on = 1, col = "black", type = "l") # 在K線圖下面位置,繪製收盤價線 addTA(Cl(Vanke2015), col = "black", type = "l") # 在K線圖下面位置,繪製35日動量線 addTA(momentum(Cl(Vanke2015), n = 35, na.pad = TRUE), col = 4, type = "l") ###################################### # 動量交易策略 # ###################################### # 提取萬科股票收盤價資料 Close <- Vanke$Close names(Close) <- "vanke.Close" # 計算35日動量值 Momen35 <- momentum(Close, n = 35, na.pad = FALSE) names(Momen35) <- "momentum35" head(Momen35, 5) # 35日動量值 < 0 : signal = -1, 表示賣出 # 35日動量值 > 0 : signal = 1, 表示買入 signal <- ifelse(Momen35 < 0, -1, 1) names(signal) <- "signal" head(signal, 3) # 計算萬科股票單期收益率 ret <- ROC(Close, 1) names(ret) <- "vanke.ret" ret <- ret[-(1:35)] head(ret) # 35日動量指標交易收益率計算 Mom35Ret <- ret[-1] * lag(signal, 1, na.pad = FALSE) names(Mom35Ret) <- "Mom35Ret" head(Mom35Ret) # 計算指標交易獲勝率 win <- Mom35Ret[Mom35Ret >= 0] winrate <- length(win) / length(Mom35Ret) winrate # 繪製動量交易策略收益率時序圖 ret <- ret[-1] plot.zoo(merge(ret, Mom35Ret), col = c("black", "red"), main = "動量交易策略收益率時序圖") legend("topright", legend = c("萬科股票", "動量交易"), col = c("black", "red"), lty = 1) # 計算交易策略的累積收益率 library(PerformanceAnalytics) chart.CumReturns(merge(ret, Mom35Ret), col = c("black", "red"), lty = c(1, 6), main = "累計收益率", legend.loc = "topleft") legend("topleft", legend = c("萬科股票", "動量交易"), col = c("black", "red"), lty = c(1, 6)) # 策略正確時,盈利的收益率 win <- Mom35Ret[Mom35Ret >= 0] # 策略失敗時,損失的收益率 loss <- Mom35Ret[Mom35Ret < 0] loss <- (-loss) par(mfrow = c(2, 1)) hist(win) hist(loss, ylim = c(0, 80)) plot(win) plot(loss) # 平均盈利收益率 mean(win) # 平均損失盈利收益率 mean(loss) summary(win) summary(loss) ################################################################################ ## # ## RSI 相對強弱指標 # ## # ################################################################################ ###################################### # 計算 RSI值 # ###################################### library(quantmod) # 讀取交通銀行股票交易資料 BOCMstock <- read.csv("data/BOCM.csv", header = TRUE) # 轉成時間序列類別 BOCMstock <- xts(BOCMstock[, -c(1, 2)], order.by = as.Date(BOCMstock$Date)) head(BOCMstock) tail(BOCMstock) # 取收盤價資料 BOCMclp <- BOCMstock[, 4] names(BOCMclp) <- "BOCMclp" head(BOCMclp, 3) # 使用RSI {TTR} 求rsi值,預設值: maType="EMA", n=14 RSIema <- RSI(BOCMclp) RSIema <- na.omit(RSIema) head(RSIema, 4) tail(RSIema, 4) # 計算RSI, maType="SMA", n=6, 12, 24 RSI6 <- RSI(BOCMclp, n = 6, maType = "SMA") names(RSI6) <- "RSI.6" RSI12 <- RSI(BOCMclp, n = 12, maType = "SMA") names(RSI12) <- "RSI.12" RSI24 <- RSI(BOCMclp, n = 24, maType = "SMA") names(RSI24) <- "RSI.24" RSI.Days <- merge(RSI6, RSI12, RSI24) RSI.Days <- na.omit(RSI.Days) head(RSI.Days) tail(RSI.Days) matplot(RSI.Days, type="l", col=2:4, lty=1, main="RSI: 6, 12, 24 days") legend(70, 15, legend=c("RSI(6)", "RSI(12)", "RSI(24)"), col=2:4, lty=1) ###################################### # RSI的超買線和超賣線 # ###################################### plot(RSI6, type = "l", main = "RSI的超買線和超賣線", ylab = "RSI") RSI6$horizontal.line.20 <- 20 RSI6$horizontal.line.80 <- 80 lines(RSI6[, "horizontal.line.20"], col = "blue") lines(RSI6[, "horizontal.line.80"], col = "blue") ###################################### # RSI的黄金交叉與死亡交叉 # ###################################### par(mfrow=c(2, 1)) plot(RSI6["2015/"], type = "l", main = "RSI的黄金交叉與死亡交叉", ylab = "RSI") lines(RSI24["2015/"], col = "red", lty = 6, lwd = 2) addLegend("bottomright", legend.names = c("RSI6", "RSI24"), col = c("black", "red"), lty = c(1, 6)) plot(BOCMclp["2015/"], type = "l", main = "交通銀行的收盤價", ylab = "收盤價") ###################################### # RSI補捉交通銀行股票買賣點 # ###################################### rsi6 <- RSI(BOCMclp, n = 6, maType = "SMA") rsi6 <- na.omit(rsi6) names(rsi6) <- "rsi6" head(rsi6) rsi24 <- RSI(BOCMclp, n = 24, maType = "SMA") rsi24 <- na.omit(rsi24) names(rsi24) <- "rsi24" head(rsi24) # 交易信號(1): rsi6補捉買賣點 # 買入點 longsig1 <- ifelse(rsi6 < 20, 1, 0) names(longsig1) <- "longsig1" # 第一個買入點信號是在2014年1月20日才出現 head(longsig1[longsig1 == 1], 4) # 賣出點 shortsig1 <- ifelse(rsi6 > 80, -1, 0) names(shortsig1) <- "shortsig1" # 第一個賣出點信號是在2014年2月11日才出現 head(shortsig1[shortsig1 == (-1)], 4) # 交易信號(2): 黄金交叉與死亡交叉 rsi6lag <- lag(rsi6, 1) #滯後一期的rsi6 rsi24lag <- lag(rsi24, 1) #滯後一期的rsi24 head(rsi6lag) head(rsi24lag) # 合併資料 RSIData <- merge(rsi6, rsi6lag, rsi24, rsi24lag) RSIData <- na.omit(RSIData) head(RSIData) # 補捉黄金交叉的買入點 longsig2 <- apply(RSIData, 1, function(x) { ifelse((x[1] > x[3]) & (x[2] < x[4]), 1, 0) }) head(longsig2, 4) longsig2 <- xts(longsig2, order.by = index(RSIData)) names(longsig2) <- "longsig2" # 補捉死亡交叉的賣出點 shortsig2 <- apply(RSIData, 1, function(x) { ifelse((x[1] < x[3]) & (x[2] > x[4]), -1, 0) }) head(shortsig2, 4) shortsig2 <- xts(shortsig2, order.by = index(RSIData)) names(shortsig2) <- "shortsig2" # 合併4種交易訊號 AllSignal <- merge(longsig1, longsig2, shortsig1, shortsig2, all = TRUE) AllSignal <- na.omit(AllSignal) head(AllSignal) tail(AllSignal) # 彙總買賣點信號 ComboSignal <- apply(AllSignal, 1, sum) ComboSignal <- xts(ComboSignal, order.by = index(AllSignal)) head(ComboSignal) # 提取買入信號 longsig <- ifelse(ComboSignal >= 1, 1, 0) index(ComboSignal)[which(longsig == 1)] # 提取賣出信號 shortsig <- ifelse(ComboSignal <= (-1), -1, 0) index(ComboSignal)[which(shortsig == -1)] ###################################### # RSI交易策略執行及回測 # ###################################### # 計算交通銀行的收益率 ret <- ROC(BOCMclp, type = "discrete") head(ret) buy <- lag(longsig, 1) sell <- lag(shortsig, 1) allsig <- longsig + shortsig trade <- lag(allsig, 1) head(trade) # 計算買入交易的收益率 buyRet <- buy * ret # 計算賣出交易的收益率 sellRet <- sell * ret # 計算買入賣出合併交易的收益率 tradeRet <- trade * ret plot.zoo(cbind(buyRet, sellRet, tradeRet), screens = c(1, 1, 2), xlab = NULL, ylab = c("buy/sell", "trade"), lty = c(1, 2, 1), col = c("green", "red", "blue"), main = " RSI指標交易策略") legend("topright", legend = c("buy", "sell"), col = c("green", "red"), lty = c(1, 2)) #addLegend("topright", on=NA, legend.names = c("buy", "sell"), # col = c("green", "red"), lty = c(1, 2)) # 建立strat函式,計算信號預測準確率、平均獲勝收益率、平均損失收益率 strat <- function(signal, ret) { RSIRet <- signal * ret WinRate <- length(RSIRet[RSIRet > 0]) / length(RSIRet[RSIRet != 0]) meanWin <- mean(RSIRet[RSIRet > 0]) meanLoss <- mean(RSIRet[RSIRet < 0]) return(c(WinRate, meanWin, meanLoss)) } Buy <- strat(buy, ret) #買入信號 Sell <- strat(sell, ret) #賣出信號 Trade <- strat(trade, ret) # 整個交易點 Test <- rbind(Buy, Sell, Trade) colnames(Test) <- c("WinRate", "meanWin", "meanLoss") Test # 比較RSI的累計收益率 # 本策略: RSI釋放買賣點訊號,隔一天,即進行買賣操作 library(PerformanceAnalytics) names(ret) <- "stockRet" names(tradeRet) <- "tradeRet" charts.PerformanceSummary(cbind(ret, tradeRet), lty = c(1, 4), main = "RSI指標交易策略績效表現") # 修正策略: RSI釋放買賣點訊號,再隔三天,才進行買賣操作 buy2 <- lag(longsig, 3) sell2 <- lag(shortsig, 3) trade2 <- lag(allsig, 3) Buy2 <- strat(buy2, ret) Sell2 <- strat(sell2, ret) Trade2 <- strat(trade2, ret) Test2 <- rbind(Buy2, Sell2, Trade2) colnames(Test2) <- c("WinRate", "meanWin", "meanLoss") Test2 tradeRet2 <- trade2 * ret names(tradeRet2) <- "ModifiedRSIRet2" charts.PerformanceSummary(cbind(ret, tradeRet2), lty = c(1, 3), main = "RSI指標修正交易策略績效表現")