[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

A zero lag noise filter



PureBytes Links

Trading Reference Links


Below is source code for A DLL that calculates a zero lag noise filter.
Also, attached is the compiled 16 bit DLL.  What the chart looks like is
quite interesting.  Some will remember that many months ago, Bob Brickey
on his web site covered an FFT - inverse FFT to produce a zero lag
filter.  He had a GIF chart for downloading.  Shortly thereafter, Mark
Brown on his web site showed that the same thing could be done in EL.
He also had a GIF chart for downloading but Mark did not disclose the
EL code.  Recently, TASC published two articles by Dennis Meyers that
covered the FFT - inverse FFT as a zero lag filter.  The articles had a
number of charts.

I erased the Brickey and Brown chart files after I viewed them but I
remember the substance of their appearance.  I do have the Meyers
articles.  Well, the forward - backward average of T3 MA's with length
of 7 comes darn close to the appearance of the FFT method.  And, this is
so much simpler.

Some have commented that a simpler approach that would not require a
DLL and would duplicate results of a forward - backward MA would be to
only move forward while summing both past and future values with
appropriate weights.  That is correct except I don't believe that EL
will allow that.  Here is my vague understanding of EL as it scans
forward from bar to bar through a historical data series.  Say it has
reached bar 1000 of a 3000 bar file of daily data.  The circular buffer
will allow looking backward up to MaxBarsBack, but there is no provision
to look forward.  So for its calculations it can use the bar 1000 value
and certain previous values but it can't get future values of the data
series even though they are in the data file.  While at bar 1000, after
calculations are done, EL will write to array cells that hold the bar
1000 values for the plots.  But, when EL has moved from bar 1000 to bar
1001, it can't write backwards to the bar 1000 plot array cells.

I am not an expert at what's under the EL hood so if I am wrong about
the above, I look forward to being corrected.

CAUTION:  Reversal of zero lag filter slope direction looks like a
perfect predictor of future price direction when viewing historical
data.  It isn't where it counts - for a date that is later than the last
date in the historical file.

' *******************************************************************
' *  ZLAGFILT.BAS  --  Zero lag noise filter DLL for EasyLanguage.  *
' *                    (C) 1999, Barry Kaufman                      *
' *                    Version 01, OCT-02-1999                      *
' *******************************************************************

' The DLL compiled from this BASIC source code can be called by a
' 16 bit version of Omega Research Tradestation or Supercharts.  Use
' the PowerBasic PBDLL version 2.0, 16 bit compiler.  This code should
' probably work (might need slight modifications) with 32 bit versions
' of Omega Research products if compiled by PowerBasic PBDLL version
' 5.0 or greater, 32 bit compiler.

' Purpose is to make a zero lag noise filter that is the average
' of a forward MA and a backward MA.  The forward and backward MA's
' can either be standard exponential or the Tim Tillson T3.

' T3 MA code is adapted from posts on the "Omega List" by Bob Fulks.

' To prevent the DLL from being de-allocated at beginning of an EL
' run (EL scanning from start to finish of data), a dummy workspace
' has to be created to place a hold on the DLL.  Do the following:

'   Open a workspace, choose your data series for DATA1, and install
'   the EL indicator below.  The only thing done in this workspace
'   is load the data series to the DLL price array so set Input
'   MODE to 0.

'   From that workspace, open a second workspace so as to keep the
'   first workspace open but inactive.  Choose the same data series
'   for DATA1.  install the same EL indicator but set its Input MODE
'   to 1 or 2.  This workspace is where the filter is calculated and
'   plotted, and where you will work.  You can set MODE to 0 at any
'   time in this workspace to re-load the data series to the DLL
'   price array.


' ==========================================================
'   Example Of EasyLanguage Indicator That Calls This DLL  =
' ==========================================================

' {
' Indicator for a zero lag noise filter.  Requires ZLAGFILT.DLL
' Oct-01-1999
' }

' INPUTS:

'   INDAT (C OF DATA1),   { Field and series for price. }
'   LENGTH (7),           { Length of forward and backward MA. }
'   SMOOTH (0.7),         { Smoothing factor (For T3 MA). }
'   MODE (0),             { 0 = Load price data only.  Don't calc. MA's. }
'                         { 1 = Do exponential MA. }
'                         { 2 = Do Tillson T3 MA. }
'   TEST (0);             { 0 = No test.  DLL returns zero lag filter. }
'                         { 1 = DLL returns price loaded during MODE 0. }
'                         { 2 = DLL returns forward MA only. }
'                         { 3 = DLL returns Backward MA only. }

' VARS:

'   CURBAR (0),           { Current bar. }
'   ZLAGFILT (0);         { Zero lag filter. }

' { Define the DLL functions. }
' DefineDLLFunc: "C:\DLLS\ZLAGFILT.DLL", INT, "LOAD_PRICE", FLOAT, LONG;
' DefineDLLFunc: "C:\DLLS\ZLAGFILT.DLL", INT, "CALC_ZLFIL", FLOAT, FLOAT,
'                                        LONG, LONG, LONG, LPFLOAT;

' { VALUE1 is dummy return integer for the DLL functions. }
' CURBAR = CurrentBar;
' IF MODE = 0 THEN BEGIN  { Mode to load price series to DLL array. }
'   VALUE1 = LOAD_PRICE (INDAT, CURBAR);
' END ELSE BEGIN  { Mode to calculate the zero lag filter. }
'   VALUE1 = CALC_ZLFIL (LENGTH, SMOOTH, MODE, CURBAR,
'                       TEST, &ZLAGFILT);
'   PLOT1 (ZLAGFILT, "ZLAGFILT");
' END;

' { End of EasyLanguage code example }


' ============================
'   DLL Compiler Directives  =
' ============================

$DEBUG PBD OFF                         ' No compile time symbolic debug.
$COMPILE DLL                           ' Compile to DLL rather than EXE.
' $HUGE                                ' Let arrays be > 64K.
$DIM ALL                               ' Declare variables before use.
$OPTION VERSION3                       ' Compatible with Windows 3.x.


' ==================================================
'   Declare Procedures Called By Other Procedures  =
' ==================================================

DECLARE SUB MA_CALC ()                 ' Sub. that does MA calculation.


' =============================
'   Declare Global Variables  =
' =============================

GLOBAL INDAT         AS SINGLE         ' Input data.
GLOBAL LENGTH        AS SINGLE         ' Length of MA.
GLOBAL SMOOTH        AS SINGLE         ' Smoothing factor for T3 MA.
GLOBAL MODE          AS LONG           ' Shows price or MA calc. mode.
GLOBAL MODE1         AS LONG           ' Passes MODE to SUB MA_CALC.
GLOBAL CURBAR        AS LONG           ' CurrentBar number from EL.
GLOBAL TEST          AS LONG           ' Test state.
GLOBAL BARCOU1       AS LONG           ' Bar counter.
GLOBAL INDEX1        AS LONG           ' Index for FOR - NEXT loop.
GLOBAL ZLAGADR       AS DWORD          ' Address of EL ZLAGFILT.
GLOBAL ZLAGPTR       AS SINGLE PTR     ' Pointer to EL ZLAGFILT.
GLOBAL TEMPF1        AS SINGLE         ' Temporary float variable.

' Global arrays.
GLOBAL PRICE ()      AS SINGLE         ' Array for input data.
GLOBAL FORMA ()      AS SINGLE         ' Array for forward MA.
GLOBAL BACMA ()      AS SINGLE         ' Array for backward MA.

' Variables for T3 MA and exponential MA.
GLOBAL B2            AS SINGLE
GLOBAL B3            AS SINGLE
GLOBAL E1            AS SINGLE
GLOBAL E1P           AS SINGLE         ' E1 on previous bar.
GLOBAL E2            AS SINGLE
GLOBAL E2P           AS SINGLE         ' E2 on previous bar.
GLOBAL E3            AS SINGLE
GLOBAL E3P           AS SINGLE         ' E3 on previous bar.
GLOBAL E4            AS SINGLE
GLOBAL E4P           AS SINGLE         ' E4 on previous bar.
GLOBAL E5            AS SINGLE
GLOBAL E5P           AS SINGLE         ' E5 on previous bar.
GLOBAL E6            AS SINGLE
GLOBAL E6P           AS SINGLE         ' E6 on previous bar.
GLOBAL C1            AS SINGLE
GLOBAL C2            AS SINGLE
GLOBAL C3            AS SINGLE
GLOBAL C4            AS SINGLE
GLOBAL F1            AS SINGLE
GLOBAL F2            AS SINGLE
GLOBAL G1            AS SINGLE
GLOBAL G1P           AS SINGLE         ' G1 on previous bar.
GLOBAL MOVAVE        AS SINGLE         ' Output from MA calc. routine.


' =====================
'   Function LibMain  =
' =====================

' Function LibMain is run once by Windows when it loads this DLL.
' This function definition is the same for any DLL.  Certain other
' run-once code can be put here as well, like initializing global
' objects.

FUNCTION LibMain (BYVAL hInstance AS INTEGER,_
                  BYVAL wDataSeg AS WORD,_
                  BYVAL wHeapSize AS WORD,_
                  lpszCmdLine AS ASCIIZ) EXPORT AS INTEGER

  LibMain = 1                          ' 1 tells WIN that load
                                       ' was a success.
END FUNCTION


' ========================
'   Function LOAD_PRICE  =
' ========================

FUNCTION LOAD_PRICE (BYVAL INDAT AS SINGLE,_
                     BYVAL CURBAR AS LONG) EXPORT AS INTEGER

' This function is called by EL when input MODE = 0.  It dimensions
' arrays and loads first through last bar of price to the price
' array.  BARCOU1 shows how many bars are in the price series.

  IF CURBAR = 1 THEN                   ' First EL bar.
    DIM PRICE (13000) AS SINGLE        ' Dimension price array.
    DIM FORMA (13000) AS SINGLE        ' Dimension forward MA array.
    DIM BACMA (13000) AS SINGLE        ' Dimension backward MA array.
    FOR INDEX1 = 1 TO 13000            ' Zero all array cells.
      PRICE (INDEX1) = 0
      FORMA (INDEX1) = 0
      BACMA (INDEX1) = 0
    NEXT INDEX1
  END IF
  ' For all EL bars.
  PRICE (CURBAR) = INDAT               ' Load price to array cell.
  BARCOU1 = CURBAR                     ' Tracks the EL bar count.

  FUNCTION = 1                         ' Return dummy integer to EL.

END FUNCTION


' ========================
'   Function CALC_ZLFIL  =
' ========================

FUNCTION CALC_ZLFIL (BYVAL LENGTH AS SINGLE,_
                     BYVAL SMOOTH AS SINGLE,_
                     BYVAL MODE AS LONG,_
                     BYVAL CURBAR AS LONG,_
                     BYVAL TEST AS LONG,_
                     BYVAL ZLAGADR AS DWORD) EXPORT AS INTEGER

' This function is called by EL when input MODE > 0.  Price should
' have already been loaded to PRICE() array by MODE being set to 0.

' Both forward and backward MA's are calculated when CurrentBar = 1.
' Then the average of these (zero lag filter) is sent to EL as EL
' scans from bar = 1 to bar = last bar on chart.

  IF CURBAR = 1 THEN                   ' First EL bar.

    MODE1 = MODE                       ' Passes MODE to SUB MA_CALC.

    ' Initialize the MA variables.
    B2 = SMOOTH * SMOOTH
    B3 = SMOOTH * SMOOTH * SMOOTH
    C1 = -B3
    C2 = 3 * B2 + 3 * B3
    C3 = -6 * B2 - 3 * SMOOTH - 3 * B3
    C4 = 1 + 3 * SMOOTH + B3 + 3 * B2
    F1 = 2 / (LENGTH + 1)
    F2 = 1 - F1

    ' ===== CALCULATE FORWARD MA =====

    ' Set these MA variables for the 1st EL bar.
    E1 = PRICE (1)
    E2 = PRICE (1)
    E3 = PRICE (1)
    E4 = PRICE (1)
    E5 = PRICE (1)
    E6 = PRICE (1)
    G1 = PRICE (1)
    FORMA (1) = PRICE (1)              ' Set 1st MA cell to 1st bar price.
    FOR INDEX1 = 2 TO BARCOU1          ' For bar 2 to last bar in array.
      TEMPF1 = PRICE (INDEX1)          ' Get price from price array.
      CALL MA_CALC                     ' Do forward MA calculation.
      FORMA (INDEX1) = MOVAVE          ' Load MA to forward MA cell.
    NEXT INDEX1

    ' ===== CALCULATE BACKWARD MA =====

    ' Set these MA variables for the last EL bar.
    E1 = PRICE (BARCOU1)
    E2 = PRICE (BARCOU1)
    E3 = PRICE (BARCOU1)
    E4 = PRICE (BARCOU1)
    E5 = PRICE (BARCOU1)
    E6 = PRICE (BARCOU1)
    G1 = PRICE (BARCOU1)
    BACMA (BARCOU1) = PRICE (BARCOU1)  ' Set last MA cell to last bar price.
    ' For last bar - 1 to 1 in array.
    FOR INDEX1 = (BARCOU1 - 1) TO 1 STEP -1
      TEMPF1 = PRICE (INDEX1)          ' Get price from price array.
      CALL MA_CALC                     ' Do backward MA calculation.
      BACMA (INDEX1) = MOVAVE          ' Load MA to backward MA cell.
    NEXT INDEX1

  END IF

  ' For all EL bars.
  ZLAGPTR = ZLAGADR                    ' Setup pointer to EL ZLAGFILT.
  SELECT CASE TEST                     ' Let EL plot intermediate results.
  CASE = 0                             ' Not a test.  Return final result.
    ' Combine forward & backward MA's and send the zero lag filt. to EL.
    @ZLAGPTR = 0.5 * (FORMA (CURBAR) + BACMA (CURBAR))
  CASE = 1                             ' Return price loaded during MODE 0.
    @ZLAGPTR = PRICE (CURBAR)
  CASE = 2                             ' Return forward MA.
    @ZLAGPTR = FORMA (CURBAR)
  CASE = 3                             ' Return backward MA.
    @ZLAGPTR = BACMA (CURBAR)
  END SELECT

  FUNCTION = 1                         ' Return dummy integer to EL.

END FUNCTION


' ================
'   SUB MA_CALC  =
' ================

SUB MA_CALC

' This subroutine calculates either an exponential MA or
' the Tillson T3 MA.

  IF MODE1 = 1 THEN                    ' For exponential MA.

    G1 = G1P + F1 * (TEMPF1 - G1P)
    MOVAVE = G1
    G1P = G1                           ' Previous bar value for next bar.

  ELSE                                 ' For T3 MA.

    E1 = F1 * TEMPF1 + F2 * E1P
    E2 = F1 * E1 + F2 * E2P
    E3 = F1 * E2 + F2 * E3P
    E4 = F1 * E3 + F2 * E4P
    E5 = F1 * E4 + F2 * E5P
    E6 = F1 * E5 + F2 * E6P
    MOVAVE = C1 * E6 + C2 * E5 + C3 * E4 + C4 * E3

    ' This is previous bar values for next bar.
    E1P = E1
    E2P = E2
    E3P = E3
    E4P = E4
    E5P = E5
    E6P = E6

  END IF

END SUB


' =================
'   Function Wep  =
' =================

' Function WEP tells Windows to unload this DLL.  This function
' definition is the same for any DLL.  Certain other run-once
' code can be put here as well, like de-allocating objects.

FUNCTION Wep (BYVAL nParameter AS INTEGER) EXPORT AS WORD

  Wep = 1                              ' Tells WIN that unload
                                       ' was a success.
END FUNCTION


' ===============
'   End Of DLL  =
' ===============