################################################# # 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指標修正交易策略績效表現") ################################################################################ ## # ## 均線系統策略 # ## # ################################################################################ library(quantmod) ###################################### # 讀取中國銀行的股票資料(收盤價) # ###################################### ChinaBank <- read.csv("data/ChinaBank.csv", header = TRUE) head(ChinaBank) dfclose <- ChinaBank[, c(2, 6)] class(dfclose) head(dfclose) CBstclose <- xts(dfclose[, -1], order.by = as.Date(dfclose$Date)) names(CBstclose) <- "Close" head(CBstclose) tail(CBstclose) summary(CBstclose) ###################################### # 計算2015年資料之三種移動平均 # ###################################### close <- CBstclose["2015"] sma10 <- SMA(close, 10) # 10日SMA names(sma10) <- "Close.SMA.10" tail(sma10) length(sma10) wma10 <- WMA(close, 10) # 10日WMA names(wma10) <- "Close.WMA.10" tail(wma10) ema10 <- WMA(close, 10) # 10日EMA names(ema10) <- "Close.EMA.10" tail(ema10) ###################################### # 繪製2015年資料之三種移動平均線 # ###################################### library(ggplot2) # xts to data.frame # df.data <- data.frame(date=index(xts.data), coredata(xts.data)) CB.close.2015.ma <- merge(close, sma10, wma10, ema10) # CB.close.2015.ma <- na.omit(CB.close.2015.ma) autoplot(CB.close.2015.ma, facet = NULL) + geom_point() + labs(title="ChinaBank 2015, moving averages") ###################################### # 均線時間跨度 (ChinaBank2015) # ###################################### sma5 <- SMA(close, 5) names(sma5) <- "Close.SMA.5" sma30 <- SMA(close, 30) names(sma30) <- "Close.SMA.30" CB.close.2015.sma5.sma30 <- merge(close, sma5, sma30) autoplot(CB.close.2015.sma5.sma30, facet = NULL) + geom_point() + labs(title="ChinaBank 2015, SMA5 vs SMA30") ###################################### # SMA制定買賣點 (ChinaBank) # ###################################### ChinaBank <- read.csv("data/ChinaBank.csv", header = TRUE) head(ChinaBank) dfclose <- ChinaBank[, c(2, 6)] class(dfclose) head(dfclose) CBstclose <- xts(dfclose[, -1], order.by = as.Date(dfclose$Date)) names(CBstclose) <- "Close" head(CBstclose) tail(CBstclose) sma10 <- SMA(CBstclose, 10) names(sma10) <- "Close.SMA.10" # 繪製close, sma10的時序圖 par(mfrow = c(2, 1)) plot(CBstclose) lines(sma10, col = "red") plot(CBstclose["2015"]) lines(sma10["2015"], col = "red") # 補捉價格線從下向上穿10日均線,和從上向下穿10日均線的日期 # 從下向上穿10日均線 => 釋放買入訊號 # 從上向下穿10日均線 => 釋放賣出訊號 # 執行買賣交易的時點,為買賣訊號出現後的第2期 # 然後評估此交易策略好壞 CBsma <- na.omit(merge(sma10, lag(sma10, 1))) head(CBsma) CBclose <- na.omit(merge(CBstclose, lag(CBstclose, 1))) head(CBclose) # 刪除前9期CBclose的資料,保持與CBsma的期數一致 CBclose <- CBclose[-(1:9), ] head(CBclose) # 作差法: 求收盤價與10日移動平均的差值 sigdata <- CBclose - CBsma colnames(sigdata) <- c("close_sma10", "lag_close_sma10") head(sigdata) # 穿越訊號 cross <- function(x) { ifelse(x[1] > 0 & x[2] < 0, 1, ifelse(x[1] < 0 & x[2] > 0, -1, 0)) } # 捕捉價格線突破均線的日期 SmaSignal <- apply(sigdata, 1, cross) SmaSignal <- xts(SmaSignal, order.by = index(sigdata)) head(SmaSignal) # 制定買賣交易日期: 交易信號滯後2期 SmaTrade <- lag(SmaSignal, 2) SmaTrade <- na.omit(SmaTrade) head(SmaTrade) # 取出買入點 SmaBuy <- SmaTrade[SmaTrade == 1] length(SmaBuy) head(SmaBuy) # 取出賣出點 SmaSell <- SmaTrade[SmaTrade == (-1)] length(SmaSell) head(SmaSell) # 計算日收益率 CBret <- ROC(CBstclose, type = "discrete") names(CBret) <- "CBret" head(CBret) smaRet <- CBret * SmaTrade names(smaRet) <- "smaRet" head(smaRet) # 繪製績效表現圖 library(PerformanceAnalytics) charts.PerformanceSummary(merge(CBret["2014-01-20/"], smaRet), lty = c(1, 6), main = "簡單均線交易績效表現") # 計算買賣點預測準確率 win <- smaRet[smaRet > 0] smawin <- length(win) / length(smaRet[smaRet != 0]) smawin ###################################### # 雙均線制定買賣點 (ChinaBank) # ###################################### sma5 <- SMA(CBstclose, 5) length(sma5) sma30 <- SMA(CBstclose, 30) head(na.omit(sma30)) # 繪製長短期均線圖 plot(sma5, type = "l", main = "長短期均線策略(ChinaBank)") lines(sma30, lty = 6, lwd = 3, col = "green") addLegend("bottomright", legend.names = c("sma5", "sma30"), col = c("black", "green"), lty = c(1, 6)) # 取lag # example: # x <- 1:10 # embed (x, 3) head(sma5) SMA5 <- embed(sma5, 2) head(SMA5) SMA30 <- embed(sma30, 2) # 合併長短期sma smaLS <- cbind(SMA5, SMA30) smaLS <- xts(smaLS, order.by = index(sma5[-1])) smaLS <- na.omit(smaLS) colnames(smaLS) <- c("sma5", "lagsma5", "sma30", "lagsma30") head(smaLS) # 判斷向上突破點 Upcross <- function(x) { ifelse(x[2] < x[4] & x[1] > x[3], 1, 0) } # 判斷向下突破點 Downcross <- function(x) { ifelse(x[2] > x[4] & x[1] < x[3], -1, 0) } # 捕捉短線向上突破長線日期 Upsig <- apply(smaLS, 1, Upcross) Upsig <- xts(Upsig, order.by = index(smaLS)) names(Upsig) <- "Upsig" head(Upsig) # 短線向上突破長線,釋放買入信號 UpBuy <- lag(Upsig) head(UpBuy) UpBuy[UpBuy == 1] # 捕捉短線向下突破長線日期 Downsig <- apply(smaLS, 1, Downcross) Downsig <- xts(Downsig, order.by = index(smaLS)) names(Downsig) <- "Downsig" # 短線向下突破長線,釋放賣出信號 DownSell <- lag(Downsig) DownSell[DownSell == -1] # 計算日收益率 CBret <- ROC(CBstclose, type = "discrete") head(CBret) # 計算買入點的預測正確率 Long <- UpBuy * CBret names(Long) <- "Long" winL <- Long[Long > 0] winLrate <- length(winL) / length(Long[Long != 0]) winLrate # 計算賣出點的預測正確率 Short <- DownSell * CBret names(Short) <- "Short" winS <- Short[Short > 0] winSrate <- length(winS) / length(Short[Short != 0]) winSrate # 計算所有買賣點的預測正確率 UpDnTrade <- UpBuy + DownSell UpDnTradeRet <- UpDnTrade * CBret names(UpDnTradeRet) <- "UpDnTradeRet" a <- length(UpDnTradeRet[UpDnTradeRet > 0]) b <- length(UpDnTradeRet[UpDnTradeRet != 0]) winrate <- a/b winrate # 長短期均線交易績效表現圖 charts.PerformanceSummary(merge(UpDnTradeRet, Long, Short), lty = c(1, 2, 6), main = "長短期均線交易績效表現") ###################################### # 異同移動平均線 (MACD) # # MACD捕捉買賣點 # ###################################### # 計算中國銀行股票的MACD CB.macd <- MACD(CBstclose, nFast = 12, nSlow = 26, nSig = 9, maType = "EMA", percent = FALSE) CB.macd <- na.omit(CB.macd) head(CB.macd) # MACD捕捉買賣點 ChinaBank <- xts(ChinaBank[, -c(1, 2)], order.by = as.Date(ChinaBank$Date)) head(ChinaBank) CB15 <- ChinaBank["2015/"] head(CB15) # K線圖 chartSeries(CB15, theme = 'white', name = '中國銀行2015年K線圖', up.col = 'red', dn.col = 'green') addMACD() # CB.macd.lag <- lag(CB.macd, 1) macd <- na.omit(merge(CB.macd, CB.macd.lag)) head(macd) # MACD 交易策略函數 macdcross <- function(x) { ifelse(x[1] > x[2] & x[3] < x[4] & all(x > 0), 1, ifelse(x[1] < x[2] & x[3] > x[4] & all(x < 0),-1, 0)) } # 求MACD指標買賣點信號 macdSignal <- apply(macd, 1, macdcross) macdSignal <- xts(as.numeric(macdSignal), order.by = index(macd)) head(macdSignal) # 設定買賣交易日期 macdTrade <- lag(macdSignal, 1) head(macdTrade) macdTrade <- macdTrade[-1] # 計算收益率 CBret <- ROC(CBstclose, type = "discrete") head(CBret) # 計算MACD指標的預測正確率 macdRet <- CBret * macdTrade win <- macdRet[macdRet > 0] macdwin <- length(win) / length(macdRet[macdRet != 0]) macdwin ###################################### # (參考) # # 多種均線指標綜合運用 # # # ###################################### # 合併交易訊號 ComboTrade <- merge(SmaTrade, UpDnTrade, macdTrade) ComboTrade[is.na(ComboTrade)] <- 0 head(ComboTrade) # 將三個交易訊號相加,得到綜合交易訊號 finTrade <- apply(ComboTrade, 1, sum) finTrade <- xts(finTrade, order.by = index(ComboTrade)) head(finTrade) # 至少兩個指標都釋出買入信號,才買入 buy <- finTrade[finTrade >= 2] buy # 至少兩個指標都釋出賣出信號,才賣出 sell <- finTrade[finTrade <= (-2)] sell # 模擬交易 head(CBstclose, 3) n <- length(CBstclose) n # 初始資金10000元 asset <- xts(rep(0, n), order.by = index(CBstclose)) asset[1] <- 10000 # 2014/01/02,買入1000股 share <- xts(rep(0, n), order.by = index(CBstclose)) share[1] <- 1000 # 2014/01/02,購買股票後的現金餘額 cash <- xts(rep(0, n), order.by = index(CBstclose)) cash[1] <- asset[1] - share[1] * CBstclose[1] CBstclose[1] cash[1] # 第一個交易信號是2014/05/14,買入 date1 <- index(CBstclose["/2014-05-14"]) tail(date1) class(date1) # 紀錄2014/01/02~5/14的交易賬戶情況 for (j in 1:(length(date1) - 1)) { i <- date1[j] share[i] <- 1000 cash[i] <- cash[1] asset[i] <- cash[i] + share[i] * CBstclose[i] } head(asset) # 2014/05/14再買1000股,更新持股數 share["2014-05-14"] <- 1000 + 1000 # 更新現金 cash["2014-05-14"] <- as.numeric(cash["2014-05-13"]) - 1000 * CBstclose["2014-05-14"] cash["2014-05-14"] # 更新資產 asset["2014-05-14"] <- cash["2014-05-14"] + share["2014-05-14"] * CBstclose["2014-05-14"] # 第2個交易信號,2014/09/24,賣出 Date2 <- index(CBstclose["2014-05-15/2014-09-23"]) tail(Date2, 3) for (j in 1:length(Date2)) { i <- Date2[j] share[i] <- share["2014-05-14"] cash[i] <- cash["2014-05-14"] asset[i] <- cash[i] + share[i] * CBstclose[i] } cash["2014-09-23"] # 2014/09/24,賣出1000股 share["2014-09-24"] <- share["2014-09-23"] - 1000 cash["2014-09-24"] <- as.numeric(cash["2014-09-23"]) + 1000 * CBstclose["2014-09-24"] asset["2014-09-24"] <- cash["2014-09-24"] + share["2014-09-24"] * CBstclose["2014-09-24"] cash["2014-09-24"] # 第3個交易信號,2014/11/28,買入 Date3 <- index(CBstclose["2014-09-25/2014-11-27"]) for (j in 1:length(Date3)) { i <- Date3[j] share[i] <- share["2014-09-24"] cash[i] <- cash["2014-09-24"] asset[i] <- cash[i] + share[i] * CBstclose[i] } # 2014/11/28,買入1000股 share["2014-11-28"] <- share["2014-11-27"] + 1000 cash["2014-11-28"] <- as.numeric(cash["2014-11-27"]) - 1000 * CBstclose["2014-11-28"] asset["2014-11-28"] <- cash["2014-11-28"] + share["2014-11-28"] * CBstclose["2014-11-28"] # 更新帳戶到2014/12/05 Date4 <- index(CBstclose["2014-11-29/2014-12-05"]) for (j in 1:length(Date4)) { i <- Date4[j] share[i] <- share["2014-11-28"] cash[i] <- cash["2014-11-28"] asset[i] <- cash[i] + share[i] * CBstclose[i] } account <- merge(asset, cash, share) account <- account["/2014-12-05"] tail(account) plot.zoo(account, col = c("red", "blue", "yellow"), main = "2014年中國銀行交易賬戶") # 假設2014/12/05賣掉所有股票,計算投資報酬率 buy <- 1000 * as.numeric(CBstclose[1]) + 1000 * as.numeric(CBstclose["2014-05-14"]) + 1000 * as.numeric(CBstclose["2014-11-28"]) sell <- 1000 * as.numeric(CBstclose["2014-09-24"]) + 2000 * as.numeric(CBstclose["2014-12-05"]) # 投資報酬率(不考慮交易成本) return <- (sell - buy) / buy return