# Implementing Technical Indicators: Tools

Programming Technical Indicators R Plotting

#### Introduction

This article is the start of my series on Implementing Technical Indicators. The tools provided here will make our lives easier when implementing actual technical indicators in the remaining articles of this series. All related code is in R.

For an introduction to technical indicators including example plots see my article Technical Indicators: An Introduction.

DISCLAIMER: None of the below is intended to be considered as any kind of investment advice. All examples serve as illustrative material only.

#### Calculation Tools

When evaluating technical indicators several operators occur repeatedly. It is considered best practice to wrap these operations in functions made available to all indicator implementations. I came up with the following relevant functions:

1. `checkWindow`
2. `checkWindows`
3. `checkVectors`
4. `isDataFrame`
5. `dateMatch`
6. `movingAverage`
7. `runningMax`
8. `runningMin`
9. `standardDeviation`
Let us briefly see what these do. The three check-something functions allow to see whether certain variables are consistent in terms of size: `checkWindow` tests whether an input vector is long enough to apply operations on sub intervals of a specific length to it, `checkWindows` validates that short and long window length are ordered appropriately while `checkVectors` ensures that up to four vectors are equal in size. The function `isDataFrame` throws an error if the input is not of type dataframe. `dateMatch` tests whether the size of a vector and the number of rows in a dataframe match. The remaining functions perform actual calculations: `movingAverage` calculates a simple moving average of specified window length. Similarly, `runningMax` and `runningMin` take an input series which is then converted into a series where each value is the maximum respectively minimum over the previous `i_window` days of the input vector. `standardDeviation` finally calculates the `i_window` days rolling standard deviation over the input vector.

I personally store the collection of all these functions as listed below in a file `Indicators/TechnicalIndicators.R`. You will find this file being included via `source()` into my indicator implementation source files.

``````
#
# helper functions in the context of calculating technical indicators
#

# check function arguments for consistency
checkWindow = function(v_values, i_window)
{
if (i_window > length(v_values)) {
stop("window length > number of values!")
}
}

checkWindows = function(i_window_short, i_window_long)
{
if (i_window_short > i_window_long) {
stop("short window length > long window length!")
}
}

checkVectors = function(v_vec1, v_vec2, v_vec3=c(), v_vec4=c())
{
b_is_error = FALSE

if (length(v_vec1) != length(v_vec2)) {
b_is_error = TRUE
} else if (!is.null(v_vec3)) {
if (length(v_vec1) != length(v_vec3)) {
b_is_error = TRUE
}
} else if (!is.null(v_vec4)) {
if (length(v_vec1) != length(v_vec4)) {
b_is_error = TRUE
}
}

if (b_is_error) {
stop("vector size mismatch!")
}
}

isDataFrame = function(df)
{
if (!is.data.frame(df)) {
stop("target is not of type 'data frame'!")
}
}

dateMatch = function(v_date, df)
{
isDataFrame(df)
if (length(v_date) != nrow(df)) {
stop("number of dates and rows of data frame do not match!")
}
}

# moving average
movingAverage = function(v_values, i_window)
{
i_length = length(v_values)

v_ma = rep(0, i_length)

d_cur_ma = v_values[1]
v_ma[1] = d_cur_ma

for (i in 2 : i_length) {
if (i <= i_window) {
d_cur_ma = d_cur_ma * (i - 1)
d_cur_ma = d_cur_ma + v_values[i]
d_cur_ma = d_cur_ma / i
} else {
d_cur_ma = d_cur_ma - v_values[i-i_window] / i_window
d_cur_ma = d_cur_ma + v_values[i] / i_window
}
v_ma[i] = d_cur_ma
}

return(v_ma)
}

# running maximum
runningMax = function(v_values, i_window)
{
i_length = length(v_values)

v_rmax = rep(0, i_length)

d_cur_max = v_values[1]
v_rmax[1] = d_cur_max

for (i in 2 : i_length) {
if (i < i_window) {
d_cur_max = max(d_cur_max, v_values[i]);
} else {
d_cur_max = max(v_values[(i-i_window+1):i]);
}
v_rmax[i] = d_cur_max;
}

return(v_rmax);
}

