bfast
on S&P 500Analyze breakpoints with the R package bfast
with an interactive d3.js visualization using rCharts and the dimplejs library.
R bfast code from blog post
For a better understanding of bfast
please see the following paper.
Verbesselt J, Hyndman R, Newnham G, Culvenor D (2010) Detecting Trend and Seasonal Changes in Satellite Image Time Series. Remote Sensing of Environment, 114(1), 106–115. http://dx.doi.org/10.1016/j.rse.2009.08.014
S&P 500 data from Yahoo! Finance - used for personal education purposes
#sample bfast code from blog post
#http://timelyportfolio.blogspot.com/2012/04/structural-breaks-bull-or-bear.html
#analyze breakpoints with the R package bfast
#please read the paper
#Verbesselt J, Hyndman R, Newnham G, Culvenor D (2010)
#Detecting Trend and Seasonal Changes in Satellite Image Time Series.
#Remote Sensing of Environment, 114(1), 106–115.
#http://dx.doi.org/10.1016/j.rse.2009.08.014
require(bfast)
require(quantmod)
getSymbols("^GSPC",from="1950-01-01")
#convert to log price
GSPC.monthly <- log(to.monthly(GSPC)[,4])
#get monthly returns for the close price
#not necessary, leave in price form
#GSPC.return <- monthlyReturn(GSPC[,4])
#need ts representation so do some brute force conversion
GSPC.ts <- ts(as.vector(GSPC.monthly["1951-01::"]),start=c(1951,1),frequency=12)
#look at the stl Seasonal-Trend decomposition procedure already in R
GSPC.stl <- stl(GSPC.ts,s.window="periodic")
plot(GSPC.stl,main="STL Decomposition of S&P 500")
#get the results from bfast
#adjusting h lower will result in more breakpoints
GSPC.bfast <- bfast(GSPC.ts,h=0.2,max.iter=1,season="none")
plot(GSPC.bfast,type="components",ylim=c(3,max(GSPC.monthly)+1),main="S&P 500 with bfast Breakpoints and Components")
plot(GSPC.bfast,type="trend",ylim=c(3,max(GSPC.monthly)+1),main="S&P 500 with bfast Trend Breakpoints")
#see everything with type="all" but in bfast calculation set seasonal to "none"
#play away with this
#plot(GSPC.bfast,type="all")
#do some additional plotting
#[[1]] is used since for speed I only did one iteration
#could plot each iteration if I did multiple
plot(GSPC.bfast$Yt/GSPC.bfast$output[[1]]$Tt-1,
main="bfast Remainder as % of S&P 500 Price",
xlab=NA, ylab="remainder (% of price)",bty="l")
#add vertical line for the breakpoints
abline(v=breakdates(GSPC.bfast$output[[1]]$bp.Vt),col="gray70")
#add horizontal line at 0
abline(h=0,col="black",lty=2)
text(x=breakdates(GSPC.bfast$output[[1]]$bp.Vt),y=par("usr")[3]+.01,
labels=breakdates(GSPC.bfast$output[[1]]$bp.Vt,format.times=TRUE),
srt=90,pos=4,cex=0.75)
require(rCharts)
options(viewer=NULL)
bfast.df <- data.frame(
date = format(index(as.xts(GSPC.bfast$output[[1]]$Tt)),"%Y-%m-%d")#as.Date(index(as.xts(GSPC.bfast$output[[1]]$Tt)))
,bfast = as.numeric(GSPC.bfast$output[[1]]$Tt)
)
#just use dimple to start
dBfast <- dPlot(
price ~ date,
data = data.frame(
date = format(as.Date(index(GSPC.monthly)),"%Y-%m-%d"),#as.numeric(as.Date(index(GSPC.monthly)))
price = as.numeric(GSPC.monthly)
),
type = "line"
)
#set up a time based x axis
dBfast$xAxis(
#type = "addCategoryAxis",
type = "addTimeAxis"
,inputFormat = "%Y-%m-%d"
,outputFormat = "%Y"
)
dBfast$yAxis(
overrideMin = 0,
overrideMax = 8
)
dBfast
#add the bfast layer
#with new dataset for layer
dBfast$templates$script = "../rCharts/inst/libraries/dimple/layouts/chart.html"
dBfast$layer(
x = "date",
y = "bfast",
data = bfast.df,
type = "line"
)
dBfast
# various cleanup experiments
# what should be in dimple/rCharts by default
# or made easier
dBfast$setTemplate(
afterScript = '
<script>
myChart.series[2].shapes
.transition().duration(10).delay(1000)
.style("stroke","#AD5277")
.style("stroke-dasharray",[10,5])
//delete some of the ticks
myChart.svg.select(".axis").selectAll(".tick")[0].forEach(function(d,i){
if (!(+d3.time.format("%Y")(new Date(+d3.select(d).datum())) % 10 == 0)) {
d.remove()
}
})
myChart.svg.select(".axis").selectAll(".tick text")
.attr("transform","none")
.style("text-anchor","middle");
</script>
'
)
dBfast