AlphaBlock Network
Search
⌃K
Comment on page
🧮

Code: ABROC

Technical analyst Welles Wilder introduced the Rate of Change indicator (ROC) in the early 1970s. This indicator calculates the percentage change in price between the current period and a user-defined number of periods in the past. It fluctuates above and below a Zero Line and can be used for trend identification as well as identifying overbought and oversold conditions. Although ROC is an oscillator, it does not have a predetermined range, making it sometimes appear unbalanced.
The AlphaBlock scripting team adapted the indicator, adding eight moving averages, Dynamic Zones, and coloured candles. These features were added to improve trend identification and simplify identifying overbought and oversold regions. Dynamic Zones dynamically adjust as the indicator oscillates, providing a statistical calculation to define extreme levels and delimiting possible overbought/oversold regions. The percentile is calculated using the method of Nearest Rank, which identifies outliers or values significantly higher or lower than the rest of the data.

Enjoy.

// © AlphaBlock Network
//@version=5
​
indicator(title='AlphaBlock ROC (Rate of Change)', shorttitle='ABROC', timeframe="", timeframe_gaps=true, precision=2, format=format.price, overlay=false)
​
import andre_007/MovingAveragesProxy/2 as MaProxy
​
// ———————————————————————————————————————— Constants {
// Moving Averages Types
var string ALMA = 'Arnaud Legoux Moving Average'
var string HMA = 'Hull Moving Average'
var string JURIK = 'Jurik Moving Average'
var string LSMA = 'Least Squares Moving Average'
var string MEDIAN = 'Median'
var string REGMA = 'Regularized Exponential Moving Average'
var string RSIMA = 'RSI Moving average'
var string SMA = 'Simple Moving Average'
var string SMMA = 'Smoothed Moving Average'
var string WMA = 'Weighted Moving Average'
var string WWMA = 'Welles Wilder Moving Average'
​
var color COLOR_BULL = color.new(#3af13c, 0)
var color COLOR_BEAR = color.new(#ff0000, 0)
var color COLOR_BULL_MA = color.new(#3af13c, 75)
var color COLOR_BEAR_MA = color.new(#ff0000, 75)
// ———————————————————————————————————————— }
​
// ———————————————————————————————————————— Global Variables {
float roc = na
float movingAverage1 = na
float movingAverage2 = na
float movingAverage3 = na
float movingAverage4 = na
float movingAverage5 = na
float movingAverage6 = na
float movingAverage7 = na
float movingAverage8 = na
float dZoneAbove = na
float dZoneBelow = na
float dZoneCenter = na
// ———————————————————————————————————————— }
​
// ———————————————————————————————————————— inputs {
// ————— ROC
var int lengthROC = input.int(defval=21, title='Length', minval=1, group='ROC', inline='1')
sourceROC = input(defval=hl2, title="Source", group='ROC', inline='1')
​
var color inputColorBullRoc = input.color(COLOR_BULL, '', inline='1', group='ROC')
var color inputColorBearRoc = input.color(COLOR_BEAR, '', inline='1', group='ROC')
​
// ————— Dynamic Zone
var int dataSmple = input.int(defval = 55, title = "Sample Length", minval = 1, group = 'Dynamic Zones', inline = '1')
var float pcntAbove = input.float(defval = 90, title = "High is Above X% of Sample", minval = 0, maxval = 100, step = 1.0, group = 'Dynamic Zones', inline = '2')
var float pcntBelow = input.float(defval = 90, title = "Low is Below X% of Sample", minval = 0, maxval = 100, step = 1.0, group = 'Dynamic Zones', inline = '2')
​
var lineDzoneTop = input.color(#143bfc, 'Upper Line of Dynamic Zone', inline='3', group='Dynamic Zones')
var lineDzoneBottom = input.color(#143bfc, 'Lower Line of Dynamic Zone', inline='3', group='Dynamic Zones')
var fillDzoneAbove = input.color(color.new(COLOR_BULL, 60), 'Fill Dynamic Zone when above', inline='4', group='Dynamic Zones')
var fillDzoneInside = input.color(color.new(#143bfc, 85), 'Fill Dynamic Zone inside', inline='5', group='Dynamic Zones')
var fillDzoneBelow = input.color(color.new(COLOR_BEAR, 60), 'Fill Dynamic Zone when below', inline='6', group='Dynamic Zones')
​
var string centerLineOptA = 'Center of Dynamic Zone (x = 50%)'
var string centerLineOptB = 'Zero'
var string centerLine = input.string(defval = centerLineOptA, title = 'Center Line', options = [centerLineOptA, centerLineOptB], group = 'Dynamic Zones', inline = '7')
var color lineDzoneCenter = input.color(#fd6c1e, 'Center Line', inline='7', group='Dynamic Zones')
​
// ————— Moving Averages
var string inputTypeMa = input.string(title='Type', defval=REGMA, options=[ALMA,HMA,JURIK,LSMA,MEDIAN,REGMA,RSIMA,SMA,SMMA,WMA,WWMA], inline='1', group='Moving Averages')
var string GRP_VWMA_TOOLTIP = 'The most common "Volume Weighted Moving Average" is a Simple Moving Average of Price x Volume, divided by Simple Moving Average of Volume. \n' +
'Enabling this checkbox, it\'s possible to have other types and less common moving averages weighted by volume, for example, Exponencial Volume Weighted Moving Average, Alma Volume Weighted Moving Average, etc...'
var bool applyVolumeWeighted = input.bool(title="Volume Weighted Moving Average?", defval=false, group='Moving Averages', tooltip=GRP_VWMA_TOOLTIP, inline='1')
​
// ————— Average 1
var bool inputShowAvg1 = input.bool(title='Moving Average 1', defval=true, inline='12', group='Moving Averages')
var color inputColorBull1 = input.color(COLOR_BULL_MA, '', inline='12', group='Moving Averages')
var color inputColorBear1 = input.color(COLOR_BEAR_MA, '', inline='12', group='Moving Averages')
var int inputLengthMa1 = input.int(5, minval=1, title='Length', inline='13', group='Moving Averages')
​
// ————— Average 2
var bool inputShowAvg2 = input.bool(title='Moving Average 2', defval=true, inline='15', group='Moving Averages')
var color inputColorBull2 = input.color(COLOR_BULL_MA, '', inline='15', group='Moving Averages')
var color inputColorBear2 = input.color(COLOR_BEAR_MA, '', inline='15', group='Moving Averages')
var int inputLengthMa2 = input.int(10, minval=1, title='Length', inline='16', group='Moving Averages')
​
// ————— Average 3
var bool inputShowAvg3 = input.bool(title='Moving Average 3', defval=true, inline='17', group='Moving Averages')
var color inputColorBull3 = input.color(COLOR_BULL_MA, '', inline='17', group='Moving Averages')
var color inputColorBear3 = input.color(COLOR_BEAR_MA, '', inline='17', group='Moving Averages')
var int inputLengthMa3 = input.int(15, minval=1, title='Length', inline='18', group='Moving Averages')
​
// ————— Average 4
var bool inputShowAvg4 = input.bool(title='Moving Average 4', defval=true, inline='19', group='Moving Averages')
var color inputColorBull4 = input.color(COLOR_BULL_MA, '', inline='19', group='Moving Averages')
var color inputColorBear4 = input.color(COLOR_BEAR_MA, '', inline='19', group='Moving Averages')
var int inputLengthMa4 = input.int(20, minval=1, title='Length', inline='20', group='Moving Averages')
​
// ————— Average 5
var bool inputShowAvg5 = input.bool(title='Moving Average 5', defval=true, inline='21', group='Moving Averages')
var color inputColorBull5 = input.color(COLOR_BULL_MA, '', inline='21', group='Moving Averages')
var color inputColorBear5 = input.color(COLOR_BEAR_MA, '', inline='21', group='Moving Averages')
var int inputLengthMa5 = input.int(25, minval=1, title='Length', inline='22', group='Moving Averages')
​
// ————— Average 6
var bool inputShowAvg6 = input.bool(title='Moving Average 6', defval=true, inline='23', group='Moving Averages')
var color inputColorBull6 = input.color(COLOR_BULL_MA, '', inline='23', group='Moving Averages')
var color inputColorBear6 = input.color(COLOR_BEAR_MA, '', inline='23', group='Moving Averages')
var int inputLengthMa6 = input.int(30, minval=1, title='Length', inline='24', group='Moving Averages')
​
// ————— Average 7
var bool inputShowAvg7 = input.bool(title='Moving Average 7', defval=true, inline='25', group='Moving Averages')
var color inputColorBull7 = input.color(COLOR_BULL_MA, '', inline='25', group='Moving Averages')
var color inputColorBear7 = input.color(COLOR_BEAR_MA, '', inline='25', group='Moving Averages')
var int inputLengthMa7 = input.int(35, minval=1, title='Length', inline='26', group='Moving Averages')
​
// ————— Average 8
var bool inputShowAvg8 = input.bool(title='Moving Average 8', defval=true, inline='27', group='Moving Averages')
var color inputColorBull8 = input.color(COLOR_BULL_MA, '', inline='27', group='Moving Averages')
var color inputColorBear8 = input.color(COLOR_BEAR_MA, '', inline='27', group='Moving Averages')
var int inputLengthMa8 = input.int(40, minval=1, title='Length', inline='28', group='Moving Averages')
​
// ————— Line colors
var string color_A = 'is below or above the next moving average'
var string color_B = 'is below or above Zero or Center of Dynamic Zone'
​
var string avgColorLogic = input.string(defval=color_B, title='Change line colors when', inline='2', group='Line Colors', options=[color_A, color_B])
var bool inputFill = input.bool(title='Fill background between averages?', defval=false, inline='3', group='Line Colors')
var int inputColorFillTransparency = input.int(defval=90 , title="Transparency for fill", minval=0, maxval=100, inline = "4", group='Line Colors')
​
// ————— Bar colors
var string bar_color_A = 'All lines are aligned'
var string bar_color_B = 'ROC is above or under all MAs'
var string bar_color_C = 'All lines are above or under Zero or Center of Dynamic Zone'
var string bar_color_E = 'ROC is above or under Zero or Center of Dynamic Zone'
var string bar_color_D = 'Never'
var string barColorsLogic = input.string(defval=bar_color_E, title='Change bar colors when', inline='2', group='Bar Colors', options=[bar_color_A, bar_color_B, bar_color_C, bar_color_E, bar_color_D])
var color inputBarColorBull = input.color(color.new(#12760e, 0), 'Bullish', inline='3', group='Bar Colors')
var color inputBarColorBear = input.color(color.new(#d45959, 0), 'Bearish', inline='3', group='Bar Colors')
​
var bool inputBarColorDzone = input.bool(title='Change bar colors when ROC is above or below Dynamic Zones?', defval=true, inline='4', group='Bar Colors')
var color inputBarColorBullDzone = input.color(COLOR_BULL, 'Bullish', inline='5', group='Bar Colors')
var color inputBarColorBearDzone = input.color(COLOR_BEAR, 'Bearish', inline='5', group='Bar Colors')
// ———————————————————————————————————————— }
​
// ———————————————————————————————————————— Functions {
// @description Returns a bar color
// @returns Color
applyBarColor() =>
color barColor = if (barColorsLogic == bar_color_D) // 'Never'
na
else if (barColorsLogic == bar_color_A) // 'All lines are aligned'
if roc >= nz(movingAverage1, roc) and
nz(movingAverage1) >= nz(movingAverage2) and
nz(movingAverage2) >= nz(movingAverage3) and
nz(movingAverage3) >= nz(movingAverage4) and
nz(movingAverage4) >= nz(movingAverage5) and
nz(movingAverage5) >= nz(movingAverage6) and
nz(movingAverage6) >= nz(movingAverage7) and
nz(movingAverage7) >= nz(movingAverage8)
inputBarColorBull
else
inputBarColorBear
else if (barColorsLogic == bar_color_B) // 'ROC is above or under all MAs'
if roc >= nz(movingAverage1, roc) and
roc >= nz(movingAverage2) and
roc >= nz(movingAverage3) and
roc >= nz(movingAverage4) and
roc >= nz(movingAverage5) and
roc >= nz(movingAverage6) and
roc >= nz(movingAverage7) and
roc >= nz(movingAverage8)
inputBarColorBull
else
inputBarColorBear
else if (barColorsLogic == bar_color_C) // 'All lines are above or under Zero or Center of Dynamic Zone'
float zero = (centerLine == centerLineOptA ? dZoneCenter : 0)
if roc >= zero and
nz(movingAverage1) >= zero and
nz(movingAverage2) >= zero and
nz(movingAverage3) >= zero and
nz(movingAverage4) >= zero and
nz(movingAverage5) >= zero and
nz(movingAverage6) >= zero and
nz(movingAverage7) >= zero and
nz(movingAverage8) >= zero
inputBarColorBull
else
inputBarColorBear
else if (barColorsLogic == bar_color_E) // 'ROC is above or under Zero or Center of Dynamic Zone'
float zero = (centerLine == centerLineOptA ? dZoneCenter : 0)
if roc >= zero
inputBarColorBull
else
inputBarColorBear
else
na
​
// 'ROC is above or under Dynamic Zone'
barColor := if inputBarColorDzone
if roc >= dZoneAbove
inputBarColorBullDzone
else if roc <= dZoneBelow
inputBarColorBearDzone
else
barColor
​
// @function calculateMovingAverage
// @description Abstract function that invokes the calculation of average according to type
// @param type Type of Moving Average
// @param src Source of series (close, high, low, etc.)
// @param len Period of loopback to calculate the average
// @returns series of moving average
calculateMovingAverage(simple string type, float src, simple int len) =>
MaProxy.getMovingAverage(
type=type, src=src, len=len,
lsmaOffset=0,
volumeWeighted=applyVolumeWeighted)
​
// @function f_SetColorLine
// @description Set color line for ROC or MA's
// @param val_1 A line
// @param val_2 Next Line
// @param colorBull Color when bullish
// @param colorBear Color when bearish
// @param previousColor Color for use when next line is deactivated
// @returns series color
f_SetColorLine(float val_1, float val_2, simple color colorBull, simple color colorBear, series color previousColor=na) =>
color color_line = if avgColorLogic == color_A // 'All lines are aligned'
if na(val_2)
previousColor
else
if nz(val_1) >= nz(val_2)
colorBull
else
colorBear
else // 'is below or above Zero or Center of Dynamic Zone'
float zero = (centerLine == centerLineOptA ? dZoneCenter : 0)
if val_1 >= zero
colorBull
else
colorBear
// ———————————————————————————————————————— }
​
// ———————————————————————————————————————— Calculations {
roc := 100 * (sourceROC - sourceROC[lengthROC])/sourceROC[lengthROC]
​
// Moving Averages
if inputShowAvg1
movingAverage1 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa1)
if inputShowAvg2
movingAverage2 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa2)
if inputShowAvg3
movingAverage3 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa3)
if inputShowAvg4
movingAverage4 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa4)
if inputShowAvg5
movingAverage5 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa5)
if inputShowAvg6
movingAverage6 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa6)
if inputShowAvg7
movingAverage7 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa7)
if inputShowAvg8
movingAverage8 := calculateMovingAverage(inputTypeMa, roc, inputLengthMa8)
​
// Dynamic Zones
dZoneAbove := ta.percentile_nearest_rank(roc, dataSmple, pcntAbove)
dZoneBelow := ta.percentile_nearest_rank(roc, dataSmple, 100 - pcntBelow)
dZoneCenter := ta.percentile_nearest_rank(roc, dataSmple, 100 - 50)
// ———————————————————————————————————————— }
​
// ———————————————————————————————————————— Bar Colors {
barcolor( applyBarColor() )
// ———————————————————————————————————————— }
​
// ———————————————————————————————————————— Plots {
// Center Line
hline(0, color = lineDzoneCenter, title="Zero", linewidth=1, linestyle=hline.style_dashed, display=(centerLine==centerLineOptB ? display.all : display.none))
plot(dZoneCenter, title="Center Line", color=lineDzoneCenter, linewidth=1, style=plot.style_line, display=(centerLine==centerLineOptA ? display.all : display.none)) // bar_index % 2 ? lineDzoneCenter : na
​
// ROC and Moving Averages
color colorLineROC = f_SetColorLine(roc, movingAverage1, inputColorBullRoc, inputColorBearRoc)
color colorLineMa1 = f_SetColorLine(movingAverage1, movingAverage2, inputColorBull1, inputColorBear1, colorLineROC)
color colorLineMa2 = f_SetColorLine(movingAverage2, movingAverage3, inputColorBull2, inputColorBear2, colorLineMa1)
color colorLineMa3 = f_SetColorLine(movingAverage3, movingAverage4, inputColorBull3, inputColorBear3, colorLineMa2)
color colorLineMa4 = f_SetColorLine(movingAverage4, movingAverage5, inputColorBull4, inputColorBear4, colorLineMa3)
color colorLineMa5 = f_SetColorLine(movingAverage5, movingAverage6, inputColorBull5, inputColorBear5, colorLineMa4)
color colorLineMa6 = f_SetColorLine(movingAverage6, movingAverage7, inputColorBull6, inputColorBear6, colorLineMa5)
color colorLineMa7 = f_SetColorLine(movingAverage7, movingAverage8, inputColorBull7, inputColorBear7, colorLineMa6)
color colorLineMa8 = f_SetColorLine(movingAverage7, movingAverage8, inputColorBull8, inputColorBear8, colorLineMa7)
​
plotROC = plot(roc, title="ROC", color=colorLineROC, linewidth=2, style=plot.style_line)
plotMa1 = plot(movingAverage1, title="Moving Average 1", color=colorLineMa1, linewidth=1, style=plot.style_circles)
plotMa2 = plot(movingAverage2, title="Moving Average 2", color=colorLineMa2, linewidth=1, style=plot.style_circles)
plotMa3 = plot(movingAverage3, title="Moving Average 3", color=colorLineMa3, linewidth=1, style=plot.style_circles)
plotMa4 = plot(movingAverage4, title="Moving Average 4", color=colorLineMa4, linewidth=1, style=plot.style_circles)
plotMa5 = plot(movingAverage5, title="Moving Average 5", color=colorLineMa5, linewidth=1, style=plot.style_circles)
plotMa6 = plot(movingAverage6, title="Moving Average 6", color=colorLineMa6, linewidth=1, style=plot.style_circles)
plotMa7 = plot(movingAverage7, title="Moving Average 7", color=colorLineMa7, linewidth=1, style=plot.style_circles)
plotMa8 = plot(movingAverage8, title="Moving Average 8", color=colorLineMa8, linewidth=1, style=plot.style_circles)
​
fill(plotROC, plotMa1, color=inputFill ? color.new(f_SetColorLine(roc, movingAverage1, inputColorBullRoc, inputColorBearRoc), inputColorFillTransparency) : na )
fill(plotMa1, plotMa2, color=inputFill ? color.new(f_SetColorLine(movingAverage1, movingAverage2, inputColorBull1, inputColorBear1), inputColorFillTransparency) : na )
fill(plotMa2, plotMa3, color=inputFill ? color.new(f_SetColorLine(movingAverage2, movingAverage3, inputColorBull2, inputColorBear2), inputColorFillTransparency) : na )
fill(plotMa3, plotMa4, color=inputFill ? color.new(f_SetColorLine(movingAverage3, movingAverage4, inputColorBull3, inputColorBear3), inputColorFillTransparency) : na )
fill(plotMa4, plotMa5, color=inputFill ? color.new(f_SetColorLine(movingAverage4, movingAverage5, inputColorBull4, inputColorBear4), inputColorFillTransparency) : na )
fill(plotMa5, plotMa6, color=inputFill ? color.new(f_SetColorLine(movingAverage5, movingAverage6, inputColorBull5, inputColorBear5), inputColorFillTransparency) : na )
fill(plotMa6, plotMa7, color=inputFill ? color.new(f_SetColorLine(movingAverage6, movingAverage7, inputColorBull6, inputColorBear6), inputColorFillTransparency) : na )
fill(plotMa7, plotMa8, color=inputFill ? color.new(f_SetColorLine(movingAverage7, movingAverage8, inputColorBull7, inputColorBear7), inputColorFillTransparency) : na )
​
// Dynamic Zones
above = plot(roc > dZoneAbove ? roc : dZoneAbove, title = "", color = color(na))
probOB = plot(dZoneAbove, title = "Dynamic Zone: Top Line", color = lineDzoneTop, linewidth=1)
probOS = plot(dZoneBelow, title = "Dynamic Zone: Bottom Line", color = lineDzoneBottom, linewidth=1)
below = plot(roc < dZoneBelow ? roc : dZoneBelow, title = "", color = color(na))
​
fill(above, probOB, color = fillDzoneAbove)
fill(probOB, probOS, color = fillDzoneInside)
fill(below, probOS, color = fillDzoneBelow)
// ———————————————————————————————————————— }