'################################################################################################ '# Indicator : Ehlers Filter (Verdo) # '# Author : VERDESOFTS # '# Copyright : VERDESOFTS # '# Website : www.verde-solution.com # '# E-mail : admin@verde-solution.com # '# Date : 07-09-2015 # '# Description : Ehlers Filter is a powerful trend-following indicator the provides precise # '# BUY and SELL signals. # '# This indicator has a minimal lag, of approximately 4 bars, which is very # '# useful in detecting start of trends. # '# In the first step we calculate the distance co-efficient - which is the # '# absolute difference between the current price and price MOM_PERIOD bars ago.# '# This difference is then price-weighted over the LENGTH bars, that is, # '# multiplied by the price, thus providing us with the LENGTH bars WMA. It is # '# similar to an EMA, but is faster with lesser lag and better response to # '# change in trends. # '# It provides excellent entries when the signal-to-noise ratio (using the # '# Signal Noise Ratio indicator) is high, implying that the whipsaws are # '# lesser. # '# BUY - Enter BUY trade when indicator color turns BLUE. Exit BUY when # '# indicator color turns RED. # '# SELL - Enter SELL trade when indicator color turns RED. Exit SELL when # '# indicator color turns BLUE. # '# Inputs : # '# a) MOM_PERIOD - The momentum period to calculate the Ehlers Filter. # '# b) LENGTH- The smoothing period of the Ehler # '# History : # '# 1.00 : Initial version. # '# # '################################################################################################ '''###################### INPUT PARAMETERS #################################################### ''' All user input parameters are defined as constants so that they are not accidentally ''' changed in the code. Const LENGTH = 8 ' Length input parameter used in Ehlers Filter calculation. Const MOM_PERIOD = 5 ' The momentum period. '''############################################################################################## ''' Indicator keys and data. Dim m_chartID ' To track the current chart ID Dim m_chartName ' To track the current chart Name Dim m_indID1, m_indID2 ' To track indicator series created by this script. Dim arrPrice(), arrEhlers(), arrCoeff(), arrBUY(), arrSELL() Dim BARS_COUNT ' To track the total number of bars on the current chart. Dim PROCESSING ' To track active processing activity. '########## System Constants ####### Const UNDEFINED = -987654321 ' Undefined value provided by VTL ' Price field constants for applied price. Const PF_CLOSE = 0 ' Price Series : Close Const PF_OPEN = 1 ' Price Series : Open Const PF_HIGH = 2 ' Price Series : High Const PF_LOW = 3 ' Price Series : Low Const PF_MEDIAN = 4 ' Price Series : Median (H+L)/2 Const PF_TYPICAL = 5 ' Price Series : Typical (H+L+C)/3 Const PF_WEIGHTED = 6 ' Price Series : Weighted (H+L+2C)/4 Const PF_VOLUME = 10 ' Price Series : Volume Const VOL_DEFAULT = 100 ' Default Volume when Volume is missing ' Color Constants Const COLOR_BLUE = 16711680 ' Blue Const COLOR_RED = 255 ' Red '//////////////////////////////////////////////////////////////////////////////////////// ' Main '//////////////////////////////////////////////////////////////////////////////////////// Public Sub main() While (PROCESSING) Wend PROCESSING = True BARS_COUNT = 0 m_chartID = ChartID() m_chartName = ChartSymbol(CLng(m_chartID)) updateBuffers performCalculations 1 ' Add indicator series to chart. m_indID1 = AddCustomIndicator(0, arrBUY, 1, False) SetSeriesStyle 0, CStr(m_indID1), LINE_CHART LineColor 0, CStr(m_indID1), COLOR_BLUE LineWeight 0, CStr(m_indID1), 3 ' Add indicator series to chart. m_indID2 = AddCustomIndicator(0, arrSELL, 1, False) SetSeriesStyle 0, CStr(m_indID2), LINE_CHART LineColor 0, CStr(m_indID2), COLOR_RED LineWeight 0, CStr(m_indID2), 3 PROCESSING = False End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnTick '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnTick(symbolName) If( PROCESSING ) Then Exit Sub If( symbolName <> ChartSymbol(0) ) Then Exit Sub If( CLng(BARS_COUNT) <> CLng(Bars(0)) ) Then Exit Sub ' Write your OnTick code from here arrPrice(CLng(BARS_COUNT)) = CDbl(getPriceValue(PF_MEDIAN, CLng(BARS_COUNT))) performCalculations CLng(BARS_COUNT) ' Write to chart update code from here ObjectSeriesSetValue 0, CStr(m_indID1), CLng(BARS_COUNT), CDbl(arrBUY(BARS_COUNT)) ObjectSeriesSetValue 0, CStr(m_indID2), CLng(BARS_COUNT), CDbl(arrSELL(BARS_COUNT)) End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnCalculate '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnCalculate(symbol, symbolPeriod, openVal, highVal, lowVal, closeVal) If (PROCESSING) Then Exit Sub If( symbol <> ChartSymbol(0) ) Then Exit Sub PROCESSING = True updateBuffers performCalculations 1 SetIndicatorData 0, CStr(m_indID1), CDbl(arrBUY(BARS_COUNT)) SetIndicatorData 0, CStr(m_indID2), CDbl(arrSELL(BARS_COUNT)) PROCESSING = False End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' updateBuffers ' Update data buffers and build / perform calculations as required. ' Loads all the required data for the indicator. This function is called during ' initialization and during OnCalculate '//////////////////////////////////////////////////////////////////////////////////////// Private Sub updateBuffers() loadPriceSeries PF_MEDIAN, arrPrice loadPriceSeries PF_CLOSE, arrEhlers loadPriceSeries PF_CLOSE, arrCoeff loadPriceSeries PF_CLOSE, arrBUY loadPriceSeries PF_CLOSE, arrSELL Dim i For i = 1 To CLng(Bars(0)) arrEhlers(i) = UNDEFINED arrBUY(i) = UNDEFINED arrSELL(i) = UNDEFINED arrCoeff(i) = UNDEFINED Next ' Make sure this is the last line of the function BARS_COUNT = CLng(Bars(0)) End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' performCalculations ' Perform calculations for the specified range on the buffer. ' E.g. if startBar = 90, it performs calculations from the 90th-bar to the latest bar. '//////////////////////////////////////////////////////////////////////////////////////// Private Sub performCalculations(Byval startBar) Dim i, count, SumCoef, Num, j For i = startBar To BARS_COUNT If( i - MOM_PERIOD > 0 ) Then arrCoeff(i) = MathAbs(arrPrice(i) - arrPrice(i - MOM_PERIOD)) End If arrBUY(i) = UNDEFINED arrSELL(i) = UNDEFINED Num = 0 SumCoef = 0 For j = 0 To LENGTH - 1 If( i - j > 0 ) Then If( arrCoeff(i-j) <> UNDEFINED ) Then Num = Num + arrCoeff(i-j) * arrPrice(i-j) SumCoef = SumCoef + arrCoeff(i-j) End If End If Next If( Num > 0 AND SumCoef > 0 ) Then arrEhlers(i) = Num / SumCoef If( i > 1) Then If( arrEhlers(i) <> UNDEFINED AND arrEhlers(i-1) <> UNDEFINED ) Then If( arrEhlers(i) > arrEhlers(i-1) ) Then arrBUY(i) = arrEhlers(i) If( arrBUY(i-1) = UNDEFINED AND arrSELL(i-1) <> UNDEFINED ) Then arrSELL(i) = arrEhlers(i) End If ElseIf ( arrEhlers(i) < arrEhlers(i-1) ) Then arrSELL(i) = arrEhlers(i) If( arrBUY(i-1) <> UNDEFINED AND arrSELL(i-1) = UNDEFINED ) Then arrBUY(i) = arrEhlers(i) End If Else arrBUY(i) = arrBUY(i-1) arrSELL(i) = arrSELL(i-1) End If End If End If Next End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' loadPriceSeries '//////////////////////////////////////////////////////////////////////////////////////// Private Sub loadPriceSeries(Byval priceField, Byref array()) ' Price Field - Close(0), Open(1), High(2), Low(3), Median(4), Typical(5), Weighted(6) Dim totalBars totalBars = CLng(Bars(0)) Erase array CopyClose 0, 1, Bars(0), array Dim arrHigh(), arrLow(), arrClose() If( priceField = PF_OPEN ) Then ' OPEN CopyOpen 0, 1, Bars(0), array Elseif( priceField = PF_HIGH ) Then ' HIGH CopyHigh 0, 1, Bars(0), array Elseif( priceField = PF_LOW ) Then ' LOW CopyLow 0, 1, Bars(0), array Elseif( priceField = PF_MEDIAN ) Then ' MEDIAN CopyHigh 0, 1, Bars(0), arrHigh CopyLow 0, 1, Bars(0), arrLow For i = 1 To totalBars array(i) = CDbl( (CDbl(arrHigh(i)) + CDbl(arrLow(i))) / 2.0) Next Elseif( priceField = PF_TYPICAL OR priceField = PF_WEIGHTED ) Then 'TYPICAL OR WEIGHTED CopyHigh 0, 1, Bars(0), arrHigh CopyLow 0, 1, Bars(0), arrLow CopyClose 0, 1, Bars(0), arrClose For i = 1 To totalBars If( priceField = PF_TYPICAL ) Then array(i) = (CDbl(arrHigh(i)) + CDbl(arrLow(i)) + CDbl(arrClose(i))) / 3.0 Elseif( priceField = PF_WEIGHTED ) Then array(i) = (CDbl(arrHigh(i)) + CDbl(arrLow(i)) + 2.0 * CDbl(arrClose(i)))/ 4.0 End If Next Elseif( priceField = PF_VOLUME ) Then ' VOLUME CopyClose 0, 1, Bars(0), array For i = 1 To totalBars array(i) = CLng(VOL_DEFAULT) Next Else ' CLOSE CopyClose 0, 1, Bars(0), array End If End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' getPriceValue ' Returns the specified price (or volume) field value for the specified bar. ' E.g. if priceField is PF_OPEN, and barNum = 9, it returns the Open price of the 9th ' bar. '//////////////////////////////////////////////////////////////////////////////////////// Private Function getPriceValue(Byval priceField, Byval barNum) ' Price Field - Close(0), Open(1), High(2), Low(3), Median(4) Dim result If( priceField = PF_OPEN ) Then ' OPEN result = GetOpen(0, CLng(barNum)) Elseif( priceField = PF_HIGH ) Then ' HIGH result = GetHigh(0, CLng(barNum)) Elseif( priceField = PF_LOW ) Then ' LOW result = GetLow(0, CLng(barNum)) Elseif( priceField = PF_MEDIAN ) Then ' MEDIAN result = (CDbl(GetHigh(0, CLng(barNum))) + CDbl(getLow(0, CLng(barNum)))) / 2.0 Elseif( priceField = PF_TYPICAL ) Then ' TYPICAL result = (CDbl(GetHigh(0, CLng(barNum))) + CDbl(getLow(0, CLng(barNum)) + CDbl(getClose(0, CLng(barNum))))) / 3.0 Elseif( priceField = PF_WEIGHTED ) Then ' WEIGHTED result = (CDbl(GetHigh(0, CLng(barNum))) + CDbl(getLow(0, CLng(barNum)) + 2.0 * CDbl(getClose(0, CLng(barNum))))) / 4.0 Elseif( priceField = PF_VOLUME ) Then result = CDbl(VOL_DEFAULT) Else ' CLOSE result = GetClose(0, CLng(barNum)) End If getPriceValue = CDbl(result) End Function '//////////////////////////////////////////////////////////////////////////////////////// ' OnInit '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnInit() End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnDeInit '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnDeInit() ObjectDelete 0, CStr(m_indID1) ObjectDelete 0, CStr(m_indID2) BARS_COUNT = 0 End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' AllDataLoaded '//////////////////////////////////////////////////////////////////////////////////////// Public Sub AllDataLoaded() End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' AccountSelected '//////////////////////////////////////////////////////////////////////////////////////// Public Sub AccountSelected(accountNumber) End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnOrderTrade '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnOrderTrade(actionType, orderID, returnValue) End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnPositionTrade '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnPositionTrade(actionType, ticketID) End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnManageOrdersReceived '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnManageOrdersReceived(manageOrders) End Sub '//////////////////////////////////////////////////////////////////////////////////////// ' OnTimer '//////////////////////////////////////////////////////////////////////////////////////// Public Sub OnTimer() End Sub