2

我提出了一个新问题,因为原始帖子已经太长了,而我得出的解决方案几乎否定了该帖子。

以下是我发现的添加与您的数据不同的周期性指标的解决方法。该解决方案是基于Brian Peterson 在 R-SIG-Finance 邮件列表上的这篇文章构建的。

代码有两个主要问题。

1) 尽管生成了信号,但该策略不占用任何位置(mktdata运行该策略后存在相应的列)

2)奇怪的是,如果indMerge()没有将 SMA 列显式重命名为"SPY.SMA"并使用,add.signal(columns = c("SPY.Close", SPY.SMA"))则会引发以下错误(也就是说我无法传入:columns = c("Close", "SMA")add.signal

Warning message:
In match.names(columns, colnames(data)) :
  all columns not located in Close SMA for SPY.Open SPY.High SPY.Low SPY.Close 
SPY.Volume SPY.Adjusted SMA Cl.gt.SMA

由于我发现解决此错误的唯一方法是下面的代码,因此下面的解决方案在具有多个符号的投资组合中实际上是无用的。无论如何,这是代码:

require(quantstrat)
require(quantmod)
require(FinancialInstrument)

symbols = "SPY"

initDate="2000-01-01"
from="2003-01-01"
to="2016-12-31"
options(width=70)

options("getSymbols.warning4.0"=FALSE)

#set account currency and system timezone
currency('USD')
stock("SPY",currency="USD",multiplier=1)
Sys.setenv(TZ="UTC")

#trade sizing and initial equity settings
tradeSize <- 1e6
initEq <- tradeSize*length(symbols)

#Brians code 
#>> http://r.789695.n4.nabble.com/R-Quantstrat-package-question-td3772989.html
indMerge <- function(x, period, k, SMAlength, maType){
  mktdata <- getSymbols(x, auto.assign = FALSE)

  xW = to.period(mktdata, period = period, k = k, indexAt = "startof")
  smaW = wSMA = SMA(Cl(xW), n = SMAlength, maType = maType)

  x <- cbind(mktdata, smaW[paste(first(index(mktdata)) ,
                                 last(index(mktdata)) , sep='/')])
  colnames(x)[ncol(x)] = paste("SPY", ".", "SMA", sep = "")
  x <- na.locf(x)
  x
} 

#get the data
getSymbols(symbols, from=from, to=to, src="yahoo", adjust=TRUE)

#apply the weekly SMA to the data without the use of add.indicator
SPY = indMerge(x = symbols, period = "weeks", k = 1, SMAlength = 14, maType = "SMA")

#set up the portfolio, account and strategy
strategy.st <- portfolio.st <- account.st <- "mtf.strat"
rm.strat(strategy.st)

initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, 
              currency='USD',initEq=initEq)
initOrders(portfolio.st, initDate=initDate)

strategy(strategy.st, store=TRUE)

#add signals
add.signal(strategy.st, name = "sigComparison", arguments = list(columns = 
              c("SPY.Close", "SPY.SMA"), relationship = "gt"), label = "Cl.gt.SMA")
add.signal(strategy.st, name = "sigComparison", arguments = list(columns = 
              c("SPY.Close", "SPY.SMA"), relationship = "lt"), label = "Cl.lt.SMA")

#test = applySignals(strategy.st, mktdata = SPY)

#add.rules
add.rule(strategy.st, name = "ruleSignal", arguments = list(sigCol = "Cl.gt.SMA", 
              sigval = 1, orderqty = 900, ordertype = "market", orderside = "long"), 
              type = "enter")

add.rule(strategy.st, name = "ruleSignal", arguments = list(sigCol = "Cl.lt.SMA", 
              sigval = 1, orderqty = "all", ordertype = "market", orderside = "long"), 
              type = "exit")


strat = getStrategy(strategy.st)
summary(strat)

#apply the strategy and get the transactions
applyStrategy(strategy = strategy.st, portfolios = portfolio.st)
getTxns(Portfolio = portfolio.st, Symbol = "SPY")
4

1 回答 1

1

这是您的代码的一个工作示例(不止一种仪器,只是 2017 年的数据,使示例更易于测试),我希望通过调整解决您的所有问题:

require(quantstrat)
require(quantmod)
require(FinancialInstrument)

symbols = c("SPY", "GOOG")

initDate="2000-01-01"
from="2017-01-01"
to=Sys.Date()
options(width=70)

options("getSymbols.warning4.0"=FALSE)

#set account currency and system timezone
currency('USD')
stock("SPY",currency="USD",multiplier=1)
stock("GOOG", currency = "USD")
Sys.setenv(TZ="UTC")

tradeSize <- 1e6
initEq <- tradeSize*length(symbols)

getSymbols(symbols, from=from, to=to, src="yahoo", adjust=TRUE)

rm.strat(strategy.st)

initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, 
         currency='USD',initEq=initEq)
initOrders(portfolio.st, initDate=initDate)

strategy(strategy.st, store=TRUE)



