Author: Copyright � 2004, MetaQuotes Software Corp.
ZLSA

This tool is a specialized technical indicator designed to help traders identify momentum and potential price reversals by smoothing out the noise typically found in standard market data. It functions as an advanced version of a "Stochastic Oscillator," which measures where the current price sits relative to its recent high and low range.

Core Logic and Data Processing

The script follows a structured multi-step calculation to transform raw price data into a readable visual signal:

  • Range Identification: The tool begins by scanning the market history to identify the highest and lowest prices over a specific period (defined by the user). This establishes the "boundaries" of recent price action.
  • Relative Positioning: It then determines where the current closing price sits within that high-to-low range. For example, if the price is near the top of the range, it indicates strong upward momentum; if it is near the bottom, it suggests downward pressure. This is converted into a percentage value.
  • Zero-Lag Smoothing: Unlike standard oscillators that can be "laggy" (showing trends only after they have already happened), this script employs a specific mathematical technique to reduce delays. It calculates a moving average of the price data and then adjusts the result by subtracting a secondary average from itself. This allows the indicator to react more quickly to sudden market shifts while still maintaining a smooth visual curve.
  • Dual Line Analysis: The tool produces two distinct lines for the user to monitor:
    1. The Main Line: Represents the primary smoothed momentum of the asset.
    2. The Signal Line: A secondary, even smoother average of the Main Line.

Visual Representation and Interpretation

The indicator appears in a separate window below the main price chart, making it easy to view without cluttering the price bars. It uses two distinct colors to help users differentiate between the primary momentum and the signal line.

By monitoring the relationship between these two lines—specifically looking for when they cross or move away from one another—traders can better anticipate whether a trend is gaining strength, losing steam, or preparing for a reversal. The inclusion of horizontal levels (such as 20 and 80) provides clear visual boundaries to help identify "overbought" or "oversold" conditions in the market.

Indicators Used
Moving average indicator
Miscellaneous
Implements a curve of type %1
9 Views
0 Downloads
0 Favorites
ZLSA
//+------------------------------------------------------------------+
//|                                          ZeroLag Stochs_true.mq4 |
//|                      Copyright © 2004, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2004, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net/"
//----
#property indicator_separate_window
#property indicator_level1  20
#property indicator_level2  80
#property indicator_buffers 2
#property indicator_color1 Orange
#property indicator_color2 LightSkyBlue
#property indicator_maximum 125
#property indicator_minimum -25
//---- input parameters
extern int KPeriod = 10;
extern int Slowing = 3;
extern int DPeriod = 3;
//---- buffers
double MainBuffer[];
double SignalBuffer[];
double HighesBuffer[];
double LowesBuffer[];
double WorkBuffer1[];
double WorkBuffer2[];
double WorkBuffer3[];
//----
int draw_begin1 = 0;
int draw_begin2 = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   string short_name;
//---- 2 additional buffers are used for counting.
   IndicatorBuffers(7);
   SetIndexBuffer(2, HighesBuffer);
   SetIndexBuffer(3, LowesBuffer);
   SetIndexBuffer(4, WorkBuffer1);
   SetIndexBuffer(5, WorkBuffer2);
   SetIndexBuffer(6, WorkBuffer3);        
//---- indicator lines
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, MainBuffer);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexBuffer(1, SignalBuffer);
//---- name for DataWindow and indicator subwindow label
   short_name="ZeroLag Stoch(" + KPeriod + "," + DPeriod + "," + Slowing + ")";
   IndicatorShortName(short_name);
   SetIndexLabel(0, short_name);
   SetIndexLabel(1, "Signal");
//----
   draw_begin1 = KPeriod + Slowing;
   draw_begin2 = draw_begin1 + DPeriod;
   SetIndexDrawBegin(0, draw_begin1);
   SetIndexDrawBegin(1, draw_begin2);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Stochastic oscillator                                            |
//+------------------------------------------------------------------+
int start()
  {
   int    i, k;
   int    counted_bars = IndicatorCounted();
   double price, EMA;
//----
   if(Bars <= draw_begin2) 
       return(0);
//---- initial zero
   if(counted_bars < 1)
     {
       for(i = 1; i <= draw_begin1; i++) 
           MainBuffer[Bars-i] = 0;
       for(i = 1; i <= draw_begin2; i++) 
           SignalBuffer[Bars-i] = 0;
     }
//---- minimums counting
   i = Bars - KPeriod;
   if(counted_bars > KPeriod) 
       i = Bars - counted_bars - 1;
   while(i >= 0)
     {
       double min = 1000000;
       k = i + KPeriod - 1;
       while(k >= i)
         {
           price = Low[k];
           if(min > price) 
               min = price;
           k--;
         }
       LowesBuffer[i] = min;
       i--;
     }
//---- maximums counting
   i = Bars - KPeriod;
   if(counted_bars > KPeriod) 
       i = Bars - counted_bars - 1;
   while(i >= 0)
     {
       double max=-1000000;
       k = i + KPeriod - 1;
       while(k >= i)
         {
           price = High[k];
           if(max < price) 
               max = price;
           k--;
         }
       HighesBuffer[i] = max;
       i--;
     }
//---- %K line
   i = Bars - draw_begin1;
   if(counted_bars > draw_begin1) 
       i = Bars - counted_bars - 1;
   while(i >= 0)
     {
       if(!CompareDouble((HighesBuffer[i] - LowesBuffer[i]), 0.0))
           WorkBuffer1[i] = 100*((Close[i] - LowesBuffer[i]) / (HighesBuffer[i] - LowesBuffer[i]));
       i--;
     }
//---- last counted bar will be recounted
   if(counted_bars > 0) 
       counted_bars--;
   int limit = Bars - counted_bars;
//---- main line (%K) is simple movimg average
   for(i = 0; i < limit; i++)
       WorkBuffer2[i] = iMAOnArray(WorkBuffer1, Bars, Slowing, 0, MODE_SMA, i);
   for(i = 0; i < limit; i++)
     {
       EMA = iMAOnArray(WorkBuffer2, Bars, Slowing, 0, MODE_SMA, i);
       MainBuffer[i] = WorkBuffer2[i] + WorkBuffer2[i] - EMA;
     }
//---- signal line (%D) is simple movimg average
   for(i = 0; i < limit; i++)
       WorkBuffer3[i] = iMAOnArray(MainBuffer, Bars, DPeriod, 0, MODE_SMA, i);
   for(i = 0; i < limit; i++)
     {
       EMA = iMAOnArray(WorkBuffer3, Bars, DPeriod, 0, MODE_SMA, i);
       SignalBuffer[i] = WorkBuffer3[i] + WorkBuffer3[i] - EMA;
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Ôóíêöèÿ
//+------------------------------------------------------------------+
bool CompareDouble (double Number1, double Number2)
  {
    bool Compare = NormalizeDouble(Number1 - Number2, 8) == 0;
    return(Compare);
  }
//+------------------------------------------------------------------+ 

Comments