This script is designed as a technical analysis tool for the MetaTrader 4 platform. Its primary purpose is to identify "divergences"—situations where the price movement of an asset (like a currency pair or stock) contradicts the behavior of a specific momentum indicator. By spotting these contradictions, traders can often anticipate potential changes in market direction.
How the Logic Works
1. Data Collection and Smoothing The script monitors a specific momentum indicator (the MACD) to establish a baseline for "market energy." It constantly looks at recent price history to determine where the highs and lows are occurring. To ensure the data is reliable, it uses a specific "extremum point" logic, which means it doesn't just look at any peak or valley; it validates that a point is a true local maximum or minimum by comparing it against surrounding price bars.
2. Identifying Key Peaks and Valleys The tool keeps track of the most recent significant highs (peaks) and lows (valleys) in both the price chart and the indicator data. It specifically looks for:
- Significant Highs: When the indicator reaches a peak but the price remains lower than its previous peak.
- Significant Lows: When the indicator reaches a valley but the price remains higher than its previous valley.
3. Detecting Divergence (The Core Logic) The script compares the "trend" of the price against the "trend" of the indicator. It performs two main types of checks:
- Bearish Divergence: If the indicator shows a downward movement (falling trend) while the actual market price is still making higher highs, the script identifies this as a potential warning sign that the upward momentum is weakening.
- Bullish Divergence: If the indicator shows an upward movement (rising trend) while the actual market price is still making lower lows, it suggests that the downward pressure is fading and a reversal might be coming.
4. Visual Feedback To make this information easy for a trader to see at a glance, the script provides visual cues:
- Histograms and Lines: It plots the movement of the indicator and specific "limit" boundaries (typically used to identify overbought or oversold conditions).
- Arrows: When a confirmed divergence is detected between the price action and the momentum indicator, the script places an arrow on the chart. These arrows act as visual signals for the user to notice where the market behavior is becoming "out of sync."
Summary for the User
Essentially, this tool acts as a "truth checker" for market trends. It looks for moments where the price is trying to move in one direction (e.g., up), but the underlying momentum (the MACD) is already starting to fail or drop. When these two elements disagree, the script alerts you with visual markers, helping you identify potential turning points in the market.
//+------------------------------------------------------------------+
//| Divergency.mq4 |
//| Copyright © Trofimov, 2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright © Trofimov, 2008"
#property link ""
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1 DarkSlateBlue
#property indicator_width1 2
#property indicator_color2 Red
#property indicator_width2 2
#property indicator_color3 FireBrick
#property indicator_width3 1
#property indicator_color4 DarkGreen
#property indicator_width4 1
#property indicator_maximum 1
#property indicator_minimum -1
extern double Delta=0.002; // - ìèíèìàëüíîå ðàññòîÿíèå ìåæäó ìèíèìóìîì è ìàêñèìóìîì
int ExtremumPoint=3; // - êîëè÷åñòâî òî÷åê ïî êîòîðûì îïðåäåëÿþòñÿ ýêñòðåìóìû. Ìîæåò áûòü ëþáûì íå÷¸òíûì çíà÷åíèåì áîëüøå åäèíèöû (Íàïðèìåð: 3,5,7,9....)
int Buffer=500; // - ðàçìåð áóôåðà ìàññèâà Stochastic[]
int CurBuffer; // - òåêóùèé (ïîñëåäíèé çàïîëíåííûé) áóôåðíûé èíäåêñ ìàññèâà Stochastic[]
double Stochastic[];
int UpStochIdx[2]; // - ìàññèâ, ñîäåðæàùèé áóôåðíûå èíäåêñû òð¸õ ïîñëåäíèõ ìàêñèìóìîâ
int DnStochIdx[2]; // - ìàññèâ, ñîäåðæàùèé áóôåðíûå èíäåêñû òð¸õ ïîñëåäíèõ ìèíèìóìîâ
int CurrentCandle;
datetime LastTime;
//---- Ìàññèâ äàííûõ èíäèêàòîðà
double StochBuffer[];
double EndLimit[];
double StochUp[],StochDn[];
//+------------------------------------------------------------------+
int init() {
//if(Buffer==0) Buffer=Bars;
ArrayResize(Stochastic, Buffer);
IndicatorBuffers(4);
//---- ïàðàìåòðû ðèñîâàíèÿ (óñòàíîâêà íà÷àëüíîãî áàðà)
SetIndexDrawBegin(0,Buffer);
//---- 2 ðàñïðåäåëåííûõ áóôåðà èíäèêàòîðà
SetIndexBuffer(0,StochBuffer);
SetIndexBuffer(1,EndLimit);
SetIndexBuffer(2,StochUp);
SetIndexBuffer(3,StochDn);
//---- èìÿ èíäèêàòîðà è ïîäñêàçêè äëÿ ëèíèé
IndicatorShortName("DivMACD("+DoubleToStr(Delta,3)+")");
SetIndexLabel(0,"Divergency");
SetIndexLabel(1,"Limit");
SetIndexLabel(2,"Top");
SetIndexLabel(3,"Low");
//--- ñòèëü îòðèñîâêè
SetIndexStyle(0, DRAW_HISTOGRAM);
SetIndexStyle(1, DRAW_HISTOGRAM);
SetIndexStyle(2, DRAW_ARROW);
SetIndexStyle(3, DRAW_ARROW);
SetIndexArrow(2, 108);
SetIndexArrow(3, 108);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
static int OldUpStochIdx,OldDnStochIdx;
int limit;
// Ïðîïóùåííûå áàðû
int counted_bars=IndicatorCounted();
//---- îáõîäèì âîçìîæíûå îøèáêè
if(counted_bars<0) return(-1);
//---- íîâûå áàðû íå ïîÿâèëèñü è ïîýòîìó íè÷åãî ðèñîâàòü íå íóæíî
limit=Bars-counted_bars-1;
//---- îñíîâíîé öèêë
for(int i=limit; i>=0; i--) {
CurrentCandle=i+1;//-ýòî ïîëíîñòüþ ñôîðìèðîâàâøàÿñÿ ñâå÷à
if(LastTime!=iTime(NULL,0,CurrentCandle)) {
AddStochastic();
LastTime=iTime(NULL,0,CurrentCandle);
//Èíäèêàòîð ïåðåñå÷åíèÿ ãðàíèö 20/80
//EndLimit[i]=0;
if(OldUpStochIdx!=UpStochIdx[0]) {
if(Stochastic[UpStochIdx[0]]>80) {
EndLimit[i]=-0.5;
OldUpStochIdx=UpStochIdx[0];
}
}
if(OldDnStochIdx!=DnStochIdx[0]) {
if(Stochastic[DnStochIdx[0]]<20) {
EndLimit[i]=0.5;
OldDnStochIdx=DnStochIdx[0];
}
}
//Èíäèêàòîð äèâåðãåíöèè
//StochBuffer[i]=0;
if(VectorStochastic(true)<0 && VectorPrice(true)>0) {
if(GetIndexNormal(UpStochIdx[0])<GetIndexNormal(DnStochIdx[0])) {//åñëè ïîñëåäíèé ìèíèìóì ñòàðåå ïîñëåäíåãî ìàêñèìóìà
StochBuffer[i]=-1;
}
}
if(VectorStochastic(false)>0 && VectorPrice(false)<0) {
if(GetIndexNormal(UpStochIdx[0])>GetIndexNormal(DnStochIdx[0])) {//åñëè ïîñëåäíèé ìàêñèìóì ñòàðåå ïîñëåäíåãî ìèíèìóìà
StochBuffer[i]=1;
}
}
//Print("===== ",TimeToStr(LastTime)," =====");
}
}
return(0);
}
//+------------------------------------------------------------------+
int AddStochastic() {
//Äîáàâëÿåò íîâîå çíà÷åíèå ñòîõàñòèêà â ìàññèâ
if(CurBuffer==0)
CurBuffer=Buffer-1;
else
CurBuffer--;
Stochastic[CurBuffer]=iMACD(NULL,0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, CurrentCandle);
//Stochastic[CurBuffer]=iStochastic(NULL,0,5,3,3,MODE_EMA,0,MODE_MAIN,CurrentCandle);
//Ïðîâåðêà íà âîçíèêíîâåíèå ýêñòðåìóìà
int countUp, countDn;
int idxTop=(ExtremumPoint-1)/2; // - íîðìàëüíûé èíäåêñ âåðøèíû
for (int i = idxTop-1; i >= 0 ; i--) { //Öûêë íîðìàëüíîãî èíäåêñà
if(Stochastic[GetIndexBuffer(i)]<Stochastic[GetIndexBuffer(i+1)] &&
Stochastic[GetIndexBuffer(idxTop+(idxTop-i))]<Stochastic[GetIndexBuffer(idxTop+(idxTop-i)-1)]) {
countUp++;
}
if(Stochastic[GetIndexBuffer(i)]>Stochastic[GetIndexBuffer(i+1)] &&
Stochastic[GetIndexBuffer(idxTop+(idxTop-i))]>Stochastic[GetIndexBuffer(idxTop+(idxTop-i)-1)]) {
countDn++;
}
} //Next i
if(countUp==idxTop) { //âåðøèíà îêàçàëàñü ìàêñèìóìîì
if(GetIndexNormal(DnStochIdx[0])<GetIndexNormal(UpStochIdx[0])) { //Åñëè ïðåäûäóùèì ñòîèò ìèíèìóì
if(Stochastic[GetIndexBuffer(idxTop)]-Stochastic[DnStochIdx[0]]>Delta){
//Åñëè ìåæäó ïðåäûäóùèì ìèíèìóìîì è ïðåäïîëîæèòåëüíûì ìàêñèìóìîì ðàñòîÿíèå ïî âåðòèêàëè áîëüøå Delta
UpStochIdx[2]=UpStochIdx[1];
UpStochIdx[1]=UpStochIdx[0];
UpStochIdx[0]=GetIndexBuffer(idxTop);
StochUp[CurrentCandle-1]=Stochastic[UpStochIdx[0]];
}
} else { //Åñëè ïðåäûäóùèì ñòîèò ìàêñèìóì
if(Stochastic[UpStochIdx[0]]<Stochastic[GetIndexBuffer(idxTop)]) { //åñëè ïðåäûäóùèé ìàêñèìóì áûë ìåíüøå íàñòîÿùåãî
StochUp[CurrentCandle-2+GetIndexNormal(UpStochIdx[0])]=EMPTY_VALUE;
//StochUp[CurrentCandle-1+idxTop]=Stochastic[GetIndexBuffer(idxTop)];
StochUp[CurrentCandle-1]=Stochastic[GetIndexBuffer(idxTop)];
UpStochIdx[0]=GetIndexBuffer(idxTop);
}
}
} else if(countDn==idxTop) { //âåðøèíà îêàçàëàñü ìèíèìóìîì
if(GetIndexNormal(UpStochIdx[0])<GetIndexNormal(DnStochIdx[0])) { //Åñëè ïðåäûäóùèì ñòîèò ìàêñèìóì
if(Stochastic[UpStochIdx[0]]-Stochastic[GetIndexBuffer(idxTop)]>Delta){
//Åñëè ìåæäó ïðåäûäóùèì ìàêñèñóìîì è ïðåäïîëîæèòåëüíûì ìèíèìóìîì ðàñòîÿíèå ïî âåðòèêàëè áîëüøå Delta
DnStochIdx[2]=DnStochIdx[1];
DnStochIdx[1]=DnStochIdx[0];
DnStochIdx[0]=GetIndexBuffer(idxTop);
StochDn[CurrentCandle-1]=Stochastic[DnStochIdx[0]];
}
} else { //Åñëè ïðåäûäóùèì ñòîèò ìèíèìóì
if(Stochastic[DnStochIdx[0]]>Stochastic[GetIndexBuffer(idxTop)]) { //åñëè ïðåäûäóùèé ìèíèìóì áûë áîëüøå íàñòîÿùåãî
StochDn[CurrentCandle-2+GetIndexNormal(DnStochIdx[0])]=EMPTY_VALUE;
//StochDn[CurrentCandle-1+idxTop]=Stochastic[GetIndexBuffer(idxTop)];
StochDn[CurrentCandle-1]=Stochastic[GetIndexBuffer(idxTop)];
DnStochIdx[0]=GetIndexBuffer(idxTop);
}
}
}
return(0);
}
//+------------------------------------------------------------------+
int GetIndexBuffer(int Idx) {
//âîçâðàùàåò áóôåðíûé èíäåêñ ìàññèâà, ãäå Idx - íîðìàëüíûé èíäåêñ
if(Idx>Buffer-1) {
Print("Íåäîïóñòèìîå çíà÷åíèå èíäåêñà äëÿ ìàññèâà");
return(-1);
}
int retIndex=CurBuffer+Idx;
if(retIndex>Buffer-1) retIndex=retIndex-Buffer;
return(retIndex);
}
//+------------------------------------------------------------------+
int GetIndexNormal(int IdxBuf) {
//âîçâðàùàåò íîðìàëüíûé èíäåêñ, ãäå IdxBuf - áóôåðíûé èíäåêñ ìàññèâà
if(IdxBuf>Buffer-1) {
Print("Íåäîïóñòèìîå çíà÷åíèå èíäåêñà äëÿ ìàññèâà");
return(-1);
}
int retIndex=IdxBuf-CurBuffer;
if(retIndex<0) retIndex=retIndex+Buffer;
return(retIndex);
}
//+------------------------------------------------------------------+
int VectorStochastic(bool MaxMin) {
//âîçâðàùàåò íàïðàâëåíèå òðåíäîâîé ëèíèè, ïðîâåä¸ííîé ÷åðåç âåðøèíû ñòîõàñòèêà:
//1 - ââåðõ, -1 - âíèç, 0 - ãîðèçîíòàëüíî
//MaxMin - òèïû àíàëèçèðóåìûõ âåðøèí: true - ìàêñèìóìû, false - ìèíèìóìû
if(MaxMin) {
//Print("Stochastic[UpStochIdx[0]]="+Stochastic[UpStochIdx[0]],", Stochastic[UpStochIdx[1]]="+Stochastic[UpStochIdx[1]]);
if(Stochastic[UpStochIdx[0]]>Stochastic[UpStochIdx[1]]) {
//Print("Stochastic[0]="+Stochastic[UpStochIdx[0]],", Stochastic[1]="+Stochastic[UpStochIdx[1]],", return 1");
return(1);
} else if(Stochastic[UpStochIdx[0]]<Stochastic[UpStochIdx[1]]) {
//Print("Stochastic[0]="+Stochastic[UpStochIdx[0]],", Stochastic[1]="+Stochastic[UpStochIdx[1]],", return -1");
return(-1);
}
} else {
//Print("Stochastic[DnStochIdx[0]]="+Stochastic[DnStochIdx[0]],", Stochastic[DnStochIdx[1]]="+Stochastic[DnStochIdx[1]]);
if(Stochastic[DnStochIdx[0]]>Stochastic[DnStochIdx[1]]) {
//Print("Stochastic[0]="+Stochastic[DnStochIdx[0]],", Stochastic[1]="+Stochastic[DnStochIdx[1]],", return 1");
return(1);
} else if(Stochastic[DnStochIdx[0]]<Stochastic[DnStochIdx[1]]) {
//Print("Stochastic[0]="+Stochastic[DnStochIdx[0]],", Stochastic[1]="+Stochastic[DnStochIdx[1]],", return -1");
return(-1);
}
}
return(0);
}
//+------------------------------------------------------------------+
int VectorPrice(bool MaxMin) {
//âîçâðàùàåò íàïðàâëåíèå òðåíäîâîé ëèíèè, ïðîâåä¸ííîé ÷åðåç ïèêè ñâå÷åé òåêóùåãî ãðàôèêà:
//1 - ââåðõ, -1 - âíèç, 0 - ãîðèçîíòàëüíî
//MaxMin - òèïû àíàëèçèðóåìûõ ïèêîâ: true - High, false - Low
int Extremum0,Extremum1;
if(MaxMin) {
Extremum0=iHighest(NULL,0,MODE_HIGH,GetIndexNormal(DnStochIdx[0]),CurrentCandle);
Extremum1=iHighest(NULL,0,MODE_HIGH,GetIndexNormal(DnStochIdx[1])-GetIndexNormal(DnStochIdx[0]),GetIndexNormal(DnStochIdx[0])+CurrentCandle);
//Print("High[Extremum0]=",High[Extremum0],", High[Extremum1]=",High[Extremum1]);
if(High[Extremum0]>High[Extremum1]) {
//Print("High[0]=",High[Extremum0],", High[1]=",High[Extremum1],", return 1");
return(1);
} else {
//Print("High[0]=",High[Extremum0],", High[1]=",High[Extremum1],", return -1");
return(-1);
}
} else {
Extremum0=iLowest(NULL,0,MODE_LOW,GetIndexNormal(UpStochIdx[0]),CurrentCandle);
Extremum1=iLowest(NULL,0,MODE_LOW,GetIndexNormal(UpStochIdx[1])-GetIndexNormal(UpStochIdx[0]),GetIndexNormal(UpStochIdx[0])+CurrentCandle);
//Print("Low[Extremum0]=",Low[Extremum0],", Low[Extremum1]=",Low[Extremum1]);
if(Low[Extremum0]>Low[Extremum1]) {
//Print("Low[0]=",Low[Extremum0],", Low[1]=",Low[Extremum1],", return 1");
return(1);
} else {
//Print("Low[0]=",Low[Extremum0],", Low[1]=",Low[Extremum1],", return -1");
return(-1);
}
}
return(0);
}
//+------------------------------------------------------------------+
Comments