ZigZagE
Download scriptThis script is designed to identify and display significant turning points in price action—specifically the "peaks" and "valleys"—on a trading chart. Rather than showing every minor fluctuation, it filters out market noise to highlight the underlying structure of a trend.
How the Logic Works
The script operates by scanning historical price data to find extreme highs and lows based on three main user-defined parameters: Depth, Deviation, and Backstep. Here is the step-by-step logic:
1. Identifying Local Extremes The tool first looks at a specific window of recent bars (the "Depth"). Within this window, it identifies the highest price reached and the lowest price dropped. It ensures that these points are significant enough to be considered "real" moves rather than tiny fluctuations by checking them against a minimum price change requirement (the "Deviation").
2. Filtering Noise and Redundancy To prevent the chart from becoming cluttered, the script performs several checks:
- Repetition Filter: If a new low or high is identical to the previous one, it is ignored.
- Proximity Check: It uses the "Backstep" logic to look at preceding bars. If a point was already marked very close to the current one, it clears the old data to ensure only the most prominent peak or valley remains.
3. Establishing Trend Direction (ZigZag Logic) Once the script finds potential peaks and valleys, it applies a "Final Cutting" logic to determine the sequence of the trend. It follows these rules:
- Successive Peaks/Valleys: It ensures that the chart alternates correctly between a high and a low. For example, if it detects two highs in a row, it compares them; if the newer one is higher, it replaces the old one. If the newer one is lower, it discards it as a minor retracement.
- Trend Continuity: By constantly comparing the current extreme to the previous one, the script "draws" a path that connects these significant points, creating a clear visual line of the market's trajectory.
4. Final Visualization In the final stage, the script organizes these points into two distinct data streams: one for the price ceilings (highs) and one for the price floors (lows). It ensures that these points are only displayed when they represent a valid transition in the market structure, providing a clean, simplified view of the price history.
Summary for the User
Essentially, this script acts as a filter. It ignores "market chatter" and identifies the skeleton of the price movement. It helps traders see where the market has officially turned around, making it easier to identify the overarching trend without getting distracted by minor price movements.
//+------------------------------------------------------------------+
//| Custom Moving Average.mq4 |
//| Copyright © 2005, MetaQuotes Software Corp. |
//| http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net/"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- indicator parameters
extern int ExtDepth=12;
extern int ExtDeviation=5;
extern int ExtBackstep=3;
//---- indicator buffers
double ExtMapBuffer[];
double ExtMapBuffer2[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
IndicatorBuffers(2);
//---- drawing settings
SetIndexStyle(0,DRAW_SECTION);
//---- indicator buffers mapping
SetIndexBuffer(0,ExtMapBuffer);
SetIndexBuffer(1,ExtMapBuffer2);
SetIndexEmptyValue(0,0.0);
ArraySetAsSeries(ExtMapBuffer,true);
ArraySetAsSeries(ExtMapBuffer2,true);
//---- indicator short name
IndicatorShortName("ZigZag("+ExtDepth+","+ExtDeviation+","+ExtBackstep+")");
//---- initialization done
return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int start()
{
int shift, back,lasthighpos,lastlowpos;
double val,res;
double curlow,curhigh,lasthigh,lastlow;
for(shift=199; shift>=0; shift--)
{
val=Low[Lowest(NULL,0,MODE_LOW,ExtDepth,shift)];
if(val==lastlow) val=0.0;
else
{
lastlow=val;
if((Low[shift]-val)>(ExtDeviation*Point)) val=0.0;
else
{
for(back=1; back<=ExtBackstep; back++)
{
res=ExtMapBuffer[shift+back];
if((res!=0)&&(res>val)) ExtMapBuffer[shift+back]=0.0;
}
}
}
ExtMapBuffer[shift]=val;
//--- high
val=High[Highest(NULL,0,MODE_HIGH,ExtDepth,shift)];
if(val==lasthigh) val=0.0;
else
{
lasthigh=val;
if((val-High[shift])>(ExtDeviation*Point)) val=0.0;
else
{
for(back=1; back<=ExtBackstep; back++)
{
res=ExtMapBuffer2[shift+back];
if((res!=0)&&(res<val)) ExtMapBuffer2[shift+back]=0.0;
}
}
}
ExtMapBuffer2[shift]=val;
}
// final cutting
lasthigh=-1; lasthighpos=-1;
lastlow=-1; lastlowpos=-1;
for(shift=199; shift>=0; shift--)
{
curlow=ExtMapBuffer[shift];
curhigh=ExtMapBuffer2[shift];
if((curlow==0)&&(curhigh==0)) continue;
//---
if(curhigh!=0)
{
if(lasthigh>0)
{
if(lasthigh<curhigh) ExtMapBuffer2[lasthighpos]=0;
else ExtMapBuffer2[shift]=0;
}
//---
if(lasthigh<curhigh || lasthigh<0)
{
lasthigh=curhigh;
lasthighpos=shift;
}
lastlow=-1;
}
//----
if(curlow!=0)
{
if(lastlow>0)
{
if(lastlow>curlow) ExtMapBuffer[lastlowpos]=0;
else ExtMapBuffer[shift]=0;
}
//---
if((curlow<lastlow)||(lastlow<0))
{
lastlow=curlow;
lastlowpos=shift;
}
lasthigh=-1;
}
}
for(shift=199; shift>=0; shift--)
{
if(shift>=Bars-ExtDepth) ExtMapBuffer[shift]=0.0;
else
{
res=ExtMapBuffer2[shift];
if(res!=0.0) ExtMapBuffer[shift]=res;
}
}
}
Comments