如何从 xgboost、caret 和 Quantmod (R) 中获得实际股票预测

How To Get Actual Stock Prediction Out of xgboost, caret and Quantmod (R)

我正在学习 R 和 Quantmod 并建立了一个非常简单的股票模型预测。我有 xgboost 和插入符模型,这是整个示例:

library(quantmod)
library(xts)
# get market data
Nasdaq100_Symbols <- c("AAPL", "ADBE", "ADI", "ADP", "ADSK", "AKAM")
getSymbols(Nasdaq100_Symbols)

# merge them all together
nasdaq100 <- data.frame(as.xts(merge(AAPL, ADBE, ADI, ADP, ADSK, AKAM)))
# set outcome variable
outcomeSymbol <- 'ADP.Volume'

# shift outcome value to be on same line as predictors
nasdaq100 <- xts(nasdaq100,order.by=as.Date(rownames(nasdaq100)))
nasdaq100 <- as.data.frame(merge(nasdaq100, lm1=lag(nasdaq100[,outcomeSymbol],-1)))
nasdaq100$outcome <- ifelse(nasdaq100[,paste0(outcomeSymbol,'.1')] > nasdaq100[,outcomeSymbol], 1, 0)

# remove shifted down volume field
nasdaq100 <- nasdaq100[,!names(nasdaq100) %in% c(paste0(outcomeSymbol,'.1'))]

# cast date to true date and order in decreasing order
nasdaq100$date <- as.Date(row.names(nasdaq100))
nasdaq100 <- nasdaq100[order(as.Date(nasdaq100$date, "%m/%d/%Y"), decreasing = TRUE),]

# calculate all day differences and populate them on same row
GetDiffDays <- function(objDF,days=c(10), offLimitsSymbols=c('outcome'), roundByScaler=3) {
  # needs to be sorted by date in decreasing order
  ind <- sapply(objDF, is.numeric)
  for (sym in names(objDF)[ind]) {
    if (!sym %in% offLimitsSymbols) {
      print(paste('*********', sym))
      objDF[,sym] <- round(scale(objDF[,sym]),roundByScaler)

      print(paste('theColName', sym))
      for (day in days) {
        objDF[paste0(sym,'_',day)] <- c(diff(objDF[,sym],lag = day),rep(x=0,day)) * -1
      }
    }
  }
  return (objDF)
}

# call the function with the following differences
nasdaq100 <- GetDiffDays(nasdaq100, days=c(1,2,3,4,5,10,20), offLimitsSymbols=c('outcome'), roundByScaler=2)

# drop most recent entry as we don't have an outcome
nasdaq100 <- nasdaq100[2:nrow(nasdaq100),]

# use POSIXlt to add day of the week, day of the month, day of the year
nasdaq100$wday <- as.POSIXlt(nasdaq100$date)$wday
nasdaq100$yday <- as.POSIXlt(nasdaq100$date)$mday
nasdaq100$mon<- as.POSIXlt(nasdaq100$date)$mon

# remove date field and shuffle data frame
nasdaq100 <- subset(nasdaq100, select=-c(date))
nasdaq100 <- nasdaq100[sample(nrow(nasdaq100)),]

# xgboost Modeling
library(xgboost)
predictorNames <- names(nasdaq100)[names(nasdaq100) != 'outcome']

set.seed(1234)
split <- sample(nrow(nasdaq100), floor(0.7*nrow(nasdaq100)))
train <-nasdaq100[split,]
test <- nasdaq100[-split,]

bst <- xgboost(data = as.matrix(train[,predictorNames]),
               label = train$outcome,
               verbose=0,
               eta = 0.1,
               gamma = 50,
               missing = NaN,
               nround = 150,
               colsample_bytree = 0.1,
               subsample = 1,
               nthread = 4,
               objective="binary:logistic")

predictions <- predict(bst, as.matrix(test[,predictorNames]), missing = NaN, outputmargin=TRUE)

library(pROC)
auc <- roc(test$outcome, predictions)
print(paste('AUC score:', auc$auc))

问题 1:
现在它训练了 70%,预测了 30%,我可以在最后打印出 AUC 分数。假设我 100% 训练并想预测明天会发生什么? IE。获取模型认为其交易量明天会上升的交易品种。

问题 2:
理想情况下,我想继续将今天收盘时的数据添加到模型中,然后让它预测明天的交易品种。现在看来我必须使用 getSymbols() 再次提取整个历史记录。有什么方法可以提取今天的数据并将其附加到该品种的 xts 对象?

问题 1 没有单一答案,而且您说 "pick tomorrow's stock symbols" 时的意思并不完全清楚(出于什么目的?)。我推测您的目标可能是尝试预测哪些股票将 outperform/underperform 在未来的某个时间范围内(例如明天的交易时段)并根据这些预测采取行动。

你的问题的答案实际上取决于你如何定义你的模型以及你将如何根据你获得的预测来选择你的股票。也许选择优化 AUC 的模型是对股票 return 标志进行分类的不错选择……或者其他指标可能效果更好(没有单一的正确答案)。

您使用的模型涉及做出许多决定。您可以按照您的建议对 return 标志使用分类,或者您可以使用回归方法而不是使用分类模型来估计 return。在决定 "pick tomorrow's stock symbols" 之前,您可能希望以某种方式过滤从模型中获得的预测。选项是无穷无尽的……困难的部分是找到真正有效的方法。而且我怀疑这里的任何人都不会告诉您出于显而易见的原因哪些方法行之有效 ;)

问题 2,

如果您想使用 quantmod 通过 Yahoo 收集数据,请为 getSymbols 使用 fromto 参数。具体看?getSymbols.yahoo、and/or打印源码(即print(getSymbols.yahoo))。此外,您可能会发现 endend(xts_object) 中一样,在发出 getSymbols 请求以更新您已存储的数据之前,可以在 xts 对象中提供最新的时间戳。

getSymbols(Symbols = "AAPL", from = "2014-01-01", to = "2014-12-31")

更新:

# Get data for 2014
sym <- "AAPL"
md <- new.env()
getSymbols(Symbols = sym, from = "2014-01-01", to = "2014-12-31", env = md)
last_date <- end(get(sym, md))
new <- getSymbols(Symbols = sym, from = last_date + 1, to = Sys.Date(), auto.assign=  FALSE)
assign(x = sym, value = rbind(get(sym, md), new), envir = md)
head(md$AAPL, 3)
# AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted
# 2014-01-02    555.68    557.03   552.02     553.13    58671200      74.11592
# 2014-01-03    552.86    553.70   540.43     540.98    98116900      72.48790
# 2014-01-06    537.45    546.80   533.60     543.93   103152700      72.88317
tail(md$AAPL, 3)
# AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted
# 2017-02-22    136.43    137.12   136.11     137.11    20745300        137.11
# 2017-02-23    137.38    137.48   136.30     136.53    20704100        136.53
# 2017-02-24    135.91    136.66   135.28     136.66    21690900        136.66

我正在处理同样的问题,但我正在尝试使用插入符号包(通过它具有的 "gafs" 函数)找到交易策略的置信度。

要回答你问题的第一部分,在 100% 的历史数据上训练你的数据,你将执行“过度拟合”,这会导致你未来的预测是非常不可靠。进一步检查此 link out for a detailed understanding about Overfitting. I recommend you explore Investopedia.com 以了解此概念。

令我惊讶的是,caret 包不仅为您提供了将数据集(即历史数据分成 70% 和 30% 的一次性块)的方法,而且还提供了一次性交叉验证的多个块比如说,遗传算法的函数。