Douglas Karabasz
2012-Sep-04 03:23 UTC
[R] Producing a SMA signal when closing price is above the moving average for 3 days
I have loaded price data for GE and then calculated a 50 day simple moving average. Then I have a created a ifelse statement that produce a 1 when GE's closing price is above the simple moving average and a 0 when GE Closing price is below the 50 day simple moving average. However, what I really want to do is to produce a 1 for when the price is above the simple moving average for 3 days and I want it to keep the 1 until the price moves back below the 50 day simple moving average for 3 days then I want to return a 0 until the Price closes above the SMA for 3 days. Thank you, Douglas library(quantmod) getSymbols("GE") # Get Price Data GEsma <- SMA(GE$GE.Close, n=50) # Simple Moving Average of the closing price GEsma[is.na(GEsma)] <- 50 # Make NA's to 50 so ifelse statement works correctly aboveSMA <- ifelse(GE$GE.Close > GEsma, 1, 0) # 1 when price is above 50 day moving average # 0 When below moving average chartSeries(GE) # Shows Price chart addSMA(n=50) # adds 50 day moving average to chart
William Dunlap
2012-Sep-05 04:10 UTC
[R] Producing a SMA signal when closing price is above the moving average for 3 days
You could think of your problem as one of combining a signal that tells when the state of the system should change to (or remain at) "on" and a signal that tells when it should change to "off" to come up with a series giving the state at each time point. E.g., OnOrOff <- function(toOn, toOff, wasOn){ # toOn and toOff are logical vectors (indexed implicitly by time). # toOn[t] is TRUE means that the state should change to (or continue to # be) "on" (1) from time t until a later toOff value turns it off. # If both toOn[t] and toOff[t] are FALSE, then state[t] is copied from # state[t-1]. # wasOn=TRUE means that the state was "on" at time 0. stopifnot(length(toOn)==length(toOff), !any(toOn & toOff)) tmp <- integer(length(toOn)) tmp[1] <- if (wasOn) 1 else -1 tmp[toOn] <- 1 tmp[toOff] <- -1 s <- tmp != 0 zeroDups <- function(x) { x[-1][x[-1]==x[-length(x)]] <- 0 ; x } tmp[s] <- zeroDups(tmp[s]) cumsum(tmp) + (tmp[1] == -1) } In your example you have a series of 1s and 0s saying whether the price is currently above or below the 50-day runing average. E.g., x <- c(1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1) (TRUE and FALSE instead of 1 and 0 would be more convenient, but I'll follow your lead.) You can use filter to to find where there were 3 aboves (TRUEs) or 3 belows (FALSEs) in a row and pass those into OnOrOff. The following does this but assumes the previous state was "off" (an exercise for the reader): SwitchAtThree <- function (x, init = c(0, 0)) { count <- function(x) filter(c(init, x), rep(1, 3), side = 1)[-seq_along(init)] OnOrOff(count3(x == 1) == 3, count3(x == 0) == 3, FALSE) } With the above x we get: > data.frame(x, fx=SwitchAtThree(x)) x fx 1 1 0 2 1 0 3 0 0 4 1 0 5 1 0 6 1 1 7 0 1 8 1 1 9 0 1 10 0 1 11 0 0 12 1 0 An advantage of this technique is that you can fiddle with the filter coefficients and the '==3' to change the start-on/start-off conditions from 3 in a row to 3 out of the last 4 or the last two plus at least one of the two prior to them or make the on/off signals assymetric (e.g., 3 in a row TRUE to turn on, 2 in a row FALSE to turn off). It is pretty quick for long series. Bill Dunlap Spotfire, TIBCO Software wdunlap tibco.com> -----Original Message----- > From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf > Of Douglas Karabasz > Sent: Monday, September 03, 2012 8:24 PM > To: r-help at r-project.org > Subject: [R] Producing a SMA signal when closing price is above the moving average for 3 > days > > I have loaded price data for GE and then calculated a 50 day simple moving > average. Then I have a created a ifelse statement that produce a 1 when > GE's closing price is above the simple moving average and a 0 when GE > Closing price is below the 50 day simple moving average. > > However, what I really want to do is to produce a 1 for when the price is > above the simple moving average for 3 days and I want it to keep the 1 until > the price moves back below the 50 day simple moving average for 3 days then > I want to return a 0 until the Price closes above the SMA for 3 days. > > Thank you, > Douglas > > > library(quantmod) > > getSymbols("GE") # Get Price Data > > GEsma <- SMA(GE$GE.Close, n=50) # Simple Moving Average of the closing > price > > GEsma[is.na(GEsma)] <- 50 # Make NA's to 50 so ifelse statement works > correctly > > aboveSMA <- ifelse(GE$GE.Close > GEsma, 1, 0) # 1 when price is above 50 > day moving average > # 0 When below moving average > > chartSeries(GE) # Shows Price chart > addSMA(n=50) # adds 50 day moving average to chart > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.