我打开了一个新问题,因为original post已经太长了,我所得到的解决方案几乎否定了这个帖子。
以下是我发现的添加与数据周期不同的指标的解决方法。该解决方案建立在this post on the R-SIG-Finance mailing list by Brian Peterson之上。
代码有两个主要问题。
1)尽管生成了信号,策略也没有占据任何位置(运行策略后Null
中存在相应的列)
2)奇怪的是,如果mktdata
没有明确地将SMA列重命名为indMerge()
并且使用"SPY.SMA"
,则会抛出以下错误(也就是说我无法通过{{ 1 {} add.signal(columns = c("SPY.Close", SPY.SMA"))
:
columns = c("Close", "SMA")
由于我发现解决此错误的唯一方法是下面的代码,因此下面的解决方案在具有多个符号的投资组合中实际上无用。无论如何,这里是代码:
add.signal
答案 0 :(得分:0)
这是您的代码的一个工作示例(多个工具,只有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
中使用了sigcol
而不是add.rules
,因此未触发任何规则。这基本上是一个错误,并不代表任何被测试的规则。 (要自己查看此内容,请在您的browser()
版本中粘贴ruleSignal
并完成调试程序。)
将sigComparison
更改为sigCrossover
。当1
时,Sig比较会返回relationship = gt
/ TRUE,表示一列的所有值都大于另一列。你想进入Close和MA的交叉,我想。
优良作法是为规则提供唯一标签。
上面的代码将您的代码概括为多个符号。这样做的一部分涉及推广我的自定义指标,我已将其命名为AddWeeklyMA
。
关于您希望能够通过&#34; general&#34;的评论列名columns = c("Close", "SMA")
,获得所需效果的一种方法是使用sigCrossoverWrapper
创建包装函数。您还可以通过简单地在每个符号对象内重命名相关列来避免想要对表单[symbol].Close
的列名进行测试的问题(即将OH24列名称中的自动收录器名称删除,因为我&#39;在上面的代码中提到。)