# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx =====================
# ==================== Tinysoft related utility functions ====================
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx =====================
#' tsInclude
#'
#' Series of functions of connect/login Tinysoft server, and remote call funcions of Tinysoft.
#' @param funchar a charactor string of tinysoft script
#' @param pars a list of funchar's parametres
#' @param syspars a list of tinysoft system parametres.(including:StockID CurrentDate Cycle bRate RateDay Precision)
#' @return tsInclude: include and load the external dll;
#' @return tsRequre: test if tinysoft connected, if not, connect it.
#' @author ruifei.yin
#' @export
#' @examples
#' tsInclude()
#' tsConnect()
#' tsLogined()
#' tsRemoteExecute("return close();",list(StockID="SZ000002",CurrentDate=rdate2ts(as.Date("2014-11-11"))))
#' # use ldply/laply/llply to transform the result from list to comfortable form
#' ll <- tsRemoteExecute("return Array(('a':1,'b':4),('a':2,'b':5),('a':3,'b':6));")
#' plyr::ldply(ll,as.data.frame)
#' plyr::laply(ll,as.array)
#' plyr::llply(ll,unlist)
#' tsRemoteCallFunc("close",,list(StockID="SZ000002"))
#' tsRemoteCallFunc("rand",list(2,3))
#' tsDisconnect()
tsInclude <- function(os = R.Version()$arch){
source(paste(.libPaths()[1],"/QDataGet/tslr/tslr.R",sep = ""))
tsLoad(os)
}
#' @rdname tsInclude
#' @export
tsLoad <- function(os = R.Version()$arch){
libpath <- .libPaths()[1]
if(os == "i386"){
dyn.load(paste(libpath,"/QDataGet/tslr/i386/tslr.dll",sep = ""))
}else if(os == "x86_64"){
dyn.load(paste(libpath,"/QDataGet/tslr/x64/tslr.dll",sep = ""))
}
}
#' @export
#' @rdname tsInclude
tsRequire <- function(){
if(!exists("tsLogined")){
tsInclude()
}
if(!is.loaded("tslConnectServer")){
tsLoad()
}
if(tsLogined()==0){
tsConnect()
}
}
#' rdate2ts
#'
#' transform the R date to tinysoft date value
#' @param rdate a vector with \bold{Date} class
#' @param GAP.R2TS the constant of R to tinysoft date-transformating
#' @return a vector containing the tinysoft date value transformed from the R date
#' @seealso \code{\link{tsdate2r}}
#' @author Ruifei.Yin
#' @export
rdate2ts <- function(rdate, GAP.R2TS=25569){
tsdate <- rdate + GAP.R2TS
tsdate <- as.numeric(tsdate)
return(tsdate)
}
#' tsdate2r
#'
#' transform the tinysoft date value to R date
#' @param tsdate a vector containing the tinysoft date value
#' @param GAP.R2TS the constant of R to tinysoft date-transformating
#' @return a vector with \bold{Date} class, transformed from the tinysoft date value
#' @seealso \code{\link{rdate2ts}}
#' @author Ruifei.Yin
#' @export
tsdate2r <- function(tsdate, GAP.R2TS=25569){
rdate <- tsdate - GAP.R2TS
rdate <- as.Date(rdate,origin="1970-01-01")
return(rdate)
}
#' ts.wss
#'
#' realize the "stock-data-expert" functions in Tinysoft.Given the stocklist, get specific variables of the stocks from Tinysoft.
#' @param stocks a vector of stockID.
#' @param funchar expression to get variables from tinysoft,a character string, usually copyed from tinysoft "stock-data-expert". If you want to specify the rptDate by param \code{rptDate}, the expression should be converted simply by replaceing the specified reportdate in the stock-data-expert expression by \code{'Rdate'}. e.g. convert \code{Last12MData(20091231,46002)} to \code{Last12MData(Rdate,46002)}.
#' @param varname vector of charactor string
#' @param rptDate a specified rptDate, with class of Date. Could be missing when unnessasry. See examples for more detail.
#' @param Time a Date object, giving the pn_date() in tinysoft
#' @param Rate a integer,giving the type of rights adjustment, could be one of 0(no adjustment),1(geometric adjustment),2(simple adjustment),3
#' @param RateDay a integer,giving the base date of right adjustment,could be one of 0(the last trading day),-1(the IPO date),or a tinysoft date integer(eg. \code{rdate2ts(as.Date("2010-01-02"))})
#' @param adjust_yoy a logic. If TRUE, param \code{Time} will be set to \code{rptDate.deadline(rptDate)}, the financial index before(not including) \code{rptDate} will be adjusted, the financial index after \code{rptDate} will not be adjusted.
#' @return a dataframe,with cols:stockID,stockName,and the returned variables.
#' @note you can get different financial index by set param Time and param adjust_yoy.
#' If you set param \code{Time} to 1900-01-01, all the financial index returned will not be adjusted; If you set param \code{Time} to \code{Sys.Date()}, all the financial index returned will be adjusted; See example for detail.
#' @export
#' @family stockDataExpert functions
#' @examples
#' stocks <- c("EQ600011","EQ000631","EQ000004")
#' funchar1 <- '"eps",reportofall(9900000,20121231),
#' "zyywlrzzl",reportofall(9900601,20121231),
#' "yszk",report(44009,20121231),
#' "isFinanceCompany",IsFCompany_(),
#' "close",close(),
#' "rtn(%)(19890705,20120705)",StockZf(32694,41095),
#' "Ndayrtn(%)(N=10)",StockZf2(10),
#' "floatMV(20110926)",StockMarketValue(40812)'
#' re1 <- ts.wss(stocks,funchar1)
#'
#' # -- specify the rptDate
#' funchar2 <- '"eps",reportofall(9900000,Rdate),
#' "zyywlrzzl",reportofall(9900601,Rdate),
#' "yszk",report(44009,Rdate),
#' "isFinanceCompany",IsFCompany_(),
#' "close",close(),
#' "rtn(%)(19890705,20120705)",StockZf(32694,41095),
#' "Ndayrtn(%)(N=10)",StockZf2(10),
#' "floatMV(20110926)",StockMarketValue(40812)'
#' re2 <- ts.wss(stocks,funchar2,rptDate=as.Date('2012-12-31'))
#'
#' all.equal(re1,re2) # TRUE
#'
#' # -- getting financial index (adjust or not)
#' ts.wss("EQ000027",'"G_NP_Q",LastQuarterData(Rdate,9900604,0)',as.Date("2007-03-31"),Time=as.Date("1900-06-29")) # 31.8 (07_adj/06_adj-1)
#' ts.wss("EQ000027",'"G_NP_Q",LastQuarterData(Rdate,9900604,0)',as.Date("2007-03-31"),Time=Sys.Date()) # 229.16 (07_unadj/06_unadj-1)
#' ts.wss("EQ000027",'"G_NP_Q",LastQuarterData(Rdate,9900604,0)',as.Date("2007-03-31"),adjust_yoy=TRUE) # 49 (07_unadj/06_adj-1) This is the correct one!
ts.wss <- function(stocks,funchar,varname,rptDate,Time=Sys.Date(),Rate=1,RateDay=0,
adjust_yoy=FALSE){
stocks <- stockID2stockID(stocks,from="local",to="ts")
if(missing(rptDate)) {
rptDate <- 0
} else {
if(adjust_yoy){
Time <- rptDate.deadline(rptDate)
}
rptDate <- rdate2int(rptDate)
}
Time=rdate2ts(Time)
syspars <- list(CurrentDate=Time,bRate=Rate,RateDay=RateDay)
stocks.str <- paste(stocks,collapse=";")
str <- paste('Rdate:=',rptDate,';\n',
'return Query("","',
stocks.str,
'",True,"","stockID",DefaultStockID(),',
funchar,
');',
sep="")
tsRequire()
re <- tsRemoteExecute(str,syspars)
re <- plyr::ldply(re,as.data.frame)
re$stockID <- stockID2stockID(re$stockID,from="ts",to="local")
if(!missing(varname)){
re <- renameCol(re,colnames(re)[-1],varname)
}
return(re)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# ================== tradingday related =============
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' memory.load
#'
#' load frequently used data into memory, including \code{.tradingdays}, \code{.QT_sus_res}, ...
#' @param reload a logic. If reload the memory data?
#' @param datasrc
#' @return return NULL, but load some data into memory.
#' @export
#' @author Ruifei.Yin
memory.load <- function(reload=FALSE){
if(!exists(".tradingdays") || reload){
if(reload){
cat("[memory data reloading]\n")
} else {
cat("[memory data loading]\n")
}
# -- the market trading days
cat(" Loading '.tradingdays' ... \n")
qr1 <- "select TradingDate from QT_TradingDay where SecuMarket=83 and IfTradingDay=1"
tradingdays <- queryAndClose.dbi(db.local("main"),qr1)[[1]]
.tradingdays <<- intdate2r(tradingdays)
con_qt <- db.local("qt")
con_main <- db.local("main")
# - QT_sus_res
cat(" Loading '.QT_sus_res' ... \n")
QT_sus_res <- dbReadTable(con_qt,"QT_sus_res")
QT_sus_res <- data.table::data.table(QT_sus_res,key = "stockID")
.QT_sus_res <<- QT_sus_res[is.na(res),res:=99990101
][,`:=`(sus=intdate2r(sus),res=intdate2r(res))
][,-("updateDate"),with=FALSE
]
# -- the market size data frame
cat(" Loading '.marketsize' ... \n")
.marketsize <<- dbReadTable(con_qt, "QT_Size")
.marketsize$date <<- intdate2r(.marketsize$date)
# - LC_ExgIndustry
cat(" Loading '.LC_ExgIndustry' ... \n")
LC_ExgIndustry <- dbReadTable(con_main,"LC_ExgIndustry")
LC_ExgIndustry <- data.table::data.table(LC_ExgIndustry,key = "stockID")
.LC_ExgIndustry <<- LC_ExgIndustry[is.na(OutDate),OutDate:=99990101
][,`:=`(InDate=intdate2r(InDate),OutDate=intdate2r(OutDate))]
dbDisconnect(con_qt)
dbDisconnect(con_main)
}
}
#' TS.sus_res
#'
#' get the suspension and resumption data
#' @param TS
#' @param datasrc
#' @return a data.frame with cols: "sus" and "res"
#' @export
#' @author Ruifei.yin
#' @examples
#' TS <- getTS(getRebDates(as.Date("2007-01-01"),as.Date("2016-01-01"),rebFreq = "week"),indexID = "EI000300")
#' microbenchmark::microbenchmark(re <- TS.sus_res(TS,datasrc="memory"),re1 <- TS.sus_res(TS,datasrc = "local"),times = 10) # 100 VS. 3000
TS.sus_res <- function(TS,datasrc="memory"){
TS_ <- TS[,c("date","stockID")]
if(datasrc == "memory"){
memory.load()
TS_ <- data.table::data.table(TS_)
re <- .QT_sus_res[TS_,.(date,stockID,x.sus,x.res),on=.(stockID,sus<=date,res>date)]
re <- renameCol(re,c("x.sus","x.res"),c("sus","res"))
re <- as.data.frame(re)
} else if(datasrc == "local"){
TS_$date <- rdate2int(TS_$date)
con <- db.local("qt")
qr <- paste(
"select date,a.stockID,sus,res
from yrf_tmp as a left join QT_sus_res as b
on a.stockID=b.stockID and sus<=date and (res>date or res is null)" )
dbWriteTable(con,name="yrf_tmp",value=TS_[,c("date","stockID")],row.names = FALSE,overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
re <- dplyr::mutate(re,date=intdate2r(date),sus=intdate2r(sus),res=intdate2r(res))
}
re <- merge.x(TS,re,by=c("date","stockID"),mult = "first")
return(re)
}
#' trday.get
#'
#' get the trading date series from begT to endT
#' @param begT a Date object.The default is as.Date("1990-12-19")
#' @param endT a Date object.The default is Sys.Date()
#' @param stockID a character string or null. If null, the market trading days, other wise the trading days of specific stock.
#' @param datasrc
#' @return a vector of class Date
#' @export
#' @author Ruifei.yin
#' @examples
#' re <- trday.get()
#' re <- trday.get(as.Date("2012-01-01"),as.Date("2012-09-30"))
#' re <- trday.get(as.Date("2012-07-01"),as.Date("2013-03-30"),stockID="EQ000527")
#' system.time(replicate(100,ii <- trday.get(datasrc="local"))) # 14.09
#' system.time(replicate(100,ii <- trday.get(datasrc="memory"))) # 0.39
#' system.time(replicate(100,ii <- trday.get(datasrc="local",stockID="EQ000527"))) # 16.38
#' system.time(replicate(100,ii <- trday.get(datasrc="memory",stockID="EQ000527"))) # 1.25
trday.get <- function(begT=as.Date("1990-12-19"),endT=Sys.Date(),
stockID=NULL,
datasrc="memory"){
# get the market trading days
if(datasrc %in% c("quant","local")){
begT <- max(begT,as.Date("1990-12-19"))
begT <- rdate2int(begT)
endT <- rdate2int(endT)
qr <- paste("select TradingDate from QT_TradingDay where SecuMarket=83 and IfTradingDay=1 and TradingDate between ",begT,"and",endT)
if(datasrc=="quant"){
trday <- queryAndClose.odbc(db.quant(),qr)
} else if(datasrc=="local"){
trday <- queryAndClose.dbi(db.local("main"),qr)
}
re <- trday[[1]]
re <- intdate2r(re)
} else if (datasrc=="memory") {
memory.load()
begT <- max(begT,as.Date("1990-12-19"))
re <- get(".tradingdays")
re <- re[re >= begT & re <= endT]
}
# get the stock's trading days
if(!is.null(stockID)){
TS <- expand.grid(date=re, stockID=stockID)
sus_res <- TS.sus_res(TS,datasrc = datasrc)
isTradingday <- is.na(sus_res$sus)
re <- re[isTradingday]
}
re <- re[order(re)]
return(re)
}
#' trday.is
#'
#' Identify if the date is trading day or not
#' @param datelist a vector of class Date
#' @param stockID a character string or NULL If NULL, the market trading days, other wise the trading days of specific stock.
#' @param TS
#' @param drop
#' @return a logical vecter with elements TRUE or FALSE depending on whether its argument is an tradingday
#' @export
#' @author Ruifei.Yin
#' @examples
#' datelist <- seq(from=as.Date("2013-01-21"),to=as.Date("2013-01-30"),by="day")
#' trday.is(datelist)
#' trday.is(datelist,stockID="EQ000527")
#' trday.is(TS=TS)
trday.is <- function(datelist,stockID=NULL,TS,
drop){
if(is.null(stockID) & missing(TS)){ # the market tradingday
mindt <- min(datelist)
maxdt <- max(datelist)
tradingday <- trday.get(begT=mindt,endT=maxdt,stockID=NULL)
re <- datelist %in% tradingday
return(re)
}
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
sus_res <- TS.sus_res(TS)
isTradingday <- trday.is(sus_res$date,stockID=NULL) & is.na(sus_res$sus)
if(drop){
re <- isTradingday
}else {
re <- cbind(TS,isTradingday)
}
return(re)
}
#' trday.nearest
#'
#' get the nearest tradingday.
#' @param datelist a vector of class Date
#' @param dir a integer. Indicating forward or backward to find, if \code{datelist} is not tradingday. -1 for backward, 1 for forward.
#' @param stockID a character string or null. If null, the market trading days, other wise the trading days of specific stock.
#' @return a vector of class Date, the value of which is the nearest tradingday before/after the \code{datelist} if \code{datelist} is not a tradingday, otherwise,the \code{datelist} itself.
#' @author Ruifei.Yin
#' @export
#' @examples
#' datelist <- as.Date(c("2012-07-21","2012-07-22","2012-07-23","2013-01-30"))
#' trday.nearest(datelist)
#' trday.nearest(datelist, dir = 1)
#' trday.nearest(datelist, dir = 1, stockID="EQ000527")
trday.nearest <- function(datelist, dir=-1L, stockID=NULL, TS,
drop){
if(is.null(stockID) & missing(TS)){ # the market tradingday
tradingdays <- trday.get(endT=Sys.Date()+365, stockID=NULL)
if(dir == -1L){
re <- tradingdays[findInterval(datelist, tradingdays)]
} else if(dir == 1L){
re <- tradingdays[findInterval.rightClosed(datelist, tradingdays)+1]
} else {
stop("unsupported \"dir\" argument!")
}
re <- as.Date(re,origin="1970-01-01")
return(re)
}
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
sus_res <- TS.sus_res(TS)
if(dir == -1L){
re <- dplyr::mutate(sus_res,nearest=ifelse(is.na(sus),
trday.nearest(date,dir = -1L),
trday.nearby(sus,by=-1,stockID=NULL)))
} else if(dir == 1L){
re <- dplyr::mutate(sus_res,nearest=ifelse(is.na(sus),
trday.nearest(date,dir = 1L),
res))
} else {
stop("unsupported \"dir\" argument!")
}
re$nearest <- as.Date(re$nearest,origin="1970-01-01")
if(drop){
re <- re$nearest
}else {
re <- dplyr::select(re,-sus,-res)
}
return(re)
}
#' trday.nearby
#'
#' get the nearby tradingday by shifting forward or backward.If the argument datelist is not a tradingday,the tradingday nearest by it will be firstly find by function \code{\link{trday.nearest}}.
#' @param datelist a vector of class Date
#' @param by a integer giving the lagging days.If negetive,get the earlyer tradingday,if positive,get the later tradingday.
#' @param stockID a character string or null. If null, the market trading days, other wise the trading days of specific stock.
#' @param dir 1L or -1L. see \code{\link{trday.nearest}}
#' @return a vector of trading days of class Date
#' @export
#' @author Ruifei.Yin
#' @examples
#' (datelist <- as.Date(c("2012-07-21","2012-07-22","2012-07-23","2013-01-30")))
#' trday.nearby(datelist,-20) # the tradingday 20 days earlyer than datelist
#' trday.nearby(datelist,20) # the tradingday 20 days later than datelist
#' trday.nearby(datelist,20,stockID="EQ000527")
trday.nearby <- function(datelist,by, stockID=NULL,
dir=if(by>0) 1L else -1L,
TS,
drop){
if(is.null(stockID) & missing(TS)){ # the market tradingday
trdingday.all <- trday.get(endT=Sys.Date()+365, stockID=NULL)
trdlist <- trdingday.all[findInterval(datelist, trdingday.all)] # get the nearest tradingday
lag.trdingday.all <- xts::lag.xts(trdingday.all, -by)
idx <- match(trdlist, trdingday.all)
re <- lag.trdingday.all[idx]
return(re)
}
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
# get the market's nearby tradingday
nearby_market <- trday.nearby(TS$date,by=by,stockID=NULL)
# get the stock's nearest tradingday
nearby <- trday.nearest(TS=data.frame(date=nearby_market,stockID=TS$stockID),dir = dir,drop = TRUE)
if(drop){
re <- nearby
} else {
re <- cbind(TS,nearby)
}
return(re)
}
#' trday.offset
#'
#' offset the datelist by months,quarters,ect. then get the nearest tradingday
#' @param datelist a vector of class Date
#' @param by a period object. See detail in package \code{lubridate}.
#' @param dir 1L or -1L. if the result date is not trdingday, get the forward nearest tradingday or the backward tradingday? See detail in \link{trday.nearest}
#' @param stockID a character string or null. If null, the market trading days, other wise the trading days of specific stock.
#' @return a vector of trading days of class Date
#' @export
#' @author Ruifei.Yin
#' @examples
#' (datelist <- as.Date(c("2012-07-21","2012-07-22","2012-07-23","2013-01-30")))
#' trday.offset(datelist,months(1)) # the tradingdays 1 month after the datelist
#' trday.offset(datelist,months(-1)) # the tradingdays 1 month before the datelist
#' trday.offset(datelist,years(1))
#' trday.offset(datelist,months(-1),stockID="EQ000527")
trday.offset <- function(datelist,by=months(1),stockID=NULL,
dir=if(as.numeric(by)>0) 1L else -1L,
TS,
drop){
if(is.null(stockID) & missing(TS)){ # the market tradingday
if (any(c(by@.Data, by@minute, by@hour, by@day) != 0)){
re <- datelist + by
} else { # if handles month and years, should use %m+%
re <- datelist %m+% by
}
re <- trday.nearest(re, dir=dir, stockID=NULL)
return(re)
}
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
# get the market's offset tradingday
offset_market <- trday.offset(TS$date,by=by,dir=dir,stockID=NULL)
# get the stock's offset tradingday
offset <- trday.nearest(TS=data.frame(date=offset_market,stockID=TS$stockID),dir = dir,drop = TRUE)
if(drop){
re <- offset
} else {
re <- cbind(TS,offset)
}
return(re)
}
#' trday.count
#'
#' get the count of the trading days between \code{begT} and \code{endT}.
#' @param begT a Date object.The default is as.Date("1990-12-19")
#' @param endT a Date object.The default is Sys.Date()
#' @param stockID a character string or null. If null, the market trading days, other wise the trading days of specific stock.
#' @return a integer
#' @export
#' @author Ruifei.Yin
#' @examples
#' trday.count(as.Date("2012-01-01"),as.Date("2012-09-30"))
#' trday.count(as.Date("2012-01-01"),as.Date("2012-09-30"),stockID="EQ000527")
trday.count <- function(begT=as.Date("1990-12-19"), endT=Sys.Date(), stockID=NULL){
trdate <- trday.get(begT,endT,stockID=stockID)
re <- length(trdate)
return(re)
}
#' trday.IPO
#' @param stockID a vector
#' @return a vector
#' @export
#' @family SecuMain functions
trday.IPO <- function(stockID,datasrc=defaultDataSRC()){
qr <- paste("select ListedDate,ID from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
re <- tmpdat[match(stockID,tmpdat[,2]),1]
re <- intdate2r(re)
return(re)
}
#' trday.unlist
#' @param stockID a vector
#' @return a vector
#' @export
#' @family SecuMain functions
trday.unlist <- function(stockID,datasrc="jy"){
if(datasrc=="jy"){
stocks <- substr(unique(stockID),3,8)
#get delist date
qr <- paste("SELECT 'EQ'+s.SecuCode 'stockID',convert(varchar,ChangeDate,112) 'delistdate'
FROM LC_ListStatus l
INNER join SecuMain s on l.InnerCode=s.InnerCode and s.SecuCategory=1
where l.ChangeType=4 and l.SecuMarket in (83,90)
and s.SecuCode in",brkQT(stocks))
tmpdat <- queryAndClose.odbc(db.jy(),qr,as.is = TRUE)
re <- tmpdat[match(stockID,tmpdat[,1]),2]
re <- intdate2r(re)
}
return(re)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# ==================== SecuMain related ==============
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' tradeCode2stockID
#'
#' Covert the tradeCode to stockID given specific secucategory.
#' @param tradeCode Vector of character,giving the stock trading code. eg. \code{c("600001","600002","000300")}
#' @param secuCate integer,giving the secuCategory.(1 for A equity,4 for index,...)
#' @param IDsrc a charactor string, could be one of "local","jy","ts","wind",etc.
#' @return a vector,return the stockID of specific datascr.
#' @export
#' @family SecuMain functions
#' @author Ruifei.Yin
#' @examples
#' tradeCode2stockID(c("600001","600002"),secuCate=1)
#' tradeCode2stockID(c("000001","000300"),secuCate=4)
tradeCode2stockID <- function(tradeCode, secuCate=1, IDsrc="local",
datasrc=defaultDataSRC()){
id_var <- switch(IDsrc,
local="ID",
quant="ID",
jy="InnerCode",
ts="StockID_TS",
wind="StockID_wind")
qr <- paste("select secucode,",id_var,"from SecuMain where secucategory=",secuCate)
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr,as.is=1)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
stockID <- tmpdat[match(tradeCode,tmpdat[,1]),2]
return(stockID)
}
intCode2tradeCode <- function(){
# 718-->"000718"
}
#' stockID2tradeCode
#'
#' Covert the stockID to tradeCode.
#' @param stockID a vector of stockID of specific datascr.
#' @param IDsrc a charactor string, could be one of "local","jy","ts","wind",etc.
#' @return a vector of character,giving the stock trading code. eg. \code{c("600001","600002","000300")}
#' @export
#' @family SecuMain functions
#' @author Ruifei.Yin
#' @examples
#' stockID2tradeCode(c("EI000001","EQ000030"),IDsrc="local")
#' stockID2tradeCode(c("SZ000001","SH000030"),IDsrc="ts")
stockID2tradeCode <- function(stockID,IDsrc="local",
datasrc=defaultDataSRC()){
id_var <- switch(IDsrc,
local="ID",
quant="ID",
jy="InnerCode",
ts="StockID_TS",
wind="StockID_wind")
qr <- paste("select secucode,",id_var,"from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr,as.is=1)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
tradeCode <- tmpdat[match(stockID,tmpdat[,2]),1]
return(tradeCode)
}
#' stockID2stockID
#'
#' Covert the stockID to another type of stockID.
#' @param stockID a vector of specific type
#' @param to a character string, giving the type of stockID convered to. Could be one of "local","ts","jy","wind".
#' @param from a character string, giving the type of stockID convered from. Could be one of "local","ts","jy","wind".
#' @return a vector,return the stockID of specific datascr.
#' @export
#' @family SecuMain functions
#' @author Ruifei.Yin
#' @examples
#' stockID2stockID(c("EI000001","EI000300"),to="jy",from="local")
#' stockID2stockID(c("SH000001","SH000300"),to="jy",from="ts")
stockID2stockID <- function(stockID, from, to,
datasrc=defaultDataSRC()){
id_from <- switch(from,
local="ID",
quant="ID",
jy="InnerCode",
ts="StockID_TS",
wind="StockID_wind")
id_to <- switch(to,
local="ID",
quant="ID",
jy="InnerCode",
ts="StockID_TS",
wind="StockID_wind")
qr <- paste("select",id_from,",",id_to,"from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
stockID_to <- tmpdat[match(stockID,tmpdat[,1]),2]
return(stockID_to)
}
#' stockID2name
#' @param stockID a vector
#' @return a vector
#' @export
#' @family SecuMain functions
#' @examples
#' stockID2name("EQ000527")
stockID2name <- function(stockID,datasrc=defaultDataSRC()){
qr <- paste("select SecuAbbr,ID from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
re <- tmpdat[match(stockID,tmpdat[,2]),1]
return(re)
}
#' stockName2ID
#' @param name a characoter vector
#' @return a dataframe with cols: 'SecuAbbr', 'ID'
#' @export
#' @family SecuMain functions
#' @examples
#' stockName2ID("ST")
stockName2ID <- function(name, datasrc=defaultDataSRC()){
qr <- paste("select SecuAbbr, ID from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
re <- tmpdat[grep(name, gsub("\\s*","",tmpdat$SecuAbbr)), ]
return(re)
}
#' SecuMarket
#' @param stockID a vector
#' @return a vector
#' @export
#' @family SecuMain functions
SecuMarket <- function(stockID,datasrc=defaultDataSRC()){
qr <- paste("select SecuMarket,ID from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
re <- tmpdat[match(stockID,tmpdat[,2]),1]
return(re)
}
#' SecuCategory
#' @param stockID a vector
#' @return a vector
#' @export
#' @family SecuMain functions
SecuCategory <- function(stockID,datasrc=defaultDataSRC()){
qr <- paste("select SecuCategory,ID from SecuMain")
if(datasrc=="quant"){
tmpdat <- queryAndClose.odbc(db.quant(),query=qr)
} else if(datasrc=="local") {
tmpdat <- queryAndClose.dbi(db.local("main"),query=qr)
}
re <- tmpdat[match(stockID,tmpdat[,2]),1]
return(re)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== sector components & sectorID =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' getComps
#'
#' get the components of the specific index, sector or plate on certain days.
#' @param ID a character string. The ID of the index, sector or plate. Could be a single-ID-code(eg. "EI000300","ES09440000",...) or a more complicated express containing some set operations and ID-codes(eg. "setdiff(union(EI000300,EI000905),ES09440000)")
#' @param endT a vector of class \code{Date}. IF missing, then get the latest components.
#' @param drop if drop the field of date and return a vector when endT is length 1 ?
#' @param datasrc
#' @return If \code{endT} is missing or is length 1 and \code{drop} is TRUE, a vector of stockID of the components; else a dataframe, with cols: "date" and "stockID"
#' @export
#' @family getComps functions
#' @examples
#' re1 <- getComps("EI000300") # same as getIndexComp("EI000300")
#' ID <- "setdiff(union(EI000300,EI399006),ES09440000)"
#' re2 <- getComps(ID)
#' re3 <- getComps(ID,endT=as.Date(c("2011-12-31","2012-12-31")))
#' more examples:
#' # CSI300 ex. financial servive sector
#' getComps("setdiff(EI000300,ES09440000)")
#' # CSI300 and financial servive sector
#' getComps("intersect(EI000300,ES09440000)")
#' # not drop
#' getComps("EI000300",drop=FALSE)
getComps <- function(ID, endT=Sys.Date(), drop=TRUE, datasrc=defaultDataSRC()){
IDs <- gsub("union|intersect|setdiff|[()]","",ID)
IDs <- strsplit(IDs,split=",")[[1]]
IDs <- unique(IDs[IDs!=""])
IDs_index <- IDs[substring(IDs,1,2)=="EI"]
IDs_sector <- IDs[substring(IDs,1,2)=="ES"]
IDs_plate <- IDs[substring(IDs,1,2)=="EP"]
if(length(IDs_index) > 0){
comp_index <- lapply(IDs_index, FUN=getIndexComp, endT=endT, drop=FALSE, datasrc=datasrc)
names(comp_index) <- IDs_index
} else {
comp_index <- list()
}
if(length(IDs_sector) > 0){
comp_sector <- lapply(IDs_sector, FUN=getSectorComp, endT=endT, drop=FALSE, datasrc=datasrc)
names(comp_sector) <- IDs_sector
} else {
comp_sector <- list()
}
if(length(IDs_plate) > 0){
comp_plate <- lapply(IDs_plate, FUN=getPlateComp, endT=endT, drop=FALSE, datasrc=datasrc)
names(comp_plate) <- IDs_plate
} else {
comp_plate <- list()
}
comps <- c(comp_index,comp_sector,comp_plate)
subfun <- function(endT0){
comps0 <- lapply(comps,function(x) x[x$date==endT0,"stockID"] )
dat0 <- with(comps0,eval(parse(text=ID)))
dat0 <- data.frame(date=endT0,stockID=dat0,stringsAsFactors=FALSE)
return(dat0)
}
# cat("Function getComps: getting the components ....\n")
re <- plyr::ldply(endT, subfun)
if(length(endT)==1 && drop==TRUE){
return(re$stockID)
} else {
return(re)
}
}
#' getIndexComp
#'
#' get the components of the specific index on certain day.
#' @param indexID the stockID of the index
#' @param endT a vector of class \code{Date}. IF missing, then get the latest components.
#' @param drop if drop the field of date and return a vector when endT is length 1 ?
#' @param datasrc
#' @return If \code{endT} is missing or is length 1 and \code{drop} is TRUE, a vector of stockID of the components; else a dataframe, with cols: "date" and "stockID"
#' @export
#' @examples
#' tmp <- getIndexComp("EI000300") # get the latest components, a vector
#' tmp <- getIndexComp("EI000300",drop=FALSE) # get the latest components, a dataframe
#' tmp <- getIndexComp("EI000300",as.Date("2012-12-31")) # get the components on single day,a vector
#' tmp <- getIndexComp("EI000300",as.Date(c("2011-12-31","2012-12-31"))) # get the components on multi-days, a data frame
#' tmp <- getIndexComp("EI000300",as.Date(c("2005-12-31","2012-12-31"))) # get the components before index's pubdate, a data frame
getIndexComp <- function(indexID, endT=Sys.Date(), drop=TRUE, datasrc=defaultDataSRC()){
pubdate <- trday.IPO(indexID)
endTdf <- data.frame(dateori=endT,date=endT)
if(indexID!='EI000985' && (!is.na(pubdate)) && min(endT)<pubdate){
warning(paste("min(endT):",min(endT)," is earlier than index's published date:",pubdate,". The early components would be approximated!",sep=""))
endT[endT<pubdate] <- pubdate
endTdf <- transform(endTdf,date=endT)
endT <- unique(endT)
}
if(datasrc %in% c("quant","local")){
endT <- rdate2int(endT)
tmpdat <- data.frame(endT=endT)
qr <- paste("SELECT a.endT as date, b.SecuID as stockID from yrf_tmp a, LC_IndexComponent b
where b.IndexID=", QT(indexID),
"and InDate<=endT and (OutDate>endT or OutDate IS NULL)")
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con, sqtable="yrf_tmp", errors=FALSE)
sqlSave(con, dat=tmpdat, tablename="yrf_tmp", safer=FALSE, rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
dbWriteTable(con, name="yrf_tmp", value=tmpdat, row.names = FALSE, overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re$date <- intdate2r(re$date)
}
if(datasrc=="ts"){
endT <- rdate2ts(endT)
indexID <- stockID2stockID(indexID,to="ts",from="local")
subfun <- function(endT0){
tsRequire()
stocks <- tsRemoteCallFunc("GetBKbyDate",list(indexID,endT0))
stocks <- as.vector(as.matrix(stocks))
stocks <- stockID2stockID(stocks,to="local",from="ts")
dat0 <- data.frame(date=tsdate2r(endT0),stockID=stocks,stringsAsFactors=FALSE)
return(dat0)
}
re <- plyr::ldply(endT,subfun)
}
endT <- endTdf$dateori
if(indexID!='EI000985' && (!is.na(pubdate)) && min(endT)<pubdate){
re <- endTdf %>% dplyr::full_join(re,by='date') %>% dplyr::select(-date) %>% dplyr::rename(date=dateori)
ipo <- data.frame(stockID=unique(re$stockID),stringsAsFactors = FALSE)
ipo$ipoday <- trday.IPO(ipo$stockID)
re <- re %>% dplyr::left_join(ipo,by='stockID') %>% dplyr::mutate(gap=date-ipoday) %>%
dplyr::filter(gap>=90) %>% dplyr::select(-ipoday,-gap)
}
re <- dplyr::arrange(re,date,stockID)
if(length(endT)==1 && drop==TRUE){
return(re$stockID)
} else {
return(re)
}
}
#' getIndexCompWgt
#'
#' get the components and wgts of the specific index on certain day.
#' @param indexID the stockID of the index
#' @param endT a vector of class \code{Date}. IF missing, then get the latest components.
#' @param datasrc
#' @return a dataframe, with cols: "date", "stockID","wgt".
#' @export
#' @family getComps functions
#' @examples
#' tmp <- getIndexCompWgt("EI000300") # get the latest components
#' tmp <- getIndexCompWgt("EI000985",as.Date("2012-12-31")) # get the components on single day
#' tmp <- getIndexCompWgt("EI000300",as.Date(c("2011-12-31","2012-12-31"))) # get the components on multi-days
getIndexCompWgt <- function(indexID="EI000300",endT,datasrc=defaultDataSRC()){
if(missing(endT)) endT <- trday.nearby(Sys.Date(),by=-1) # if endT missing, get the nearest wgt data.
endT <- trday.nearest(endT) # if endT is not tradingday, get the nearest trading days.
trday.nearbyinDB <- function(indexID,endT,datasrc){
# sometimes, the index-component-weight in database is not daily data, this function is used to get nearest date on which the weight data is available.
daymat <- data.frame(oldday=endT)
endT <- rdate2int(endT)
qr <- paste(
"SELECT DISTINCT EndDate
FROM LC_IndexComponentsWeight
where IndexID=",QT(indexID),"order by EndDate"
)
if(datasrc=="quant"){
con <- db.quant()
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
re <- dbGetQuery(con,qr)
dbDisconnect(con)
} else if (datasrc=="jy"){
con <- db.jy()
indexID <- stockID2stockID(indexID,to="jy",from="local")
qr <- paste(
"SELECT DISTINCT convert(varchar,EndDate,112) 'EndDate'
FROM LC_IndexComponentsWeight
where IndexCode=",QT(indexID),"order by EndDate"
)
re <- sqlQuery(con,query=qr)
odbcClose(con)
}
if(nrow(re)==0){
return(0)
}
if(min(endT)<min(re$EndDate)){
return(0)
} else{
endT<- re[findInterval(endT,re$EndDate),]
daymat$newday <- endT
return(daymat)
}
}
daymat <- trday.nearbyinDB(indexID,endT,datasrc)
if(is.numeric(daymat)){ # -- calulate the estimated wgt by 'free_foat_MV'
warning("There is no wgt data in table 'LC_IndexComponentsWeight', calulate the estimated wgt by 'free_foat_MV'.")
# TS <- getTS(endT,indexID)
TS <- getIndexComp(indexID = indexID ,endT = endT, drop = FALSE)
TSF <- gf.free_float_sharesMV(TS)
re <- plyr::ddply(TSF,"date",transform,wgt=factorscore/sum(factorscore,na.rm=TRUE))
re <- re[,c("date","stockID","wgt" )]
return(re)
}
endT <- unique(daymat$newday)
if(datasrc %in% c("quant","local")){
tmpdat <- data.frame(endT=endT)
qr <- paste("SELECT a.endT as date, b.SecuID as stockID, Weight/100 as wgt
from yrf_tmp a, LC_IndexComponentsWeight b
where b.IndexID=", QT(indexID),
"and a.endT=b.EndDate")
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con, sqtable="yrf_tmp", errors=FALSE)
sqlSave(con, dat=tmpdat, tablename="yrf_tmp", safer=FALSE, rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
dbWriteTable(con, name="yrf_tmp", value=tmpdat, row.names = FALSE, overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re=merge(re,daymat,by.x="date",by.y ="newday" )
re=re[,c("oldday","stockID","wgt")]
colnames(re)<-c("date","stockID","wgt")
}
if(datasrc=="jy"){
indexID <- stockID2stockID(indexID,to="jy",from="local")
subfun <- function(endT0){
qr <- paste(
"SELECT InnerCode as stockID, Weight/100 as wgt
FROM LC_IndexComponentsWeight as a
where IndexCode=",QT(indexID) ,"and a.EndDate=",QT(endT0)
)
dat <- queryAndClose.odbc(db.jy(),query=qr)
if(nrow(dat)==0){
warning(paste("weight data is missing on",endT0,"!"))
} else {
dat <- data.frame(date=intdate2r(endT0),dat,stringsAsFactors=FALSE)
}
return(dat)
}
cat("Function getIndexCompWgt: getting the component wgts ....\n")
re <- plyr::ldply(endT,subfun,.progress="text")
re$stockID <- stockID2stockID(re$stockID,to="local",from="jy")
}
re <- dplyr::arrange(re,date,stockID)
return(re)
}
#' getSectorComp
#'
#' get the components of the specific sector on certain day.
#' @param sectorID ID of the sector. eg. "ES09440000" for "financial service" the 1st level sector of SHENWAN; "ES09440100" for "bank" the 2nd level sector of SHENWAN. Get details with \code{CT_industryList()}
#' @param endT a vector of class \code{Date}. IF missing, then get the latest components.
#' @param drop if drop the field of date and return a vector when endT is length 1 ?
#' @param datasrc
#' @return If \code{endT} is missing or is length 1 and \code{drop} is TRUE, a vector of stockID of the components; else a dataframe, with cols: "date" and "stockID"
#' @export
#' @family getComps functions
#' @examples
#' tmp <- getSectorComp("ES09440000") # get the latest components, a vector
#' tmp <- getSectorComp("ES09440000",as.Date("2012-12-31")) # get the components on single day,a vector
#' tmp <- getSectorComp("ES09440000",as.Date(c("2011-12-31","2012-12-31"))) # get the components on multi-days, a data frame
getSectorComp <- function(sectorID, endT=Sys.Date(), drop=TRUE, datasrc=defaultDataSRC()){
level <- CT_industryList(ID=sectorID)$Level
sectorVar <- paste("Code",level,sep="")
if(datasrc %in% c("quant","local")){
endT <- rdate2int(endT)
tmpdat <- data.frame(endT=endT)
qr <- paste("SELECT a.endT as date, b.stockID as stockID from yrf_tmp a, LC_ExgIndustry b
where ",sectorVar,"=", QT(sectorID),
"and InDate<=endT and (OutDate>endT or OutDate IS NULL)")
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con, sqtable="yrf_tmp", errors=FALSE)
sqlSave(con, dat=tmpdat, tablename="yrf_tmp", safer=FALSE, rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
dbWriteTable(con, name="yrf_tmp", value=tmpdat, row.names = FALSE, overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re$date <- intdate2r(re$date)
}
re <- dplyr::arrange(re,date,stockID)
if(length(endT)==1 && drop==TRUE){
return(re$stockID)
} else {
return(re)
}
}
#' @family getComps functions
getPlateComp <- function(plateID,endT,drop,datasrc){
}
#' sectorID2name
#' @export
sectorID2name <- function(sectorID){
tmpdat <- CT_industryList(ID=sectorID)
tmpdat <- tmpdat[,c("IndustryID","IndustryName")]
re <- tmpdat[match(sectorID,tmpdat[,1]),2]
return(re)
}
plateID2name <- function(plateID){
}
#' sectorID2indexID
#' @export
#' @examples
#' sctID <- getSectorID(stockID = "EQ000001",drop=TRUE)
#' sectorID2indexID(sctID)
sectorID2indexID <- function(sectorID){
tmpdat2 <- queryAndClose.odbc(db.jy(),
"select A.*, B.SecuCode
from JYDB.dbo.LC_CorrIndexIndustry A,
JYDB.dbo.SecuMain B
where A.IndexCode = B.InnerCode")
tmpdat2 <- subset(tmpdat2, IndustryStandard == 24 )
tmpdat2 <- subset(tmpdat2, substr(SecuCode,1,3) == "801")
tmpdat2 <- tmpdat2[,c("IndustryCode", "SecuCode")]
tmpdat2 <- renameCol(tmpdat2, "IndustryCode", "sector")
tmpdat2$sector <- paste0("ES33",tmpdat2$sector)
# output
sectorID_df <- data.frame("sector" = sectorID)
re <- merge.x(sectorID_df, tmpdat2, by = "sector")
re$SecuCode <- paste0("EI",re$SecuCode)
return(re$SecuCode)
}
#' stockID2indexID
#' @export
#' @examples
#' stockID2indexID(stockID = "EQ000001")
stockID2indexID <- function(TS, stockID, withsector = FALSE){
re <- getSectorID(TS = TS, stockID = stockID)
re$indexID <- sectorID2indexID(re$sector)
if(!withsector){
re <- dplyr::select(re, -sector)
}
return(re)
}
#' getSectorID
#'
#' get the sectorID of the stocks on specific dates.
#' @param TS a \bold{TS} object
#' @param stockID a vector of stockID
#' @param endT a vector of Date
#' @param sectorAttr a list(See more in \code{\link{defaultSectorAttr}}) or NULL,or "existing".
#' @param ret a charactor string,could be one of "ID" or "name",indicating sectorID or sectorName returned.
#' @param drop a logical. Shoud the \code{TS} be exculded in the result?
#' @param fillNA
#' @param ungroup
#' @param datasrc
#' @return a data.frame,with the same cols of TS,added by "\code{sector}". Or a vector if \code{drop} is TRUE. You can get more sector infomation by \code{\link{CT_industryList}}
#' @note param TS and combination of stockID and endT should at least have one and only have one. The combination of vector stockID and endT could be different length, which abide by the recycling rule.
#' @author Ruifei.Yin
#' @export
#' @examples
#' # - with TS
#' TS <- getTS(getRebDates(as.Date('2007-03-17'),as.Date('2012-05-20')),'EI000300')
#' getSectorID(TS)
#' # - one stock, multiple dates
#' getSectorID(stockID="EQ000001", endT=as.Date(c("2010-01-01","2012-01-01","2013-01-01")))
#' # - one date, multiple stocks
#' getSectorID(stockID=c("EQ000001","EQ000002","EQ000004"), endT=as.Date("2010-01-01"))
#' # - get 'ZHONGXIN' sector
#' getSectorID(stockID=c("EQ000001","EQ000002","EQ000004"), endT=as.Date("2010-01-01"), sectorAttr=list(3,1), ret="name")
#' getSectorID(stockID=c("EQ000001","EQ000002","EQ000004"), endT=as.Date("2010-01-01"), sectorAttr=list(3,2), ret="name")
#' # -- combined sectorAttr
#' test <- getSectorID(TS, sectorAttr= defaultSectorAttr("fct",fct_level = 5))
#' test <- getSectorID(TS, sectorAttr= defaultSectorAttr("ind_fct",ind_std = 33,ind_level = 1,fct_level = 5))
#' test <- getSectorID(TS, sectorAttr= defaultSectorAttr("ind_fct",ind_std = c(336,33),ind_level = 1,fct_level = 5))
#' test <- getSectorID(TS, sectorAttr= defaultSectorAttr("fct",fct_std = buildFactorLists_lcfs(c("F000001","F000006"),factorRefine = refinePar_default("none",NULL)),fct_level = 5))
#' factorList1 <- buildFactorList(factorFun = "gf_cap",factorRefine=refinePar_default("scale",NULL))
#' test2 <- getSectorID(TS, sectorAttr= list(std=list(factorList1,33),level=list(5,1)))
#' # - speed compares (20 VS. 200)
#' microbenchmark::microbenchmark(re <- getSectorID(TS,datasrc="memory"),re1 <- getSectorID(TS,datasrc = "local"),times = 10)
getSectorID <- function(TS, stockID, endT=Sys.Date(),
sectorAttr=defaultSectorAttr(),
ret=c("ID","name"),
drop=FALSE,
fillNA=FALSE,
ungroup=NULL,
datasrc="memory"){
if(identical(sectorAttr,"existing") | is.null(sectorAttr)){
return(TS)
}
# arguments checking
ret <- match.arg(ret)
if (missing(TS) && missing(stockID)) {
stop("Param TS and combination of stockID and endT should at least have one!")
}
if (!missing(TS) && !missing(stockID)) {
stop("Param TS and combination of stockID and endT should only have one!")
}
if (missing(TS)){
TS <- expand.grid(date=endT, stockID=stockID)
}
names(sectorAttr) <- c("std","level")
if(length(sectorAttr$std) != length(sectorAttr$level)) stop("The argument of sectorAttr is not complete.")
if("sector" %in% colnames(TS)){
warning('There is already a "sector" field in TS, it will be overwritten!')
TS$sector <- NULL
}
# looping
loop <- length(sectorAttr$std)
for( i in 1:loop) {
if(is.numeric(sectorAttr$std[[i]])){ # by industrys
sectorSTD <- sectorAttr$std[[i]]
level <- sectorAttr$level[[i]]
sectorvar <- if (ret=="ID") paste("Code",level,sep="") else paste("Name",level,sep="")
TS_ <- TS[,c("date","stockID")]
if(datasrc %in% c("quant","local")){
TS_$date <- rdate2int(TS_$date)
qr <- paste(
"select date,a.stockID,",sectorvar,"as sector_
from yrf_tmp as a left join LC_ExgIndustry as b
on a.stockID=b.stockID and InDate<=date and (OutDate>date or OutDate is null)
where b.Standard=",sectorSTD
)
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con,sqtable="yrf_tmp",errors=FALSE)
sqlSave(con,dat=TS_,tablename="yrf_tmp",safer=FALSE,rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
dbWriteTable(con,name="yrf_tmp",value=TS_,row.names = FALSE,overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re$date <- intdate2r(re$date)
TS <- merge.x(TS,re,by=c("date","stockID"))
} else if (datasrc=="memory"){
memory.load()
TS_ <- data.table::data.table(TS_)
LC_ExgIndustry <- .LC_ExgIndustry[Standard==sectorSTD]
re <- LC_ExgIndustry[TS_,c("date","stockID",paste("x.",sectorvar,sep="")),on=.(stockID,InDate<=date,OutDate>date),with=FALSE]
re <- renameCol(re,paste("x.",sectorvar,sep=""),"sector_")
re <- as.data.frame(re)
TS <- merge.x(TS,re,by=c("date","stockID"))
}
if(fillNA){
TS$sector_ <- sector_NA_fill(sector = TS$sector_, sectorAttr = list(std = sectorSTD, level = level))
}
} else { # by factors
factorList <- sectorAttr$std[[i]]
level <- sectorAttr$level[[i]]
tmpTS <- TS[,c("date","stockID")]
tmpTSF <- getTSF(TS = tmpTS, FactorList = factorList)
tmpTSF <- dplyr::group_by(tmpTSF, date)
tmpTSF <- dplyr::mutate(tmpTSF,sector_=cut(rank(-factorscore,na.last="keep"),breaks =level,labels=FALSE))
tmpTSF <- dplyr::select(tmpTSF,-factorscore)
TS <- merge.x(TS,tmpTSF, by=c("date","stockID"))
}
# join together
if(i==1L){
TS <- renameCol(TS,"sector_","sector")
} else {
TS$sector <- paste(TS$sector, TS$sector_, sep="_")
TS <- dplyr::select(TS,-sector_)
}
}
# ungroup
if(!is.null(ungroup)){
TS <- sector_ungroup(TS,N=ungroup)
}
# return
if(drop){
return(TS[,"sector"])
} else {
return(TS)
}
}
#' is component of specific sector or index?
#'
#' @param TS
#' @param stockID
#' @param endT
#' @param sectorID a character string. The ID of the index, sector or plate. See detail in \code{\link{getComps}}
#' @param drop
#' @param datasrc
#' @return a dataframe or a vector(if drop==TRUE)
#' @export
#' @examples
#' is_component(stockID = c("EQ000001","EQ300089"),sectorID = "EI000300",drop=TRUE)
#' is_component(stockID = c("EQ000001","EQ300089"),sectorID = "ES09440000")
#' TS <- getTS(as.Date(c("2014-01-01","2016-01-01")),indexID = "EI000906")
#' re <- is_component(TS,sectorID = "EI000300")
is_component <- function(TS, stockID, endT=Sys.Date(),
sectorID,
drop=FALSE,
datasrc=defaultDataSRC()){
if (missing(TS) && missing(stockID)) {
stop("Param TS and combination of stockID and endT should at least have one!")
}
if (!missing(TS) && !missing(stockID)) {
stop("Param TS and combination of stockID and endT should only have one!")
}
if (missing(TS)){
TS <- expand.grid(date=endT, stockID=stockID)
}
indexComp <- getComps(sectorID,unique(TS$date),drop = FALSE,datasrc = datasrc)
indexComp$is_comp <- 1L
TSF <- merge.x(TS,indexComp,by=c('date','stockID'))
TSF[is.na(TSF$is_comp),"is_comp"] <- 0
if(drop){
return(TSF[,"is_comp"])
} else {
return(TSF)
}
}
#' deal with the NA value of sectorID
#'
#' replace the NA value of sectorID with an "OTHER" sector
#' @param sector a charactor vector of sectorID
#' @param sectorAttr
#' @export
sector_NA_fill <- function(sector, sectorAttr=defaultSectorAttr()){
Standard=c( 3, 3, 3, 9, 9, 9, 9, 9, 33, 33, 33, 336)
Level=c( 1, 2, 3, 1, 2, 3, 98, 99, 1, 2, 3, 1)
IndustryID=c( 'ES0370', 'ES037010', 'ES03701010', 'ES09510000', 'ES09510100', 'ES09510101', 'ES0951000098', 'ES0951000099', 'ES33510000','ES33510100','ES33510101', 'ES6')
replace_sec_value <- IndustryID[Standard==sectorAttr[[1]]&Level==sectorAttr[[2]]]
sector[is.na(sector)] <- replace_sec_value
return(sector)
}
# inner-func
# Turn two-stage group ID to one-stage when group members is less than a certain number.
sector_ungroup <- function(TSS,N=10){
if(stringr::str_detect(TSS[1,"sector"],'_') && substr(TSS$sector,1,2)=="ES"){
nsector <- TSS %>% group_by(date,sector) %>% summarise(num=n()) %>% ungroup()
if(any(nsector$num<N)){
nsector <- tidyr::separate(nsector,'sector',c("ind","fct"),sep="_",remove=FALSE)
nsector <- nsector %>% group_by(date,ind) %>% mutate(minnum=min(num)) %>% ungroup()
nsector <- transform(nsector,
sectornew=ifelse(minnum<N,ind,stringr::str_c(ind,fct,sep="_")))
TSS <- dplyr::left_join(TSS,nsector[,c("date","sector","sectornew")],by=c('date','sector'))
TSS <- transform(TSS,sector=sectornew,sectornew=NULL)
}
}
return(TSS)
}
#' @rdname getSectorID
#' @export
gf_sector <- function(TS, sectorAttr) {
TSS <- getSectorID(TS,sectorAttr = sectorAttr,fillNA = TRUE)
re <- cast_sector(TSS)
return(re)
}
#' @rdname getSectorID
#' @param TSS a dataframe, with cols: date,stockID,and some dummy variables of sectors.
#' @export
cast_sector <- function(TSS){
check.TSS(TSS)
TSS$.tmp <- 1
re <- reshape2::dcast(TSS,date+stockID~sector,fill=0,value.var = '.tmp')
TSS$.tmp <- NULL
re <- merge.x(TSS,re,by = c("date","stockID"))
return(re)
}
#' check.colnames_sectorfs
#'
#' @export
check.colnames_sectorfs <- function(data){
check.colnames(data,"sector")
cols <- colnames(data)
if(!any(substr(cols,1,2)=="ES")){
stop("the data must contain the sector-factors!")
}
}
#' defaultSectorAttr
#'
#' get the sectorAttr list.
#' @param type Currently supporting types : ind, fct, ind_fct, fct_ind
#' @param ind_std vector of integer.
#' @param ind_level vector of integer
#' @param fct_std a \bold{FactorLists} object
#' @param fct_level vector of integer. The number of fct splitted groups.
#' @return A \bold{sectorAttr} object. A list with two items:
#' \itemize{
#' \item std: a list( or a vector, if sector standards only include industry, not include factors) of sector standard;
#' \item level: a vector of sector level
#' }
#' @export
#' @examples
#' defaultSectorAttr()
#' defaultSectorAttr("ind",ind_std=c(3,33))
#' defaultSectorAttr("fct")
#' defaultSectorAttr("ind_fct")
#' defaultSectorAttr("fct_ind")
#' defaultSectorAttr("ind_fct",fct_level=5)
#' defaultSectorAttr("ind_fct",fct_std = RFactorModel::buildFactorLists_lcfs(c("F000001","F000006")),fct_level=c(2,3))
defaultSectorAttr <- function(type = c("ind","fct","ind_fct","fct_ind"),
ind_std = 33,
ind_level=1,
fct_std = list(fl_cap()),
fct_level = 3){
type <- match.arg(type)
if(length(ind_std)>length(ind_level)){
ind_level <- rep(ind_level,length(ind_std))
}
if(length(fct_std)>length(fct_level)){
fct_level <- rep(fct_level,length(fct_std))
}
if(type == "ind"){
re <- list(std = ind_std, level = ind_level)
} else if(type =="fct"){
re <- list(std = fct_std, level = fct_level)
} else if(type == "ind_fct"){
re <- list(std = c(as.list(ind_std), fct_std), level = c(ind_level, fct_level))
} else if (type == "fct_ind"){
re <- list(std = c(fct_std, as.list(ind_std)), level = c(fct_level, ind_level))
}
return(re)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== Constant value infomation =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' CT_SystemConst
#' @export
#' @examples
#' CT_SystemConst(LB=1081)
CT_SystemConst <- function(LB,datasrc=defaultDataSRC()){
qr <- "select * from CT_SystemConst"
if(datasrc=="local"){
re <- queryAndClose.dbi(db.local("main"),qr)
} else if(datasrc=="quant"){
re <- queryAndClose.odbc(db.quant(),qr)
} else if(datasrc=="jy"){
re <- queryAndClose.odbc(db.jy(),qr)[,c("LB","LBMC", "DM","MS")]
}
if(!missing(LB)){
re <- re[re$LB==LB,]
}
return(re)
}
#' CT_SecuCategory
#' @export
#' @examples
#' CT_SecuCategory(DM=c(1,4))
#' CT_SecuCategory(MS="xxx")
#' CT_SecuCategory()
CT_SecuCategory <- function(DM,MS){
re <- CT_SystemConst(LB=1177)
if(!missing(DM)){
re <- re[re$DM %in% DM, ]
}
if(!missing(MS)){
re <- re[grep(MS,re$MS),]
}
return(re)
}
#' CT_SecuMarket
#' @export
#' @examples
#' CT_SecuMarket(DM=c(83,90))
#' CT_SecuMarket(MS="xxx")
#' CT_SecuMarket()
CT_SecuMarket <- function(DM,MS){
re <- CT_SystemConst(LB=201)
if(!missing(DM)){
re <- re[re$DM %in% DM, ]
}
if(!missing(MS)){
re <- re[grep(MS,re$MS),]
}
return(re)
}
#' CT_sectorSTD
#' @export
#' @examples
#' CT_sectorSTD(DM=9)
#' CT_sectorSTD(DM=c(3,9))
#' CT_sectorSTD(MS="xxx")
#' CT_sectorSTD()
CT_sectorSTD <- function(DM,MS){
re <- CT_SystemConst(LB=1081)
if(!missing(DM)){
re <- re[re$DM %in% DM, ]
}
if(!missing(MS)){
re <- re[grep(MS,re$MS),]
}
return(re)
}
#' CT_industryList
#' @export
#' @examples
#' re <- CT_industryList(std=c(9,3))
#' CT_industryList(std=9,level=1)
#' CT_industryList(ID=c("ES0310","ES0312"))
#' CT_industryList(name="SHENWAN")
CT_industryList <- function(std,level,ID,name,
datasrc=defaultDataSRC()){
qr <- "select * from CT_IndustryList"
if(datasrc=="local"){
re <- queryAndClose.dbi(db.local("main"),qr)
} else if(datasrc=="quant"){
re <- queryAndClose.odbc(db.quant(),qr)
}
if(!missing(std)){
re <- re[re$Standard %in% std, ]
}
if(!missing(level)){
re <- re[re$Level %in% level, ]
}
if(!missing(ID)){
re <- re[re$IndustryID %in% ID, ]
}
if(!missing(name)){
re <- re[grep(name,re$IndustryName),]
}
return(re)
}
#' CT_TechVars
#' @export
CT_TechVars <- function(datasrc,secuCate,tableName,vars){
# -- Only local database allowed!
re <- queryAndClose.dbi(db.local("main"),"select * from CT_TechVars")
if(! missing(datasrc)){
re <- re[re$datasrc==datasrc,]
}
if(! missing(secuCate)){
re <- re[re$secuCate==secuCate,]
}
if(! missing(tableName)){
re <- re[re$tableName==tableName,]
}
if(! missing(vars)){
re <- re[re$varName %in% vars,]
}
return(re)
}
#' CT_FactorLists
#' @export
CT_FactorLists <- function(factorID,factorName,factorType){
# -- Only local database allowed!
re <- queryAndClose.dbi(db.local("fs"),"select * from CT_FactorLists")
if(! missing(factorID)){
re <- re[match(factorID,re[,1]),]
}
if(! missing(factorName)){
re <- re[re$factorName %in% factorName,]
}
if(! missing(factorType)){
re <- re[re$factorType %in% factorType,]
}
return(re)
}
#' factorID2name
#' @export
factorID2name <- function(factorID){
re <- CT_FactorLists(factorID)$factorName
return(re)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== Future related =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' getIFlastfirstday
#'
#' get the first,last and open dates of all IFs.
#'
#' Note that the "firstday" is the date when the current-month IF switching,while the "openday" is the date the IF IPOing.
#' @param begM beginning month,a yearmon object.
#' @param endM ending month,a yearmon object.
#' @return a dataframe,with cols: date(of class Date),IF01(of class character) and firstday,lastday,openday(of class Date)
#' @export
#' @author Ruifei.Yin
#' @examples
#' getIFlastfirstday()
getIFlastfirstday <- function(begM=zoo::as.yearmon("2010-05"),endM=zoo::as.yearmon(Sys.Date())){
dt <- seq(from=zoo::as.Date(zoo::as.yearmon("2010-05")),to=Sys.Date()+1/12,by="month")
IF01 <- paste("IF",substr(as.character(dt),3,4),substr(as.character(dt),6,7),sep="")
# ---- lastday
lastday0 <- as.Date(timeDate::timeNthNdayInMonth(dt,5,3))
lastday <- as.Date(ifelse(trday.is(lastday0)|(lastday0>=Sys.Date()),lastday0,trday.nearby(lastday0,1)))
# ---- firstday
lastday_lag <-lag.m(lastday,1,TRUE)
firstday <- as.Date(ifelse(dt!=as.Date("2010-05-01"),trday.nearby(lastday_lag,1),as.Date("2010-04-16")))
firstday <- as.Date(ifelse(lastday_lag>=Sys.Date()&(!is.na(lastday_lag)),lastday_lag+3,firstday)) # this is a very tricky method!
# ---- openday
openday <- vector(length=length(dt))
for(ii in 1:length(dt)){
mm <-month(dt[ii])
if(mm %in% c(3,6,9,12)){
if(ii<=7){
openday[ii] <-as.Date("2010-04-16")
} else {
openday[ii] <-firstday[ii-7]
}
} else {
if(ii<=1){
openday[ii] <-as.Date("2010-04-16")
} else {
openday[ii] <-firstday[ii-1]
}
}
}
openday <- as.Date(openday)
# ---- merge and subset
re <- data.frame(date=dt,IF01,firstday,lastday,openday,stringsAsFactors=FALSE)
begM <- max(zoo::as.yearmon("2010-05"),begM)
endM <- min(zoo::as.yearmon(Sys.Date())+1/12,endM)
re <- re[re$date>=as.Date(begM)&re$date<=as.Date(endM),]
return(re)
}
#' getIFlist
#'
#' get the list(the 4 future at one time) of codes of all CSI300 index futures and the first and last day of every current-month future.
#' @param begM beginning month,a yearmon object.
#' @param endM ending month,a yearmon object.
#' @return a dataframe,with cols: date,IF01,IF02,IF03,IF04,firstday,lastday,openday
#' @export
#' @author Ruifei.Yin
#' @examples
#' getIFlist()
getIFlist <- function(begM=zoo::as.yearmon("2010-05"),endM=zoo::as.yearmon(Sys.Date())){
begM <- max(zoo::as.yearmon("2010-05"),begM)
endM <- min(zoo::as.yearmon(Sys.Date())+1/12,endM)
d1 <- seq(from=as.Date(begM),to=as.Date(endM),by="month")
d2 <- d1+months(1)
d3 <- vector(length=length(d1))
for(i in 1:length(d1)){
mm <-month(d1[i])
if(mm %in% c(1,4,7,10)){d3[i] <-d1[i]+months(2)}
if(mm %in% c(2,5,8,11)){d3[i] <-d1[i]+months(4)}
if(mm %in% c(3,6,9,12)){d3[i] <-d1[i]+months(3)}
}
d3 <- as.Date(d3)
d4 <- d3+months(3)
IF01 <- paste("IF",substr(as.character(d1),3,4),substr(as.character(d1),6,7),sep="")
IF02 <- paste("IF",substr(as.character(d2),3,4),substr(as.character(d2),6,7),sep="")
IF03 <- paste("IF",substr(as.character(d3),3,4),substr(as.character(d3),6,7),sep="")
IF04 <- paste("IF",substr(as.character(d4),3,4),substr(as.character(d4),6,7),sep="")
IFlist <- data.frame(date=d1,IF01,IF02,IF03,IF04,stringsAsFactors=FALSE)
IFlastfirstday <- getIFlastfirstday(begM,endM)
re <- merge(IFlist,IFlastfirstday)
return(re)
}
#' getIFcontinuousCode
#'
#' get the continuous index future code on every trading day
#' @param begT
#' @param endT
#' @return a datafame with cols:tradingday,IF00,IF01,IF02,IF03,IF04,firstday,lastday...
#' @export
#' @author Ruifei.Yin
#' @examples
#' begT <- as.Date("2010-04-16")
#' endT <- Sys.Date()
#' getIFcontinuousCode()
getIFcontinuousCode <- function(begT=as.Date("2010-04-16"),endT=Sys.Date()){
tradingday <- data.frame(tradingday=trday.get(begT,endT),stringsAsFactors=FALSE)
IFlist <- getIFlist()
sqlchar1 <- "select * from tradingday as a ,IFlist as b
where a.tradingday <= b.lastday and a.tradingday >= b.firstday"
re <- sqldf(sqlchar1)
return(re)
}
#' getIFrtn
#'
#' get index future daily return series
#' @param code the code of the future(eg."IF00","IF01","IF02"...)
#' @param begT an object of class "Date"
#' @param endT an object of class "Date"
#' @param adj a logical,with default FALSE. if true, the daily return of future will be aligned with the trading time(starting from 9:30 and ending to 15:30) of CSI300 index.
#' @return the daily return series of class xts.
#' @export
#' @author Ruifei.Yin
#' @examples
#' begT <- as.Date("2011-01-01")
#' endT <- as.Date("2011-02-01")
#' rtn <- getIFrtn("IF00",begT,endT)
#' rtn.adj <- getIFrtn("IF00",begT,endT,adj=TRUE)
getIFrtn <- function(code,begT,endT,adj=FALSE){
qt <- getQuote_ts(code,begT,endT,variables=c("price","yclose"),Cycle="cy_15m()")
rtn <- qt$price/qt$yclose-1
time <- qt$date
time.adj<- time
for(ii in 1:length(time)){
if(lubridate::hour(time[ii])==15 & lubridate::minute(time[ii])==15){
time.adj[ii] <- time[ii+1]-3600
}
}
if(adj){
rtn.xts <- xts(rtn,time.adj)
} else {
rtn.xts <- xts(rtn,time)
}
rtn.daily <- aggregate(rtn.xts,by=zoo::as.Date,PerformanceAnalytics::Return.cumulative)
colnames(rtn.daily) <- code
return(rtn.daily)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== Mutual Fund related =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' mutual fund stats functions
#'
#' @name MF_funcs
#' @examples
#' #---MF_getQuote--------------------------------------------------------------
#' fundID <- c("519983.OF","519987.OF")
#' begT <- as.Date("2016-01-05")
#' # -- get one variable from wind
#' variables <- "NAV_adj_return1"
#' re <- MF_getQuote(fundID = fundID, begT = begT, variables = variables)
#' # -- get multiple variables from wind
#' variables <- "nav,NAV_adj,NAV_adj_return1"
#' re <- MF_getQuote(fundID = fundID, begT = begT, variables = variables)
#' # -- get one variable from jy
#' variables <- "NVDailyGrowthRate"
#' re <- MF_getQuote(fundID = fundID, variables = variables,datasrc = 'jy')
#' variables <- "UnitNV,NVDailyGrowthRate"
#' re <- MF_getQuote(fundID = fundID, variables = variables,datasrc = 'jy')
#'
#' #---MF_getStockPort----------------------------------------------------------
#' fundID <- c("519983.OF","519987.OF")
#' re <- MF_getStockPort(fundID,as.Date("2016-09-30"),mode="top10",datasrc = "jy")
#'
#' #---MF_Turnover_annual-------------------------------------------------------
#' begrptDate <- as.Date("2015-06-30")
#' endrptDate <- as.Date("2016-12-31")
#' fundID <- c("519983.OF","519987.OF")
#' re <- MF_Turnover_annual(fundID, begrptDate, endrptDate)
#'
#' #---MF_setupday-------------------------------------------------------
#' re <- MF_setupday(fundID)
#'
#' #---MF_nav_stat----------------------------------------------------------
#' # -- get one fund's nav stats from set up date.
#' mfstat <- MF_nav_stat(fundID='100038.OF')
#' # -- get one fund's yearly nav stats from set up date.
#' mfstat <- MF_nav_stat(fundID='100038.OF',freq='year')
#' # -- get mutiple funds' nav stats from specified date.
#' fundID <- c('162411.OF','501018.OF')
#' begT <- as.Date('2016-01-04')
#' endT <- as.Date('2017-12-31')
#' mfstat <- MF_nav_stat(fundID=fundID,begT=begT,endT=endT)
#' # -- define benchmark by yourself.
#' fundID <- c('000978.OF','000877.OF')
#' bmk <- c('EI000905','EI000300')
#' mfstat <- MF_nav_stat(fundID=fundID,bmk=bmk,datasrc='jy')
#' # -- pass raw data by yourself.
#' mfstat <- MF_nav_stat(fundnav=fundnav)
NULL
#' \code{MF_getQuote} get fund's quote from multiple data source.
#'
#' @rdname MF_funcs
#' @param variables see examples.
#' @export
MF_getQuote <- function(fundID,begT,endT,variables="NAV_adj_return1",datasrc = c("wind","jy","ts"),NAfill=FALSE){
datasrc <- match.arg(datasrc)
if(missing(begT)){
begT <- MF_setupday(fundID,datasrc = datasrc)
}
if(missing(endT)){
endT <- trday.nearby(Sys.Date(),-1)
}
fundinfo <- data.frame(fundID=fundID,begT=begT,endT=endT,stringsAsFactors = FALSE)
if(datasrc == "jy"){
qr <- paste("select convert(varchar,f.EndDate,112) 'date',
s.SecuCode+'.OF' 'fundID',",variables,
"from MF_NetValue f,SecuMain s
where f.InnerCode=s.InnerCode
and s.SecuCode in",brkQT(stringr::str_replace_all(fundID,'.OF','')),
" order by f.EndDate,s.SecuCode")
fundts <- queryAndClose.odbc(db.jy(),qr,stringsAsFactors = FALSE)
fundts <- fundts %>% dplyr::mutate(date=intdate2r(date))
tradingdays <- trday.get(min(fundts$date),max(fundts$date)) #remove untrading days
fundts <- fundts %>% dplyr::filter(date %in% tradingdays) %>%
dplyr::left_join(fundinfo,by='fundID') %>%
dplyr::filter(date>=begT,date<=endT) %>% dplyr::select(-begT,-endT)
}else if(datasrc == "ts"){
#
}else if(datasrc == "wind"){
# NAV_adj_return1 : fu quan dan wei jing zhi zeng zhang lv (in % unit)
# NAV_adj: fu quan dan wei jing zhi, houfuquan
require(WindR)
w.start(showmenu = FALSE)
fundts <- data.frame()
for(i in 1:nrow(fundinfo)){
fundts_ <- w.wsd(fundinfo$fundID[i],variables,fundinfo$begT[i],fundinfo$endT[i])[[2]]
fundts_ <- fundts_ %>% dplyr::rename(date=DATETIME) %>% dplyr::mutate(fundID=fundinfo$fundID[i]) %>%
dplyr::select(date,fundID,dplyr::everything())
fundts <- rbind(fundts,fundts_)
}
}
if(NAfill){
fundts[is.na(fundts)] <- 0
}
return(fundts)
}
#' \code{MF_getStockPort} get fund's stock portfolio from financial reports.
#'
#' @rdname MF_funcs
#' @export
MF_getStockPort <- function(fundID,rptDate,mode=c("all","top10"),datasrc = c("jy","ts","wind")){
#variables=c("date","stockID","wgt")
datasrc <- match.arg(datasrc)
mode <- match.arg(mode)
if(datasrc == "jy"){
fundID <- substr(fundID,1,6)
fundIDqr <- paste(fundID,collapse = "','")
if(mode == "all"){
sheetname <- "MF_StockPortfolioDetail"
}else if(mode == "top10"){
sheetname <- "MF_KeyStockPortfolio"
}
qr <- paste0("select convert(varchar(8),A.ReportDate,112) rptDate, A.RatioInNV wgt, B.SecuCode fundID, C.SecuCode stockID
from JYDB.dbo.",sheetname," A,
JYDB.dbo.SecuMain B, JYDB.dbo.SecuMain C
where A.InnerCode = B.InnerCode
and A.StockInnerCode = C.InnerCode
and B.SecuCode in ('",fundIDqr,"')")
tmpdat <- queryAndClose.odbc(db.jy(),qr)
tmpdat$stockID <- paste0('EQ',substr(tmpdat$stockID + 1000000,2,7))
tmpdat$fundID <- paste0(substr(tmpdat$fundID + 1000000,2,7),".OF")
tmpdat$rptDate <- intdate2r(tmpdat$rptDate)
tmpdat <- tmpdat[tmpdat$rptDate %in% rptDate,]
}
re <- tmpdat[,c("fundID","rptDate","stockID","wgt")]
re <- renameCol(re,"rptDate","date")
rownames(re) <- NULL
return(re)
}
#' \code{MF_Turnover_annual} get fund's annual turnover rate.
#'
#' @rdname MF_funcs
#' @export
MF_Turnover_annual <- function(fundID,begrptDate,endrptDate){
# buy in and sell out db
fundID <- substr(fundID,1,6)
fundIDqr <- paste(fundID, collapse="','")
qr <- paste0("select B.SecuCode fundID, convert(varchar(8),A.ReportDate,112) rptDate,
A.BuyingCost+A.SellingIncome value
from JYDB.dbo.MF_FundTradeInfo A,
JYDB.dbo.SecuMain B
where A.InnerCode = B.InnerCode
and B.SecuCode in ('",fundIDqr,"')")
tmpdat <- queryAndClose.odbc(db.jy(),qr)
tmpdat$rptDate <- intdate2r(tmpdat$rptDate)
tmpdat$fundID <- substr(tmpdat$fundID + 1000000, 2, 7)
# mkt_value db
qr2 <- paste0("select convert(varchar(8),A.ReportDate,112) rptDate,
A.MarketValue mkt_cap, B.SecuCode fundID
from JYDB.dbo.MF_StockPortfolioDetail A,
JYDB.dbo.SecuMain B
where A.InnerCode = B.InnerCode
and B.SecuCode in ('",fundIDqr,"')")
tmpdat2 <- queryAndClose.odbc(db.jy(), qr2)
tmpdat2 <- dplyr::group_by(tmpdat2, rptDate, fundID)
tmpdat2 <- dplyr::summarise(tmpdat2, mkt_sum = sum(mkt_cap))
tmpdat2$rptDate <- intdate2r(tmpdat2$rptDate)
tmpdat2$fundID <- substr(tmpdat2$fundID + 1000000, 2, 7)
# computing process
finalre <- data.frame()
for( i in 1:length(fundID)){
# numerator
tmpdat_ <- tmpdat[tmpdat$fundID == fundID[i],]
tmpdat_ <- dplyr::arrange(tmpdat_, rptDate)
tmpdat_ <- subset(tmpdat_, rptDate >= begrptDate & rptDate <= endrptDate)
ind_ <- substr(tmpdat_$rptDate,6,10) == "12-31"
ind_[length(ind_)] <- TRUE
if(ind_[1] == FALSE){
ind_[1] <- TRUE
tmpdat_$value[1] <- tmpdat_$value[1]*(-1)
}else if(ind_[1] == TRUE){
ind_[1] <- FALSE
}
subre_ <- tmpdat_[ind_,]
nominator_ <- sum(subre_$value)
# denominator
tmpdat2_ <- tmpdat2[tmpdat2$fundID == fundID[i],]
tmpdat2_ <- subset(tmpdat2_, rptDate > begrptDate & rptDate <= endrptDate)
denominator_ <- mean(tmpdat2_$mkt_sum)
# years
yy_ <- nrow(tmpdat2_)*0.5
# output
re_ <- nominator_/yy_/2/denominator_
finalre_ <- data.frame("fundID" = fundID[i], "turnover_ann" = re_)
finalre <- rbind(finalre, finalre_)
}
# output
finalre$fundID <- paste0(finalre$fundID,".OF")
return(finalre)
}
#' \code{MF_setupday} get fund's set up date.
#'
#' @rdname MF_funcs
#' @export
MF_setupday <- function(fundID,datasrc = c('jy','wind')){
datasrc <- match.arg(datasrc)
if(datasrc=='wind'){
require(WindR)
w.start(showmenu = FALSE)
f_setup_date <- w.wss(fundID,'fund_setupdate')[[2]]
f_setup_date <- f_setup_date %>% dplyr::mutate(FUND_SETUPDATE=w.asDateTime(FUND_SETUPDATE,asdate = TRUE))
re <- f_setup_date[match(fundID,f_setup_date[,'CODE']),2]
}else if(datasrc=='jy'){
qr <- paste("select s.SecuCode+'.OF' 'fundID',
convert(varchar,f.EstablishmentDate,112) 'begT'
from MF_FundArchives f,SecuMain s
where f.InnerCode=s.InnerCode
and s.SecuCode in ",brkQT(stringr::str_replace_all(fundID,'.OF','')))
fundinfo <- queryAndClose.odbc(db.jy(),qr,stringsAsFactors = FALSE)
fundinfo <- transform(fundinfo,begT=intdate2r(begT))
re <- fundinfo[match(fundID,fundinfo[,'fundID']),2]
}
return(re)
}
#' \code{MF_nav_stat} get fund's nav stats.
#'
#' @rdname MF_funcs
#' @param fundID is vector of fundID.
#' @param begT is a vector of begin date,can be missing,if missing,then fund's set up date will be begT
#' @param endT is end date,can be missing,if missing,then the nearest trading day for \bold{today} will be endT.
#' @param freq is fund's nav statistic frequency,default value is \code{NULL},same as \code{\link[QUtility]{rtn.periods}}.
#' @param scale is number of periods in a year,for daily return default value is 250,for monthly return default value is 12.
#' @param datasrc
#' @param fundnav is a data frame with four columns,contains \code{date},\code{fundID},\code{nav_rtn},\code{bmk_rtn}.fundnav can be missing,if missing,this function with get data from specified data source.
#' @export
MF_nav_stat <- function(fundID,begT,endT,bmk,freq=NULL,scale=250,datasrc=c('wind','jy'),fundnav){
if(missing(fundnav)){
datasrc <- match.arg(datasrc)
#get begT and endT
if(missing(endT)){
endT <- trday.nearby(Sys.Date(),-1)
}
setupday <- MF_setupday(fundID,datasrc = datasrc)
if(missing(begT)){
f_info <- data.frame(fundID=fundID,begT=setupday,endT=endT,stringsAsFactors = FALSE)
}else{
f_info <- data.frame(fundID=fundID,begT=begT,endT=endT,tmpday=setupday,stringsAsFactors = FALSE)
f_info <- f_info %>% dplyr::mutate(begT=ifelse(begT<tmpday,tmpday,begT)) %>%
dplyr::mutate(begT=as.Date(begT,origin = "1970-01-01"))%>% dplyr::select(-tmpday)
}
#get fund's nav return
if(datasrc=='wind'){
fundnav <- MF_getQuote(fundID = f_info$fundID, begT = f_info$begT, endT = f_info$endT, variables = "NAV_adj_return1",datasrc = 'wind',NAfill = TRUE)
fundnav <- fundnav %>% dplyr::rename(nav_rtn=NAV_ADJ_RETURN1) %>% dplyr::mutate(nav_rtn=nav_rtn/100)
}else if(datasrc=='jy'){
fundnav <- MF_getQuote(fundID = f_info$fundID, begT = f_info$begT, endT = f_info$endT, variables = "NVDailyGrowthRate",datasrc = 'jy',NAfill = TRUE)
fundnav <- fundnav %>% dplyr::rename(nav_rtn=NVDailyGrowthRate)
}
#get benchmark's pct_chg
result <- data.frame()
if(missing(bmk)){
require(WindR)
w.start(showmenu = FALSE)
bmk <- w.wss(f_info$fundID,'fund_benchindexcode')[[2]]
f_info <- transform(f_info,benchindexcode=bmk$FUND_BENCHINDEXCODE)
bmkqt <- data.frame()
for(i in 1:nrow(f_info)){
bmkqt_ <-w.wsd(f_info$benchindexcode[i],"pct_chg",f_info$begT[i],f_info$endT[i])[[2]]
bmkqt_ <- bmkqt_ %>% dplyr::rename(date=DATETIME,bmk_rtn=PCT_CHG) %>%
dplyr::mutate(fundID=f_info$fundID[i],bmk_rtn=bmk_rtn/100) %>% dplyr::select(date,fundID,bmk_rtn)
bmkqt <- rbind(bmkqt,bmkqt_)
}
fundnav <- fundnav %>% dplyr::left_join(bmkqt,by=c('date','fundID'))
}else{
f_info <- f_info %>% dplyr::mutate(benchindexcode=bmk)
bmkqt <- getIndexQuote(bmk,begT = min(f_info$begT),endT=max(f_info$endT),variables = 'pct_chg',datasrc = 'jy')
bmkqt <- bmkqt %>% dplyr::rename(benchindexcode=stockID,bmk_rtn=pct_chg) %>%
dplyr::mutate(benchindexcode=as.character(benchindexcode))
fundnav <- fundnav %>% dplyr::left_join(f_info[,c('fundID','benchindexcode')],by='fundID') %>%
dplyr::left_join(bmkqt,by=c('date','benchindexcode')) %>% dplyr::select(-benchindexcode)
}
}
#stats inner function
navstats_innerfunc <- function(fnav,scale){
fnav <- fnav %>% dplyr::mutate(exc_rtn=nav_rtn-bmk_rtn)
fundstat <- fnav %>% dplyr::group_by(fundID) %>%
dplyr::summarise(nyear=as.numeric(max(date)-min(date))/365,
rtn=prod(1+nav_rtn)-1,rtn_ann=(1+rtn)^(1/nyear)-1,
bench=prod(1+bmk_rtn)-1,bench_ann=(1+bench)^(1/nyear)-1,
alpha=rtn-bench,alpha_ann=rtn_ann-bench_ann,
hitratio=sum(exc_rtn>0)/n(),
bias=mean(abs(exc_rtn)),
TE=sqrt(sum(exc_rtn^2)/(n()-1)) * sqrt(scale),
alphaIR=alpha_ann/TE,
rtn_min=min(exc_rtn),
rtn_max=max(exc_rtn)) %>% dplyr::ungroup()
#get two dates
sdate <- fnav %>% dplyr::select(date,fundID,exc_rtn) %>%
dplyr::left_join(fundstat[,c('fundID','rtn_min','rtn_max')],by='fundID')
sdate_ <- sdate %>% dplyr::filter(exc_rtn==rtn_max) %>% dplyr::group_by(fundID) %>%
dplyr::summarise(rtn_maxdate=min(date)) %>% dplyr::ungroup()
sdate <- sdate %>% dplyr::filter(exc_rtn==rtn_min) %>% dplyr::group_by(fundID) %>%
dplyr::summarise(rtn_mindate=min(date)) %>% dplyr::ungroup() %>% dplyr::left_join(sdate_,by='fundID')
fundstat <- fundstat %>% dplyr::left_join(sdate,by='fundID')
#get max drawdown
maxDD <- split(fnav,fnav$fundID)
maxDDinnerfunc <- function(df,varname='exc_rtn'){
df <- reshape2::dcast(df,date~fundID,value.var = varname,fill = 0)
fnames <- colnames(df)[-1]
df <- xts::xts(df[,-1],order.by = df[,1])
df <- PerformanceAnalytics::table.Drawdowns(df,1)
df <- df[,c("Depth","From","Trough")]
colnames(df) <- c('alphamaxDD','maxDDbegT','maxDDendT')
return(df)
}
maxDD <- plyr::ldply(maxDD,maxDDinnerfunc,.id = 'fundID')
maxDD <- maxDD %>% dplyr::mutate(fundID=as.character(fundID))
fundstat <- fundstat %>% dplyr::left_join(maxDD,by='fundID')
fundstat <- as.data.frame(fundstat)
return(fundstat)
}
#stats
if(is.null(freq)){
fundstat <- navstats_innerfunc(fundnav,scale=scale)
}else{
fundnav <- fundnav %>% dplyr::mutate(date_break=as.Date(cut.Date2(date,breaks =freq)))
fundnav <- split(fundnav,fundnav$date_break)
fundstat <- plyr::ldply(fundnav,navstats_innerfunc,scale=scale,.id = 'date')
fundstat <- fundstat %>% dplyr::mutate(date=as.Date(date))%>% dplyr::arrange(date,fundID)
}
return(fundstat)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== rptDate related =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# -------------------- ~~ rptDate funcs ----------------
#' rptDate.is
#'
#' Is it a proper report date?
#' @param rptDate a vector of rptDate , with class Date.
#' @return a logical vector with the same length of rptDate.
#' @export
#' @author Ruifei.Yin
#' @seealso \code{\link{check.rptDate}}
#' @examples
#' rptDate.is(ymd(c(20100103,20141231,20130630)))
#' rptDate.is(ymd(c(20100630,20141231,20130930)))
#' rptDate.is(ymd(c(20100630,20141231,20130930)),"h")
rptDate.is <- function(rptDate,freq=c("q","y","h")){
freq <- match.arg(freq)
md <- 100*lubridate::month(rptDate) + lubridate::day(rptDate)
if(freq=="q"){
re <- md %in% c(331,630,930,1231)
} else if(freq=="h"){
re <- md %in% c(630,1231)
} else {
re <- md %in% c(1231)
}
return(re)
}
#' check.rptDate
#'
#' Is it a proper rptDate object? If TRUE, return NULL; else return an error.
#' @param rptDate a vector of rptDate , with class Date.
#' @export
#' @author Ruifei.Yin
#' @seealso \code{\link{rptDate.is}}
#' @examples
#' check.rptDate(ymd(c(20100103,20141231,20130630)))
#' check.rptDate(ymd(c(20100630,20141231,20130930)))
check.rptDate <- function(rptDate){
rptDate <- na.omit(rptDate) # omit the NA
re <- rptDate.is(rptDate)
re_all <- all(re)
if(!re_all) {
warning("rptDate is not proper report date!")
cat("Following is not proper rptDate:\n")
print(rptDate[!re])
}
}
#' rptDate.yoy
#' @param rptDate a vector of rptDate , with class Date.
#' @return a vector of yoy rptDate.
#' @export
#' @author Ruifei.Yin
#' @examples
#' rptDate.yoy(lubridate::ymd(c(20100630,20141231,20130930)))
rptDate.yoy <- function(rptDate){
check.rptDate(rptDate)
re <- rptDate - lubridate::years(1)
re <- as.Date(re,tz="")
return(re)
}
#' rptDate.qoq
#' @param rptDate a vector of rptDate , with class Date.
#' @return a vector of qoq rptDate.
#' @export
#' @author Ruifei.Yin
#' @examples
#' rptDate.qoq(lubridate::ymd(c(20100630,20141231,20130930)))
rptDate.qoq <- function(rptDate){
check.rptDate(rptDate)
re <- rptDate %m-% months(3)
re <- lubridate::ceiling_date(re,unit="month") - lubridate::days(1)
re <- as.Date(re,tz="")
return(re)
}
#' rptDate.offset
#' @param rptDate a vector of rptDate , with class Date.
#' @param by a vector of integer
#' @param freq charactor string: "y" or "q".
#' @return a vector or a dataframe according to the length of rptDate and by.
#' @export
#' @author Ruifei.Yin
#' @examples
#' # multi rptDate and 1 by:
#' rptDate.offset(as.Date(c("2016-03-31","2016-06-30","2016-09-30")),-1,"q")
#' rptDate.qoq(as.Date(c("2016-03-31","2016-06-30","2016-09-30")))
#' rptDate.offset(as.Date(c("2016-03-31","2016-06-30","2016-09-30")),-1,"y")
#' rptDate.yoy(as.Date(c("2016-03-31","2016-06-30","2016-09-30")))
#' # 1 rptDate and multi by:
#' rptDate.offset(as.Date("2016-03-31"),-2:0,"q")
#' # multi rptDate and multi by:
#' rptDate.offset(as.Date(c("2016-03-31","2016-06-30","2016-09-30")),-2:0,"q")
rptDate.offset <- function(rptDate,by,freq){
check.rptDate(rptDate)
if(length(rptDate)>1 && length(by)>1){
for(i in 1:length(by)){
re_ <- rptDate.offset(rptDate = rptDate, by=by[i], freq=freq)
re_ <- data.frame(re_)
if(i==1L){
re <- re_
} else{
re <- cbind(re,re_)
}
}
colnames(re) <- paste(freq,by,sep = "")
} else {
if(freq=="y"){
re <- rptDate + lubridate::years(by)
}else if(freq=="q"){
re <- rptDate %m+% months(by*3)
re <- lubridate::ceiling_date(re,unit="month") - lubridate::days(1)
}else if(freq=="h"){
re <- rptDate %m+% months(by*6)
re <- lubridate::ceiling_date(re,unit="month") - lubridate::days(1)
}else{
stop("uncorrect freq!")
}
re <- as.Date(re,tz="")
}
return(re)
}
#' rptDate.deadline
#' return the deadline of rptDate.
#' @param rptDate a vector of rptDate, with class Date.
#' @return a vector of Date
#' @export
#' @author Ruifei.Yin
#' @examples
#' rptDate.deadline(ymd(c(20100630,20141231,20130930)))
rptDate.deadline <- function(rptDate){
check.rptDate(rptDate)
q <- lubridate::quarter(rptDate)
y <- lubridate::year(rptDate)
re <- ISOdate(y,4,30,tz="")
re[q==2] <- ISOdate(y[q==2], 8, 31, tz="")
re[q==3] <- ISOdate(y[q==3], 10, 31, tz="")
re[q==4] <- ISOdate(y[q==4]+1, 4, 30, tz="")
re <- as.Date(re,tz="")
return(re)
}
#' rptDate.yearrpt
#' @param datelist a vector of date , with class Date.
#' @return a vector of yearly rptDate.
#' @export
#' @author Ruifei.Yin
#' @examples
#' rptDate.nearest(as.Date(c("2015-01-11","2016-06-21","2016-12-31")),"q",1)
#' rptDate.nearest(as.Date(c("2015-01-11","2016-06-21","2016-12-31")),"y",-1)
rptDate.nearest <- function(datelist,freq=c("q","y","h"),dir=-1L){
freq <- match.arg(freq)
if(freq=="y"){
if(dir==-1L){
re <- dplyr::if_else(rptDate.is(datelist,freq = "y"),datelist,
lubridate::floor_date(datelist,unit="year") - lubridate::days(1))
} else {
re <- lubridate::ceiling_date(datelist,unit="year") - lubridate::days(1)
}
} else if(freq=="q"){
if(dir==-1L){
re <- dplyr::if_else(rptDate.is(datelist,freq = "q"),datelist,
lubridate::floor_date(datelist,unit="quarter") - lubridate::days(1))
} else {
re <- lubridate::ceiling_date(datelist,unit="quarter") - lubridate::days(1)
}
} else if(freq=="h"){
if(dir==-1L){
re <- dplyr::if_else(rptDate.is(datelist,freq = "h"),datelist,
lubridate::floor_date(datelist,unit="halfyear") - lubridate::days(1))
} else {
re <- lubridate::ceiling_date(datelist,unit="halfyear") - lubridate::days(1)
}
}
re <- as.Date(re,tz="")
return(re)
}
#' rptDate.yearrpt
#' @param begT
#' @param endT
#' @param freq
#' @param dir 1L,-1L,or 0L
#' @return a vector of yearly rptDate.
#' @export
#' @author Ruifei.Yin
#' @examples
#' rptDate.get(as.Date("2011-02-06"),as.Date("2011-10-23"),freq="h",dir=1)
#' rptDate.get(as.Date("2011-12-31"),as.Date("2013-06-30"),freq="q",dir=0)
rptDate.get <- function(begT, endT, freq=c("q","y","h"), dir=0L){
freq <- match.arg(freq)
datelist <- c(seq(begT,endT,by='month'),endT)
if(dir==-1L){
re <- rptDate.nearest(datelist = datelist, freq = freq, dir = -1L)
}else if(dir==1L){
re <- rptDate.nearest(datelist = datelist, freq = freq, dir = 1L)
}else{
re <- rptDate.nearest(datelist = datelist, freq = freq, dir = -1L)
re <- re[re>=begT & re<=endT]
}
re <- unique(re)
return(re)
}
#' rptDate.publ
#'
#' @export
#' @author Aming.Tao
#' @examples
#' rptTS <- getrptTS(begT=as.Date("2016-02-06"),endT=as.Date("2017-8-23"),univ='EI000300')
#' re <- rptDate.publ(rptTS)
#' rptDate <- rptDate.get(as.Date("2011-02-06"),as.Date("2013-10-23"))
#' re <- rptDate.publ(rptDate=rptDate,stockID=c("EQ000001","EQ000002"))
rptDate.publ <- function(rptTS,rptDate,stockID,datasrc=defaultDataSRC()){
if (missing(rptTS) && any(missing(stockID),missing(rptDate))) {
stop("Param rptTS and combination of stockID and rptDate should at least have one!")
}
if (!missing(rptTS) && !all(missing(stockID),missing(rptDate))) {
stop("Param rptTS and combination of stockID and rptDate should only have one!")
}
if (missing(rptTS)){
rptTS <- expand.grid(rptDate=rptDate, stockID=stockID,stringsAsFactors = FALSE)
}
check.rptTS(rptTS)
if(datasrc=="quant"){
rptTS <- transform(rptTS,rptDate=rdate2int(rptDate))
con <- db.quant()
qr <- paste("select a.*,b.PublDate from yrf_tmp a left join LC_RptDate b on a.stockID=b.stockID and a.rptDate=b.EndDate")
sqlDrop(con,sqtable="yrf_tmp",errors=FALSE)
sqlSave(con,dat=rptTS,tablename="yrf_tmp",safer=FALSE,rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
re <- transform(re,rptDate=intdate2r(rptDate))
}else if(datasrc=="local"){
rptTS <- transform(rptTS,rptDate=rdate2int(rptDate))
con <- db.local("main")
dbWriteTable(con,name="yrf_tmp",value=rptTS,row.names = FALSE,overwrite = TRUE)
qr <- paste("select a.*,b.PublDate from yrf_tmp a left join LC_RptDate b on a.stockID=b.stockID and a.rptDate=b.EndDate")
re <- dbGetQuery(con,qr)
dbDisconnect(con)
re <- transform(re,rptDate=intdate2r(rptDate))
}else if(datasrc=="ts"){
re <- rptTS.getFin_ts(rptTS,'"PublDate",report(128006,RDate)')
}
re <- transform(re,PublDate=intdate2r(PublDate))
return(re)
}
# -------------------- ~~ rptTS funcs ----------------
#' getrptTS
#' @param begT
#' @param endT
#' @param freq
#' @param dir 1L,-1L,or 0L
#' @param univ
#' @param rptDates
#' @param stocks
#' @return a \bold{rptTS} object.a dataframe,with cols:
#' \itemize{
#' \item date: the rptDates
#' \item stockID: the stockID
#' }.IF rptDates or stocks is not missing then use them directly, else get rptDates and stocks by \code{\link{rptDate.get}} and \code{\link{getComps}}.
#' @export
#' @author Ruifei.Yin
#' @examples
#' re1 <- getrptTS(begT=as.Date("2011-02-06"),endT=as.Date("2011-10-23"),univ="EI000300")
#' re2 <- getrptTS(rptDates=as.Date(c("2016-03-31","2016-09-30")),univ="EI000300")
#' re3 <- getrptTS(rptDates=as.Date(c("2016-03-31","2016-09-30")),stocks=c("EQ000001","EQ000002"))
#' re4 <- getrptTS(begT=as.Date("2011-02-06"),endT=as.Date("2011-10-23"),stocks=c("EQ000001","EQ000002"))
getrptTS <- function(begT,endT,freq=c("q","y","h"),dir=0,univ,rptDates,stocks){
freq <- match.arg(freq)
if(missing(rptDates)){
rptDates <- rptDate.get(begT = begT, endT = endT, freq = freq, dir = dir)
}
check.rptDate(rptDates)
if(missing(stocks)){
re <- getComps(ID=univ,endT=rptDates,drop=FALSE)
re <- renameCol(re,"date","rptDate")
} else {
re <- expand.grid(rptDate=rptDates,stockID=stocks)
}
return(re)
}
#' rptTS.getFin
#'
#' get financtial indicators via \bold{rptTS} through WindR, or TinySoft.
#' @rdname rptTS.getFin
#' @name rptTS.getFin
#' @aliases rptTS.getFin_windR
#' @param rptTS a \bold{rptTS} object. a dataframe with cols:"rptDate","stockID"
#' @param field character strting or a vector of character string, giving the windfields. eg. "OPEN,CLOSE,HIGH" or c("OPEN","CLOSE","HIGH")
#' @param varname vector of charactor string
#' @param ... other arguments except \code{rptDate} in \code{w.wss}
#' @return a dataframe with the same length with rptTS, but added by some other financial indicator fields.
#' @export
#' @seealso \code{\link[WindR]{w.wss}}
#' @author Ruifei.Yin
#' @examples
#' rptTS <- getrptTS(begT=as.Date("2011-02-06"),endT=as.Date("2011-10-23"),stocks=c("EQ000001","EQ000002"))
#' # rptTS.getFin_windR
#' re <- rptTS.getFin_windR(rptTS,"np_belongto_parcomsh",options ="rptType=1")
rptTS.getFin_windR <- function(rptTS, field, varname, ...){
check.rptTS(rptTS)
require(WindR)
if(!w.isconnected()){
w.start(showmenu=FALSE)
}
rptTS2 <- transform(rptTS, stockID_wind=stockID2stockID(stockID,from="local",to="wind"), stringsAsFactors=FALSE)
Dts <- unique(rptTS$rptDate)
Dts <- na.omit(Dts)
df <- data.frame()
for(Dt in Dts){
Dt <- as.Date(Dt,origin = "1970-01-01")
codes <- rptTS2[rptTS2$rptDate==Dt, "stockID_wind", drop=TRUE]
w_out <- w.wss(codes=codes, fields=field, paste('rptDate=',rdate2int(Dt)), ...)
if(!w_out$ErrorCode==0){
stop(paste('Error in w.wss running! rptDate =',rdate2int(Dt),'; errorcode=',w_out$ErrorCode))
}
out <- data.frame(rptDate=Dt, w_out$Data)
if(dim(df)[1]==0) {
df <- out
} else {
df <- rbind(df,out)
}
}
df$stockID <- stockID2stockID(df$CODE,"wind","local")
re <- merge.x(rptTS,df,by=c("rptDate","stockID"))
re$CODE <- NULL
if(!missing(varname)){
re <- renameCol(re,setdiff(names(re),names(rptTS)), varname)
}
return(re)
}
#' @rdname rptTS.getFin
#' @param funchar expression to get variables from tinysoft,a character string, usually copyed from tinysoft "stock-data-expert" and then replace the specified reportdate in the stock-data-expert expression by \code{'Rdate'}. e.g. convert \code{Last12MData(20091231,46002)} to \code{Last12MData(Rdate,46002)}.
#' @param ... other arguments in \code{ts.wss}.
#' @export
#' @seealso \code{\link{ts.wss}}
#' @examples
#' # rptTS.getFin_ts
#' re2 <- rptTS.getFin_ts(rptTS,'"np_belongto_parcomsh",report(46078,RDate)')
#' multi_funchar <- '"eps",reportofall(9900000,RDate),
#' "zyywlrzzl",reportofall(9900601,RDate),
#' "yszk",report(44009,RDate)'
#' re3 <- rptTS.getFin_ts(rptTS,multi_funchar)
rptTS.getFin_ts <- function(rptTS, funchar,varname, ...){
check.rptTS(rptTS)
Dts <- unique(rptTS$rptDate)
Dts <- na.omit(Dts)
df <- data.frame()
for(Dt in Dts){
Dt <- as.Date(Dt,origin = "1970-01-01")
codes <- rptTS[rptTS$rptDate==Dt, "stockID", drop=TRUE]
ts_out <- ts.wss(stocks=codes, funchar=funchar,varname = varname, rptDate=Dt, adjust_yoy=TRUE, ...)
out <- data.frame(rptDate=Dt, ts_out)
if(dim(df)[1]==0) {
df <- out
} else {
df <- rbind(df,out)
}
}
re <- merge.x(rptTS,df,by=c("rptDate","stockID"))
re$stockName <- NULL
return(re)
}
#' @rdname rptTS.getFin
#' @export
#' @examples
#' # rptTS.getFinSeri_ts
#' FinSeri <- rptTS.getFinSeri_ts(rptTS,12,"q",'"np_belongto_parcomsh",report(46078,RDate)')
#' Finseri2 <- rptTS.getFinSeri_ts(rptTS,3,"y",multi_funchar)
rptTS.getFinSeri_ts <- function(rptTS, N, freq, funchar,varname, ...){
check.rptTS(rptTS)
# get rptTS_seri
rptDate_df <- rptDate.offset(rptTS$rptDate, by=-N:0, freq = freq)
rptTS_seri <- cbind(rptTS[,c("stockID","rptDate")],rptDate_df)
rptTS_seri <- reshape2::melt(rptTS_seri,id.vars=c("stockID","rptDate"),variable.name="lagN",value.name="lag_rptDate")
# remove repdate before IPO
rptTS_seri$ipoDate <- trday.IPO(rptTS_seri$stockID)
rptTS_seri <- dplyr::filter(rptTS_seri,lag_rptDate>=ipoDate)
rptTS_seri <- dplyr::arrange(rptTS_seri,stockID,rptDate,desc(lag_rptDate))
# get the financial index data
rptTS_uniq <- unique(rptTS_seri[,c("stockID","lag_rptDate")])
rptTS_uniq <- renameCol(rptTS_uniq,"lag_rptDate","rptDate")
rptTS_uniq <- rptTS.getFin_ts(rptTS=rptTS_uniq,funchar=funchar, varname = varname, ...)
rptTS_uniq <- renameCol(rptTS_uniq,"rptDate","lag_rptDate")
re <- merge.x(rptTS_seri,rptTS_uniq,by =c("stockID","lag_rptDate"))
return(re)
}
#' calcFinStat
#'
#' @export
#' @examples
#' # calcFinStat
#' FinStat <- calcFinStat(FinSeri,"mean")
calcFinStat <- function(FinSeri,stat=c('mean','sum','slope','slope/mean','slope/growthsd','sd','mean/sd'),fname,rm_N){
if(missing(fname)){
fname <- guess_factorNames(FinSeri,no_factorname = c("stockID", "rptDate","lagN","lag_rptDate","ipoDate"),is_factorname = "factorscore",silence = TRUE)
}
# melt & group_by
FinSeri <- reshape2::melt(FinSeri,measure.vars=fname,variable.name = "fname", value.name = "value")
FinSeri <- dplyr::group_by(FinSeri,fname,stockID,rptDate)
if(!missing(rm_N)){ # remove the too short seri
FinSeri <- FinSeri %>% dplyr::filter(n() > rm_N)
}
# get rptTS_stat
if(stat=="mean"){
rptTS_stat <- dplyr::summarise(FinSeri,value=mean(value,na.rm = TRUE))
} else if (stat=="sum"){
rptTS_stat <- dplyr::summarise(FinSeri,value=sum(value,na.rm = TRUE))
} else if (stat=="sd"){
rptTS_stat <- dplyr::summarise(FinSeri,value=sd(value,na.rm = TRUE))
} else if (stat=="mean/sd"){
rptTS_stat <- dplyr::summarise(FinSeri,value=mean(value,na.rm = TRUE)/sd(value,na.rm = TRUE))
} else if (stat %in% c("slope","slope/mean","slope/growthsd")){
FinSeri$lagN <- as.integer(substr(FinSeri$lagN,2,1000))
if(stat=="slope"){
rptTS_stat <- dplyr::do(FinSeri,mod = lm(value ~ lagN, data = .))
rptTS_stat <- broom::tidy(rptTS_stat,mod)
rptTS_stat <- rptTS_stat[rptTS_stat$term=='lagN',c("fname","stockID","rptDate","estimate")]
rptTS_stat <- renameCol(rptTS_stat,"estimate","value")
}else if(stat %in% c("slope/mean","slope/growthsd")){
if(stat=="slope/mean"){
rptTS_stat1 <- FinSeri %>% dplyr::summarise(value2=mean(value,na.rm = TRUE))
}else{
FinSeri <- FinSeri %>% dplyr::mutate(value2=value/dplyr::lead(value)-1)
FinSeri <- FinSeri %>% dplyr::filter(!is.na(value2))
rptTS_stat1 <- dplyr::summarise(FinSeri,value2=sd(value2,na.rm = TRUE))
}
rptTS_stat2 <- dplyr::do(FinSeri,mod = lm(value ~ lagN, data = .))
rptTS_stat2 <- broom::tidy(rptTS_stat2,mod)
rptTS_stat2 <- rptTS_stat2[rptTS_stat2$term=='lagN',c("fname","stockID","rptDate","estimate")]
rptTS_stat <- dplyr::left_join(rptTS_stat1,rptTS_stat2,by=c("fname","stockID","rptDate"))
rptTS_stat <- transform(rptTS_stat,value=estimate/value2,estimate=NULL,value2=NULL)
}
}
# cast
re <- reshape2::dcast(rptTS_stat,stockID+rptDate~fname)
return(re)
}
#' rptTS.getFinStat_ts
#'
#' @export
#' @examples
#' # rptTS.getFinStat_ts
#' FinStat <- rptTS.getFinStat_ts(rptTS,12,"q",'"np_belongto_parcomsh",report(46078,RDate)',stat="mean")
rptTS.getFinStat_ts <- function(rptTS, N, freq, funchar, varname,
stat=c('mean','sum','slope','slope/mean','slope/growthsd','sd','mean/sd'),
rm_N, ...){
stat <- match.arg(stat)
check.rptTS(rptTS)
FinSeri <- rptTS.getFinSeri_ts(rptTS = rptTS,N = N,freq = freq,funchar = funchar, varname = varname, ...)
rptTS_stat <- calcFinStat(FinSeri=FinSeri,stat = stat,fname = varname, rm_N = rm_N)
re <- merge.x(rptTS,rptTS_stat,by=c("stockID","rptDate"))
return(re)
}
# -------------------- ~~ TS.getFin_by_rptTS ----------------
#' getrptDate_newest
#'
#' get the newest rptDate of the stocks on specific dates.
#' @param TS a \bold{TS} object
#' @param stockID a vector of stockID
#' @param endT a vector of Date
#' @param mult a character string. Could be one of "last","first","all". IF a listed company publish more than one financial reports in a single day, which one should be returned? the newest one(the default value), the earliest one or all of them? See example for dedail.
#' @param drop a logical. Shoud the \code{TS} be exculded in the result?
#' @param datasrc
#' @return a data.frame,with the same cols of TS,added by "\code{rptDate}". Or a vector if \code{drop} is TRUE.
#' @note param TS and combination of stockID and endT should at least have one and only have one. The combination of vector stockID and endT could be different length, which abide by the recycling rule.
#' @author Ruifei.Yin
#' @export
#' @examples
#' # - with TS
#' TS <- getTS(getRebDates(as.Date('2007-03-17'),as.Date('2012-05-20'),rebFreq="year"),'EI000300')
#' getrptDate_newest(TS)
#' # - one stock, multiple dates
#' getrptDate_newest(stockID="EQ000001", endT=seq(from=as.Date("2010-12-31"),to=as.Date("2011-12-31"),by="month"))
#' # - one date, multiple stocks
#' getrptDate_newest(stockID=c("EQ000001","EQ000002","EQ000004"), endT=as.Date("2003-04-30"))
#' # - multi="all"
#' getrptDate_newest(stockID=c("EQ000001","EQ000002","EQ000004"), endT=as.Date("2003-04-30"),mult="all")
#' # - multi="first"
#' getrptDate_newest(stockID=c("EQ000001","EQ000002","EQ000004"), endT=as.Date("2003-04-30"),mult="first")
getrptDate_newest <- function(TS,stockID,endT=Sys.Date(),freq=c("q","y","h"),
mult=c("last","first","all"),
drop=FALSE,
datasrc=defaultDataSRC()){
freq <- match.arg(freq)
mult <- match.arg(mult)
if (missing(TS) && missing(stockID)) {
stop("Param TS and combination of stockID and endT should at least have one!")
}
if (!missing(TS) && !missing(stockID)) {
stop("Param TS and combination of stockID and endT should only have one!")
}
if (missing(TS)){
TS <- data.frame(date=endT, stockID=stockID)
}
check.TS(TS)
if(datasrc %in% c("quant","local")){
TS_new <- TS
TS_new$date <- rdate2int(TS_new$date)
qr <- paste(
"select date, a.stockID, EndDate as rptDate
from yrf_tmp as a left join LC_RptDate as b
on a.stockID=b.stockID and PublDate<=date and (PublDate_next>date or PublDate_next is null)
order by date, a.stockID, rptDate"
)
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con,sqtable="yrf_tmp",errors=FALSE)
sqlSave(con,dat=TS_new[,c("date","stockID")],tablename="yrf_tmp",safer=FALSE,rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
dbWriteTable(con,name="yrf_tmp",value=TS_new[,c("date","stockID")],row.names = FALSE,overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re <- transform(re, date=intdate2r(date), rptDate=intdate2r(rptDate))
if(freq %in% c("y","h")){ # get the newest yearly report or halfyearly report
re$rptDate <- rptDate.nearest(re$rptDate,freq = freq,dir = -1L)
}
re <- merge.x(TS,re,by=c("date","stockID"),mult=mult)
}
if(drop){
return(re[,"reptDate"])
} else {
return(re)
}
}
#' TS.getFin_by_rptTS
#'
#' get financial factorscore via rptTS
#' @param TS
#' @param fun a function or a non-empty character string naming the function to be called, which get the financtial indicators from \bold{rptTS}. Note that the function must contain a param of 'rptTS' .
#' @param ... optional arguments except rptTS of fun.
#' @return a dataframe with the same length with TS, but added by some other financial indicator fields.
#' @export
#' @seealso \code{\link{rptTS.getFin_windR}}, \code{\link{rptTS.getFin_ts}}
#' @author Ruifei.Yin
#' @examples
#' TS <- Model.TS(modelPar.univ(indexID="ES09440000"))
#' re <- TS.getFin_by_rptTS(TS,fun="rptTS.getFin_windR",field="np_belongto_parcomsh","rptType=1")
#' re2 <- TS.getFin_by_rptTS(TS,fun="rptTS.getFin_ts",funchar='"np_belongto_parcomsh",report(46078,RDate)')
#' # -- Following is a speed comparison of three different methods to get financial factorscores:
#'
#' TS <- Model.TS(setmodelPar.time(modelPar.default(),begT=as.Date("2007-12-01"),endT=as.Date("2014-05-01")))
#' system.time(re.wind <- TS.getFin_by_rptTS(TS,fun="rptTS.getFin_windR",field="np_belongto_parcomsh","rptType=1")) # 73.69
#' system.time(re.ts_dir <- TS.getFin_ts(TS,funchar='report(46078,RDate)',varname="np_belongto_parcomsh")) # 12.49
#' system.time(re.ts_rpt <- TS.getFin_by_rptTS(TS,fun="rptTS.getFin_ts",funchar='"np_belongto_parcomsh",report(46078,RDate)')) # 6.29
TS.getFin_by_rptTS <- function(TS, fun, ...){
check.TS(TS)
TS <- getrptDate_newest(TS,mult="last")
rptTS <- unique(TS[, c("rptDate","stockID")])
rptTSF <- do.call(fun, list(rptTS=rptTS, ...))
TSF <- merge.x(TS, rptTSF, by=c("rptDate","stockID"))
return(TSF)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== Others =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' is_suspend
#'
#' @param nearby a integer vector. 0 means today, 1 means next tradingday. default is 0L. see detail in \code{\link{trday.nearby}}.
#' @author Ruifei.yin
#' @examples
#' RebDates <- getRebDates(as.Date('2013-03-17'),as.Date('2016-04-17'),'month')
#' TS <- getTS(RebDates,'EI000985')
#' re <- is_suspend(TS) # Suspend of nextday
#' re1 <- is_suspend(TS,nearby=c(0,1))# Suspend of today and nextday
#' @export
is_suspend <- function(TS,nearby=0,
datelist,stockID,
drop,
datasrc=defaultDataSRC()){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
check.TS(TS)
if(datasrc=='ts'){
sus <- rep(FALSE,nrow(TS))
for (by in nearby){
TS_ <- data.frame(date=trday.nearby(TS$date,by), stockID=TS$stockID)
TS_ <- getTech_ts(TS_, funchar="istradeday4()",varname="trading")
sus_ <- (!TS_$trading == 1) & TS_$date<=Sys.Date()
sus <- sus|sus_
}
} else {
sus <- rep(FALSE,nrow(TS))
for (by in nearby){
TS_ <- data.frame(date=trday.nearby(TS$date,by), stockID=TS$stockID)
istradingday <- trday.is(TS=TS_, drop = TRUE)
sus_ <- (!istradingday)
sus <- sus|sus_
}
}
TS <- data.frame(TS,sus=ifelse(is.na(sus), FALSE, sus))
if(drop){
return(TS$sus)
}else{
return(TS)
}
}
#' is_priceLimit
#'
#' if over-price-limit
#' @param nearby a integer vector. 0 means today, 1 means next tradingday. default is 0L. see detail in \code{\link{trday.nearby}}.
#' @param lim a vector of length 2.
#' @param priceType "close" or "open".
#' @author Ruifei.yin
#' @examples
#' RebDates <- getRebDates(as.Date('2013-03-17'),as.Date('2016-04-17'),'month')
#' TS <- getTS(RebDates,'EI000985')
#' re <- is_priceLimit(TS)
#' re1 <- is_priceLimit(TS,nearby=-1:1)
#' re2 <- is_priceLimit(TS,lim=c(-Inf,10)) # limit-up
#' is_priceLimit(stockID = "EQ300576",datelist = as.Date("2016-12-22"),priceType = "open") # open-price over limit
#' @export
is_priceLimit <- function(TS,nearby=0,lim=c(-10, 10), priceType=c("close","open"),
datelist,stockID,
drop,
datasrc=defaultDataSRC()){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
check.TS(TS)
priceType <- match.arg(priceType)
if(priceType=="close"){
if(datasrc=='ts'){
overlim <- rep(FALSE,nrow(TS))
for (by in nearby){
TS_ <- data.frame(date=trday.nearby(TS$date,by), stockID=TS$stockID)
TS_ <- getTech_ts(TS_, funchar=c("StockPrevClose3()","close()"),varname=c("pre_close","close"))
in_lim <- TS_$close > round(TS_$pre_close*(1+lim[1]/100),2) & TS_$close < round(TS_$pre_close*(1+lim[2]/100),2)
overlim_ <- (!in_lim) & TS_$date<=Sys.Date()
overlim <- overlim|overlim_
}
} else {
overlim <- rep(FALSE,nrow(TS))
for (by in nearby){
TS_ <- data.frame(date=trday.nearby(TS$date,by), stockID=TS$stockID)
TS_ <- getTech(TS_,variables=c("pre_close","close") ,datasrc = datasrc)
in_lim <- TS_$close > round(TS_$pre_close*(1+lim[1]/100),2) & TS_$close < round(TS_$pre_close*(1+lim[2]/100),2)
overlim_ <- (!in_lim)
overlim <- overlim|overlim_
}
}
} else if(priceType=="open"){
if(datasrc=='ts'){
overlim <- rep(FALSE,nrow(TS))
for (by in nearby){
TS_ <- data.frame(date=trday.nearby(TS$date,by), stockID=TS$stockID)
TS_ <- getTech_ts(TS_, funchar=c("StockPrevClose3()","open()"),varname=c("pre_close","open"))
in_lim <- TS_$open > round(TS_$pre_close*(1+lim[1]/100),2) & TS_$open < round(TS_$pre_close*(1+lim[2]/100),2)
overlim_ <- (!in_lim) & TS_$date<=Sys.Date()
overlim <- overlim|overlim_
}
} else {
overlim <- rep(FALSE,nrow(TS))
for (by in nearby){
TS_ <- data.frame(date=trday.nearby(TS$date,by), stockID=TS$stockID)
TS_ <- getTech(TS_,variables=c("pre_close","open") ,datasrc = datasrc)
in_lim <- TS_$open > round(TS_$pre_close*(1+lim[1]/100),2) & TS_$open < round(TS_$pre_close*(1+lim[2]/100),2)
overlim_ <- (!in_lim)
overlim <- overlim|overlim_
}
}
} else {
stop("Invalid param of 'priceTpye'!")
}
TS <- data.frame(TS,overlim=ifelse(is.na(overlim), FALSE, overlim)) # if NA, set to FALSE
if(drop){
return(TS$overlim)
}else{
return(TS)
}
}
#' @export
is_blacklist <- function(TS,
datelist,stockID,
drop,
datasrc=defaultDataSRC()){
blklist=c("EQ600061","EQ600886","EQ600216") # temporally
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
check.TS(TS)
TS$is_blacklist <- TS$stockID %in% blklist
if(drop){
return(TS$is_blacklist)
}else{
return(TS)
}
}
#' is_st
#'
#' is st stock
#' @author Ruifei.yin
#' @examples
#' RebDates <- getRebDates(as.Date('2013-03-17'),as.Date('2016-04-17'),'month')
#' TS <- getTS(RebDates,'EI000985')
#' re <- is_st(TS)
#' @export
is_st <- function(TS,
datelist,stockID,
drop,
datasrc=defaultDataSRC()){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
check.TS(TS)
if(datasrc=='ts'){
TS_ <- TS.getTech_ts(TS, funchar="IsST_()")
TS_ <- renameCol(TS_, c("IsST_()"), c("is_st"))
TS_$is_st <- ifelse(TS_$is_st==1,TRUE,FALSE)
} else {
TS_ <- transform(TS,date=rdate2int(date))
con <- db.local("qt")
RSQLite::dbWriteTable(con,"yrf_tmp",TS_,overwrite=TRUE,row.names=FALSE)
qr <- "select y.*,q.SecuAbbr 'is_st' from yrf_tmp y
left join QT_DailyQuote2 q on y.date=q.TradingDay and y.stockID=q.ID"
TS_ <- RSQLite::dbGetQuery(con,qr)
RSQLite::dbDisconnect(con)
TS_ <- transform(TS_,date=intdate2r(date),
is_st=stringr::str_detect(is_st,'ST'))
}
if(drop){
return(TS_$is_st)
}else{
return(TS_)
}
}
#' is_delist
#'
#' judeg whether stocks to be delisted
#' @export
is_delist <- function(TS,nearby=months(2),datelist,stockID, drop,datasrc='jy'){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
check.TS(TS)
if(datasrc=='jy'){
stocks <- substr(unique(TS$stockID),3,8)
#get delist date
qr <- paste("SELECT 'EQ'+s.SecuCode 'stockID',convert(varchar,ChangeDate,112) 'delistdate'
FROM LC_ListStatus l
INNER join SecuMain s on l.InnerCode=s.InnerCode and s.SecuCategory=1
where l.ChangeType=4 and l.SecuMarket in (83,90)
and s.SecuCode in",brkQT(stocks))
re <- queryAndClose.odbc(db.jy(),qr,as.is = TRUE)
if(nrow(re)>0){
re <- transform(re,delistdate=intdate2r(delistdate))
TS <- TS %>% dplyr::left_join(re,by='stockID') %>%
dplyr::mutate(tmpdate=trday.offset(date,nearby),delist=ifelse(is.na(delistdate),FALSE,delistdate<=tmpdate)) %>%
dplyr::select(-tmpdate,-delistdate)
}
}
if(drop){
return(TS$delist)
}else{
return(TS)
}
}
#' @export
getTech <- function(TS,
variables = select.list(CT_TechVars(datasrc=datasrc,secuCate="EQ",tableName=tableName)[["varName"]],graphics=TRUE,multiple=TRUE),
tableName="QT_DailyQuote2",
datelist,stockID,
drop,
datasrc=defaultDataSRC()){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
missing_TS <- TRUE
} else {
missing_TS <- FALSE
}
re <- TS.getTech(TS=TS,variables = variables,tableName = tableName,datasrc = datasrc)
if(missing(drop)){
drop <- if(missing_TS&length(variables)==1) TRUE else FALSE
}
if(drop){
return(re[,variables])
}else{
return(re)
}
}
#' @export
getTech_ts <- function(TS,funchar,varname=funchar, Rate=1, RateDay=0,
datelist,stockID,
drop){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)&length(funchar)==1) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
result <- TS.getTech_ts(TS=TS,funchar = funchar,varname = varname,Rate = Rate,RateDay = RateDay)
if(drop){
return(result[,varname])
}else{
return(result)
}
}
#' @export
getFin_ts <- function(TS,funchar,varname=funchar,Rate=1,RateDay=0,
datelist,stockID,
drop){
if (missing(TS) && any(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should at least have one!")
}
if (!missing(TS) && !all(missing(stockID),missing(datelist))) {
stop("Param TS and combination of stockID and datelist should only have one!")
}
if(missing(drop)){
drop <- if(missing(TS)&length(funchar)==1) TRUE else FALSE
}
if (missing(TS)){
TS <- expand.grid(date=datelist, stockID=stockID)
}
result <- TS.getFin_ts(TS=TS,funchar = funchar,varname = varname,Rate = Rate,RateDay = RateDay)
if(drop){
return(result[,varname])
}else{
return(result)
}
}
#' TS.getTech
#' @export
TS.getTech <- function(TS,
variables = select.list(CT_TechVars(datasrc=datasrc,secuCate="EQ",tableName=tableName)[["varName"]],graphics=TRUE,multiple=TRUE),
tableName="QT_DailyQuote2",
datasrc=defaultDataSRC()){
check.TS(TS)
tmpdat <- transform(TS[,c("stockID","date")], date = rdate2int(date))
tmpdat$PK_ <- 1:NROW(tmpdat)
vars <- CT_TechVars(datasrc=datasrc,secuCate="EQ",tableName=tableName,vars=variables)
if(NROW(vars)==0){
stop(paste("No fields matched in table",QT(tableName),"in datasrc",QT(datasrc),"!"))
}
vars <- paste(vars$func,"as",QT(vars$varName), collapse=", ")
qr <- paste("select a.*,",vars,"from yrf_tmp a left join",tableName ,"b on a.stockID=b.ID and a.date=b.TradingDay")
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con,sqtable="yrf_tmp",errors=FALSE)
sqlSave(con,dat=tmpdat,tablename="yrf_tmp",safer=FALSE,rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- if(tableName =="QT_FactorScore") db.local("fs") else db.local("qt")
dbWriteTable(con,name="yrf_tmp",value=tmpdat,row.names = FALSE,overwrite = TRUE)
if(tableName %in% c("QT_DailyQuote2","QT_DailyQuote","QT_FactorScore")){
dbExecute(con, 'CREATE INDEX [IX_yrf_tmp] ON [yrf_tmp]([date],[stockID]);')
}
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re <- dplyr::arrange(re,PK_)[,variables,drop=FALSE]
re <- cbind(TS,re)
return(re)
}
#' TS.getTech_ts
#'
#' get technical factors throug a tinysoft expression, which could be a simple expresion, e.g 'close()','StockZf2(20)','BBIBOLL_v(11,6)',..,or more complicated expression, e.g. 'close()/open()', 'StockZf2(10)-StockZf2(20)'...
#' @param TS a \bold{TS} object
#' @param funchar a vector of character,the tinysoft function with the arguments. e.g \code{"BBIBOLL_v(11,6)"}
#' @param varname character string, giving the name of the returned variables
#' @return A \bold{TSF} object
#' @note Note that the tinysoft function must contain ONLY two(no more!) system parameters: pn_stock() and pn_date() ,which is specifyed by the two fields in the TS respectively.
#' @author Ruifei.Yin
#' @export
#' @examples
#' TS <- getTS(getRebDates(as.Date('2011-03-17'),as.Date('2012-04-17')),'EI000300')
#' p1 <- 11
#' p2 <- 6
#' funchar <- paste('BBIBOLL_v(',p1,',',p2,')',sep='')
#' TSF <- TS.getTech_ts(TS,funchar)
#' TSF <- TS.getTech_ts(TS, funchar="StockAveHsl2(20)/StockAveHsl2(60)", varname="avgTurnover_1M3M")
#' funchar <- c('BBIBOLL_v(11,6)','StockAveHsl2(20)/StockAveHsl2(60)')
#' TSF2 <- TS.getTech_ts(TS, funchar)
TS.getTech_ts <- function(TS,funchar,varname=funchar, Rate=1, RateDay=0){
check.TS(TS)
tmpfile <- TS
tmpfile$stockID <- stockID2stockID(tmpfile$stockID,from="local",to="ts")
tmpfile$date <- as.character(tmpfile$date)
tmpcsv <- tempfile(fileext=".csv")
tmpcsv2 <- stringr::str_replace_all(tmpcsv,'\\\\',"\\\\\\\\")
write.csv(tmpfile,tmpcsv,row.names=FALSE,quote=FALSE)
subqr <- ""
for( i in 1:length(funchar)){
subqr <- paste0(subqr, ' factorexp[',i-1,'] := &"',funchar[i],'"; ')
}
subqr2 <- ""
if(!is.null(Rate)){
subqr2 <- paste0(subqr2, ' SetSysParam(pn_rate(), ',Rate,'); ')
}
if(!is.null(RateDay)){
subqr2 <- paste0(subqr2, ' SetSysParam(pn_rateday(), ',RateDay,'); ')
}
len.funchar <- length(funchar)-1
qrstr <- paste0('oV:=BackUpSystemParameters();
SetSysParam(pn_cycle(),cy_day());
',subqr2,'
rdo2 importfile(ftcsv(),"","',tmpcsv2,'",timestockframe);
factorexp := array();
',subqr,'
result:=array();
for i:=0 to length(timestockframe)-1 do
begin
SetSysParam(pn_stock(),timestockframe[i]["stockID"]);
SetSysParam(pn_date(),strtodate(timestockframe[i]["date"]));
for j:= 0 to ',len.funchar,' do
begin
factorvalue:=eval(factorexp[j]);
result[i][j]:=factorvalue;
end;
end;
RestoreSystemParameters(oV);
return result;')
tsRequire()
fct <- tsRemoteExecute(qrstr)
fct <- plyr::ldply(fct, unlist)
colnames(fct) <- varname
result <- cbind(TS,fct)
return(result)
}
#' TS.getFin_ts
#'
#' get financial factors throug a tinysoft expression, which could be simple or more complicated.
#'
#' Note that the tinysoft function must contain ONLY two system parameters(no more!):pn_stock() and pn_date() ,which is supplyed from the two fields in the TS respectively.Also,the function must contain a expression of 'Rdate:=NewReportDateOfEndT2(sp_time())' to get the newest Rdate of sp_time.
#' @param TS a \bold{TS} object
#' @param funchar a vector of character string, giving a tinysoft expression to get the financtial indicators of the stock. The expression can be made simply by replaceing the specified reportdate in the stock-data-expert expression by \code{'Rdate'}. e.g. change \code{Last12MData(20091231,46002)} to \code{Last12MData(Rdate,46002)}.
#' @param varname character string, giving the name of the returned variables
#' @return A \bold{TSF} object,a dataframe, containing at least cols:\bold{date}(with class of Date),\bold{stockID},\bold{varname},\bold{Rdate}
#' @note Note that the tinysoft function must contain ONLY two system parameters(no more!):pn_stock() and pn_date() ,which is supplyed from the two fields in the TS respectively. Also,the function must contain a expression of 'Rdate:=NewReportDateOfEndT2(sp_time())' to get the newest Rdate of sp_time.
#' @author Ruifei.Yin
#' @export
#' @examples
#' TS <- getTS(getRebDates(as.Date('2011-03-17'),as.Date('2012-04-17')),'EI000300')
#' TSF <- TS.getFin_ts(TS,"ReportOfAll(9900416,Rdate)")
#' TSF2 <- TS.getFin_ts(TS,"GrowthOfNReport(@@LastQuarterData(DefaultRepID(),9900003,0),Rdate,3,1)")
#' TSF3 <- TS.getFin_ts(TS,"StockAveHsl2(20)+reportofall(9900003,Rdate)")
#' funchar <- c("ReportOfAll(9900416,Rdate)","StockAveHsl2(20)+reportofall(9900003,Rdate)")
#' TSF4 <- TS.getFin_ts(TS, funchar)
TS.getFin_ts <- function(TS,funchar,varname=funchar,Rate=1,RateDay=0){
check.TS(TS)
tmpfile <- TS
tmpfile$stockID <- stockID2stockID(tmpfile$stockID,from="local",to="ts")
tmpfile$date <- as.character(tmpfile$date)
tmpcsv <- tempfile(fileext=".csv")
tmpcsv2 <- stringr::str_replace_all(tmpcsv,'\\\\',"\\\\\\\\")
write.csv(tmpfile,tmpcsv,row.names=FALSE,quote=FALSE)
subqr <- ""
for( i in 1:length(funchar)){
subqr <- paste0(subqr, ' factorexp[',i-1,'] := &"',funchar[i],'"; ')
}
subqr2 <- ""
if(!is.null(Rate)){
subqr2 <- paste0(subqr2, ' SetSysParam(pn_rate(), ',Rate,'); ')
}
if(!is.null(RateDay)){
subqr2 <- paste0(subqr2, ' SetSysParam(pn_rateday(), ',RateDay,'); ')
}
len.funchar <- length(funchar)-1
qrstr <- paste0('oV:=BackUpSystemParameters();
SetSysParam(pn_cycle(),cy_day());
',subqr2,'
rdo2 importfile(ftcsv(),"","',tmpcsv2,'",timestockframe);
factorexp := array();
',subqr,'
result:=array();
for i:=0 to length(timestockframe)-1 do
begin
SetSysParam(pn_stock(),timestockframe[i]["stockID"]);
SetSysParam(pn_date(),strtodate(timestockframe[i]["date"]));
Rdate:=NewReportDateOfEndT2(sp_time());
for j:=0 to ',len.funchar,' do
begin
factorvalue:=eval(factorexp[j]);
result[i][j]:=factorvalue;
end;
result[i]["Rdate"]:=Rdate;
end;
RestoreSystemParameters(oV);
return result;')
tsRequire()
fct <- tsRemoteExecute(qrstr)
fct <- plyr::ldply(fct,as.data.frame)
colnames(fct) <- c(varname, "RDate")
result <- cbind(TS,fct)
return(result)
}
#' getQuote_ts
#'
#' get Quote series of some stocks in certain period
#' @param stocks a vector of charactor
#' @param begT an object of class "Date"
#' @param endT an object of class "Date"
#' @param variables a vector of charactor,elements of which could be stockID,stockName,date,price,open,high,low,vol,amount,yclose,sectional_yclose,cjbs,...
#' @param Cycle a charactor string,eg."cy_day()","cy_30m()","cy_month()",...
#' @param Rate a integer,giving the type of rights adjustment, could be one of 0(no adjustment),1(geometric adjustment),2(simple adjustment),3
#' @param RateDay a integer,giving the base date of right adjustment,could be one of 0(the last trading day),-1(the IPO date),or a tinysoft date integer(eg.\code{rdate2ts(as.Date("2010-01-02"))})
#' @param melt a logical. If FALSE(default), the style of result is "stockID+date~variable";If TRUE, the quote data will be melted(see the examples for details).
#' @param split
#' @param splitNbin
#' @return the quote data, a data frame object with cols:stockID,stockName,date(\bold{of class POSIXct}) and the elements the param \code{variable} containing
#' @export
#' @author Ruifei.Yin
#' @examples
#' stocks <- c("SZ002001","SZ002002")
#' begT <- as.Date("2011-01-01")
#' endT <- as.Date("2011-02-01")
#' variables <- c("price","open")
#' qt.asis <- getQuote_ts(stocks,begT,endT,variables)
#' qt.melt <- getQuote_ts(stocks,begT,endT,variables,melt=TRUE)
getQuote_ts <- function(stocks,begT,endT,variables,Cycle="cy_day()",Rate=0,RateDay=0,melt=FALSE,
split = if(length(stocks) > splitNbin) TRUE else FALSE,
splitNbin = 50){
# stocks <- c("SZ002001","SZ002002")
# begT <- as.Date("2008-01-01")
# endT <- as.Date("2011-02-01")
# variables <- c("price","yclose")
# Cycle="cy_day()"
# Rate=0
# RateDay=0
subfun <- function(stocks,begT,endT,variables,Cycle,Rate,RateDay,melt){
stockID <- paste(stocks,collapse=",")
begT <- rdate2ts(begT)
endT <- rdate2ts(endT)
variables <- paste('["',variables,'"]',sep="",collapse=",")
tsRequire()
qt <- tsRemoteCallFunc("getQuote",list(stockID,begT,endT,variables,Cycle,Rate,RateDay))
qt <- plyr::ldply(qt,as.data.frame)
qt$date <- as.POSIXct(qt$date,tz="")
if(melt){
qt <- reshape2::melt(qt,id.vars=c("stockID","date"))
}
return(qt)
}
if(!split){
re <- subfun(stocks,begT,endT,variables,Cycle,Rate,RateDay,melt)
} else {
Ngroup <- length(stocks) %/% splitNbin +1
Ngroup <- if(Ngroup>1) Ngroup else Ngroup+1
bby <- cut(1:length(stocks),Ngroup,labels=FALSE)
warning(paste('Possibly dealing with a big quote data. The process is split to ',Ngroup,'groups.'))
for(i in 1:Ngroup){
# i <- 2
substocks <- stocks[bby==i]
cat("Dealing with ",i," of ",Ngroup,"groups ... \n")
gc()
qt <- subfun(substocks,begT,endT,variables,Cycle,Rate,RateDay,melt)
if(i==1L){
re <- qt
} else {
re <- rbind(re,qt)
}
}
}
return(re)
}
#' getQuote
#'
#' get Quote series of stocks, indexs, futures in certain period
#' @aliases getQuote getIndexQuote getIFquote
#' @param stocks a charactor vector of stockID or indexID.
#' @param begT an object of class "Date"
#' @param endT an object of class "Date"
#' @param variables a vector of charactor. Call funtion \code{CT_TechVars(secuCate="EQ")} to get all available variables of equity, funtion \code{CT_TechVars(secuCate="EI")} of equity index, and funtion \code{CT_TechVars(secuCate="IF")} of index future.
#' @param melt a logical. If FALSE(default), the style of result is "stockID+date~variable";If TRUE, the quote data will be melted(see the examples for details).
#' @param split
#' @param splitNbin
#' @param tableName character string, giving the table name from which get data.
#' @return the quote data, a data frame object with cols:stockID,date and the elements the param \code{variable} containing. If melt is TRUE, data frame with cols:stockID,date,variable,value
#' @export
#' @author Ruifei.Yin
#' @examples
#' # get stock's quote
#' stocks <- c("EQ002001","EQ002002")
#' begT <- as.Date("2007-01-01")
#' endT <- as.Date("2013-02-01")
#' variables <- c("close","pct_chg","vwap")
#' re <- getQuote(stocks,begT,endT,variables,datasrc="local")
#' re <- getQuote(stocks,begT,endT,variables,melt=TRUE,datasrc="local")
#' stocks <- getIndexComp("EI000300")
#' system.time(uu2 <- getQuote(stocks,begT,endT,variables,datasrc="local",split=FALSE))
#' system.time(uu1 <- getQuote(stocks,begT,endT,variables,datasrc="local",split=TRUE))
getQuote <- function(stocks, begT=as.Date("1990-12-19"), endT=Sys.Date(),
variables = select.list(CT_TechVars(datasrc=datasrc,secuCate="EQ",tableName=tableName)[["varName"]],graphics=TRUE,multiple=TRUE),
melt=FALSE,
split = if(length(stocks) > splitNbin) TRUE else FALSE,
splitNbin = 300,
tableName = "QT_DailyQuote",
datasrc=defaultDataSRC()){
begT <- rdate2int(begT)
endT <- rdate2int(endT)
if(begT>endT){
stop(paste("begT ",begT,"is later then endT ",endT))
}
techVars <- CT_TechVars(datasrc=datasrc,secuCate="EQ",tableName=tableName,vars=variables)
if(NROW(techVars)==0){
stop(paste("No fields matched in table", QT(tableName),"in datasrc",QT(datasrc),"!"))
}
subfun <- function(stocks,melt){
stocks_char <- paste("(",paste(QT(stocks),collapse=","),")",sep="")
vars <- techVars
vars <- paste(vars$func,"as",QT(vars$varName), collapse=", ")
querychar <- paste("select ID as stockID,TradingDay as date,",vars,"from",tableName ,"where ID in", stocks_char, "and TradingDay >=", begT, "and TradingDay <=" ,endT)
if(datasrc=="quant"){
qt <- queryAndClose.odbc(db.quant(),querychar)
} else if(datasrc=="local"){
qt <- queryAndClose.dbi(db.local("qt"),querychar)
}
qt$date <- intdate2r(qt$date)
if(melt){
qt <- reshape2::melt(qt,id.vars=c("stockID","date"))
}
return(qt)
}
if(!split){
re <- subfun(stocks,melt)
} else {
Ngroup <- length(stocks) %/% splitNbin +1
# Ngroup <- if(Ngroup>1) Ngroup else Ngroup+1
bby <- cut(1:length(stocks),Ngroup,labels=FALSE)
warning(paste('Possibly dealing with a big data. The process is splited to ',Ngroup,'groups.'))
for(i in 1:Ngroup){
substocks <- stocks[bby==i]
cat("Dealing with ",i," of ",Ngroup,"groups ... \n")
gc()
qt <- subfun(substocks,melt)
if(i==1L){
re <- qt
} else {
re <- rbind(re,qt)
}
}
}
rslt <- re
return(rslt)
}
#' @rdname getQuote
#' @export
#' @examples
#' # get index quote
#' indexs <- c("EI000001","EI000300")
#' begT <- as.Date("2015-01-01")
#' endT <- as.Date("2016-08-01")
#' variables <- c("close","pct_chg")
#' re <- getIndexQuote(indexs,begT,endT,variables,datasrc="local")
#' re <- getIndexQuote(indexs,begT,endT,variables,datasrc="jy")
getIndexQuote <- function(stocks,
begT=as.Date("1990-12-19"), endT=Sys.Date(),
variables = select.list(CT_TechVars(datasrc=datasrc,secuCate="EI",tableName="QT_IndexQuote")[["varName"]],graphics=TRUE,multiple=TRUE),
melt=FALSE,
datasrc=defaultDataSRC()){
begT <- rdate2int(begT)
endT <- rdate2int(endT)
vars <- CT_TechVars(datasrc=datasrc,secuCate="EI",tableName="QT_IndexQuote",vars=variables)
if(NROW(vars)==0){
stop(paste("No fields matched in table 'QT_IndexQuote' in datasrc",QT(datasrc),"!"))
}
subfun <- function(stocks,melt){
stocks_char <- paste("(",paste(QT(stocks),collapse=","),")",sep="")
vars <- paste(vars$func,"as",QT(vars$varName), collapse=", ")
querychar <- paste("select ID as stockID,TradingDay as date,",vars,"from QT_IndexQuote where ID in", stocks_char, "and TradingDay >=", begT, "and TradingDay <=" ,endT)
if(datasrc=="quant"){
con <- db.quant()
qt <- queryAndClose.odbc(db.quant(),querychar)
} else if(datasrc=="local"){
qt <- queryAndClose.dbi(db.local("main"),querychar)
}else if(datasrc=="jy"){
stocks_char <- paste("(",paste(QT(substr(stocks,3,8)),collapse=","),")",sep="")
begT <- intdate2r(begT)
endT <- intdate2r(endT)
querychar <- paste("SELECT 'EI'+s.SecuCode 'stockID',CONVERT(varchar,TradingDay,112) 'date',",
vars," FROM QT_IndexQuote q,SecuMain s
where q.InnerCode=s.InnerCode and s.SecuCode in",stocks_char,
" and q.TradingDay>=",QT(begT)," and q.TradingDay<=",QT(endT))
qt <- queryAndClose.odbc(db.jy(),querychar)
qt <- dplyr::arrange(qt,stockID,date)
}
qt$date <- intdate2r(qt$date)
if(melt){
qt <- reshape2::melt(qt,id.vars=c("stockID","date"))
}
return(qt)
}
re <- subfun(stocks,melt)
return(re)
}
#' getPeriodrtn
#'
#' get the period return of the stocks
#' @param SP a \bold{SP} object ('stock*period'): a data frame with cols: "stockID","begT","endT"(with class of Date).
#' @param stockID a vector of stockID
#' @param begT a vector of Date
#' @param endT a vector of Date
#' @param tradeType a character string("close","nextavg","nextopen"),indicating the trading type.
#' @param drop a logical. If the \code{SP} shoud be exculded in the result?
#' @param datasrc
#' @return a data frame, with cols of SP and "periodrtn". Or a vector if \code{drop} is TRUE.
#' @note param SP and combination of stockID, begT and endT should at least have one and only have one. The combination of vector stockID, begT and endT could be different length, which abide by the recycling rule.
#' @author Ruifei.Yin
#' @export
#' @examples
#' # -- with SP
#' getPeriodrtn(data.frame(stockID="EQ601313",begT=as.Date("2012-01-20"),endT=as.Date("2012-09-27")))
#' getPeriodrtn(data.frame(stockID="EQ601313",begT=as.Date("2012-01-20"),endT=as.Date("2012-09-27")),tradeType="nextopen")
#' TS <- getTS(getRebDates(as.Date('2007-03-17'),as.Date('2012-05-20')),'EI000300')
#' TS <- renameCol(TS,"date","begT")
#' SP <- data.frame(TS,endT=trday.offset(TS$begT,months(1)))
#' system.time(re <- getPeriodrtn(SP,datasrc="ts")) # 8.40
#' system.time(re1 <- getPeriodrtn(SP,datasrc="local")) # 1.94
#' system.time(re <- getPeriodrtn(SP,tradeType = "nextavg",datasrc="ts")) # 10.80
#' system.time(re1 <- getPeriodrtn(SP,tradeType = "nextavg",datasrc="local")) # 16.7
#'
#' #-- with combination of vector stockID, begT and endT
#' getPeriodrtn(stockID="EQ000001",begT=as.Date("2012-01-01"), endT=as.Date("2012-01-01")+c(10,20,30))
#' getPeriodrtn(stockID=c("EQ000001","EQ000002","EQ000004"),begT=as.Date("2012-01-01"), endT=as.Date("2013-01-01"))
getPeriodrtn <- function(SP, stockID, begT, endT,
tradeType=c("close","nextavg","nextopen"),drop=FALSE,
datasrc=defaultDataSRC()){
tradeType <- match.arg(tradeType)
if (missing(SP) && any(missing(stockID),missing(begT),missing(endT))) {
stop("Param SP and combination of stockID, begT and endT should at least have one!")
}
if (!missing(SP) && !all(missing(stockID),missing(begT),missing(endT))) {
stop("Param SP and combination of stockID, begT and endT should only have one!")
}
if (missing(SP)){
SP <- data.frame(stockID=stockID,begT=begT,endT=endT)
}
check.SP(SP)
if("periodrtn" %in% names(SP)){
warning("Column 'periodrtn' is already exist. It will be drop!")
SP$periodrtn <- NULL
}
if(datasrc=="ts"){
tmpdat <- transform(SP, stockID = stockID2stockID(stockID,from="local",to="ts"),
begT = as.character(begT),
endT = as.character(endT))
tmpcsv <- tempfile(fileext=".csv")
write.csv(tmpdat,tmpcsv,row.names=FALSE,quote=FALSE,fileEncoding="GB2312")
tsRequire()
periodrtn <- tsRemoteCallFunc("getperiodrtn",list(tmpcsv,tradeType))
periodrtn <- plyr::laply(periodrtn,as.array)
re <- cbind(SP, periodrtn)
}
if(datasrc %in% c("quant","local")){
# -- deal with the trading days
if(tradeType=="close"){
tmpdat <- transform(SP[,c("stockID","begT","endT")], begT = trday.nearest(begT), endT = trday.nearest(endT))
tmpdat <- transform(tmpdat, begT = rdate2int(begT), endT = rdate2int(endT))
tmpdat$PK_ <- 1:NROW(tmpdat)
} else {
begT_ <- trday.nearby(TS = dplyr::select(SP,date=begT,stockID),by = 1,drop = TRUE)
endT_ <- trday.nearby(TS = dplyr::select(SP,date=endT,stockID),by = 1,drop = TRUE)
tmpdat <- data.frame(stockID=SP$stockID,begT=begT_,endT=endT_)
tmpdat <- transform(tmpdat, begT = rdate2int(begT), endT = rdate2int(endT))
tmpdat$PK_ <- 1:NROW(tmpdat)
}
# -- query
if(tradeType=="close"){
qr <- "select a.*,b.RRClosePrice as P0,c.RRClosePrice as P1
from yrf_tmp a left join QT_DailyQuote2 b
on a.begT=b.TradingDay and a.stockID=b.ID
left join QT_DailyQuote2 as c
on a.endT=c.TradingDay and a.stockID=c.ID"
} else if(tradeType=="nextopen"){
qr <- "select a.*,(b.OpenPrice*b.RRFactor) as P0,(c.OpenPrice*c.RRFactor) as P1
from yrf_tmp a left join QT_DailyQuote2 b
on a.begT=b.TradingDay and a.stockID=b.ID
left join QT_DailyQuote2 as c
on a.endT=c.TradingDay and a.stockID=c.ID"
} else if(tradeType=="nextavg"){
qr <- "select a.*,(b.TurnoverValue/b.TurnoverVolume*b.RRFactor) as P0,
(c.TurnoverValue/c.TurnoverVolume*c.RRFactor) as P1
from yrf_tmp a left join QT_DailyQuote2 b
on a.begT=b.TradingDay and a.stockID=b.ID
left join QT_DailyQuote2 as c
on a.endT=c.TradingDay and a.stockID=c.ID"
}
# -- fetch
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con,sqtable="yrf_tmp",errors=FALSE)
sqlSave(con,dat=tmpdat,tablename="yrf_tmp",safer=FALSE,rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("qt")
dbWriteTable(con,name="yrf_tmp",value=tmpdat,row.names = FALSE,overwrite = TRUE)
dbExecute(con, 'CREATE INDEX [IX_yrf_tmp] ON [yrf_tmp]([begT],[stockID]);')
dbExecute(con, 'CREATE INDEX [IX2_yrf_tmp] ON [yrf_tmp]([endT],[stockID]);')
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re <- dplyr::arrange(re,PK_)[,c("P0","P1")]
re <- re$P1/re$P0-1
re <- cbind(SP,periodrtn=re)
}
if(drop){
return(re[,"periodrtn"])
} else {
return(re)
}
}
#' @rdname getPeriodrtn
#' @export
#' @examples
#' # -- getPeriodrtn_EI
#' getPeriodrtn_EI(stockID="EI000300",begT=as.Date("2012-01-01"), endT=as.Date("2012-01-01")+c(10,20,30))
getPeriodrtn_EI <- function(SP, stockID, begT, endT, drop=FALSE,
datasrc=defaultDataSRC()){
if (missing(SP) && any(missing(stockID),missing(begT),missing(endT))) {
stop("Param SP and combination of stockID, begT and endT should at least have one!")
}
if (!missing(SP) && !all(missing(stockID),missing(begT),missing(endT))) {
stop("Param SP and combination of stockID, begT and endT should only have one!")
}
if (missing(SP)){
SP <- data.frame(stockID=stockID,begT=begT,endT=endT)
}
check.SP(SP)
if(datasrc=="ts"){
tmpdat <- transform(SP, stockID = stockID2stockID(stockID,from="local",to="ts"),
begT = as.character(begT),
endT = as.character(endT))
tmpcsv <- tempfile(fileext=".csv")
write.csv(tmpdat,tmpcsv,row.names=FALSE,quote=FALSE,fileEncoding="GB2312")
tsRequire()
periodrtn <- tsRemoteCallFunc("getperiodrtn",list(tmpcsv,"close"))
periodrtn <- plyr::laply(periodrtn,as.array)
re <- cbind(SP, periodrtn)
}
if(datasrc %in% c("quant","local")){
# -- deal with the trading days
if(TRUE){
tmpdat <- transform(SP[,c("stockID","begT","endT")], begT = trday.nearest(begT), endT = trday.nearest(endT))
tmpdat <- transform(tmpdat, begT = rdate2int(begT), endT = rdate2int(endT))
tmpdat$PK_ <- 1:NROW(tmpdat)
}
# -- query
if(TRUE){
qr <- "select a.*,b.ClosePrice as P0,c.ClosePrice as P1
from yrf_tmp a left join QT_IndexQuote b
on a.begT=b.TradingDay and a.stockID=b.ID
left join QT_IndexQuote as c
on a.endT=c.TradingDay and a.stockID=c.ID"
}
# -- fetch
if(datasrc=="quant"){
con <- db.quant()
sqlDrop(con,sqtable="yrf_tmp",errors=FALSE)
sqlSave(con,dat=tmpdat,tablename="yrf_tmp",safer=FALSE,rownames=FALSE)
re <- sqlQuery(con,query=qr)
odbcClose(con)
} else if (datasrc=="local"){
con <- db.local("main")
dbWriteTable(con,name="yrf_tmp",value=tmpdat,row.names = FALSE,overwrite = TRUE)
re <- dbGetQuery(con,qr)
dbDisconnect(con)
}
re <- dplyr::arrange(re,PK_)[,c("P0","P1")]
re <- re$P1/re$P0-1
re <- cbind(SP,periodrtn=re)
}
if(drop){
return(re[,"periodrtn"])
} else {
return(re)
}
}
#' @rdname getPeriodrtn
#' @export
#' @examples
#' # -- getPeriodrtn_FU
#' getPeriodrtn_FU(stockID="FUIF00",begT=as.Date("2012-01-01"), endT=as.Date("2012-01-01")+c(10,20,30))
getPeriodrtn_FU <- function(SP, stockID, begT, endT, drop=FALSE,
datasrc="ts"){
if (missing(SP) && any(missing(stockID),missing(begT),missing(endT))) {
stop("Param SP and combination of stockID, begT and endT should at least have one!")
}
if (!missing(SP) && !all(missing(stockID),missing(begT),missing(endT))) {
stop("Param SP and combination of stockID, begT and endT should only have one!")
}
if (missing(SP)){
SP <- data.frame(stockID=stockID,begT=begT,endT=endT)
}
check.SP(SP)
if(datasrc=="ts"){# todo
# tmpdat <- transform(SP, stockID = stockID2stockID(stockID,from="local",to="ts"),
# begT = as.character(begT),
# endT = as.character(endT))
# tmpcsv <- tempfile(fileext=".csv")
# write.csv(tmpdat,tmpcsv,row.names=FALSE,quote=FALSE,fileEncoding="GB2312")
# periodrtn <- tsRemoteCallFunc("getperiodrtn",list(tmpcsv,"close"))
# periodrtn <- plyr::laply(periodrtn,as.array)
# re <- cbind(SP, periodrtn)
}
if(datasrc %in% c("quant","local")){
}
if(drop){
return(re[,"periodrtn"])
} else {
return(re)
}
}
#' getTradeList
#'
#' @param port_ini a dataframe with cols: "stockID" (with EQ format),"amount".
#' @param port_obj a dataframe with cols: "stockID","wgt"
#' @param money_obj a numeric
#' @param splitN a integer
#' @return a list with 3 items: tradeList_N,tradeList_remain,summaryTable
#' @export
#' @author Han.Qian
getTradeList <- function(port_ini, port_obj, money_obj, splitN=1, outputstyle = c("hs")){
# get the cashflow and tradelist from the S_combine
make_tradelist_cashflow <- function(S_combine, lastday, style){
# calculate cash flow
S_money <- S_combine
date <- rep(lastday, length(S_money$stockID))
TS_money <- data.frame(date, "stockID" = S_money$stockID)
TS_money <- TS.getTech_ts(TS_money, funchar = "close()", varname = "close")
S_money$close <- TS_money$close
S_money$total <- S_money$diff * S_money$close
buy <- -sum(S_money$total[S_money$dir == 1])
sell <- sum(S_money$total[S_money$dir == 2])
net <- sell + buy
S_summary <- data.frame(buy, sell, net)
# make trade list
if(style == "hs"){
res <- S_combine
res$amount <- res$diff
res$commandPrice <- 0
res$priceMode <- 4
# res$mktCode <- getmktCode(res$stockID, format = "local")
secuMarket <- SecuMarket(res$stockID)
res$mktCode <- ifelse(secuMarket==90L,2L,1L) # 1:SH, 2:SZ
res$stockID <- stockID2tradeCode(res$stockID, IDsrc = "local")
res <- dplyr::select(res,
stockID,
dir,
amount,
commandPrice,
priceMode,
mktCode)
}
reslist <- list(res, S_summary)
return(reslist)
}
check.colnames(port_ini, c("stockID","amount"))
# if(sum(port_ini$wgt) != 1){stop("The weight does not sum up to 1.")} #does not work. Reason unknown.
check.colnames(port_obj, c("stockID","wgt"))
match.arg(outputstyle)
# find nearest trading day
today <- Sys.Date()
if(trday.is(today)){
lastday <- trday.nearby(today, by = -1)
}else{
lastday <- trday.nearest(today, dir = -1)
}
# contruct TS_new
date <- rep(lastday, length(port_obj$stockID))
TS_new <- data.frame(date, "stockID" = port_obj$stockID)
TS_new <- TS.getTech_ts(TS = TS_new, funchar = "close()",varname = "close")
TS_new$amount <- port_obj$wgt*money_obj/TS_new$close
# organize S_old and S_new
S_old <- data.frame("stockID" = port_ini$stockID, "amount_old" = port_ini$amount)
S_new <- data.frame("stockID" = TS_new$stockID, "amount_new" = TS_new$amount)
# merge
S_combine <- merge(S_old, S_new, by = "stockID", all = TRUE)
S_combine$amount_old[is.na(S_combine$amount_old)] <- 0
S_combine$amount_new[is.na(S_combine$amount_new)] <- 0
S_combine$diff <- (S_combine$amount_new - S_combine$amount_old)
S_combine$diff <- S_combine$diff / 100
S_combine$diff[S_combine$amount_new != 0] <- round(S_combine$diff[S_combine$amount_new != 0])
S_combine <- subset(S_combine, diff != 0)
S_combine$dir <- (S_combine$diff < 0) + 1L
S_combine$diff <- abs(S_combine$diff)
if(splitN > 1){
S_combine_N <- S_combine
S_combine_N$diff <- S_combine_N$diff %/% splitN
S_combine_N$diff <- S_combine_N$diff * 100
S_combine_remain <- S_combine
S_combine_remain$diff <- S_combine_remain$diff %% splitN
S_combine_remain$diff <- S_combine_remain$diff * 100
S_combine_remain <- subset(S_combine_remain, diff != 0)
if(nrow(S_combine_remain) == 0){
S_combine_remain <- NULL
}
}else{
S_combine_N <- S_combine
S_combine_N$diff <- S_combine_N$diff * 100
S_combine_remain <- NULL
}
# get the cashflow and tradelist from the S_combine
reslist_N <- make_tradelist_cashflow(S_combine_N, lastday, outputstyle)
if(!is.null(S_combine_remain)){
reslist_remain <- make_tradelist_cashflow(S_combine_remain, lastday, outputstyle)
}else{
reslist_remain <- NULL
}
# return:
tradeList_N <- reslist_N[[1]]
split <- reslist_N[[2]]
if(!is.null(S_combine_remain)){
tradeList_remain <- reslist_remain[[1]]
total <- reslist_N[[2]]*splitN + reslist_remain[[2]]
}else{
tradeList_remain <- NULL
total <- reslist_N[[2]]*splitN
}
summaryTable <- data.frame(splitN,
"buy_total" = total$buy,
"sell_total" = total$sell,
"turnover" = (total$sell-total$buy)/money_obj/2,
"net_total" = total$net,
"buy_split" = split$buy,
"sell_split" = split$sell,
"net_split" = split$net)
finalres <- list("tradeList_N" = tradeList_N, "tradeList_remain" = tradeList_remain, "summaryTable" = summaryTable)
return(finalres)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== gf.xx functions =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
#' gf_cap
#' @param bc_lambda NULL, "auto", or a specific numeric.
#' @export
#' @examples
#' system.time(re <- gf_cap(ts,datasrc = "local"))
#' system.time(re2 <- gf_cap(ts,datasrc = "memory"))
gf_cap <- function(TS,
log=FALSE,
bc_lambda = NULL,
var=c("float_cap","mkt_cap","free_cap"),
na_fill=TRUE,
varname="factorscore",
datasrc="memory"){
var <- match.arg(var)
# shrink columns, merge back later
TS_core <- TS[,c("date","stockID")]
# retrieve data
if(datasrc=="local"){
if(var=="free_cap"){
re <- gf.free_float_sharesMV(TS_core)
re <- renameCol(re,"factorscore","cap")
} else {
re <- getTech(TS_core,variables=var)
re <- renameCol(re,var,"cap")
re$cap <- re$cap/10000 # 100 million ("yi")
}
} else if(datasrc=="memory"){
memory.load()
TS_core_DT <- data.table(TS_core, key = c("stockID","date"))
marketsize_DT <- data.table(.marketsize, key = c("stockID","date"))
re <- marketsize_DT[TS_core_DT, roll = TRUE]
re <- re[, c("date","stockID",var), with = FALSE]
colnames(re) <- c("date","stockID","cap")
re <- as.data.frame(re)
}
if(log){
re$cap <- log(re$cap)
}
if(!is.null(bc_lambda)){
re <- factor_bcPower(re, fname = "cap", lambda = bc_lambda)
}
if(na_fill){
re[is.na(re$cap),"cap"] <- median(re$cap, na.rm = TRUE)
}
re <- renameCol(re,"cap",varname)
# merge back
re <- merge.x(TS, re, by = c("date","stockID"))
return(re)
}
#' fl_cap
#' @export
fl_cap <- function(log=FALSE,bc_lambda=NULL,var="float_cap",na_fill=TRUE,datasrc="memory"){
re <- list(
factorFun = "gf_cap",
factorPar = list(log=log, bc_lambda=bc_lambda, var=var, na_fill=na_fill,datasrc=datasrc),
factorDir = 1 ,
factorRefine = list(
outlier=list(method = "none", par=NULL, sectorAttr= NULL),
std=list(method = "none", log=FALSE, sectorAttr=NULL, regLists=NULL),
na=list(method = "none", sectorAttr=NULL)
),
factorName = if(log) "ln_cap" else "cap",
factorID = "",
factorType = "",
factorDesc = ""
)
return(re)
}
#' gf.free_float_shares
#' @export
gf.free_float_shares <- function(TS){
qr <- "select b.date, b.stockID,a.freeShares as 'factorscore'
from QT_FreeShares a, yrf_tmp b
where a.rowid=(
select rowid from QT_FreeShares
where stockID=b.stockID and date<=b.date
order by date desc limit 1)"
con <- db.local("main")
TS$date <- rdate2int(TS$date)
dbWriteTable(con,name="yrf_tmp",value=TS,row.names = FALSE,overwrite = TRUE)
re <- dbGetQuery(con,qr)
re <- merge.x(TS,re,by=c("date","stockID"))
re <- transform(re, date=intdate2r(date))
dbDisconnect(con)
return(re)
}
#' gf.free_float_sharesMV
#' @export
gf.free_float_sharesMV <- function(TS){
ffs <- gf.free_float_shares(TS)
close <- getTech(TS,variables='close')
re <- merge.x(ffs,close,by=c('date','stockID'))
re$factorscore <- re$factorscore*re$close
re <- re[,c("date","stockID","factorscore")]
return(re)
}
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# =============== transplanted inner functions =========
# ===================== xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ==============
# copy from RFactorModel
default.factorName <- function (factorFun, factorPar, factorDir) {
f.fun <- substring(factorFun,4)
if(is.list(factorPar)){
f.par <- paste(factorPar,collapse="_")
} else if(is.character(factorPar)){
factorPar <- gsub("\\w*=","",factorPar)
f.par <- gsub("\'","",gsub("\"","",gsub(",","_",factorPar)))
} else {
stop("The factorPar must be a list or a character string!")
}
factorName <- if(f.par != "") paste(f.fun,f.par,sep="_") else f.fun
f.dir <- if(missing(factorDir) || factorDir==1L) "" else "_"
factorName <- paste(factorName,f.dir,sep="")
return(factorName)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.