#SPY = indMerge(x = symbols, period = "weeks", k = 1, SMAlength = 14, maType = "SMA")
#Brians code 
#>> http://r.789695.n4.nabble.com/R-Quantstrat-package-question-td3772989.html
AddWeeklyMA <- function(x, period, k, SMAlength, maType){
  # Don't use getSymbols here. It is redundant.  Use x, which is the daily OHLC for the symbol you've selected
  #mktdata <- getSymbols(x, auto.assign = FALSE)

  # YOU MUST USE indexAt as "endof" instead of "startof" otherwise you introduce look ahead bias in your weekly indicator signal. (Sees the future in the backtest)  Bad!!!
  xW <- to.period(x, period = period, k = k, indexAt = "endof")
  wSMA <- SMA(Cl(xW), n = SMAlength, maType = maType)

  y <- merge(wSMA, xts(, order.by = index(x)), fill = na.locf) 
  x <- y[index(x)] # just to be safe, in case any extra timestamps where generated in the merge above to make y.
  # Note that the column name of x is simply "SMA" rather than "SPY.SMA" etc.  You can of course relabel the column name here if you wish.
  x
} 

add.indicator(strategy = strategy.st, 
              name = "AddWeeklyMA", 
              arguments = list(x = quote(mktdata),
                               period = "weeks",
                               k = 1,
                               SMAlength = 14,
                               maType = "SMA"),
              label = "weeklyMA")


#add signals.
# one way to handle column names is simply rename the OHLC columns, removing the name of the symbol.  e.g. .Open .High .Low .Close, then pass columns = c(".Close", "SMA.weeklyMA") which will work for multiple symbols.
#add.signal(strategy.st, name = "sigCrossover", arguments = list(columns = 
#                                                                   c("SPY.Close", "SMA.weeklyMA"), relationship = "gt"), label = "Cl.gt.SMA")

sigCrossoverWrapper <- function(x, label, col1 = "Close", col2 = "weeklyMA", relationship) {
  Col1 <- grep(pattern = col1, colnames(x), value = TRUE)[1]
  Col2 <- grep(pattern = col2, colnames(x), value = TRUE)[1]  
  # Basic checks.  If we can't find a column name like col1, col2, throw an error. also use the [1] index, particular for col1 values like "Close", in case multiple column labels are returned that all contain "Close".  The assumption is that the OHLC data are always the first for columns in the symbol data object.
  stopifnot(length(Col1) == 1)
  stopifnot(length(Col2) == 1)
  columns <- c(Col1, Col2)
  r <- sigCrossover(data = x, label = label, columns = columns, relationship = relationship)
  r
}

add.signal(strategy.st, name = "sigCrossoverWrapper", arguments = list(x = quote(mktdata), 
                                                                       col1 = "Close", 
                                                                       col2 = "weeklyMA", 
                                                                       relationship = "gt"), 
           label = "Cl.gt.SMA")

add.signal(strategy.st, name = "sigCrossoverWrapper", arguments = list(x = quote(mktdata), 
                                                                       col1 = "Close", 
                                                                       col2 = "weeklyMA", 
                                                                       relationship = "lt"), 
           label = "Cl.lt.SMA")

add.rule(strategy.st, name = "ruleSignal", arguments = list(sigcol = "Cl.gt.SMA", 
                                                            sigval = 1, 
                                                            orderqty = 900, 
                                                            ordertype = "market", 
                                                            orderside = "long"), 
         label = "enterL", # Add label names for rules.
         type = "enter")

add.rule(strategy.st, name = "ruleSignal", arguments = list(sigcol = "Cl.lt.SMA", 
                                                            sigval = 1, 
                                                            orderqty = "all", 
                                                            ordertype = "market", 
                                                            orderside = "long"), 
         label = "exitL", # Add label names for rules.
         type = "exit")


applyStrategy(strategy = strategy.st, portfolios = portfolio.st)

# [1] "2017-07-06 00:00:00 GOOG 900 @ 906.690002"
# [1] "2017-07-07 00:00:00 GOOG -900 @ 918.590027"
# [1] "2017-07-10 00:00:00 GOOG 900 @ 928.799988"
# [1] "2017-07-28 00:00:00 GOOG -900 @ 941.530029"
# [1] "2017-09-14 00:00:00 GOOG 900 @ 925.109985"
# [1] "2017-09-15 00:00:00 GOOG -900 @ 920.289978"
# [1] "2017-09-28 00:00:00 GOOG 900 @ 949.5"
# [1] "2017-04-18 00:00:00 SPY 900 @ 231.585741736316"
# [1] "2017-08-21 00:00:00 SPY -900 @ 241.70049982835"
# [1] "2017-08-23 00:00:00 SPY 900 @ 243.352306359548"

for (sym in symbols) {
  print(paste0("txns for ", sym, ":"))
  print(getTxns(Portfolio = portfolio.st, Symbol = sym)  )
}

您的代码有几个问题:

没有规则被触发,因为您使用sigCol而不是sigcolin add.rules。这基本上是一个错误,意味着没有任何规则被测试。(要亲自查看,请坚持browser()使用您的版本ruleSignal并通过调试器)。

更改sigComparisonsigCrossover1当 时,对于一列的所有值大于另一列的Sig 比较返回/TRUE relationship = gt。我想你想在收盘价和 MA 的交叉点上入场。

为规则提供唯一标签是一种很好的做法。

上面的代码将您的代码概括为多个符号。这样做的一部分涉及概括我命名的自定义指标AddWeeklyMA

关于您对希望能够传递“通用”列名的评论,columns = c("Close", "SMA")获得所需效果的一种方法是像我一样制作一个包装函数sigCrossoverWrapper。您还可以通过简单地重命名每个符号对象内的相关列来避免想要针对表单的列名进行测试的[symbol].Close问题(即,将代码名称放在 OHLC 列名中,正如我在上面的代码中提到的那样) .

于 2017-11-08T06:22:14.420 回答