# running minimum
runningMin = function(v_values, i_window)
{
i_length = length(v_values)

v_rmin = rep(0, i_length)

d_cur_min = v_values[1]
v_rmin[1] = d_cur_min

for (i in 2 : i_length) {
if (i < i_window) {
d_cur_min = min(d_cur_min, v_values[i]);
} else {
d_cur_min = min(v_values[(i-i_window+1):i]);
}
v_rmin[i] = d_cur_min;
}

return(v_rmin);
}

# lagged standard deviation
standardDeviation = function(v_values, i_window)
{
i_length = length(v_values)

v_sdv = rep(0, i_length)
v_sdv[1] = 0

for (i in 2 : i_length) {
if (i < i_window) {
v_sdv[i] = sd(v_values[1:i])
} else {
v_sdv[i] = sd(v_values[(i-i_window+1):i])
}
}

return(v_sdv)
}
```
```

#### Plotting Tools

Although R comes with fantastic plotting capabilities it always takes me some time to make thinks look as demanded. To me common issues are coloured backgrounds, date axes, legend positioning and so on. While many R packages offering solutions to these tasks exist I prefer to set things up from first principles on. In the context of plotting technical indicators and visualising trading strategies I came up with the following relevant functions:

1. `plotIndicator`
2. `plotIndicator2`
3. `plotStock`
The functions `plotIndicator` and `plotIndicator2` both generate a jpeg file with the plot of the indicator of interest over time. Especially the date axis formatting and legend positioning are being taken care of. In addition, `plotIndicator` colours the plot's background according to the `v_signals` trading signal input vector, where times during which the strategy positions long are coloured greenish, times during which the position is short are coloured reddish and the remainder is left white. The function `plotStock` produces a straightforward jpeg plot of a stocks historical price series.

Similarly to the calculation tools script I store the plotting tools in a file `Indicators/IndicatorPlottingFunctions.R`.

``````
#
# helper functions in the context of plotting technical indicators
#

# define constants
COLOR_LONG_POSITION    = rgb(186/255, 255/255, 179/255, alpha=0.5)
COLOR_SHORT_POSITION   = rgb(255/255, 179/255, 186/255, alpha=0.3)
COLOR_NEUTRAL_POSITION = "white"

plotIndicator = function(v_date, v_signals, df_data, v_colors, v_legend, s_path)
{
jpeg(s_path, width=1200, height=700)

v_x = seq(1:nrow(df_data))

# determine x axis date labels
v_ticks      = c(v_x[1])
s_prev_date  = format(as.Date(v_date[1]), "%m-%Y")
v_tick_dates = c(s_prev_date)
for (i in 2 : length(v_x)) {
s_cur_date = format(as.Date(v_date[i]), "%m-%Y")
if (s_cur_date != s_prev_date) {
v_ticks      = c(v_ticks, v_x[i])
v_tick_dates = c(v_tick_dates, s_cur_date)
s_prev_date  = s_cur_date
}
}

# determine start and end coordinates for signal boxes
v_long_start    = c()
v_long_end      = c()
v_neutral_start = c()
v_neutral_end   = c()
v_short_start   = c()
v_short_end     = c()
i_start = 1
i_end   = 1
for (i in 2 : length(v_signals)) {
i_signal = v_signals[i]
if (i_signal == v_signals[i-1]) {
i_end = i
} else {
if (v_signals[i-1] == 1) {
v_long_start = c(v_long_start, i_start)
v_long_end   = c(v_long_end, i_end+1)
} else if (v_signals[i-1] == -1) {
v_short_start = c(v_short_start, i_start)
v_short_end   = c(v_short_end, i_end+1)
} else if (v_signals[i-1] == 0) {
v_neutral_start = c(v_neutral_start, i_start)
v_neutral_end   = c(v_neutral_end, i_end+1)
}
i_start = i
i_end   = i
}
}
if (i_signal == 1) {
v_long_start = c(v_long_start, i_start)
v_long_end   = c(v_long_end, i)
} else if (i_signal == -1) {
v_short_start = c(v_short_start, i_start)
v_short_end   = c(v_short_end, i)
} else if (i_signal == 0) {
v_neutral_start = c(v_neutral_start, i_start)
v_neutral_end   = c(v_neutral_end, i)
}

# create plot
d_max     = max(df_data)
d_min     = min(df_data)
v_y_ticks = pretty(seq(d_min, d_max))

par(xpd=TRUE, mar=par("mar")+c(0, 0, 0, 7))

plot(range(v_x), c(d_min, d_max), type="n", xaxt="n", yaxt="n", ylab="", xlab="", xaxs="i")
if (length(v_long_start) > 0) {
rect(xleft=v_long_start, xright=v_long_end, ybottom=par("usr")[3],
ytop=par("usr")[4], border="transparent", col=COLOR_LONG_POSITION)
}
if (length(v_short_start) > 0) {
rect(xleft=v_short_start, xright=v_short_end, ybottom=par("usr")[3],
ytop=par("usr")[4], border="transparent", col=COLOR_SHORT_POSITION)
}
if (length(v_neutral_start) > 0) {
rect(xleft=v_neutral_start, xright=v_neutral_end, ybottom=par("usr")[3],
ytop=par("usr")[4], border="transparent", col=COLOR_NEUTRAL_POSITION)
}
legend(nrow(df_data)+3, d_max, legend=v_legend, col=v_colors, lty=rep(1, length(v_colors)), lwd=1.5)
par(xpd=FALSE)
axis(1, at=v_ticks, labels=v_tick_dates)
axis(2, at=v_y_ticks, labels=v_y_ticks)
abline(h=v_y_ticks, v=v_ticks, col="gray", lty=3)
for (i in 1 : ncol(df_data)) {
lines(df_data[, i], type="l", col=v_colors[i])
}
box()

dev.off()
}

