[R-SIG-Finance] quantstrat help - simple combine error using windows and walk.forward
Derek Wong
treydog999 at gmail.com
Tue Sep 30 09:34:24 CEST 2014
Hello,
I have been able to reproduce this error in Ubuntu based system as well not
just on windows. I was wondering if anyone had any insights or ways to to
solve this or create a work around. If there is any additional information
you require let me know. Please I would really appreciate help on this. It
is totally out of my depth and I am hoping that this fine community can
help.
On Wed, Sep 24, 2014 at 9:36 PM, Derek Wong <treydog999 at gmail.com> wrote:
> Hello,
>
> I am having a lot of trouble with using walk.forward.in windows. i get
> the following error. This may be related to bug #5814. If someone could
> please help me i would really appreciate it. The reproducible code below is
> based on the pair_trade example. Thanks.
>
> error calling combine function:
> <simpleError in fun(result.1, result.2, result.3, result.4, result.5,
> result.6, result.7, result.8, result.9, result.10, result.11,
> result.12, result.13, result.14, result.15, result.16, result.17,
> result.18, result.19, result.20, result.21, result.22, result.23,
> result.24, result.25, result.26, result.27, result.28, result.29,
> result.30, result.31, result.32, result.33, result.34, result.35,
> result.36, result.37, result.38, result.39, result.40, result.41,
> result.42, result.43, result.44, result.45, result.46, result.47,
> result.48, result.49, result.50, result.51, result.52, result.53,
> result.54, result.55, result.56, result.57, result.58, result.59,
> result.60, result.61, result.62, result.63, result.64, result.65,
> result.66, result.67, result.68, result.69, result.70, result.71,
> result.72, result.73, result.74, result.75, result.76, result.77,
> result.78, result.79, result.80, result.81, result.82, result.83,
> result.84, result.85, result.86, result.87, result.88, result.89,
> result.90, result.91, result.92, result.93, result.94, result.95,
> result.96, result.97, result.98, result.99, result.100, result.101,
> result.102, result.103, result.104, result.105, result.106, result.107,
> result.108, result.109, result.110, result.111, result.112, result.113,
> result.114, result.115, result.116, result.117, result.118, result.119,
> result.120, result.121, result.122, result.123, result.124, result.125,
> result.126, result.127, result.128, result.129, result.130, result.131,
> result.132, result.133, result.134, result.135, result.136,
> result.137, result.138, result.139, result.140, result.141, result.142,
> result.143, result.144, result.145, result.146, result.147, result.148,
> result.149, result.150, result.151, result.152, result.153, result.154,
> result.155, result.156, result.157, result.158, result.159, result.160,
> result.161, result.162, result.163, result.164, result.165, result.166,
> result.167, result.168, result.169, result.170, result.171,
> result.172, result.173, result.174, result.175, result.176, result.177,
> result.178, result.179, result.180): attempt to select less than one
> element>
> Error in walk.forward(pairStrat, paramset.label = "BBOPT", portfolio.st =
> portfolio1.st, :
> obj.func() returned empty result
> In addition: Warning message:
> In max(x$tradeStats$Net.Trading.PL <http://net.trading.pl/>) :
> no non-missing arguments to max; returning -Inf
>
>
> Reproducable code below:
> ------------------------------------------------------------
>
>
> #Kindly contributed to quantstrat by Garrett See
> #code borrowed heavily from existing quantstrat demos
>
> # This is a simple pairs trading example intended to illustrate how you can
> # extend existing quantstrat functionality. It uses addPosLimits to specify
> # levels and position limits, and shows how to pass a custom order sizing
> # function to osFUN
>
> # Note that it would be easier to build a spread first and treat it as a single
> # instrument instead of dealing with a portfolio of stocks.
>
> ## given 2 stocks, calculate the ratio of their notional values. If the ratio
> # falls below it's 2 stdev band, then when it crosses back above it, buy stock 1
> # and sell stock 2. If the ratio rises above it's 2 stdev band, then when it
> # crosses back below it, sell stock 1 and buy stock 2. If the ratio crosses
> # its moving average, then flatten any open positions.
>
> # The Qty of Stock A that it buys (sells) = MaxPos / lvls
> # The Qty of Stock B that is sells (buys) = MaxPos * Ratio / lvls
>
> require(quantstrat)
>
> suppressWarnings(rm("order_book.pair1",pos=.strategy))
> suppressWarnings(rm("account.pairs", "portfolio.pair1", pos=.blotter))
> suppressWarnings(rm("initDate", "endDate", "startDate", "initEq", "SD", "N",
> "symb1", "symb2", "portfolio1.st", "account.st",
> "pairStrat", "out1"))
>
> ##### PLACE DEMO AND TEST DATES HERE #################
> #
> #if(isTRUE(options('in_test')$in_test))
> # # use test dates
> # {initDate="2011-01-01"
> # endDate="2012-12-31"
> # } else
> # # use demo defaults
> # {initDate="1999-12-31"
> # endDate=Sys.Date()}
>
> initDate <- '2009-01-01'
> endDate <- '2011-05-01'
> startDate <- '2009-01-02'
> initEq <- 100000
> SD <- 2
> N <- 20
>
> MaxPos <- 1500 #max position in stockA;
> # max position in stock B will be max * ratio, i.e. no hard position limit in
> # Stock B
> lvls <- 3 #how many times to fade; Each order's qty will = MaxPos/lvls
>
> symb1 <- 'SPY' #change these to try other pairs
> symb2 <- 'DIA' #if you change them, make sure position limits still make sense
> portfolio1.st <- 'pair1'account.st <- 'pairs'
>
> getSymbols(c(symb1, symb2), from=startDate, to=endDate, adjust=TRUE)
>
> # The following function is used to make sure the timestamps of all symbols are
> # the same deletes rows where one of the stocks is missing data
> alignSymbols <- function(symbols, env=.GlobalEnv) {
> # This is a simplified version of qmao::alignSymbols()
> if (length(symbols) < 2)
> stop("Must provide at least 2 symbols")
> if (any(!is.character(symbols)))
> stop("Symbols must be vector of character strings.")
> ff <- get(symbols[1],env=env)
> for (sym in symbols[-1]) {
> tmp.sym <- get(sym,env=env)
> ff <- merge(ff, tmp.sym, all=FALSE)
> }
> for (sym in symbols) {
> assign(sym,ff[,grep(sym, colnames(ff))], env=env)
> }
> symbols
> }
> alignSymbols(c(symb1, symb2))
>
> # Define Instruments
> currency("USD")
> stock(symb1, currency="USD", multiplier=1)
> stock(symb2, currency="USD", multiplier=1)
>
> # Initialize Portfolio, Account, and Orders
> initPortf(name=portfolio1.st, c(symb1,symb2), initDate=initDate)
> initAcct(account.st, portfolios=portfolio1.st, initDate=initDate, initEq=initEq)
> initOrders(portfolio=portfolio1.st, initDate=initDate)
>
> # osFUN will need to know which symbol is leg 1 and which is leg 2 as well as
> # what the values are for MaxPos and lvls. So, create a slot in portfolio to
> # hold this info.
> pair <- c(1, 2, MaxPos, lvls)
> names(pair) <- c(symb1, symb2, "MaxPos", "lvls")
> .blotter[[paste('portfolio', portfolio1.st, sep='.')]]$pair <- pair
>
> # Create initial position limits and levels by symbol
> # allow 3 entries for long and short if lvls=3.
> addPosLimit(portfolio=portfolio1.st, timestamp=initDate, symbol=symb1,
> maxpos=MaxPos, longlevels=lvls, minpos=-MaxPos, shortlevels=lvls)
> addPosLimit(portfolio=portfolio1.st, timestamp=initDate, symbol=symb2,
> maxpos=MaxPos, longlevels=lvls, minpos=-MaxPos, shortlevels=lvls)
>
> # Create a strategy object
> pairStrat <- strategy('pairStrat')
>
> # Indicator function
> calcRatio <- function(x) {
> #returns the ratio of notional close prices for 2 symbols
> x1 <- get(x[1])
> x2 <- get(x[2])
> mult1 <- getInstrument(x[1])$multiplier
> mult2 <- getInstrument(x[2])$multiplier
> rat <- (mult1 * Cl(x1)) / (mult2 * Cl(x2))
> colnames(rat) <- 'Ratio'
> rat
> }
> # Indicator used for determining entry/exits
> Ratio <- calcRatio(c(symb1[1], symb2[1]))
>
> # Store hedge ratio in portfolio so that it's available for order sizing
> # function. In this example, the hedge ratio happens to be the same as the
> # Ratio indicator.
> .blotter[[paste('portfolio',portfolio1.st,sep='.')]]$HedgeRatio <- Ratio
> #and make a function to get the most recent HedgeRatio
> getHedgeRatio <- function(portfolio, timestamp) {
> portf <- getPortfolio(portfolio)
> timestamp <- format(timestamp,"%Y-%m-%d %H:%M:%S")
> # above line ensures you don't get last value of next day if using intraday
> # data and timestamp=midnight
> toDate <- paste("::", timestamp, sep="")
> Ratio <- last(portf$HedgeRatio[toDate])
> as.numeric(Ratio)
> }
>
> # Create an indicator - BBands on the Ratio
> pairStrat <- add.indicator(strategy=pairStrat, name = "calcRatio",
> arguments=list(x=c(symb1,symb2)))
> pairStrat <- add.indicator(strategy=pairStrat, name = "BBands",
> arguments=list(HLC=quote(Ratio), sd=SD, n=N,
> maType='SMA'),
> label = "BBands")
>
> #applyIndicators(strategy=pairStrat,mktdata=get(symb1[1])) #for debugging
>
> # Create signals - buy when crossing lower band from below, sell when crossing
> # upper band from above, flatten when crossing mavg from above or from below
> pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover",
> arguments=list(columns=c("Ratio","up"),
> relationship="lt"),
> label="cross.up")
> pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover",
> arguments=list(columns=c("Ratio","dn"),
> relationship="gt"),
> label="cross.dn")
> pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover",
> arguments=list(columns=c("Ratio","mavg"),
> relationship="lt"),
> label="cross.mid.fa")
> pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover",
> arguments=list(columns=c("Ratio","mavg"),
> relationship="gt"),
> label="cross.mid.fb")
>
> # make an order sizing function
> #######################_ORDER SIZING FUNCTION_##################################
> # check to see which stock it is. If it's the second stock, reverse orderqty and
> # orderside
> osSpreadMaxPos <- function (data, timestamp, orderqty, ordertype, orderside,
> portfolio, symbol, ruletype, ..., orderprice) {
> portf <- getPortfolio(portfolio)
> #check to make sure pair slot has the things needed for this function
> if (!any(portf$pair == 1) && !(any(portf$pair == 2)))
> stop('pair must contain both values 1 and 2')
> if (!any(names(portf$pair) == "MaxPos") || !any(names(portf$pair) == "lvls"))
> stop('pair must contain MaxPos and lvls')
>
> if (portf$pair[symbol] == 1) legside <- "long"
> if (portf$pair[symbol] == 2) legside <- "short"
> MaxPos <- portf$pair["MaxPos"]
> lvls <- portf$pair["lvls"]
> ratio <- getHedgeRatio(portfolio, timestamp)
> pos <- getPosQty(portfolio, symbol, timestamp)
> PosLimit <- getPosLimit(portfolio, symbol, timestamp)
> qty <- orderqty
> if (legside == "short") {#symbol is 2nd leg
> ## Comment out next line to use equal ordersizes for each stock.
> addPosLimit(portfolio=portfolio, timestamp=timestamp, symbol=symbol,
> maxpos=round(MaxPos*ratio,0), longlevels=lvls,
> minpos=round(-MaxPos*ratio,0), shortlevels=lvls)
> ##
> qty <- -orderqty #switch orderqty for Stock B
> }
>
> if (qty > 0) orderside = 'long'
> if (qty < 0) orderside = 'short'
>
> orderqty <- osMaxPos(data=data,timestamp=timestamp, orderqty=qty,
> ordertype=ordertype, orderside=orderside,
> portfolio=portfolio, symbol=symbol, ruletype=ruletype,
> ...)
>
> #Add the order here instead of in the ruleSignal function
> if (!is.null(orderqty) & !orderqty == 0 & !is.null(orderprice)) {
> addOrder(portfolio=portfolio, symbol=symbol,
> timestamp=timestamp, qty=orderqty, price=as.numeric(orderprice),
> ordertype=ordertype, side=orderside, replace=FALSE,
> status="open", ...=...)
> }
> return(0) #so that ruleSignal function doesn't also try to place an order
> }
> ################################################################################
>
> # Create entry and exit rules for longs and for shorts. Both symbols will get
> # the same buy/sell signals, but osMaxPos will reverse those for the second
> # symbol.
> # orderqty's are bigger than PosLimits allow. osMaxPos will adjust the orderqty
> # down to 1/3 the max allowed. (1/3 is because we are using 3 levels in
> # PosLimit)
> pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal',
> arguments=list(sigcol="cross.dn", sigval=TRUE,
> orderqty=1e6, ordertype='market',
> orderside=NULL, osFUN='osSpreadMaxPos'),
> type='enter')
> pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal',
> arguments=list(sigcol="cross.up", sigval=TRUE,
> orderqty=-1e6, ordertype='market',
> orderside=NULL, osFUN='osSpreadMaxPos'),
> type='enter')
> pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal',
> arguments=list(sigcol="cross.mid.fb", sigval=TRUE,
> orderqty='all', ordertype='market',
> orderside=NULL),
> type='exit')
> pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal',
> arguments=list(sigcol="cross.mid.fa", sigval=TRUE,
> orderqty='all', ordertype='market',
> orderside=NULL),
> type='exit')
>
>
> ## for debugging
> # applySignals(strategy=pairStrat,
> # mktdata=applyIndicators(strategy=pairStrat, mktdata=get(symb1)))
> ##
>
> out1<-applyStrategy(strategy=pairStrat, portfolios=portfolio1.st)
>
> updatePortf(Portfolio=portfolio1.st,
> Dates=paste("::", as.Date(Sys.time()), sep=''))
> updateAcct(account.st, Dates=paste(startDate, endDate, sep="::"))
> updateEndEq(account.st, Dates=paste(startDate, endDate, sep="::"))
> getEndEq(account.st, Sys.time())
>
> dev.new()
> chart.Posn(Portfolio=portfolio1.st, Symbol=symb1)
> dev.new()
> chart.Posn(Portfolio=portfolio1.st, Symbol=symb2)
> dev.new()
> chartSeries(Cl(get(symb1))/Cl(get(symb2)), TA="addBBands(n=N,sd=SD)")
>
> ret1 <- PortfReturns(account.st)
> ret1$total <- rowSums(ret1)
> #ret1
>
> if("package:PerformanceAnalytics" %in% search() ||
> require("PerformanceAnalytics",quietly=TRUE)) {
> # getSymbols("SPY", from='1999-01-01')
> # SPY.ret <- Return.calculate(SPY$SPY.Close)
> # tmp <- merge(SPY.ret,ret1$total,all=FALSE)
> dev.new()
> charts.PerformanceSummary(ret1$total, geometric=FALSE, wealth.index=TRUE)
> }
>
>
> ###############################################################################
> # R (http://r-project.org/) Quantitative Strategy Model Framework
> #
> # Package Copyright (c) 2009-2012
> # Peter Carl, Dirk Eddelbuettel, Brian G. Peterson, Jeffrey Ryan, and Joshua Ulrich
> #
> # This library is distributed under the terms of the GNU Public License (GPL)
> # for full details see the file COPYING
> #
> # $Id$
> #
> ###############################################################################
>
> ##### PLACE THIS BLOCK AT END OF DEMO SCRIPT ###################
> # book = getOrderBook(port)
> # stats = tradeStats(port)
> # rets = PortfReturns(acct)
> ################################################################
>
> #Distribution Initialization
> pairStrat <- add.distribution(strategy = pairStrat,
> paramset.label ="BBOPT",
> component.type = "indicator",
> component.label = "BBands",
> variable = list(n = seq(10,200, by = 10)),
> label = "n")
>
> pairStrat <- add.distribution(strategy = pairStrat,
> paramset.label ="BBOPT",
> component.type = "indicator",
> component.label = "BBands",
> variable = list(sd = seq(1,5,by = 0.5)),
> label = "sd")
>
>
> # Objective Function
> my.obj.func <- function(x)
> {
> # pick one of the following objective functions (uncomment)
>
> #return(max(x$tradeStats$Max.Drawdown) == x$tradeStats$Max.Drawdown)
>
> return(max(x$tradeStats$Net.Trading.PL <http://net.trading.pl/>) == x$tradeStats$Net.Trading.PL <http://net.trading.pl/>)
>
> }
>
> #WFA
> require(doParallel)
> cl <- makePSOCKcluster(2)
> registerDoParallel(cl)
>
> result <- walk.forward(pairStrat,
> paramset.label = "BBOPT",
> portfolio.st = portfolio1.st,
> account.st = account.st,
> period = "months",
> k.training = 6,
> k.testing = 3,
> obj.func = my.obj.func,
> obj.args = list(x=quote(result$apply.paramset)),
> audit.prefix = "wfa",
> anchored = FALSE,
> verbose = TRUE)
>
>
>
>
>
>
[[alternative HTML version deleted]]
More information about the R-SIG-Finance
mailing list