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.
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.)
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)
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
I'm still playing around with Guy Yollins quantstrat example. In this example he buys 1000 shares of the SPY when it crosses its 10 day MA. Since we define an initial equity, is it possible to always buy for the whole portfolio amount and not just 900 shares? 'all' didn't work for the enter, just the exit..
if (!exists('.blotter')) .blotter <- new.env()
if (!exists('.strategy')) .strategy <- new.env()
if (!exists('.instrument')) .instrument <- new.env()
currency("USD")
stock("SPY",currency="USD",multiplier=1)
ls(envir=FinancialInstrument:::.instrument)
initDate <- '1997-12-31'
startDate <- '1998-01-01'
endDate <- '2013-07-31'
initEq <- 1e6
Sys.setenv(TZ="UTC")
getSymbols('SPY', from=startDate, to=endDate, adjust=T)
SPY=to.monthly(SPY, indexAt='endof')
SPY$SMA10m <- SMA(Cl(SPY), 10)
# inz portfolio, account
qs.strategy <- "qsFaber"
rm.strat(qs.strategy) # remove strategy etc. if this is a re-run
initPortf(qs.strategy,'SPY', initDate=initDate)
initAcct(qs.strategy,portfolios=qs.strategy, initDate=initDate, initEq=initEq)
initOrders(portfolio=qs.strategy,initDate=initDate)
# instantiate a new strategy object
strategy(qs.strategy,store=TRUE)
add.indicator(strategy = qs.strategy, name = "SMA",
arguments = list(x = quote(Cl(mktdata)), n=10), label="SMA10")
add.signal(qs.strategy,name="sigCrossover",
arguments = list(columns=c("Close","SMA10"),relationship="gt"),
label="Cl.gt.SMA")
add.signal(qs.strategy,name="sigCrossover",
arguments = list(columns=c("Close","SMA10"),relationship="lt"),
label="Cl.lt.SMA")
add.rule(qs.strategy, name='ruleSignal',
arguments = list(sigcol="Cl.gt.SMA", sigval=TRUE, orderqty=900,
ordertype='market', orderside='long', pricemethod='market'),
type='enter', path.dep=TRUE)
add.rule(qs.strategy, name='ruleSignal',
arguments = list(sigcol="Cl.lt.SMA", sigval=TRUE, orderqty='all',
ordertype='market', orderside='long', pricemethod='market'),
type='exit', path.dep=TRUE)
out <- applyStrategy(strategy=qs.strategy , portfolios=qs.strategy)
updatePortf(qs.strategy)
updateAcct(qs.strategy)
updateEndEq(qs.strategy)
myTheme<-chart_theme()
myTheme$col$dn.col<-'lightblue'
myTheme$col$dn.border <- 'lightgray'
myTheme$col$up.border <- 'lightgray'
# plot performance
chart.Posn(qs.strategy, Symbol = 'SPY', Dates = '1998::',theme=myTheme)
plot(add_SMA(n=10,col=4, on=1, lwd=2))
You cannot use orderqty="all" on entries because "all" refers to the current position size (i.e., when you want to exit the entire position).
It's possible to purchase an amount equal to the total available portfolio equity, but you have to define a custom order sizing function. And that function would necessarily have to mark the book (using updatePortf) in order to determine the amount of available equity.
Here is a toy example that achieves what you want.
You need to introduce an order sizing function.
Take a look at the arguments to the function ruleSignal (e.g. formals(ruleSignal) and ?ruleSignal).
You'll see there is an argument osFUN, which is where you can write your custom function that will determine how you order size.
You modify the appropriate parameters in add.rule to introduce ordersizing (on entry trades).
osFUN_all_eq <- function (data, timestamp, orderqty, ordertype, orderside, equity, portfolio, symbol, ruletype, ..., initEq) {
datePos <- format(timestamp,"%Y-%m-%d")
updatePortf(Portfolio = portfolio, Symbol = symbol, Dates = paste0(start(data), "/", datePos))
trading_pl <- sum(.getPortfolio(portfolio)$summary$Net.Trading.PL)
# The total equity in the strategy for this symbol (and this symbol only in isolation always, as this is how quantstrat by default works with applyStrategy)
equity <- initEq + trading_pl
ClosePrice <- getPrice(data, prefer = "Close")[datePos]
UnitSize <- as.numeric(trunc(equity / ClosePrice))
UnitSize <- osMaxPos(data, timestamp, UnitSize, ordertype, orderside, portfolio, symbol, ruletype, digits=0)
UnitSize
}
library(quantstrat)
currency("USD")
stock("SPY",currency="USD",multiplier=1)
initDate <- '1997-12-31'
startDate <- '1998-01-01'
endDate <- '2013-07-31'
initEq <- 1e6
Sys.setenv(TZ="UTC")
getSymbols('SPY', from=startDate, to=endDate, adjust=T)
SPY=to.monthly(SPY, indexAt='endof')
SPY$SMA10m <- SMA(Cl(SPY), 10)
qs.strategy <- "qsFaber"
rm.strat(qs.strategy) # remove strategy etc. if this is a re-run
initPortf(qs.strategy,'SPY', initDate=initDate)
initAcct(qs.strategy,portfolios=qs.strategy, initDate=initDate, initEq=initEq)
initOrders(portfolio=qs.strategy,initDate=initDate)
# instantiate a new strategy object
strategy(qs.strategy,store=TRUE)
# Specify the max quantity you could hold in the SPY instrument. Here we simply assume 1e5 units. You could reduce this number to limit the exposure
max_qty_traded <- 1e5
addPosLimit(qs.strategy, "SPY", timestamp = startDate, maxpos = max_qty_traded)
add.indicator(strategy = qs.strategy, name = "SMA",
arguments = list(x = quote(Cl(mktdata)), n=10), label="SMA10")
add.signal(qs.strategy,name="sigCrossover",
arguments = list(columns=c("Close","SMA10"),relationship="gt"),
label="Cl.gt.SMA")
add.signal(qs.strategy,name="sigCrossover",
arguments = list(columns=c("Close","SMA10"),relationship="lt"),
label="Cl.lt.SMA")
add.rule(qs.strategy, name='ruleSignal',
arguments = list(sigcol="Cl.gt.SMA",
sigval=TRUE,
orderqty = 1, # the acutal orderqty size becomes redundant when supplying a function to the argument `osFUN`
osFUN = osFUN_all_eq,
ordertype='market', orderside='long', pricemethod='market'),
type='enter', path.dep=TRUE)
add.rule(qs.strategy, name='ruleSignal',
arguments = list(sigcol="Cl.lt.SMA",
sigval=TRUE,
orderqty='all', # flatten all open long positions
ordertype='market',
orderside='long',
pricemethod='market'),
type='exit',
path.dep=TRUE)
# supply initEq parameter and its value, which pass through to `osFUN`
out <- applyStrategy(strategy=qs.strategy , portfolios=qs.strategy, initEq=initEq)
updatePortf(qs.strategy)
updateAcct(qs.strategy)
updateEndEq(qs.strategy)
myTheme<-chart_theme()
myTheme$col$dn.col<-'lightblue'
myTheme$col$dn.border <- 'lightgray'
myTheme$col$up.border <- 'lightgray'
# plot performance
chart.Posn(qs.strategy, Symbol = 'SPY', Dates = '1998::',theme=myTheme)
plot(add_SMA(n=10,col=4, on=1, lwd=2))
There are a few things you should consider in an order sizing function:
1) If you already have a position open, do you want to permit "stacking"/pyramidying of positions on a particular side? For example, if you want to just have one position on, which you don't contribute further to, you could include getPosQty(qs.strategy, "SPY", timestamp) in your osFUN and return 0 if the current position held is not 0.
2) Do you want a max trade size? This can be handled using addPosLimit() as was done in this example above.
I know this question was posted long ago, but check out package "IKTrading," and the order sizing function "osMaxDollar." Here's a blog post on the topic; when you use this order sizing function you can set the dollar value of each trade and the total position.
https://quantstrattrader.wordpress.com/2014/08/29/comparing-atr-order-sizing-to-max-dollar-order-sizing/
I'm stuck with the following analysis:
library(quantstrat)
stock_size = 200
tickers = c("XOM", "MCD")
init.date = as.Date("2008-01-01")
usd = "USD"
currency(usd)
for(ticker in tickers){
stock(ticker, currency=usd, multiplier = 1)
}
options("getSymbols.warning4.0"=FALSE)
getSymbols(tickers,from=init.date,to.assign=TRUE)
suppressWarnings(rm(strat, port, acct, ords))
port.name <- "MyPort"
port <- initPortf(port.name,tickers,initDate=init.date)
acct.name <- "MyAcct"
acct <- initAcct(acct.name,portfolios=port.name, initDate=init.date, initEq=35000)
ords <- initOrders(portfolio=port.name,initDate=init.date)
strat.name <- "MyStrat"
strat<- strategy(strat.name)
strat<- add.indicator(strategy = strat, name = "SMA", arguments = list(x=quote(Ad(mktdata)), n=20),label= "ma20" )
strat<- add.indicator(strategy = strat, name = "SMA", arguments = list(x=quote(Ad(mktdata)), n=50),label= "ma50")
strat<- add.signal(strat, name="sigCrossover", arguments = list(columns=c("ma20","ma50"), relationship="gte"), label="ma20.gt.ma50")
strat<- add.signal(strat, name="sigCrossover", arguments = list(column=c("ma20","ma50"), relationship="lt"), label="ma20.lt.ma50")
strat<- add.rule(strategy = strat,name='ruleSignal', arguments = list(sigcol="ma20.gt.ma50", sigval=TRUE, orderqty=stock_size, ordertype='market', orderside='long', pricemethod='market'), type='enter', path.dep=TRUE)
strat<- add.rule(strategy = strat,name='ruleSignal', arguments = list(sigcol="ma20.lt.ma50", sigval=TRUE, orderqty='all',
ordertype='market', orderside='long', pricemethod='market'), type='exit', path.dep=TRUE)
out<-try(applyStrategy(strategy=strat, portfolios=port.name))
charts.PerformanceSummary()
because I got this couple of errors:
Error in `colnames<-`(`*tmp*`, value = c("XOM.Adjusted.SMA.50", "XOM.Adjusted.SMA.20.ma20.SMA.50" :
length of 'dimnames' [2] not equal to array extent
Error in inherits(x, "xts") : argument "R" is missing, with no default
Can anyone help me to find what's wrong?
In the current version of TTR, the names of the columns returned by the MA-indicators are prefixed by the name of the input column. Eg. SMA(MCD.Adjusted, n=20) returns a column named MCD.Adjusted.SMA.20.
Ad() will return all column names that match the string Adjusted.
By the time your second SMA-indicator gets called, Ad() will match 2 column names (the original MCD.Adjusted column plus the output column for the first indicator MCD.Adjusted.SMA.20). This results in a dimension error, because in the current implementation SMA() can only handle one input column at the time.
The solution is to pass only the first match, using quote(Ad(mktdata)[,1]) in your argument list.