Since my shared chart doesn’t contain the range bands, and in response to some feedback, below is code for range bands. Follow these steps:
- Right-click on an empty area of a chart and select Create New, Indicator Block Diagram.
- Call it EaUpperBand and click Ok
- Drag the input for "Numeric Plot” to an empty part of the diagram and select Create Code Block
- Select Bar and Int to Line and click Ok
- Name the block EaUpperBandCode and click Ok
- Paste the contents of the code below between Public Overrides and End Sub
- Before saving the block paste the separate functions called HighestHigh() and LowestLow() into the code block after End Sub but before End Class.
- Click Ok to save the code block.
- Once back at the block diagram, drag the input for EaUpperBand to the Green Price History on the chart at the top
- Make the other input 12 and make the color blue.
- When your done it should appear as on the left.
- Repeat the same steps and create the EaLowerBand indicator and create the EaLowerBandCode code block. Make the color red.
I use a parameter of 12 by default but would love if the Wordens can add an optimization feature for BackScanner that would allow us to see the results of a trading system across a range of parameter values.
Paste this between Calculate and End Sub:
'***************************************************************
' Calculate the EAUpper band as follows:
'
' Calculate the high, low and the midpoint as the difference
' between the high and the low
'
' And while doing that, also calculate the Average True Range
' for the same bars back.
'
' This function is called once for the entire data set
' Copyright (c) 2009 TCX Systems
'
'****************************************************************
Dim i As Integer
Dim dReturn As Single
Dim nLookBack As Integer
' High and Low
Dim dHigh As Single
Dim dLow As Single
Dim dDate As Date
Dim dHighestHigh As Single
Dim dLowestLow As Single
Dim dRange As Single
' Prior high and low
Dim dPriorClose As Single
' Running sum of ranges
Dim dRunningSum As Single
' Average True Range
Dim dTheAtr As Single
Dim dPrevAtr As Single
' 1.06 times the ATR
Dim dAtrOffset As Single
' Midpoint uses for calculations
Dim dMidPoint As Single
' Set lookback
nLookBack = Me.CodeBlock.ParameterValue
If nLookBack < 1 Then nLookBack = 1
If nLookBack > inputcount-2 Then nLookBack = inputcount - 2
'calc first precATR
dPriorClose = 0
' Running Sum action
dRunningSum = 0
For nNdx As Integer = 0 To nLookBack
dHigh = Me.CodeBlock.InputHigh(nNdx)
dLow = Me.CodeBlock.InputLow(nNdx)
dDate = Me.CodeBlock.InputDate(nNdx)
dRange = System.Math.Abs(dHigh - dLow)
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dHigh))
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dLow))
dRunningSum += dRange
dPriorClose = Me.CodeBlock.InputLast(nNdx)
Next nNdx
' Calculate first ATR
dPrevAtr = dRunningSum/nLookBack
' For each row in the set
For i = nLookBack To Me.CodeBlock.InputCount -1
' Grab prior high and low
dPriorClose = Me.CodeBlock.InputLast(i-1)
' Calculate current high,low
dHigh = Me.CodeBlock.InputHigh(i)
dLow = Me.CodeBlock.InputLow(i)
dDate = Me.CodeBlock.InputDate(i)
' Calculate ATR
dRange = System.Math.Abs(dHigh - dLow)
' Consider yesterdays close - high
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dHigh))
' Consider yesterday's close low
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dLow))
' Calculate ATR here
dTheAtr = ((dRange - dPrevAtr)/nLookBack) + dPrevAtr
' Calculate ATR Offset
dAtrOffset = dTheAtr * 1.06
' Grab the close
dHighestHigh = HighestHigh(i,nLookBack)
dLowestLow = LowestLow(i,nLookBack)
' Set return value
dRange = dHighestHigh-dLowestLow
' Calculate midpoint
dMidPoint = dLowestLow+(dRange*0.5)
' Calculate upper band
dReturn = dMidPoint + dAtrOffset
' Log the return
Log.Info("dHighestHigh, dLowestLow, dMidPoint, dAtr, dReturn" & dHighestHigh & ", " & dLowestLow & "," & dMidPoint & "," & dTheAtr & "," & dReturn)
' Grab the value
Me.AddToOutput(CodeBlock.InputDate(i), dReturn)
' Save for next go round
dPrevAtr = dTheAtr
Next i
Paste this after End Sub and before End Class:
Function HighestHigh(i As Integer, nLookBack As Integer) As Single
Dim j As Integer
Dim dRetVal As Single
Dim dHigh As Single
' Set initial return value
dRetVal = 0
' Look back nLookBack bars
For j = i - nLookBack To i
' Grab the close
dHigh = CodeBlock.InputHigh(j)
' Grab max and min
If (dHigh > dRetVal) Then
dRetVal = dHigh
End If
Next j
' Set return value
HighestHigh = dRetVal
End Function
Function LowestLow(i As Integer, nLookBack As Integer) As Single
Dim j As Integer
Dim dRetVal As Single
Dim dLow As Single
' Set initial return value
dRetVal = 1000000.0
' Look back nLookBack bars
For j = i - nLookBack To i
' Grab the close
dLow = CodeBlock.InputLow(j)
' Grab max and min
If (dLow < dRetVal) Then
dRetVal = dLow
End If
Next j
' Set return value
LowestLow = dRetVal
End Function
Same thing for EaLowerBandCode:
'***************************************************************
' Calculate the EALower band as follows:
'
' Calculate the high, low and the midpoint as the difference
' between the high and the low
'
' And while doing that, also calculate the Average True Range
' for the same bars back.
'
'****************************************************************
Dim i As Integer
Dim dReturn As Single
Dim nLookBack As Integer
' High and Low
Dim dHigh As Single
Dim dLow As Single
Dim dHighestHigh As Single
Dim dLowestLow As Single
Dim dRange As Single
' Prior high and low
Dim dPriorClose As Single
' Running sum of ranges
Dim dRunningSum As Single
' Average True Range
Dim dTheAtr As Single
Dim dPrevAtr As Single
' 1.06 times the ATR
Dim dAtrOffset As Single
' Midpoint uses for calculations
Dim dMidPoint As Single
' Set lookback
nLookBack = Me.CodeBlock.ParameterValue
If nLookBack < 1 Then nLookBack = 1
If nLookBack > inputcount - 2 Then nLookBack = inputcount - 2
'calc first precATR
dPriorClose = 0
' Running Sum action
dRunningSum = 0
For nNdx As Integer = 0 To nLookBack - 1
dHigh = Me.CodeBlock.InputHigh(nNdx)
dLow = Me.CodeBlock.InputLow(nNdx)
dRange = System.Math.Abs(dHigh - dLow)
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dHigh))
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dLow))
dRunningSum += dRange
dPriorClose = Me.CodeBlock.InputLast(nNdx)
Next nNdx
' Calculate first ATR
dPrevAtr = dRunningSum / nLookBack
' For each row in the set
For i = nLookBack To Me.CodeBlock.InputCount - 1
' Grab prior high and low
dPriorClose = Me.CodeBlock.InputLast(i - 1)
' Calculate current high,low
dHigh = CodeBlock.InputHigh(i)
dLow = CodeBlock.InputLow(i)
' Calculate ATR
dRange = System.Math.Abs(dHigh - dLow)
' Consider yesterdays close - high
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dHigh))
' Consider yesterday's close low
dRange = System.Math.Max(dRange, system.Math.Abs(dPriorClose - dLow))
' Calculate ATR here
dTheAtr = ((dRange - dPrevAtr) / nLookBack) + dPrevAtr
' Calculate ATR Offset
dAtrOffset = dTheAtr * 1.06
' Grab the close
dHighestHigh = HighestHigh(i, nLookBack)
dLowestLow = LowestLow(i, nLookBack)
' Set return value
dRange = dHighestHigh - dLowestLow
' Calculate midpoint
dMidPoint = dLowestLow + (dRange * 0.5)
' Calculate upper band
dReturn = dMidPoint - dAtrOffset
' Log the return
Log.Info("dHighestHigh, dLowestLow, dMidPoint, dAtr, dReturn" & dHighestHigh & ", " & dLowestLow & "," & dMidPoint & "," & dTheAtr & "," & dReturn)
' Grab the value
Me.AddToOutput(CodeBlock.InputDate(i), dReturn)
' Save for next go round
dPrevAtr = dTheAtr
Next i
Use the same HighestHigh and LowestLow functions found above. Let me know feedback if any issues.