Bollinger Bands indicator in R - r

I am currently trying to write a simple strategy using Bollinger Bands in R. The goal is to enter a long position when the closing price touches the lower band and exit when it touches the upper one. To do that I firstly wrote two simple function to use as indicators:
BBandsDown <- function(HLC,n=20,maType,sd=2){
bbdown <- BBands(HLC,n,maType,sd)$dn
colnames(bbdown)<-"bbdown"
return(bbdown)
}
BBandsUp <- function(HLC,n=20,maType,sd=2){
bbup <- BBands(HLC,n,maType,sd)$up
colnames(bbup)<-"bbup"
return(bbup)
}
Then I added the indicators
add.indicator(strategy = strategy.st,
name = 'Cl',
arguments = list(x=quote(mktdata)),
label = 'close')
add.indicator(strategy = strategy.st,
name = 'BBandsDown',
arguments = list(HLC = quote(Cl(mktdata)), n=10,maType="SMA",sd=1.5),
label = 'bbandsdown1.5')
add.indicator(strategy = strategy.st,
name = 'BBandsUp',
arguments = list(HLC = quote(Cl(mktdata)), n=10,maType="SMA",sd=1.5),
label = 'bbandsup1.5')
Then I define Signals and Rules. My problem is that I cannot use the applyStrategy command because it reply.
Error in BBands(HLC, n, maType, sd) (from strategy_bbands.r!15334IYx#2) :
Price series must be either High-Low-Close, or Close/univariate.
I tried with both HLC = quote(Cl(mktdata)) and HLC = quote(HLC(mktdata)) but the error is the same. What am I doing wrong?

You haven't provided a reproducible example.
The error is pretty clear that you're passing in the wrong data.
I suspect that you have mangled the data prior to calling applyStrategy , but there isn't enough here to validate that.
See the bbands.R demo in the demos directory for a working example.

Related

Error when using for loops to make multiple objects with different name in R

I'm trying to make 6 different objects titled env1, env2, env3... and so on by labelling them and calling audio files with the corresponding names.
I just can't understand why this is keep throwing errors at me.
for (i in 1:6) {
trial <- paste0("env", i)
trial[i] <- slider_page(trial[i],
div(p(trial[i]),
tags$audio(src = paste0("audioResources/", trial[i], ".mp3"),
type = "audio/mp3", autoplay = FALSE, control = FALSE)
),
min = 0, max = 100, value = 50, tick = FALSE)
print(trial[i])
}
The error says
Error in trial[i] <- slider_page(trial[i], div(p(trial[i]), tags$audio(src = paste0("audioResources/", :
incompatible types (from S4 to character) in subassignment type fix
Can anybody help me explain why this isn't working?
Cheers

Log chart in blotter function chart.Posn() possible?

Is it possible to draw a log price chart in the chart.Posn() or chart.Reconcile() functions of blotter? I tried adding log.scale = TRUE to the function call without success. Is the underlying chart_Series function still too "experimental" to support this functionality or is the function call not correct?
chart.Posn(Portfolio = portfolio.st, Symbol = "GSPC", log.scale = TRUE)
Update: I have been trying to use the chart_Series() function directly, setting the ylog graphical parameter:
par(ylog=TRUE)
chart_Series(Cl(GSPC))
But I receive an error "log scale needs positive bounds" despite the data being all positive.
Btw, GSPC is an OHLCV time-series xts of the S&P 500 that plots in chartSeries() and chart_Series(), but just not with log-scale for either charting functions.
I found this old post not as a solution but as an alternative:
Does chart_Series() work with logarithmic axis?
I don't think there is any parameter like log.scale that chart_Series recognises. You could simply do chart_Series(log(Cl(GSPC)). You could also do some basic modifications to chart.Posn to put things on the log scale. Use as a starting point the source code for chart.Posn.
Here is an example of a modified function you could make. You can obviously modify it further in any way you please.
# We need an example. So,
# Source this code from the directory containing quantstrat, or at least source the macd.R demo in quantstrat.
source("demo/macd.R")
log.chart.Posn <- function(Portfolio, Symbol, Dates = NULL, env = .GlobalEnv) {
pname<-Portfolio
Portfolio<-getPortfolio(pname)
x <- get(Symbol, env)
Prices <- log(x)
chart_Series(Prices)
#browser()
if(is.null(Dates)) Dates<-paste(first(index(Prices)),last(index(Prices)),sep='::')
#scope the data by Dates
Portfolio$symbols[[Symbol]]$txn<-Portfolio$symbols[[Symbol]]$txn[Dates]
Portfolio$symbols[[Symbol]]$posPL<-Portfolio$symbols[[Symbol]]$posPL[Dates]
Trades = Portfolio$symbols[[Symbol]]$txn$Txn.Qty
Buys = log(Portfolio$symbols[[Symbol]]$txn$Txn.Price[which(Trades>0)])
Sells = log(Portfolio$symbols[[Symbol]]$txn$Txn.Price[which(Trades<0)])
Position = Portfolio$symbols[[Symbol]]$txn$Pos.Qty
if(nrow(Position)<1) stop ('no transactions/positions to chart')
if(as.POSIXct(first(index(Prices)))<as.POSIXct(first(index(Position)))) Position<-rbind(xts(0,order.by=first(index(Prices)-1)),Position)
Positionfill = na.locf(merge(Position,index(Prices)))
CumPL = cumsum(Portfolio$symbols[[Symbol]]$posPL$Net.Trading.PL)
if(length(CumPL)>1)
CumPL = na.omit(na.locf(merge(CumPL,index(Prices))))
else
CumPL = NULL
if(!is.null(CumPL)) {
CumMax <- cummax(CumPL)
Drawdown <- -(CumMax - CumPL)
Drawdown<-rbind(xts(-max(CumPL),order.by=first(index(Drawdown)-1)),Drawdown)
} else {
Drawdown <- NULL
}
if(!is.null(nrow(Buys)) && nrow(Buys) >=1 ) (add_TA(Buys,pch=2,type='p',col='green', on=1));
if(!is.null(nrow(Sells)) && nrow(Sells) >= 1) (add_TA(Sells,pch=6,type='p',col='red', on=1));
if(nrow(Position)>=1) {
(add_TA(Positionfill,type='h',col='blue', lwd=2))
(add_TA(Position,type='p',col='orange', lwd=2, on=2))
}
if(!is.null(CumPL)) (add_TA(CumPL, col='darkgreen', lwd=2))
if(!is.null(Drawdown)) (add_TA(Drawdown, col='darkred', lwd=2, yaxis=c(0,-max(CumMax))))
plot(current.chob())
}
log.chart.Posn(Portfolio = portfolio.st, Sym = "AAPL", Dates = NULL, env = .GlobalEnv)
add_MACD() # Simply added to make the plot almost identical to what is in demo/macd.R
This is what the original chart looks like:
New plot, with log scales:

object mktdata not found

I believe this is a formatting issue with my indicator. Can someone tell me what im doing wrong here?
#....omitted the portfolio initialization above
#returns change from past day, or NA if one of the values is invalid
changeDaily<-function(x,y){if(is.na(x+y)==T){return(NA)};ifelse(x-y>0,"UP","DOWN")}
#creates column called lagPredict which uses the function changeDaily
add.indicator(strat, name = "changeDaily",arguments = list(HLC = quote(mktdata),Cl(mktdata),Lag(Cl(mktdata))), label='lagPredict')
error:
Error in has.Cl(x) : object 'mktdata' not found
Traceback:
traceback()
3: has.Cl(x)
2: Cl(mktdata)
1: add.indicator(strat, name = "changeDaily", arguments = list(HLC = quote(mktdata),
Cl(mktdata), Lag(Cl(mktdata))), label = "lagPredict")
Complete code:
source("forex.functions.R")
startDate <- '2010-01-01' # start of data
endDate <- '2015-05-01' # end of data
symbols<-c("USD/EUR")
portfolio<-acct<-strat<-"simpleLookAhead"
initSetup(symbols,portfolio,acct,strat)
dump<-lapply(symbols,function(x)forex.weeklyOHLC(x))
symbols<-gsub("/","",symbols)
#############################################################
#returns change from past day, or NA if one of the values is invalid
changeDaily<-function(x,y){if(is.na(x+y)==T){return(NA)};ifelse(x-y>0,"UP","DOWN")}
#creates column called lagPredict which uses the function changeDaily to return UP or DOWN in reference to yesterdays price
add.indicator(strat, name = "changeDaily",arguments = list(HLC = quote(mktdata),Cl(mktdata),Lag(Cl(mktdata))), label='lagPredict')
forex.functions.R
library(PerformanceAnalytics)
library(quantmod)
library(lattice)
library(IKTrading)
library(quantstrat)
Sys.setenv(TZ="EST") # set time zone
if (!exists('.blotter')) .blotter <- new.env()
if (!exists('.strategy')) .strategy <- new.env()
forex.weeklyOHLC<-function(ss){
ss<-getSymbols(ss,src="oanda",from=startDate,to=endDate)
x<-get(ss)
#x<-adjustOHLC(x,symbol.name=symbol) #calls get Splits which calls getSymbols which fails bc src != oanda
x<-to.weekly(x,indexAt='lastof',drop.time=TRUE)
indexFormat(x)<-'%Y-%m-%d'
colnames(x)<-gsub("x",ss,colnames(x))
assign(ss,x)
}
initSetup<-function(symbols,portfolio, acct, strat){
initDate <- '2009-12-31'
initEq <- 1e6
currency("USD")
stock(symbols, currency="USD", multiplier=1)
rm.strat(strat) # remove portfolio, account, orderbook if re-run
initPortf(name=portfolio, symbols, initDate=Sys.Date())
initAcct(name=acct, portfolios=portfolio,initDate=Sys.Date(), initEq=initEq)
initOrders(portfolio=portfolio, initDate=Sys.Date())
strategy(strat, store=TRUE)
}
You need to quote all the objects in the arguments list in the call to add.indicator to prevent them from being evaluated. You also need to specify the correct arguments to pass to your changeDaily function. You pass HLC, but changeDaily does not have a HLC argument.
Your add.indicator call should look something like this:
add.indicator(strat, name = "changeDaily",
arguments = list(x = quote(Cl(mktdata)), y = quote(Lag(Cl(mktdata)))),
label = 'lagPredict')

quantstrat logical error - missing value where TRUE/FALSE needed

I am getting this error when applying strategy in quantstrat:
Error in if (length(j) == 0 || (length(j) == 1 && j == 0)) { :
missing value where TRUE/FALSE needed
My code is as follows:
.blotter <- new.env()
.strategy <- new.env()
Sys.setenv(TZ="UTC")
STRATEGY<-'PFReplicate'
try(rm.strat(STRATEGY))
n<-130
#SMA signals and rules
LONG.ENTRY.SIGNAL.SMA<-"CLOSE_GT_SMA_SIG_LONG"
LONG.EXIT.SIGNAL.SMA<-"CLOSE_LT_SMA_SIG_LONG"
SHORT.ENTRY.SIGNAL.SMA<-"CLOSE_LT_SMA_SIG_SHORT"
SHORT.EXIT.SIGNAL.SMA<-"CLOSE_GT_SMA_SIG_SHORT"
LONG.ENTRY.RULE.SMA<-'L_ENTRY_SMA_RULE'
LONG.EXIT.RULE.SMA<-'L_EXIT_SMA_RULE'
SHORT.ENTRY.RULE.SMA<-'S_ENTRY_SMA_RULE'
SHORT.EXIT.RULE.SMA<-'S_EXIT_SMA_RULE'
LONG.ORDERSET.NAME<-'CLOSELONGSMA'
SHORT.ORDERSET.NAME<-'CLOSESHORTSMA'
strategy(STRATEGY,store=TRUE)
Set up SMA indicator
add.indicator(strategy = STRATEGY,name='SMA',
arguments=list(x=quote(mktdata),n),
label='SMA')
#Set up signals
#SMA signals
add.signal(strategy = STRATEGY,name="sigCrossover",
arguments=list(columns=c('Close','SMA'),
relationship="gt"),
label=LONG.ENTRY.SIGNAL.SMA)
add.signal(strategy = STRATEGY,name="sigCrossover",
arguments=list(columns=c('Close','SMA'),
relationship="lt"),
label=LONG.EXIT.SIGNAL.SMA)
add.signal(strategy = STRATEGY,name="sigCrossover",
arguments=list(columns=c('Close','SMA'),
relationship="lt"),
label=SHORT.ENTRY.SIGNAL.SMA)
add.signal(strategy = STRATEGY,name="sigCrossover",
arguments=list(columns=c('Close','SMA'),
relationship="gt"),
label=SHORT.EXIT.SIGNAL.SMA)
#Add our SMA rules (enabled)
add.rule(strategy = STRATEGY,name="ruleSignal",
arguments=list(sigcol=LONG.ENTRY.SIGNAL.SMA,sigval=TRUE,
orderqty=100,ordertype="market",
TxnFees=0,orderside="long",
orderset=LONG.ORDERSET.NAME),
type="enter",label=LONG.ENTRY.RULE.SMA)
add.rule(strategy = STRATEGY,name="ruleSignal",
arguments=list(sigcol=LONG.EXIT.SIGNAL.SMA,sigval=TRUE,
orderqty='all',ordertype="market",
TxnFees=0,orderside="long",
orderset=LONG.ORDERSET.NAME),
type="exit",label=LONG.EXIT.RULE.SMA)
add.rule(strategy = STRATEGY,name="ruleSignal",
arguments=list(sigcol=SHORT.ENTRY.SIGNAL.SMA,sigval=TRUE,
orderqty=100,ordertype="market",
TxnFees=0,orderside="short",
orderset=SHORT.ORDERSET.NAME),
type="enter",label=SHORT.ENTRY.RULE.SMA)
add.rule(strategy = STRATEGY,name="ruleSignal",
arguments=list(sigcol=SHORT.EXIT.SIGNAL.SMA,sigval=TRUE,
orderqty='all',ordertype="market",
TxnFees=0,orderside="short",
orderset=SHORT.ORDERSET.NAME),
type="exit",label=SHORT.EXIT.RULE.SMA)
symbol <- mar.rep
port <- 'mar.rep'
currency("USD")
stock(primary_id = symbol,currency = "USD",multiplier = 1)
Sys.setenv(TZ="UTC")
initDate <- '1971-01-05'
startDate <- '1972-01-06'
endDate<- '2010-12-31'
initEq <- 1e6
initPortf(name = port,symbols = symbol,initDate=initDate)
initAcct(name = port,portfolios = port,initDate=initDate,initEq=initEq)
initOrders(portfolio = port,initDate=initDate)
applyStrategy(strategy =STRATEGY,portfolios = port,debug = TRUE)
I've tried to keep the code simple, so as to avoid dumb errors, but I still get this one. The applyStrategy runs and lists thousands of transactions, and after 30 minutes, I get this error. I am guessing the fix is simple, but I am not seeing it. Thanks for your help!
I figured out the problem after posting my question. For anyone else who runs across this error when running quantstrat, check your data for NAs. Plus make sure all assets have explicitly-defined columns that match exactly the columns referenced in add.signal.
This may sound obvious, but data management was the biggest obstacle to getting results in my case. My data came from various data providers, with varying column formats (csv files, primarily). After spending a few hours cleaning and setting up my data to run through the strategy, it is working (I'm at hour 7 so far of processing).
Quantstrat can be difficult to debug, as some error messages are not easy to interpret. Note that this error message is telling you that one or more logical comparisons in an if statement results in NA. If you see this error, check your data for NA to see if this may be the problem.
nrow(na.omit(data)) == nrow(data)
If this is not true, you have NAs. You can remove them with
data_cleaned <- na.omit(data)
but it will depend on your data format.
Sorry if this is a remedial error for everyone. I just wanted to post a detailed answer to this error, as it seems to come up a fair amount for people. If I had seen an explanation like this yesterday, I would have saved several hours of frustration!

r - taking difference of two xyplots?

I have several xyplot objects that I have saved as .RDATA files. I am now interested in being able to look at their differences. I have tried things like
plot1-plot2
but this does not work (I get the "non-numeric argument to binary operator error).
I would also be able to do this if I knew how to extract the timeseries data stored within the lattice xyplot object, but I have looked everywhere and can't figure out how to do this either.
Any suggestions?
EDIT:
just to make it perfectly clear what I mean for MrFlick, by "taking the difference of two plots" I mean plotting the elementwise difference of the timeseries from each plot, assuming it exists (i.e. assuming that the plots have the same domain). Graphically,
I might want to take the following two plots, stored as xyplot objects:
and end up with something that looks like this:
-Paul
Here is a little function I wrote to plot the difference of two xyplots:
getDifferencePlot = function(plot1,plot2){
data1 = plot1$panel.args
data2 = plot2$panel.args
len1 = length(data1)
len2 = length(data2)
if (len1!=len2)
stop("plots do not have the same number of panels -- cannot take difference")
if (len1>1){
plotData = data.table(matrix(0,0,4))
setNames(plotData,c("x","y1","y2","segment"))
for (i in 1:len1){
thing1 = data.table(cbind(data1[[i]]$x,data1[[i]]$y))
thing2 = data.table(cbind(data2[[i]]$x,data2[[i]]$y))
finalThing = merge(thing1, thing2,by = "V1")
segment = rep(i,nrow(finalThing))
finalThing = cbind(finalThing,segment)
setNames(finalThing,c("x","y1","y2","segment"))
plotData = rbind(plotData,finalThing)
}
}
if (len1==1){
plotData = data.table(matrix(0,0,3))
setNames(plotData,c("x","y1","y2"))
thing1 = data.table(cbind(data1[[i]]$x,data1[[i]]$y))
thing2 = data.table(cbind(data2[[i]]$x,data2[[i]]$y))
plotData = merge(thing1, thing2,by = "V1")
}
plotData$difference = plotData$y1-plotData$y2
if (len1==1)
diffPlot = xyplot(difference~x,plotData,type = "l",auto.key = T)
if (len1>1)
diffPlot = xyplot(difference~x|segment,plotData,type = "l",auto.key = T)
return(diffPlot)
}

Resources