Goal: produce a stop limit using time stamp (aka not a trailing stop). Most of the coding is stolen from Ilya Kipnis' design for calculating position size based on ATR. The link to the code is in comments, below, so it could be reproduced.
I'm fairly certain that the function produces the desired effect, but I don't know what type of information the order.price requires. It seems I need to indicate that this is a function, not a number.
I'm running the following function in a chain order, to calculate order.price.
stopATR <- function(atrMod="") {
atrString <- paste0("atr",atrMod)
atrCol <- grep(atrString, colnames(mktdata))
atrTimeStamp <- mktdata[timestamp, atrCol]
atrStop <- atrTimeStamp * pctATR*100
atrString <- paste0("EMA.currentPrice")
priceCol <- grep(atrString, colnames(mktdata))
currentPrice <- mktdata[timestamp, priceCol]
out <- currentPrice-atrStop
colnames(out) <- "atrStopLoss"
return(out)
}
#rules
add.rule(strategy.st, name="ruleSignal",
arguments=list(sigcol="buyTrigger", sigval=TRUE, ordertype="market",
orderside="long", replace=FALSE, prefer="Open",
osFUN=osDollarATR, tradeSize=tradeSize,
pctATR=pctATR, atrMod="X"),
type="enter", path.dep=TRUE,
label="newEntry")
add.rule(strategy.st, name="ruleSignal",
arguments=list(sigcol="buyTrigger", sigval=TRUE, ordertype="stoplimit",
orderside="long", replace=FALSE,
orderqty='all',
order.price=stopATR,
orderset="orders"),
type="chain",
parent="newEntry",
label="stopLossLong",
path.dep=TRUE)
The error is:
Error in as.numeric(orderprice) :
cannot coerce type 'closure' to vector of type 'double'
I wrote the following function and run it through add.indicator. Then I just refer to the column in mktdata to use it as a stoplimit.
stopOut <- function (x, n, maType, HLC, pctATR) {
EMA <- EMA(x, n, maType=maType)
ATR <- ATR(HLC, n=n, maType=maType)
ATR <- ATR$atr
atrStop <- EMA - (ATR*100*pctATR)
return(atrStop)
}
add.indicator(strategy.st, name="stopOut",
arguments=list(x=quote(HLC(mktdata)), n=period, wilder=TRUE, HLC=quote(HLC(mktdata)), pctATR=pctATR),
label="stopLimit")
add.rule(strategy.st, name="ruleSignal",
arguments=list(sigcol="buyTrigger",
sigval=TRUE,
ordertype="stoplimit",
orderside="long",
replace=FALSE,
orderqty='all',
order.price=quote(mktdata$EMA.stopLimit[timestamp]),
orderset="orders"),
type="chain",
parent="newEntry",
label="takeProfitLong",
path.dep=TRUE)
Related
I can't figure out how I can backtest a strategy trading ticker X and ticker Y based on a signal from a synthetic asset created from a combination of ticker X and Y.
The data background is a list of XTS series of tickers. Right now I am solving it by trading the synthetic asset, not the individual assets:
initDate = "1990-01-01"
from = "2010-07-22"
to = "2016-12-31"
initeq = 1000000
NBDG <- lXTS[[1]]
UKPSPIR <- lXTS[[2]]
CoIntV <- list(1, -9.90)
Diff <- NBDG - as.numeric(CoIntV[2])*UKPSPIR
colnames(Diff) <- "Close"
strategy.st <- portfolio.st <- account.st <- "test"
rm.strat(strategy.st)
initPortf(portfolio.st, symbols = list("Diff"), initDate=initDate)
initAcct(account.st, portfolios=portfolio.st)
initOrders(portfolio.st)
strategy(strategy.st, store = TRUE)
Diff <- cbind(Diff, BBands(Diff, maType="SMA", n=12, sd=2))
add.signal(strategy=strategy.st, name="sigCrossover",
arguments = list(columns=c("Close", "up"),
relationship="gt"),
label="cl.gt.up")
add.signal(strategy=strategy.st, name="sigCrossover",
arguments = list(columns=c("Close", "dn"),
relationship="lt"),
label="cl.lt.dn")
add.signal(strategy=strategy.st, name="sigCrossover",
arguments = list(columns=c("Close", "mavg"),
relationship="gte"),
label="mid.cross.frombelow")
add.signal(strategy=strategy.st, name="sigCrossover",
arguments = list(columns=c("Close", "mavg"),
relationship="lte"),
label="mid.cross.fromabove")
tmp <- applySignals(strategy = strategy.st, mktdata=Diff)
add.rule(stratBBands,name='ruleSignal',
arguments = list(sigcol="cl.gt.up",
sigval=TRUE,
orderqty=-1,
ordertype='market',
orderside=NULL,
threshold=NULL),
type='enter')
add.rule(stratBBands,name='ruleSignal',
arguments = list(sigcol="cl.lt.dn",
sigval=TRUE,
orderqty=1,
ordertype='market',
orderside=NULL,
threshold=NULL),
type='enter')
add.rule(stratBBands,name='ruleSignal',
arguments = list(sigcol="mid.cross.frombelow",
sigval=TRUE,
orderqty='all',
ordertype='market',
orderside=NULL,
threshold=NULL),
type='exit')
add.rule(stratBBands,name='ruleSignal',
arguments = list(sigcol="mid.cross.fromabove",
sigval=TRUE,
orderqty='all',
ordertype='market',
orderside=NULL,
threshold=NULL),
type='exit')
out <- applyStrategy(strategy=strategy.st,portfolios=portfolio.st)
updatePortf(portfolio.st)
dateRange <- time(getPortfolio(portfolio.st)$summary)[-1]
updateAcct(portfolio.st,dateRange)
updateEndEq(account.st)
I get the following warnings when doing so:
1: In getInstrument(symbol) :
instrument Diff not found, please create it first.
2: In getInstrument(Symbol) :
instrument Diff not found, please create it first.
3: In .updatePosPL(Portfolio = pname, Symbol = as.character(symbol), :
Instrument Diff not found, things may break
but I am getting results out.
Does anyone know anything?
You have not defined your instruments, which quantstrat expects (although your simulation probably still runs OK). Just as the warning says to you.... Define your synthetic instrument before you run the strategy (before rm.strat in your code above, say).
You also should define your currency (not sure if it is GBP, but by default it is USD, which I assume here):
currency(c("USD"))
spread(primary_id = 'Diff', currency = "USD", members = c('NBDG','UKPSPIR'), memberratio = c(1, -9.90))
Run your code with these changes and the warnings will disappear.
(Also, in your code you post, you have arbitrarily changed from strategy.st to stratBBands at add.rules.)
So I am trying to just test simple strategy, when open goes crosses moving average up buy, vise versa;
Signal seems to work fine with View(mktdata) but for some reason it's not executing the trades.
Any insights?
rm(list=ls(.blotter), envir=.blotter)
rm.strat(strategy.st)
strategy.st<-"firststrat"
portfolio.st<-"firststrat"
account.st<-"firststrat"
#assignsymbol
getSymbols("SPY",auto.assign=TRUE,adjust=TRUE)
initdate<-"2009-01-01"
from<-"2010-01-01"
to<-"2016-11-01"
Sys.setenv(TZ="UTC")
currency("USD")
stock("SPY",currency="USD",multiplier=1)
tradesize<-10000
inieq<-100000
rm.strat(portfolio.st)
initPortf(portfolio.st,symbols="SPY",initDate=initdate,currency='USD')
initAcct(account.st,portfolios = portfolio.st,initDate = initdate,initEq = inieq,currency="USD")
initOrders(portfolio = portfolio.st,initDate = initdate)
strategy(strategy.st,store=TRUE)
add.indicator(strategy = strategy.st,name="EMA",arguments=list(x=quote(Cl(mktdata)),n=50),label="EMA50")
#if closing price goes over moving average 50 and TSi fference is less then 0.15, then long
#short when closing price touches below original closing price by x(depends on atr? previous lows?)
add.signal(strategy.st,name="sigCrossover",
arguments = list(columns=c("Close","EMA50"),
relationship="gt"),
label="crossentry"
)
add.signal(strategy.st,name="sigCrossover",
arguments = list(columns=c("Close","EMA50"),
relationship="lt"),
label="crossexit"
)
add.rule(strategy.st,name="ruleSignal",
arguments=list(sigcol = "crossentry",
sigval=TRUE,
orderqty="all",
ordertype="market",
orderside="long",
replace=FALSE,
prefer="Open",
path.dep=TRUE
),
type="enter"
)
add.rule(strategy.st,name="ruleSignal",
arguments=list(sigcol = "crossexit",
sigval=TRUE,
orderqty="all",
ordertype="market",
orderside="long",
replace=FALSE,
prefer="Open",
path.dep=TRUE
),
type="exit"
)
out <- applyStrategy(strategy = strategy.st, portfolios = portfolio.st)
View(mktdata)
> out
NULL
You need to specify an orderqty value indicating the size of each trade for market orders to enter positions (not "all", which can be used for exits, stops, take profits). Otherwise the strategy doesn't know how what the trade sizes should actually be.
You code should run if you modify your entry rule like this:
add.rule(strategy.st,name="ruleSignal",
arguments=list(sigcol = "crossentry",
sigval=TRUE,
orderqty= 100, # numeric qty value
ordertype="market",
orderside="long",
replace=FALSE,
prefer="Open",
path.dep=TRUE
),
type="enter"
)
I am new to R and am trying to create a very simple trading strategy (Buy the VIX when it's up by 2%, sell it when it's down by 2%). I am getting an error with the add.signal command: "Error in match.names(column, colnames(data)) :
argument "column" is missing, with no default."
I've searched everywhere and I can't seem to find the fix or understand what R is trying to tell me. Any input would be appreciated.
require(quantstrat)
options("getSymbols.warning4.0"=FALSE) #suppress warnings
rm(list=ls(.blotter), envir=.blotter) #house cleaning, clears blotter
rm(list=ls(.strategy), envir=.strategy)#clears strategy
rm.strat(qs.portfolio)#clear the portfolio environment
rm.strat(qs.strategy)#clear the strategy environment
rm.strat(qs.account)#clear the account environment
currency("USD")
stock("VIX",currency="USD",multiplier=1)
# system settings
initDate <- '2013-12-31'
startDate <- '2014-01-01'
endDate <- '2016-04-07'
initEq <- 100000
Sys.setenv(TZ="UTC") #Timezone
getSymbols('^VIX', from=startDate, to=endDate, index.class="POSIXct", adjust=TRUE)
VIX$lagROC <- lag(round(ROC(Cl(VIX)), 4), n=1, type="discrete")
VIX$lagROC[is.na(VIX$lagROC)] <- 0
# initialize portfolio, account, orders
qs.strategy <- "qsJones"
initPortf(qs.strategy,'VIX')
initAcct(qs.strategy,portfolios=qs.strategy, initEq=initEq)
initOrders(portfolio=qs.strategy)
#create a new strategy object
strategy(qs.strategy,store=TRUE)
strat <- getStrategy(qs.strategy)
thresh1 <- (.02*-1)
thresh2 <- .02
add.indicator(strategy = qs.strategy, name = "ROC",
arguments = list(x = quote(Cl(mktdata)), n=1), label="lagROC")
test <- applyIndicators(qs.strategy, VIX)
add.signal(qs.strategy, name="sigThreshold",
arguments=list(column="lagROC", threshold=thresh1, relationship="lte", cross=FALSE),
label="lt.ROCThresh1")
add.signal(qs.strategy, name="sigThreshold",
arguments=list(column="lagROC", threshold=thresh2, relationship="gte", cross=FALSE),
label="gt.ROCThresh2")
test <- applySignals(qs.strategy, test)
# exit when lagROC < .02
add.rule(qs.strategy, name='ruleSignal',
arguments=list(sigcol="Cl.lt.lagROC", sigval=TRUE, replace=FALSE, orderqty='all',
ordertype='market', orderside='long'),
type='exit', path.dep=TRUE)
# go long when lagROC > .02
add.rule(qs.strategy, name='ruleSignal',
arguments=list(sigcol="Cl.gt.lagROC", sigval=TRUE, replace=FALSE, orderqty=1500,
ordertype='market', orderside='long'),
type='enter', path.dep=TRUE)
applyStrategy(strategy=qs.strategy , portfolios=qs.strategy)
tail(mktdata)
mktdata["2014"]
getTxns(Portfolio=qs.strategy, Symbol="VIX")
Your add.signal calls create two columns: "lt.ROCThresh1" and "gt.ROCThresh2", while your add.rule calls reference columns "Cl.lt.lagROC" and "Cl.gt.lagROC" (which don't exist).
You need to either:
Change the label= argument in your add.signal calls from "lt.ROCThresh1" and "gt.ROCThresh2" to "Cl.lt.lagROC" and "Cl.gt.lagROC", respectively, or
Change the sigcol= argument in your add.rule calls from "Cl.lt.lagROC" and "Cl.gt.lagROC" to "lt.ROCThresh1" and "gt.ROCThresh2", respectively.
I get an error when running my quantmod code:
´Error in .xts(e, .index(e1), .indexCLASS = indexClass(e1), .indexFORMAT = indexFormat(e1), :
index length must match number of observations´
My code (partly from http://rbresearch.wordpress.com/2013/02/19/momentum-in-r-part-4-with-quantstrat/) is:
# qstratRank.R
qstratRank <- function(symbols, init.equity=100000, top.N=1,
max.size=1000, max.levels=1) {
# The qstratRank function uses the quantstrat framework to backtest a
# ranking or relative strength strategy
#
# args
# symbols : character vector of symbols
# init.equity : initial equity
# top.N : trade the top N ranked assets
# max.size : maximum position size
# max.levels : maximum levels to scale in a trade
# max.size and max.levels are passed to addPosLimit
#
# return value
# returns a list: end.eq, returns, book, stats
# remove variables
suppressWarnings(rm("order_book.Rank", pos=.strategy))
suppressWarnings(rm("account.Rank", "portfolio.Rank", pos=.blotter))
suppressWarnings(rm("account.st", "port.st", "stock.str", "stratRank",
"initDate", "initEq", 'start_t', 'end_t'))
# set initial variables
initDate <- "1900-01-01"
initEq <- init.equity
port.st <- "Rank"
account.st <- "Rank"
# trade the top "N" ranked symbols
N <- top.N
# initialize quantstrat objects
initPortf(port.st, symbols=symbols, initDate=initDate)
initAcct(account.st, portfolios=port.st, initDate=initDate,initEq=initEq)
initOrders(portfolio=port.st, initDate=initDate)
# initialize a strategy object
stratRank <- strategy("Rank")
# there are two signals
# the first signal is when Rank is less than or equal to N
# (i.e. trades the #1 ranked symbol if N=1)
stratRank <- add.indicator(strategy=stratRank, name="SMA",
arguments=list(x = quote(Cl(mktdata)), n=50), label="SMA50")
stratRank <- add.signal(stratRank, name="sigComparison",
arguments=list(columns=c("Close", "SMA50"), relationship="gt"), label="Cl.gt.SMA50")
# the second signal is when Rank is greter than or equal to N
# (i.e. trades the #1 ranked symbol if N=1)
stratRank <- add.signal(strategy=stratRank, name="sigThreshold",
arguments=list(threshold=N, column="Rank",
relationship="gt", cross=FALSE),
label="Rank.gt.N")
# add buy rule
stratRank <- add.rule(strategy=stratRank, name='ruleSignal',
arguments = list(sigcol="Cl.gt.SMA50", sigval=TRUE,
orderqty=max.size, ordertype='market',
orderside='long', pricemethod='market',
replace=FALSE, osFUN=osMaxPos),
type='enter', path.dep=TRUE)
stratRank <- add.rule(strategy=stratRank, name='ruleSignal',
arguments = list(sigcol="Rank.lte.N", sigval=TRUE,
orderqty=max.size, ordertype='market',
orderside='long', pricemethod='market',
replace=FALSE, osFUN=osMaxPos),
type='enter', path.dep=TRUE)
# add exit rule
stratRank <- add.rule(strategy = stratRank, name='ruleSignal',
arguments = list(sigcol="Rank.gt.N", sigval=TRUE,
orderqty='all', ordertype='market',
orderside='long', pricemethod='market',
replace=FALSE),
type='exit', path.dep=TRUE)
#set max position size and levels
for(symbol in symbols){ addPosLimit(port.st, symbol, initDate, max.size, max.levels) }
print("setup completed")
# apply the strategy to the portfolio
start_t <- Sys.time()
out <- try(applyStrategy(strategy=stratRank, portfolios=port.st))
end_t <- Sys.time()
print(end_t-start_t)
# update Portfolio
start_t <- Sys.time()
updatePortf(Portfolio=port.st, Dates=paste('::', as.Date(Sys.time()), sep=''))
end_t <- Sys.time()
print("trade blotter portfolio update:")
print(end_t - start_t)
# update account
updateAcct(account.st)
# update ending equity
updateEndEq(account.st)
# get ending equity
eq <- getEndEq(account.st, Sys.Date()) + initEq
# view order book to confirm trades
order.book <- getOrderBook(port.st)
# get trade statistics
stats <- tradeStats(port.st)
# portfolio returns
ret1 <- PortfReturns(port.st)
ret1$total <- rowSums(ret1, na.rm=TRUE)
return(list(end.eq=eq, returns=ret1, book=order.book, stats=stats))
}
I then run:
bt <- qstratRank(symbols=symbols, init.equity=100000, top.N=2,
max.size=1000, max.levels=1)
The issue might be with my ´SMA50´ indicator, and signal and rule.
Any ideas?
Best Regards
How to enter orders that cancel each other in quantstrat? For example, once I enter a trade, I immediately open two orders: "stop loss" and "take profit". Once one gets filled, the other will be cancelled.
#Enter signal
strategy <- add.rule(strategy, name="ruleSignal",
arguments=list(sigcol="EnterBuy", sigval=TRUE, orderqty=100,
ordertype="market", orderside="long",
pricemethod="market", osFUN=osMaxPos),
type="enter", path.dep=TRUE)
#Stop loss
strategy <- add.rule(strategy, name="ruleSignal",
arguments=list(sigcol="EnterBuy", sigval=TRUE,
orderqty="all", ordertype="stoplimit",
orderside="short", threshold=-5,
tmult=FALSE),
type="exit", path.dep=TRUE)
#Take profit
strategy <- add.rule(strategy, name="ruleSignal",
arguments=list(sigcol="EnterBuy", sigval=TRUE,
orderqty="all", ordertype="stoplimit",
orderside="short", threshold=5,
tmult=FALSE),
type="exit", path.dep=TRUE)
Currently, they are working independently.
SVN r 1010 adds code to quantstrat to make it easier to use OCO (One Cancels Other) order sets. There is an example in the 'macd' demo here which uses the newly exposed orderset parameter to provide OCO functionality on the exit orders.
You will need to be using current svn (r1010 or later) to use this functionality. I'll also note that the order sizing functionality is a bit broken right now, we're working on it.
Your example, to use order sets, would look something like this:
#Enter signal
strategy <- add.rule(strategy, name="ruleSignal",
arguments=list(sigcol="EnterBuy", sigval=TRUE, orderqty=100,
ordertype="market", orderside="long",
pricemethod="market", osFUN=osMaxPos),
type="enter", path.dep=TRUE)
#Stop loss
strategy <- add.rule(strategy, name="ruleSignal",
arguments=list(sigcol="EnterBuy", sigval=TRUE,
orderqty="all", ordertype="stoplimit",
orderside="long", threshold=-5,
tmult=FALSE, orderset='altexits'),
type="exit", path.dep=TRUE)
#Take profit
strategy <- add.rule(strategy, name="ruleSignal",
arguments=list(sigcol="EnterBuy", sigval=TRUE,
orderqty="all", ordertype="stoplimit",
orderside="long", threshold=5,
tmult=FALSE, orderset='altexits'),
type="exit", path.dep=TRUE)
Note the addition of the orderset='altexits' parameter to the arguments list for ruleSignal.