# plot indicator
plotIndicator2 = function(v_date, v_indicator, df_data, v_colors, v_legend, s_path)
{
jpeg(s_path, width=1200, height=700)

v_x = seq(1:nrow(df_data))

# determine x axis date labels
v_ticks      = c(v_x[1])
s_prev_date  = format(as.Date(v_date[1]), "%m-%Y")
v_tick_dates = c(s_prev_date)
for (i in 2 : length(v_x)) {
s_cur_date = format(as.Date(v_date[i]), "%m-%Y")
if (s_cur_date != s_prev_date) {
v_ticks      = c(v_ticks, v_x[i])
v_tick_dates = c(v_tick_dates, s_cur_date)
s_prev_date  = s_cur_date
}
}

# create plot
d_max     = max(df_data)
d_min     = min(df_data)
v_y_ticks = pretty(seq(d_min, d_max))

par(xpd=TRUE, mar=par("mar")+c(0, 0, 0, 8))

plot(range(v_x), c(d_min, d_max), type="n", xaxt="n", yaxt="n", ylab="", xlab="", xaxs="i")
legend(nrow(df_data)+8, d_max, legend=v_legend, col=v_colors, lty=rep(1, length(v_colors)),
pch=c(1, rep(NA, length(v_colors)-1)), lwd=1.5)
par(xpd=FALSE)
axis(1, at=v_ticks, labels=v_tick_dates)
axis(2, at=v_y_ticks, labels=v_y_ticks)
abline(h=v_y_ticks, v=v_ticks, col="gray", lty=3)
for (i in 1 : ncol(df_data)) {
lines(df_data[, i], type="l", col=v_colors[i+1])
}
par(new=TRUE)
plot(v_x, v_indicator, type="o", col=v_colors[1], axes=FALSE, bty="n", xlab="", ylab="", xaxs="i")
axis(4, at=pretty(range(v_indicator)))
box()

dev.off()
}

plotStock = function(v_date, v_price, s_path)
{
jpeg(s_path, width=1200, height=700)

v_x = seq(1:length(v_price))

# determine x axis date labels
v_ticks      = c(v_x[1])
s_prev_date  = format(as.Date(v_date[1]), "%m-%Y")
v_tick_dates = c(s_prev_date)
for (i in 2 : length(v_x)) {
s_cur_date = format(as.Date(v_date[i]), "%m-%Y")
if (s_cur_date != s_prev_date) {
v_ticks      = c(v_ticks, v_x[i])
v_tick_dates = c(v_tick_dates, s_cur_date)
s_prev_date  = s_cur_date
}
}

# create plot
d_max     = max(v_price)
d_min     = min(v_price)
v_y_ticks = pretty(seq(d_min, d_max))

plot(v_x, v_price, type="l", xaxt="n", yaxt="n", ylab="", xlab="", xaxs="i")

axis(1, at=v_ticks, labels=v_tick_dates)
axis(2, at=v_y_ticks, labels=v_y_ticks)
abline(h=v_y_ticks, v=v_ticks, col="gray", lty=3)

box()

dev.off()
}
```
```