Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save timelyportfolio/3230354 to your computer and use it in GitHub Desktop.
Save timelyportfolio/3230354 to your computer and use it in GitHub Desktop.
construction of horizon plot
#look at steps in constructing a horizon plot version
#of http://www.mebanefaber.com/timing-model/
#do horizon of percent above or below 10 month / 200 day moving average
require(lattice)
require(latticeExtra)
require(quantmod)
#since we are focused on the horizon plot, let's just look at one stock
tckrs <- "VTI"
getSymbols(tckrs, from = "2006-12-31")
#do horizon of percent above or below 10 month or 200 day moving average
prices <- get(tckrs[1])[,6]
#remove comments below if you would like to look at more than one symbol
#for (i in 2:length(tckrs)) {
# prices <- merge(prices,get(tckrs[i])[,4])
#}
colnames(prices) <- tckrs
#set n to desired moving average width; we'll do 200
n=200
ma <- runMean(prices, n = n)
colnames(ma) <- paste(tckrs, ".MovAvg", sep = "")
xyplot(merge(prices,ma),
col = c("black", "red"),
lty = c(1,3),
screens = 1,
scales = list(tck = c(1,0)),
xlab = NULL,
main = "VTI and 200-day Moving Average")
#but for timing system more interested in whether above or below
#get percent above or below
#we'll leave code to expand beyond one symbol
pctdiff <- (prices / apply(prices, MARGIN = 2, FUN = runMean, n = n) - 1)[n:NROW(prices),]
xyplot(pctdiff,
col.line = "steelblue4",
scales = list(tck = c(1,0)),
xlab = NULL)
xyplot(pctdiff,
border = NA,
col.line = "steelblue4",
scales = list(tck = c(1,0)),
xlab = NULL,
panel = function (...) {
panel.xyarea(origin=0, ...)
#draw horizontal lines at 10% to show where we will place bands
panel.abline(h = seq(-0.4, 0.4, 0.10), col = "white", lwd = 2)
#add black 0 axis back
panel.abline(h = 0, col = "black")
})
#takes a lot of height to represent so let's mirror the negative
#so we can cut height by 1/2
xyplot(pctdiff,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL,
#limit to max of absolute value since we will mirror the negative
ylim = c(0,ceiling(max(abs(coredata(pctdiff)))*10)/10),
panel = function (x, y, ...) {
#do the positive values in blue
panel.xyarea(x, ifelse(y > 0, y ,0), col.line = "steelblue4", origin=0, ...)
#do the positive values in blue
panel.xyarea(x, ifelse(y < 0, abs(y) ,0), col.line = "indianred3", origin=0, ...)
#draw horizontal lines at 10% to show where we will place bands
panel.abline(h = seq(-0.4, 0.4, 0.10), col = "white", lwd = 2)
#add black 0 axis back
panel.abline(h = 0, col = "black")
})
#do same chart as above but draw box around bands
xyplot(pctdiff,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL,
#limit to max of absolute value since we will mirror the negative
ylim = c(0,ceiling(max(abs(coredata(pctdiff)))*10)/10),
panel = function (x, y, ...) {
#do the positive values in blue
panel.xyarea(x, ifelse(y > 0, y ,0), col.line = "steelblue4", origin=0, ...)
#do the positive values in blue
panel.xyarea(x, ifelse(y < 0, abs(y) ,0), col.line = "indianred3", origin=0, ...)
#draw horizontal lines at 10% to show where we will place bands
panel.abline(h = seq(-0.4, 0.4, 0.10), col = "white", lwd = 2)
#add black 0 axis back
panel.abline(h = 0, col = "black")
panel.xblocks(x,abs(y)>0,height=0.128,col="white",border="black",alpha=0.3)
panel.text(x=x[1],y=0.11,labels="band1", pos=4)
panel.xblocks(x,abs(y)>0,height=0.228,col="white",border="black",alpha=0.25)
panel.text(x=x[1],y=0.21,labels="band2", pos=4)
panel.xblocks(x,abs(y)>0,height=0.328,col="white",border="black",alpha=0.2)
panel.text(x=x[1],y=0.31,labels="band3", pos=4)
panel.xblocks(x,abs(y)>0,height=0.428,col="white",border="black",alpha=0.15)
panel.text(x=x[1],y=0.41,labels="band4", pos=4)
})
#get 4 reds and 4 blues (one for each band)
reds <- brewer.pal("Reds", n=8)[4:8]
blues <- brewer.pal("Blues", n=8)[4:8]
#so let's start banding to use even less height
#for band1 so we will only show graph from 0 to 0.1
band1 <- xyplot(pctdiff,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
lattice.options = list(axis.padding = list(numeric = 0)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
x = list(col.line="black"),
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL,
#limit y to band height; in this case 10%
ylim = c(0,0.1),
panel = function (x, y, ...) {
#do the positive values in blue
panel.xyarea(x, ifelse(y > 0, y ,0), col.line = blues[4], origin=0, alpha = 0.3, ...)
#do the positive values in blue
panel.xyarea(x, ifelse(y < 0, abs(y) ,0), col.line = reds[4], origin=0, alpha = 0.3, ...)
#add black 0 axis back
panel.abline(h = 0, col = "black")
})
print(band1)
#we are missing all the values > 0.10
#we will draw band2 0.1 to 0.2 with a darker color
band2 <- xyplot(pctdiff,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
lattice.options = list(axis.padding = list(numeric = 0)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
x = list(draw = FALSE),
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL,
#limit y to band height; in this case 10%
ylim = c(0, 0.1),
panel = function (x, y, ...) {
#do the positive values in blue
panel.xyarea(x, ifelse(y > 0.1, y - 0.1, 0), col.line = blues[4], origin=0, alpha = 0.5, ...)
#do the positive values in blue
panel.xyarea(x, ifelse(y < -0.1, abs(y) - 0.1, 0), col.line = reds[4], origin=0, alpha = 0.5, ...)
})
print(band2)
#now we are missing all the values > 0.10 + 0.10
#we will draw band3 0.2 to 0.3 with a darker color
band3 <- xyplot(pctdiff,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
lattice.options = list(axis.padding = list(numeric = 0)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
x = list(draw = FALSE),
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL,
#limit y to band height; in this case 10%
ylim = c(0, 0.1),
panel = function (x, y, ...) {
#do the positive values in blue
panel.xyarea(x, ifelse(y > 0.2, y - 0.2, 0), col.line = blues[4], origin=0, alpha = 0.7, ...)
#do the positive values in blue
panel.xyarea(x, ifelse(y < -0.2, abs(y) - 0.2, 0), col.line = reds[4], origin=0, alpha = 0.7, ...)
})
print(band3)
#going to four bands is not recommended but for this example we will
band4 <- xyplot(pctdiff,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
lattice.options = list(axis.padding = list(numeric = 0)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
x = list(draw = FALSE),
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL,
#limit y to band height; in this case 10%
ylim = c(0, 0.1),
panel = function (x, y, ...) {
#do the positive values in blue
panel.xyarea(x, ifelse(y > 0.3, y - 0.3, 0), col.line = blues[4], origin=0, alpha = 1, ...)
#do the positive values in blue
panel.xyarea(x, ifelse(y < -0.3, abs(y) - 0.3, 0), col.line = reds[4], origin=0, alpha = 1, ...)
})
print(band4)
#combine all four bands/layers to one horizonplot
print(band1+band2+band3+band4)
#of course using the horizonplot function from latticeExtra
#makes this much easier
horizonplot(pctdiff,
strip.left=FALSE,
strip=FALSE,
#remove border around chart and axis lines
par.settings = list(axis.line = list(col = NA),
strip.border = list(col = NA),
strip.background = list(col = NA)),
lattice.options = list(axis.padding = list(numeric = 0)),
border = NA,
scales = list(tck = c(1,0), #remove tick lines on top
x = list(col.line="black"),
y = list(col.line="black", rot=0)), #make ticks black and not rotated
xlab = NULL
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment