一、牛市追涨杀跌模型
2019年,随着贸易战的和谈,国内政策面的刺激,A股迎来了一波比较客观的小牛市。由此,我们选择建立追涨杀跌模型来进行投资。接下去以所选股票池(结语有介绍)内的稳定型股票——中直股份以及活跃型股票——中国应急为例,至于选择这两只股票的原因除了类型不同外,更重要的是这两只股票都属于国防军共板块,因此建模对比效果更佳具有说服力。选择中线追涨杀跌模型]进行分析。区间选择为2019-01-01至2019-04-20。
二、个股实现及对比
我们分别把稳定型股票——中直股份和活跃型股票——中国应急带入模型,结果发现在牛市中,该模型并不是适用于所有股票,稳定型股票可能会亏钱,而活跃型股票赚钱效益明显超越稳定型股票。
1、稳定型——中直股份(附代码)
当股价大于等于20日最高价时作为买入信号点,当股价小于等于10日最低价时作为卖出信号点。我们利用R语言对股票数据的进行操作,实现追涨杀跌模型的实例,并根据模型模拟交易,通过区间收益探究模型的有效性。从而验证我的们投资理论。
具体R代码如下:
1.1 数据准备
#加载需要的R包
library(plyr)
library(xts)
library(TTR)
library(ggplot2)
library(scales)
# 加载数据
df<-read.table("stock.csv",header=T,sep = ",", na.strings = "NULL") # 读文件
names(df)<-c("code","date","Open","High","Low","Close","Volume") # 设置列名
dl<-split(df[-1],df$code) #按ccode分组
data <- lapply(dl,function(row){xts(row[-1],order.by = as.Date(row$date))}) # 换成xts类型数据
class(data) # data的类型
head(names(data))
length(data)
# 获得时间范围
dateArea<-function(sDate=Sys.Date()-365,eDate= Sys.Date(),before=0){ # 开始日期,结束日期,提单开始时if(class(sDate)=='character') sDate=as.Date(sDate)if(class(eDate)=='character') eDate=as.Date(eDate) return(paste(sDate-before,eDate,sep="/"))
}
# 查看股票600038.SZ
head(data[['600038.SH']])
title<-'600038.SH' #
stock<-data[[title]] # 获得股票数据
sDate<-as.Date("2019-01-02") # 开始日期
eDate<-as.Date("2019-4-19") # 结束日期
cdata<-stock[dateArea(sDate,eDate,365)]$Close # 获得收盘价
vdata<-stock[dateArea(sDate,eDate,365)]$Volume # 获得交易量
names(cdata)<-"Value" # 重置列名
# 交易量
tail(vdata)
1.2 多曲线可视化
#定义画图函数drawLine(),支持画出多条曲线,包括收盘价,最高价,最低价
# 画图函数drawLine<-function(cdata,titie="Stock",sDate=min(index(cdata)),eDate=max(index(cdata)),breaks="1 year"){if(sDate<min(index(cdata))) sDate=min(index(cdata))if(eDate>max(index(cdata))) eDate=max(index(cdata)) cdata<-na.omit(cdata)g<-ggplot(aes(x=Index, y=Value),data=fortify(cdata[,1],melt=TRUE))g<-g+geom_line()if(ncol(cdata)>1){ # 多条线g<-g+geom_line(aes(colour=Series),data=fortify(cdata[,-1],melt=TRUE)) } g<-g+scale_x_date(labels=date_format("%Y-%m"),breaks=date_breaks(breaks),limits = c(sDate,eDate))g<-g+ylim(min(cdata$Value), max(cdata$Value))g<-g+xlab("") + ylab("Price")+ggtitle(title)g}
# 计算最近20日的最高价和10日的最低价minmax<-function(data,max=20,min=10){d1<-na.locf(data,fromLast=TRUE)d2<-merge(d1,min=runMin(d1,min),max=runMax(d1,max))return(d2[,-1])}
# 画出股价,最高价和最低价
ldata<-cbind(cdata,minmax(cdata))
drawLine(ldata,title,sDate,eDate,'3 month') # 画图
# 上图中有3条线,黑色线为每日收盘价,蓝色线为最近20日最高价,红色线为最近10日最低价。
1.3 买入信号及可视化
根据模型的计算公式,我们计算买入信号,当股价向上突破最近20日最高价格时买入。
# 买入信号函数buyPoint<-function(ldata){ idx<-which(ldata$Value == ldata$max)return(ldata[idx,]) }# 计算买入的点
buydata<-buyPoint(ldata)
buydata
# 画出买入的信号图,让我们可以直观的看到效果。
# 定义画图函数
drawPoint<-function(ldata,pdata,titie,sDate,eDate,breaks="1 year"){ldata<-na.omit(ldata)g<-ggplot(aes(x=Index, y=Value),data=fortify(ldata[,1],melt=TRUE))g<-g+geom_line()g<-g+geom_line(aes(colour=Series),data=fortify(ldata[,-1],melt=TRUE))if(is.data.frame(pdata)){g<-g+geom_point(aes(x=Index,y=Value,colour=op),data=pdata,size=4)}else{g<-g+geom_point(aes(x=Index,y=Value,colour=Series),data=na.omit(fortify(pdata,melt=TRUE)),size=4) }g<-g+scale_x_date(labels=date_format("%Y-%m"),breaks=date_breaks(breaks),limits = c(sDate,eDate))g<-g+xlab("") + ylab("Price")+ggtitle(title)g}
drawPoint(ldata,buydata$Value,title,sDate,eDate,'1 month') # 画图
如上图所示,蓝色的点为股价大于等于最近20日最高价的点,作为买入信号。所有买入信号点,都是出现在单边上行的牛势中,对于2019年以来的行情来说,追涨的信号会被大量触发。接下来,我们继续计算卖出信号点,当股价小于等于最近10日最低价时作为卖出信号点。
1.4 卖出信号及可视化
# 计算卖出的信号点
stopPoint<-function(ldata,buydata){ idx<-which(ldata$Value == ldata$min)idx<-idx[which(c(0,diff(idx))!=1)] # 第一点用0表示selldata<-ldata[idx,] # 所有低于最小值的点 idx2<-sapply(index(buydata),function(e){ # 买后的卖点head(which(index(selldata)>e),1)})return(selldata[unique(idx2),])}
# 卖出信号
selldata<-stopPoint(ldata,buydata)
selldata # 买卖信号,画图
bsdata<-merge(buydata$Value,selldata$Value)
names(bsdata)<-c("buy","sell")
drawPoint(ldata,bsdata,title,sDate,eDate,'1 month') #画图
上图中,紫色点为卖出信号点,红色点为买入信号点。我们可以很明显的看出,如果根据交易信号在红色点买入,
紫色点卖出,那么怎么知道到底赚了多少还是亏了多少呢,因此我们需要定义函数计算出来。
1.5 模拟交易
1.5.1 参数定义
# 合并交易信号
signal<-function(buy, sell){selldf<-data.frame(sell,op=as.character(rep("S",nrow(sell))))buydf<-data.frame(buy,op=as.character(rep("B",nrow(buy))))sdata<-rbind(buydf,selldf) # 交易信号数据sdata[order(as.Date(row.names(sdata))),]}
# 合并交易信号
sdata<-signal(buydata,selldata)
sdata
接下来,我们利用交易信号数据,进行模拟交易。我们设定交易参数和规则:
- 以20万元人民币为本金。
- 买入信号出现时,以收盘价买入,每次买入价值1万元的股票。若连续出现买入信号,则一直买入。若现金不足1万元时,则跳过买入信号。
- 卖出信号出现时,以收盘价卖出,一次性平仓信号对应的股票。
- 手续费为0元
# 定义模拟交易函数
trade<-function(sdata,capital=200000,fixMoney=10000){ # 交易信号,总资金,每次定投资金amount<-0cash<-capital ticks<-data.frame()for(i in 1:nrow(sdata)){row<-sdata[i,]if(row$op=='B'){if(cash<fixMoney){print(paste(row.names(row),"No enough cash"))next}amount0<-floor(fixMoney/row$Value) # 本次交易量amount<-amount+amount0cash<-cash-amount0*row$Value}if(row$op=='S'){cash<-cash+amount*row$Valueamount<-0}row$cash<-round(cash,2)row$amount<-amountrow$asset<-round(cash+amount*row$Value,2)ticks<-rbind(ticks,row)}ticks$diff<-c(0,round(diff(ticks$asset),2))rise<-ticks[intersect(which(ticks$diff>0),which(ticks$op=='S')),] # 赚钱的交易fall<-ticks[intersect(which(ticks$diff<0),which(ticks$op=='S')),] # 赔钱的交易return(list(ticks=ticks,rise=rise,fall=fall))}
1.5.2 交易明细
# 交易结果
result<-trade(sdata,200000,10000)
result$ticks #每笔明细交易
从上面的结果我们可以看到,在交易区间内,如果我们根据追涨杀跌模型对中直股份进行操作,我们会亏损729.22元。
这……在牛市里这个模型竟然都不能赚钱???
2、中国应急(代码略)
以同样的交易参数和规则,我们对中国应急进行探究。
2.1 买卖信号可视化
上图中,蓝色点为买入信号指标,并没有出现卖出信号指标,可以很清晰看出如果我们根据买卖指标操作,我们肯定会盈利,不过具体盈利多少还是要通过交易明细来体现。
2.1 交易明细
从上面的结果我们可以看到,在交易区间内,如果我们根据追涨杀跌模型对中国应急进行操作,我们会盈利31474.52元。
模型小结
对比中直股份和中国应急的区间盈利差异,我们可以得出以下结论:
1、在牛市中,我们的追涨杀跌模型并不是对所有股票都有效;
2、在同一个板块中,不同类型的股票对该模型的适应能力有很大差异;
3、在牛市选择股票时,我们应该选择活跃型股票,如上例的中国应急,这样才能获得更高的收益。
结语
该模型用到的股票池等相关信息,后期会用一篇完整的文章介绍。
1、 行业的确定
2、 稳定型股票池A确定
3、 稳定型股票池B确定
4、 整合股票池A、B,得到股票池C
5、 寻找潜在潜在风向标个股
6、 选取行业与上证的关联性
7、 股票池内各股票的内在联系