Automatic Support/Resistance indicator using ZigZag
To write an indicator drawing support and resistance lines you need a set of rules that a computer can follow to create those lines. This technique uses the ZigZag indicator to find potential S/R levels and then refines further by finding multiple points.
The code here is a combination for MT4 and MT5. Most code is the same and I show where there are differences.
Start with the input statements, these are common for MT4 and MT5. The first block of inputs are just for the values that will be used by the ZigZag indicator.
// Zigzag inputs input int InpDepth = 12; // Depth input int InpDeviation = 5; // Deviation input int InpBackstep = 3; // Backstep
Next capture inputs to set the gap between points where multiple points would be considered part of a level, the minimum number of points needed to set a level, and how many ZIgZag points to capture to draw S/R lines
// Peak analysis inputs input int InpGapPoints = 100; // Minimum gap between peaks in points input int InpSensitivity = 2; // Peak sensitivity input int InpLookback = 50; // Lookback
The last set of inputs are just used to set the common prefix name for the support and resistance line objects, colour and size of the lines
// Drawing inputs input string InpPrefix = "SRLevel_"; // Object name prefix input color InpLineColour = clrYellow; // Line colour input int InpLineWeight = 2; // Line weight
Then I define an array to hold the S/R line prices
// For the levels double SRLevels[];
and for MT5 create a handle for the ZigZag indicator and a buffer to hold the values form the ZigZag indicator.
// For the MT5 ZigZag indicator double Buffer[]; int Handle;
In the OnInit section for MT5 initialise the indicator handle and set up the buffer to hold ZZ values.
int OnInit() {
// Init the zz indicator Handle = iCustom(Symbol(), Period(), "Examples\\ZigZag", InpDepth, InpDeviation, InpBackstep); if (Handle==INVALID_HANDLE) { Print("Could not create a handle to zigzag indicator"); return(INIT_FAILED); } ArraySetAsSeries(Buffer, true);
Also in the OnInit section, for both MT4 and MT5 add some code to clean up in case an earlier indicator has left SR lines showing on the chart and set up the SRLevels array to hold the maximum number of levels.
// Clean up any sr levels left from earlier indicators ObjectsDeleteAll(0, InpPrefix, 0, OBJ_HLINE); ChartRedraw(0); ArrayResize(SRLevels, InpLookback); return(INIT_SUCCEEDED); } // end OnInit
In OnDeInit for MT5 release the handle to the ZigZag indicator.
void OnDeinit(const int reason) {
IndicatorRelease(Handle);
and for both MT4 and MT5 again clean up the S/R level lines on exit
ObjectsDeleteAll(0, InpPrefix, 0, OBJ_HLINE); ChartRedraw(0); } // end OnDeInit
The OnCalculate function then is where most of the code happens. To begin for both MT4 and MT5 convert the gap size in points entered in the inputs into a price based gap, check that this is a new bar by comparing rates_total and prev_calculated (this indicator only processes on a new bar) and set up an array to hold peak values from the ZigZag indicator.
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { // One time convert points to a price gap static double levelGap = InpGapPoints*SymbolInfoDouble(Symbol(), SYMBOL_POINT); // Only do this on a new bar if (rates_total==prev_calculated) return(rates_total); // Get the most recent <lookback> peaks double zz = 0; double zzPeaks[]; int zzCount = 0; ArrayResize(zzPeaks, InpLookback); ArrayInitialize(zzPeaks, 0.0);
The following section gathers values from the ZigZag indicator and it is different between MT4 and MT5 due to the different way the products handle indicators. First for MT4 simply look through and use iCustom to get values from the indicator, bars that are not peaks will return zero or empty values
for (int i=1; i<rates_total && zzCount<InpLookback; i++) { zz = iCustom(Symbol(), Period(), "ZigZag", InpDepth, InpDeviation, InpBackstep, 0, i); if (zz!=0 && zz!=EMPTY_VALUE) { zzPeaks[zzCount] = zz; zzCount++; } } ArraySort(zzPeaks);
For MT5 iCustom was set up in the initialisation and we only need to copy information from the indicator handle. The MT5 version also checks that the handle is ready and values are available and exits the loop early if not
int count = CopyBuffer(Handle, 0, 0, rates_total, Buffer); if (count<0) { int err=GetLastError(); return(0); } for (int i=1; i<rates_total && zzCount<InpLookback; i++) { zz = Buffer[i]; if (zz!=0 && zz!=EMPTY_VALUE) { zzPeaks[zzCount] = zz; zzCount++; } } ArraySort(zzPeaks);
The final line in both of the above just places the peaks in ascending ordder to make finding peaks at the same level easier.
The remaining code is common to MT4 and MT5.
This code will loop through the ZigZag peaks array, matching prices within the range specified in the inputs and counting the number of peaks in each range. If enough peaks are found the average price is calculated and that price is set as a S/R level.
// Search for groupings and set levels int srCounter = 0; double price = 0; int priceCount = 0; ArrayInitialize(SRLevels, 0.0); for (int i=InpLookback-1; i>=0; i--) { if (zzPeaks[i]>0) { price += zzPeaks[i]; priceCount++; } if (i==0 || (zzPeaks[i]-zzPeaks[i-1])>levelGap) { if (priceCount>=InpSensitivity) { price = price/priceCount; SRLevels[srCounter] = price; srCounter++; } price = 0; priceCount = 0; } } DrawLevels(); //--- return value of prev_calculated for next call return(rates_total); } // end OnCalculate
The DrawLevels function called above will scan through the SRLevels array, move any existing lines to any changed prices, draw new lines where needed and clean up any extra lines.
void DrawLevels() { for (int i=0; i<InpLookback; i++) { string name = InpPrefix + IntegerToString(i); if (SRLevels[i]==0) { ObjectDelete(0, name); continue; } if (ObjectFind(0, name)<0) { ObjectCreate(0, name, OBJ_HLINE, 0, 0, SRLevels[i]); ObjectSetInteger(0, name, OBJPROP_COLOR, InpLineColour); ObjectSetInteger(0, name, OBJPROP_WIDTH, InpLineWeight); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, true); } else { ObjectSetDouble(0, name, OBJPROP_PRICE, SRLevels[i]); } } ChartRedraw(0); } // end DrawLevels
how to sent my file you you need option attachment i already do this point
can you send my mt4 version to mail
[email protected]
// Zigzag inputs
input int InpDepth = 12; // Depth
input int InpDeviation = 5; // Deviation
input int InpBackstep = 3; // Backstep
// Peak analysis inputs
input int InpGapPoints = 100; // Minimum gap between peaks in points
input int InpSensitivity = 2; // Peak sensitivity
input int InpLookback = 50; // Lookback
// Drawing inputs
input string InpPrefix = “SRLevel_”; // Object name prefix
input color InpLineColour = clrYellow; // Line colour
input int InpLineWeight = 2; // Line weight
// For the levels
double SRLevels[];
int OnInit() {
// Clean up any sr levels left from earlier indicators
ObjectsDeleteAll(0, InpPrefix, 0, OBJ_HLINE);
ChartRedraw(0);
ArrayResize(SRLevels, InpLookback);
return(INIT_SUCCEEDED);
} // end OnInit
void OnDeinit(const int reason) {
ObjectsDeleteAll(0, InpPrefix, 0, OBJ_HLINE);
ChartRedraw(0);
} // end OnDeInit
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]) {
// One time convert points to a price gap
static double levelGap = InpGapPoints*SymbolInfoDouble(Symbol(), SYMBOL_POINT);
// Only do this on a new bar
if (rates_total==prev_calculated) return(rates_total);
// Get the most recent <lookback> peaks
double zz = 0;
double zzPeaks[];
int zzCount = 0;
ArrayResize(zzPeaks, InpLookback);
ArrayInitialize(zzPeaks, 0.0);
for (int i=1; i<rates_total && zzCount=0; i–) {
if (zzPeaks[i]>0)
price += zzPeaks[i];
priceCount++;
}
if (i==0 || (zzPeaks[i]-zzPeaks[i-1])>levelGap) {
if (priceCount>=InpSensitivity) {
price = price/priceCount;
SRLevels[srCounter] = price;
srCounter++;
}
price = 0;
priceCount = 0;
}
DrawLevels();
return(rates_total);
} // end OnCalculate
void DrawLevels() {
for (int i=0; i<InpLookback; i++) {
string name = InpPrefix + IntegerToString(i);
if (SRLevels[i]==0) {
ObjectDelete(0, name);
continue;
}
if (ObjectFind(0, name)<0) {
ObjectCreate(0, name, OBJ_HLINE, 0, 0, SRLevels[i]);
ObjectSetInteger(0, name, OBJPROP_COLOR, InpLineColour);
ObjectSetInteger(0, name, OBJPROP_WIDTH, InpLineWeight);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, true);
} else {
ObjectSetDouble(0, name, OBJPROP_PRICE, SRLevels[i]);
}
}
ChartRedraw(0);
} // end DrawLevels
Hi your Mt4 code not work
// Zigzag inputs
input int InpDepth = 12; // Depth
input int InpDeviation = 5; // Deviation
input int InpBackstep = 3; // Backstep
// Peak analysis inputs
input int InpGapPoints = 100; // Minimum gap between peaks in points
input int InpSensitivity = 2; // Peak sensitivity
input int InpLookback = 50; // Lookback
// Drawing inputs
input string InpPrefix = “SRLevel_”; // Object name prefix
input color InpLineColour = clrYellow; // Line colour
input int InpLineWeight = 2; // Line weight
// For the levels
double SRLevels[];
int OnInit() {
// Clean up any sr levels left from earlier indicators
ObjectsDeleteAll(0, InpPrefix, 0, OBJ_HLINE);
ChartRedraw(0);
ArrayResize(SRLevels, InpLookback);
return(INIT_SUCCEEDED);
} // end OnInit
void OnDeinit(const int reason) {
ObjectsDeleteAll(0, InpPrefix, 0, OBJ_HLINE);
ChartRedraw(0);
} // end OnDeInit
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]) {
// One time convert points to a price gap
static double levelGap = InpGapPoints*SymbolInfoDouble(Symbol(), SYMBOL_POINT);
// Only do this on a new bar
if (rates_total==prev_calculated) return(rates_total);
// Get the most recent <lookback> peaks
double zz = 0;
double zzPeaks[];
int zzCount = 0;
ArrayResize(zzPeaks, InpLookback);
ArrayInitialize(zzPeaks, 0.0);
for (int i=1; i<rates_total && zzCount=0; i–) {
if (zzPeaks[i]>0)
price += zzPeaks[i];
priceCount++;
}
if (i==0 || (zzPeaks[i]-zzPeaks[i-1])>levelGap) {
if (priceCount>=InpSensitivity) {
price = price/priceCount;
SRLevels[srCounter] = price;
srCounter++;
}
price = 0;
priceCount = 0;
}
DrawLevels();
return(rates_total);
} // end OnCalculate
void DrawLevels() {
for (int i=0; i<InpLookback; i++) {
string name = InpPrefix + IntegerToString(i);
if (SRLevels[i]==0) {
ObjectDelete(0, name);
continue;
}
if (ObjectFind(0, name)<0) {
ObjectCreate(0, name, OBJ_HLINE, 0, 0, SRLevels[i]);
ObjectSetInteger(0, name, OBJPROP_COLOR, InpLineColour);
ObjectSetInteger(0, name, OBJPROP_WIDTH, InpLineWeight);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, true);
} else {
ObjectSetDouble(0, name, OBJPROP_PRICE, SRLevels[i]);
}
}
ChartRedraw(0);
} // end DrawLevels
My code works. You are missing some code like
// Search for groupings and set levels
int srCounter = 0;
double price = 0;
int priceCount = 0;
ArrayInitialize(SRLevels, 0.0);