有时,我们不能直接用原始数据作图,而是需要先计算,再用得到的结果作图。以股票数据为例,尽管K线图和成交量图可直接用原始数据画出,但要想对分析指标作图,却要先把这些指标计算出来。
一、获取数据
在下面的例子中,我们要用quantmod包中的get Symbols函数,从网络上下载股票数据,并绘制图表。无法下载数据的读者,可直接使用课件中名为"AAPL. csv"的文件。
# install.packages(c("quantmod", "TTR"))
library(quantmod) # 用于获取数据
library(TTR) # 用于计算移动平均值等指标
library(cowplot)
library(ggplot2)
library(lubridate) # 使用wday
library(reshape2) # 使用melt
options(scipen=10)
# 下载数据
mydata=get Symbols(Symbols="AAPL", src="yahoo", from="2019-05-06", to=’2019-08-31’, auto.assign=FALSE)
在以上代码中,Symbols参数需指向股票代码。例如,苹果公司的代码为"AAPL",微软公司的代码为"MSFT",深市代码需以".sz"结尾,沪市代码需以".ss"结尾。另外,道琼斯指数为"^DJI",纳斯达克指数为"^IXIC",标准普尔500指数为"^GSPC"。src为数据来源,我们选择"yahoo"(雅虎财经)即可。from和to为数据的日期范围(节假日不会出现在数据中)。auto.assign必须设为FALSE,否则无法生成对象。
# 整理数据
mydata=as.data.frame(mydata)[, -6] # 转化成数据框并去掉不需要的列
mydata=cbind(rownames(mydata), mydata) # 将行标题变为数据中的一列
rownames(mydata)=1: nrow(mydata)
colnames(mydata)=c("Date", "Open", "High", "Low", "Close","Volume")
二、K线图和成交量图
尽管quantmod包提供了chart Series等用于作图的函数,但这些函数生成的图表有时并不能满足我们的要求,所以我们改用ggplot作图。
K线图可分为日K线图、周K线图、月K线图以及以分钟为间隔的K线图等。我们在此只示范日K线图的绘制方法,成交量图常常跟日K线图一起出现,为方便操作,我们使用已保存在硬盘上的文件。
dat=read.csv("AAPL.csv", row.names=1) # 课件中的文件
# 为方便后续操作,提取出数据框中的变量
n=nrow(dat)
DA=dat$Date
OP=dat$Open
HI=dat$High
LO=dat$Low
CL=dat$Close
VO=dat$Volume
# 我们不使用日期为X轴变量,而是使用1至n的整数,以便绘制折线图。但这样一来,我们就需要手动选择X轴标签。我们将只标注周一的日期,如果周一无数据,就标注周二的日期
lab_pos=which(wday(as.Date(DA)) %in% c(2, 3)) # 先用wday选出所有周一、周二的位置。注意:在wday的结果中,1代表周日,2和3代表周一和周二
delete_these=c() # 用for循环删掉紧挨着周一的周二
for (i in 2: length(lab_pos)){
if (lab_pos[i]-lab_pos[i-1]==1) delete_these=append(delete_these, i)
}
if (length(delete_these)>0) lab_pos=lab_pos[-delete_these]
lab=DA[lab_pos]
lab=gsub("\\d\\d\\d\\d\\-", "", lab) # 只保留月和日
lab=gsub("\\-", "\n", lab)
# 其他调整
plot_title=paste(" AAPL [", DA[1], " ~ ", DA[n], "]", sep="")
# 图表标题
rect_fill=rep("limegreen", n) # 生成颜色向量,收盘价高于开盘价用绿色表示(阳线),收盘价低于开盘价用红色表示(阴线)。注意:国内外使用这两种颜色的习惯相反
rect_fill[OP>=CL]="red"
bar_fill=rect_fill # 成交量图使用的颜色
# 日K线图中的细线是每日最高价与最低价之间的连线,用geom_segment绘制。柱体用geom_tile绘制,阳线的上端是收盘价,下端是开盘价,阴线的上端是开盘价,下端是收盘价
kline=ggplot()+
geom_segment(aes(x=1: n, xend=1: n, y=LO, yend=HI), color="grey50")+
geom_tile(aes(x=1: n, y=(OP+CL)/2, width=0.7, height=abs(OPCL)), fill=rect_fill, color="grey50")
# 修改附属元素
kline=kline+labs(title=plot_title)+
scale_x_continuous(breaks=lab_pos, labels=lab)+
scale_y_continuous(limits=range(HI, LO))+
theme(
panel.background=element_blank(),
panel.grid=element_blank(),
panel.grid.major.y=element_line(linetype=2, color="grey75"),
axis.title=element_blank(),
axis.text=element_text(size=13),
plot.title=element_text(size=15)
)
# 成交量
bar=ggplot()+
geom_bar(aes(x=1: n, y=VO), stat="identity", fill=bar_fill, width=0.7)+
scale_y_continuous(
labels=function(x) format(x, big.mark=", "),
expand=expansion(0)
)+
geom_text(aes(x=1, y=0.95*max(VO), label="Volume"), color="grey30", size=5, fontface=2, hjust="left", vjust="top")+
theme(
panel.background=element_blank(),
panel.grid=element_blank(),
panel.grid.major.y=element_line(linetype=2, color="grey75"),
axis.title=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_text(size=13),
axis.line.x=element_line()
)
# 合并K线和成交量
plot_grid(kline, bar, align="v", ncol=1, rel_heights=c(2.5, 1)) # 坐标轴在垂直方向上对齐,K线图的高度是条形图的2.5倍
#==========
# 练习:把K线图和成交量图改造成互动图表
#==========
# 我们之前已经学过了互动图表的绘制方法,现在我们来把上边的图表改造成在鼠标悬停时显示标签,并可放置在网页中的互动图表。事实上,只要使用geom_*_interactive图层就可达到这一目的了(图8-2-1)
图8-2-1 互动K线图和成交量图
library(ggiraph)
# 生成鼠标悬停时显示的标签
tip=apply(dat, 1, FUN=function(x) paste("Date: ", x[1], "<br>","Open: ", x[2], "<br>", "High: ", x[3], "<br>", "Low: ", x[4], "<br>","Close: ", x[5], "<br>", "Volume: ", x[6], sep=""))
# 分别画出K线图和成交量图。注意,为了使这两个图表对应起来,图层中的data_id应该是一样的
kline=ggplot()+
geom_segment_interactive(aes(x=1: n, xend=1: n, y=LO, yend=HI, tooltip=tip, data_id=1: n), color="grey50")+
geom_tile_interactive(aes(x=1: n, y=(OP+CL)/2, width=0.7, height=abs(OP-CL), tooltip=tip, data_id=1: n), fill=rect_fill, color="grey50")
kline=kline+labs(title=plot_title)+
scale_x_continuous(breaks=lab_pos, labels=lab)+
scale_y_continuous(limits=range(HI, LO))+
theme(
panel.background=element_blank(),
panel.grid=element_blank(),
panel.grid.major.y=element_line(linetype=2, color="grey75"), axis.title=element_blank(),
axis.text=element_text(size=13),
plot.title=element_text(size=15)
)
bar=ggplot()+
geom_bar_interactive(aes(x=1: n, y=VO, tooltip=tip, data_id=1: n), stat="identity", fill=bar_fill, width=0.7)+
scale_y_continuous(
labels=function(x) format(x, big.mark=", "),
expand=expansion(0)
)+
geom_text(aes(x=1, y=0.95*max(VO), label="Volume"), color="grey30", size=5, fontface=2, hjust="left", vjust="top")+(www.xing528.com)
theme(
panel.background=element_blank(),
panel.grid=element_blank(),
panel.grid.major.y=element_line(linetype=2, color="grey75"),
axis.title=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_text(size=13),
axis.line.x=element_line()
)
# 生成互动图表
final=plot_grid(kline, bar, align="v", ncol=1, rel_heights=c(2.5, 1))
girafe(ggobj=final, pointsize=33, width_svg=8, height_svg=7, options=list(opts_tooltip(use_fill=TRUE)))
二、移动平均线
接下来,我们手动计算一些技术指标,并把它们添加到图表上。
移动平均线是各时段股价的均值连线。
ma5=run Mean(CL, n=5) # 5日均线的数据点。均值上每个数据点是当天及前4天的股价的均值。我们的数据不包含5月6日之前的数据,所以计算结果中的前4个数据点均为缺失值
ma10=run Mean(CL, n=10) # 10日均线的数据点
kline+
geom_line(na.rm=TRUE, aes(x=1: n, y=ma5), color="brown", size=1.2)+
geom_line(na.rm=TRUE, aes(x=1: n, y=ma10), color="purple", size=1.2)
三、KDJ指标
KDJ指标包含K、D、J三个值(图8-2-2)。由于该指标计算步骤比较复杂,我们在此仅给出计算函数,有兴趣的读者可通过查阅相关书籍了解计算原理。
在以下函数中,close、high、low为每日收盘价、最高价、最低价。n为计算起始日期的位置,默认值为9,即,从数据中的第9个交易日开始计算,而前8日的计算结果均为缺失值。first_k和first_d为起始日前一日的K值和D值。在本例中,我们设n=9,第9个交易日为5月16日。查询资料可知,前一日(5月15日)的K值和D值分别为23.71和28.36。如果无资料供查阅,也可使用这两个参数的默认值50。method参数用于设置J值的计算方法,当method=1(默认)时, J=3*K-2*D,这也是新浪财经(https://finance.sina.com.cn/)及一些股票软件采用的计算方法‘;当method=2时,J=3*D-2*K。新浪财经页面上的KDJ图表允许用户设置K、D、J三个值,其中的K值相等于本函数中的参数n,而D和J一般设为3,在本函数中无法修改。
图8-2-2 KDJ指标
get_kdj=function(close, high, low, n=9, first_k=50, first_d=50, method= 1){
get_rsv=function(CLOSE, HIGH, LOW, N){
a=CLOSE-TTR::run Min(LOW, n=N)
b=TTR::run Max(HIGH, n=N)-TTR::run Min(LOW, n=N)
100*a/b
}
rsv=get_rsv(close, high, low, N=n)
num=length(close)
k=rep(NA, num)
d=rep(NA, num)
k[n-1]=first_k
d[n-1]=first_d
for (i in n: num){
ilast=i-1
k[i]=(2*k[ilast]/3)+rsv[i]/3
d[i]=(2*d[ilast]/3)+k[i]/3
}
j=if (method==1) 3*k-2*d else 3*d-2*k
data.frame(Date=1: num, K=round(k, 2), D=round(d, 2), J=round(j, 2))
}
value_kdj=get_kdj(CL, HI, LO, n=9, first_k=23.71, first_d=28.36, method=1)
# 用melt调整数据并作图
value_kdj=melt(value_kdj, id.vars="Date", measure.vars=c("K", "D","J"))
colnames(value_kdj)=c("Date", "KDJ", "Value")
p_kdj=ggplot(value_kdj)+
geom_line(data=value_kdj, na.rm=TRUE, aes(Date, Value, color=KDJ), size=1)+
scale_color_manual(values=c("K"="gold", "D"="skyblue", "J"="purple"),
guide=guide_legend(override.aes=list(size=1.5))
)+
theme_void()+
theme(
legend.position="top",
legend.title=element_text(size=13),
legend.text=element_text(size=13),
panel.background=element_rect(fill="#EBEBEB", color=NA),
panel.grid.major.y=element_line(color="white"),
axis.text.y=element_text(size=13)
)
plot_grid(kline, p_kdj, align="v", ncol=1, rel_heights=c(2.5, 1))
四、布林通道指标
布林通道指标,用三条曲线和一个阴影区域表示:中间线为移动平均线(多取20日均线),上曲线为中间线加上2倍移动标准差,下曲线为中间线减去2倍移动标准差(图8-2-3)。以此方式求得的数据等于用TTR::BBands求得的结果。
# 用自编函数计算指标值。函数中的close为收盘价,n为计算移动平均值使用的天数
get_boll=function(close, n=20){
mave=TTR::run Mean(close, n=n)
add_sd=2*TTR::run SD(close, n=n, sample=FALSE)
data.frame(Date=1: length(close), MA=mave, UPPER=mave+add_sd, LOWER=mave-add_sd)
}
value_boll=get_boll(CL)
# 作图时,先画出上曲线和下曲线之间的阴影区域,再添加三条线
kline+
geom_ribbon(data=value_boll, na.rm=TRUE, aes(Date, ymin=LOWER, ymax=UPPER), alpha=0.2, fill="skyblue")+ #
geom_line(data=value_boll, na.rm=TRUE, aes(Date, MA), size=1, color="skyblue")+
geom_line(data=value_boll, na.rm=TRUE, aes(Date, UPPER), size=1, color="gold")+
geom_line(data=value_boll, na.rm=TRUE, aes(Date, LOWER), size=1, color="purple")
图8-2-3 布林通道指标
五、MACD指标
MACD指标,用两条曲线和一个条形图来表示(图8-2-4)。
图8-2-4 MACD指标
# 用自编函数计算指标值。函数中的close为收盘价,dif、dea、macd相当于新浪财经上允许用户更改的三个同名参数,分别代表快速移动周期、慢速移动周期和信号周期
get_macd=function(close, dif=12, dea=26, macd=9){
di=TTR::EMA(close, n=dif)-TTR::EMA(close, n=dea)
de=TTR::EMA(di, n=macd)
barline=2*(di-de)
data.frame(Date=1: length(close), DIF=di, DEA=de, MACD= barline)
}
value_macd=get_macd(CL)
barline_color=ifelse(value_macd$MACD>0, "orangered", "palegreen1") #条形图颜色
# 用melt调整数据,以便绘制曲线
two_line=melt(value_macd, id.vars="Date", measure.vars=c("DIF","DEA"))
colnames(two_line)=c("Date", "MACD", "Value")
p_macd=ggplot()+
geom_segment(data=value_macd, na.rm=TRUE, aes(x=Date, xend= Date, y=0, yend=MACD), color=barline_color, size=1)+
geom_line(data=two_line, na.rm=TRUE, aes(Date, Value, color= MACD), size=1)+
scale_color_manual(values=c("DIF"="skyblue", "DEA"="purple"),
guide=guide_legend(override.aes=list(size=1.5))
)+
theme_void()+
theme(
legend.position="top",
legend.title=element_text(size=13),
legend.text=element_text(size=13),
panel.background=element_rect(fill="#EBEBEB", color=NA),
panel.grid.major.y=element_line(color="white"),
axis.text.y=element_text(size=13)
)
plot_grid(kline, p_macd, align="v", ncol=1, rel_heights=c(2.5, 1))
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。