[R-SIG-Finance] quantstrat newbie sigFormula example
Brian G. Peterson
brian at braverock.com
Sun Mar 17 12:41:13 CET 2013
On 03/16/2013 07:20 PM, Rob Schmidt wrote:
> Hi All,
>
> I'm posting a small example of using signal formulas to help out other
> beginners that are getting started with quantstrat. It also includes stuff
> copied from other examples such as the CUD custom indicator from
> timelyportfolio, reading a OHLC CSV file with intraday bars downloaded from
> Dukascopy, adding TA indicators to plots, and saving results to files. I
> may have gone a bit off the deep end with the signal formulas. I'm certain
> that there are smarter ways to do some of this. I am also attaching a small
> CSV file to play with.
>
> Thanks in advance for comments, suggestions, and warnings.
>
> Rob Schmidt
Rob,
Thanks for doing this. The community grows because people contribute.
First, I'd like to ask if I can adapt this and include it in the demos
for the package. We need a sigFormula demo. I'd simplify it somewhat,
likely using getSymbols and not saving things to files, but otherwise I
think it is a good overall example in most respects.
Second, let's talk about how you could do signal checks faster, for your
benefit later on.
sigFormula is seductive, since you can construct any formula at all. It
is also insanely slow, because we have to turn things back into a
data.frame, and rely on a bunch of R-internals magic to evaluate the
formula.
Because of that, for simple two-column comparisons, or for comparisons
to some scalar variable, sigCrossover, sigThreshold, and sigComparison
will be much faster. Thousands of times faster. For small amounts of
data this may not matter, for large amounts of data, or things like
parameter tests where you'll have thousands of trials, it does.
So, these:
cudUp = "(CUD > 0)"
cudDn = "(CUD < 0)"
smaUp = "(smaFast > smaSlow)"
smaDn = "(smaFast < smaSlow)"
closeAbvS = paste("(",symbol,".Close > smaSlow)",sep='')
closeBlwS = paste("(",symbol,".Close < smaSlow)",sep='')
closeAbvF = paste("(",symbol,".Close > smaFast)",sep='')
closeBlwF = paste("(",symbol,".Close < smaFast)",sep='')
would all be faster with sigThreshold, sigComparison, or sigCrossover
(which calls sigComparison internally).
Lots faster.
These:
# goLong = paste(cudUp,"&",closeAbvS,sep='')
# exitLong = paste(cudDn,"|",closeBlwS,sep='')
# goShort = paste(cudDn,"&",closeBlwS,sep='')
# exitShort = paste(cudUp,"|",closeAbvS,sep='')
# goLong = paste(smaUp,"&",closeAbvF,"&",cudUp,sep='')
# exitLong = paste(smaDn,"|",closeBlwF,sep='')
# goShort = paste(smaDn,"&",closeBlwF,"&",cudDn,sep='')
# exitShort = paste(smaUp,"|",closeAbvF,sep='')
# goLong = paste(smaUp,"&",closeAbvF,"&",cudUp,sep='')
# exitLong = paste(smaDn,"|",closeBlwS,sep='')
# goShort = paste(smaDn,"&",closeBlwF,"&",cudDn,sep='')
# exitShort = paste(smaUp,"|",closeAbvS,sep='')
because of the presence of the & and | operators, and the more complex
formula, would need to use sigFormula as written. sigFormula is super
convenient for these types of compound comparisons, and why I wrote it.
When you inevitably want to speed things up, you'll get faster results
by combining multiple sigComparison, sigCrossover, and sigThreshold
calls for your & clauses, because indicators and signals run in the
order they are declared in the strategy, and can use the results of a
previous one.
For the | operator, I can't think of a simple combination of faster
signal functions that could work.
Thanks again,
Brian
-------------- next part --------------
# the frankenstein of signal formulas, Rob Schmidt
# prices from online, or from a CSV file downloaded from dukascopy
# thanks to the people who made these great packages and
# thanks to all who made the examples from which I copied
csvPath = '/home/rob/work/csvdata/dukascopy/' # these need to change
resultsPath = '/home/rob/work/R/quantstrat/'
setwd(resultsPath)
require(quantstrat)
try(rm("order_book.frank", pos=.strategy), silent=TRUE)
try(rm("account.frank", "portfolio.frank", pos=.blotter), silent=TRUE)
csvName = '' # assign an empty string to choose daily data from yahoo
# example file downloaded from dukascopy for evaluation
#csvName = 'AMZN.US_Candlestick_15_m_BID_01.01.2013-12.01.2013.csv'
stratg = "frank" # a creature from a collection of parts
symbol = "AMZN"
cudPeriods = 4
fastPeriods = 15
slowPeriods = 2*fastPeriods
initEq = 1.0e6
orderSize = 100
# CUD is the n-period sum of (up days = 1) and (down days = -1)
CUD = function(cl, n)
{ temp = runSum(ifelse(ROC(cl, 1, type="discrete") > 0, 1, -1), n)
colnames(temp) = "CUD"
temp
}
currency("USD")
stock(symbol, currency="USD", multiplier=1)
if(csvName == '') # get price data from yahoo online
{ initDate = '2011-07-01'
endDate = '2012-01-01'
getSymbols(symbol, from=initDate, to=endDate, adjust=TRUE)
} else # get price data from a CSV file
{ dukasFormat = '%d.%m.%Y %H:%M:%S'
csvData = read.csv(paste(csvPath, csvName, sep=''), sep=',',
header=TRUE)
# ignore empty trading periods, makes the plots prettier
csvData = csvData[(csvData$High > csvData$Low),]
#initDate = '' # if empty string calculate from the start of the data
initDate = '2013-01-05 00:00:00' # else set init date
#endDate = '' # if empty string calculate to the end of the data
endDate = '2013-01-09 00:00:00' # else set end date
# apply the user's end date if it is specified
if(initDate != '')
{ initTime = as.POSIXct(strptime(initDate, '%Y-%m-%d %H:%M:%S'))
csvData = csvData[(as.POSIXct(strptime(
csvData$Time, dukasFormat)) > initTime),]
}
if(endDate != '')
{ endTime = as.POSIXct(strptime(endDate, '%Y-%m-%d %H:%M:%S'))
csvData = csvData[(as.POSIXct(strptime(
csvData$Time, dukasFormat)) < endTime),]
}
symb = as.xts(csvData[,2:6],
as.POSIXct(strptime(csvData[,1], dukasFormat)))
colnames(symb) = c(paste(symbol,'.Open',sep=''),
paste(symbol,'.High',sep=''),
paste(symbol,'.Low',sep=''),
paste(symbol,'.Close',sep=''),
paste(symbol,'.Volume',sep=''))
assign(symbol,symb)
initDate = start(get(symbol))
endDate = end(get(symbol))
}
# make some signal formula parts from indicators
cudUp = "(CUD > 0)"
cudDn = "(CUD < 0)"
smaUp = "(smaFast > smaSlow)"
smaDn = "(smaFast < smaSlow)"
closeAbvS = paste("(",symbol,".Close > smaSlow)",sep='')
closeBlwS = paste("(",symbol,".Close < smaSlow)",sep='')
closeAbvF = paste("(",symbol,".Close > smaFast)",sep='')
closeBlwF = paste("(",symbol,".Close < smaFast)",sep='')
# combine parts for entry/exit, long/short signal formulas
# goLong = cudUp
# exitLong = cudDn
# goShort = cudDn
# exitShort = cudUp
goLong = cudDn # counter-trend madness
exitLong = cudUp
goShort = cudUp
exitShort = cudDn
# goLong = paste(cudUp,"&",closeAbvS,sep='')
# exitLong = paste(cudDn,"|",closeBlwS,sep='')
# goShort = paste(cudDn,"&",closeBlwS,sep='')
# exitShort = paste(cudUp,"|",closeAbvS,sep='')
# goLong = paste(smaUp,"&",closeAbvF,"&",cudUp,sep='')
# exitLong = paste(smaDn,"|",closeBlwF,sep='')
# goShort = paste(smaDn,"&",closeBlwF,"&",cudDn,sep='')
# exitShort = paste(smaUp,"|",closeAbvF,sep='')
# goLong = paste(smaUp,"&",closeAbvF,"&",cudUp,sep='')
# exitLong = paste(smaDn,"|",closeBlwS,sep='')
# goShort = paste(smaDn,"&",closeBlwF,"&",cudDn,sep='')
# exitShort = paste(smaUp,"|",closeAbvS,sep='')
initPortf(stratg, symbol, initDate=initDate)
initAcct(stratg, portfolios=stratg, initDate=initDate,
initEq=initEq)
initOrders(portfolio=stratg, initDate=initDate)
strat = strategy(stratg)
strat = add.indicator(strategy=strat, name="SMA", label="smaFast",
arguments=list(x=quote(Cl(mktdata)), n=fastPeriods))
strat = add.indicator(strategy=strat, name="SMA", label="smaSlow",
arguments=list(x=quote(Cl(mktdata)), n=slowPeriods))
strat = add.indicator(strategy=strat, name="CUD", label="CUD",
arguments=list(cl=get(symbol)[,4], n=cudPeriods))
strat = add.signal(strat, name="sigFormula", label="goLongSig",
arguments = list(columns=c("smaFast","smaSlow","CUD"),
formula = goLong, cross=TRUE))
strat = add.signal(strat, name="sigFormula", label="exitLongSig",
arguments = list(columns=c("smaFast","smaSlow","CUD"),
formula = exitLong, cross=TRUE))
strat = add.signal(strat, name="sigFormula", label="goShortSig",
arguments = list(columns=c("smaFast","smaSlow","CUD"),
formula = goShort, cross=TRUE))
strat = add.signal(strat, name="sigFormula", label="exitShortSig",
arguments = list(columns=c("smaFast","smaSlow","CUD"),
formula = exitShort, cross=TRUE))
strat = add.rule(strategy = strat, name='ruleSignal', type='enter',
arguments = list(sigcol="goLongSig", sigval=TRUE,
orderqty=orderSize, ordertype='market', orderside='long',
osFUN=osMaxPos))
strat = add.rule(strategy = strat, name='ruleSignal', type='exit',
arguments = list(sigcol="exitLongSig", sigval=TRUE,
orderqty='all', ordertype='market', orderside='long'))
strat = add.rule(strategy = strat, name='ruleSignal', type='enter',
arguments = list(sigcol="goShortSig", sigval=TRUE,
orderqty=-orderSize, ordertype='market', orderside='short',
osFUN=osMaxPos))
strat = add.rule(strategy = strat, name='ruleSignal', type='exit',
arguments = list(sigcol="exitShortSig", sigval=TRUE,
orderqty='all', ordertype='market', orderside='short'))
addPosLimit(stratg, symbol, timestamp=initDate,
maxpos=orderSize, minpos=-orderSize)
out = applyStrategy(strategy=strat, portfolios=stratg, prefer='Open')
updatePortf(Portfolio=stratg)
updateAcct(name=stratg)
# make plots
dateRange = paste(initDate,'::',endDate,sep='')
chart.Posn(Portfolio = stratg, Symbol = symbol, Dates=dateRange)
add_SMA(n=fastPeriods, on=1, col='blue')
add_SMA(n=slowPeriods, on=1, col='tan')
plot(add_TA(CUD(cl=get(symbol)[,4],n=cudPeriods)))
# write the results to files
ob = getOrderBook(stratg)
write.zoo(ob[1], quote=TRUE,
file = paste(stratg, "_", symbol, "_orderbook.csv",sep=''))
write.zoo(mktdata, quote=TRUE,
file=paste(stratg, "_",symbol, "_mktdata.csv", sep=''))
write.zoo(getTxns(stratg, symbol), quote=TRUE,
file = paste(stratg, "_", symbol, "_txns.csv", sep=''))
More information about the R-SIG-Finance
mailing list