ind_DivPeakTroughSto_SW_v1
Download scriptThis script is a specialized technical analysis tool designed for the MetaTrader platform. It focuses on identifying specific geometric patterns and momentum shifts by analyzing price movements relative to an "Oscillator" (the Opposite Momentum Oscillator).
Here is a professional breakdown of the logic used by this tool:
Core Foundation: The Oscillator
The script begins by calculating a modified Oscillator value. Instead of looking at raw prices, it transforms a standard Stochastic calculation into a zero-centered oscillator. This means that values above zero generally indicate upward momentum, while values below zero indicate downward momentum.
Peak and Trough Identification
The primary logic of the tool revolves around detecting "extreme" points in this oscillator. It scans the market history to find specific peaks (high points) and troughs (low points) based on your defined sensitivity settings.
To ensure these aren't just minor fluctuations, the script performs a multi-directional check:
- Left and Right Validation: It confirms that a point is a true peak or trough by ensuring that the values on both its left side and right side are lower (for peaks) or higher (for troughs) than the point itself.
- Memory System: The tool keeps track of the "most recent" significant peak and trough. When a new extreme occurs, it "remembers" the previous one to use as a point of comparison for drawing patterns.
Pattern Recognition Logic
The script does not just mark highs and lows; it looks for specific structural relationships between two consecutive peaks or two consecutive troughs:
1. For Peaks (Upper Analysis): The tool compares a current peak with a previous peak. It identifies specific scenarios where the height of the peak in the oscillator window interacts with the actual price on the chart.
- It looks for "divergence" or structural shifts—cases where the oscillator might be reaching a new high while the price is behaving differently, or vice-versa.
- When these conditions are met, it generates specific signals (represented by arrows) and draws trendlines to visually connect the peaks.
2. For Troughs (Lower Analysis): The logic mirrors the peak analysis but focuses on the bottom of the oscillator range. It compares two consecutive troughs to find points where price action and oscillator momentum are moving in significant opposition or specific alignment.
Visual Output and User Experience
The tool is designed to be highly visual rather than just a data stream:
- Dynamic Trendlines: Based on the logic described above, the script automatically draws trendlines connecting historical peaks and troughs. This allows users to see the "path" of momentum over time.
- Color Coding: It uses distinct colors (such as Red/Deep Pink for peaks and Lime/Yellow-Green for troughs) to help the user instantly distinguish between different types of market structures.
- Automatic Cleanup: The script includes a management system that clears old drawings when necessary, ensuring your chart remains clean and only displays relevant, current data.
Summary for the User
In simple terms, this script acts as an "automated pattern scout." It filters out the noise of the market to find the most significant turning points in momentum. By connecting these points with lines and marking them with signals, it provides a visual map of how price energy is shifting, helping you identify potential structural changes in the market trend.
//+------------------------------------------------------------------+
//| ind_DivPeakTroughOsMA_v1.mq4 |
//| * |
//| * |
//+------------------------------------------------------------------+
#property copyright "*"
#property link "*"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 Orange
#property indicator_color2 Silver
#property indicator_color3 SlateGray
#property indicator_width2 1
#property indicator_width3 1
//---- input parameters
extern int StKPeriod=5;
extern int StDPeriod=3;
extern int StSPeriod=3;
extern int StMethod=0; // 0-Close, 1-Open, 2-High, 3-Low, 4-Median, 5-Typical, 6-Weighted
extern int StPrice=0; // 0 - Low/High, 1 - Close/Close
extern int ExtrLeftBars=2; // áàðîâ ñëåâà îò ýêñòðåìóìà
extern int ExtrRightBars=1; // áàðîâ ñïðàâà îò ýêñòðåìóìà
extern double PlusSens=1;
extern double MinusSens=-1;
extern bool DrawLinesSW=true;
extern bool DrawLinesChW=true;
extern color Col_Peak_1=Red;
extern color Col_Peak_2=DeepPink;
extern color Col_Trough_1=LimeGreen;
extern color Col_Trough_2=YellowGreen;
extern string ShortName="DPTSto";
//---- buffers
double osma[];
double Sig1[];
double Sig2[];
double peack_1_i[];
double peack_2_i[];
double trogh_1_i[];
double trogh_2_i[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(7);
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,osma);
SetIndexStyle(1,DRAW_ARROW);
SetIndexArrow(1,159);
SetIndexBuffer(1,Sig1);
SetIndexStyle(2,DRAW_ARROW);
SetIndexArrow(2,159);
SetIndexBuffer(2,Sig2);
SetIndexBuffer(3,peack_1_i);
SetIndexBuffer(4,peack_2_i);
SetIndexBuffer(5,trogh_1_i);
SetIndexBuffer(6,trogh_2_i);
IndicatorShortName(ShortName);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
if(DrawLinesSW || DrawLinesChW)fObjDeleteByPrefix(ShortName);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start(){
int limit=Bars-IndicatorCounted();
for(int i=limit-1;i>=0;i--){
osma[i]=iStochastic(NULL,0,StKPeriod,StDPeriod,StSPeriod,StMethod,StPrice,MODE_MAIN,i)-50;
int extri=i+ExtrRightBars;
Sig1[i]=EMPTY_VALUE;
Sig2[i]=EMPTY_VALUE;
peack_1_i[i]=peack_1_i[i+1];
peack_2_i[i]=peack_2_i[i+1];
trogh_1_i[i]=trogh_1_i[i+1];
trogh_2_i[i]=trogh_2_i[i+1];
bool PeackNow=false;
bool TroghNow=false;
double extrv=osma[extri];
if(extrv>PlusSens){
for(int j=i;j<extri;j++){
if(extrv<=osma[j]){
break;
}
}
if(j==extri){
int extril=extri+ExtrLeftBars;
for(j=extril;j>extri;j--){
if(extrv<=osma[j]){
break;
}
}
if(j==extri){
PeackNow=true;
if(peack_1_i[i]==EMPTY_VALUE){
peack_1_i[i]=Time[extri];
}
else{
if(osma[extri]>osma[iBarShift(NULL,0,peack_1_i[i],false)]){
peack_1_i[i]=Time[extri];
}
}
}
}
}
if(extrv<MinusSens){
for(j=i;j<extri;j++){
if(extrv>=osma[j]){
break;
}
}
if(j==extri){
extril=extri+ExtrLeftBars;
for(j=extril;j>extri;j--){
if(extrv>=osma[j]){
break;
}
}
if(j==extri){
TroghNow=true;
if(trogh_1_i[i]==EMPTY_VALUE){
trogh_1_i[i]=Time[extri];
}
else{
if(osma[extri]<osma[iBarShift(NULL,0,trogh_1_i[i],false)]){
trogh_1_i[i]=Time[extri];
}
}
}
}
}
if(osma[i]>0 && osma[i+1]<=0){
peack_2_i[i]=peack_1_i[i];
peack_1_i[i]=EMPTY_VALUE;
}
if(osma[i]<0 && osma[i+1]>=0){
trogh_2_i[i]=trogh_1_i[i];
trogh_1_i[i]=EMPTY_VALUE;
}
string ObjName1=ShortName+"_PeakIW_"+Time[extri];
string ObjName2=ShortName+"_PeakPW_"+Time[extri];
ObjectDelete(ObjName1);
ObjectDelete(ObjName2);
if(PeackNow){
if(peack_1_i[i]!=EMPTY_VALUE){
if(peack_2_i[i]!=EMPTY_VALUE){
if(osma[extri]>=osma[iBarShift(NULL,0,peack_1_i[i],false)]){
int z2=iBarShift(NULL,0,peack_2_i[i],false);
int z1=extri;
if(osma[z2]<osma[z1] && High[z2]>High[z1]){
Sig1[i]=osma[i]+Point/4;
if(DrawLinesSW)fObjTrendLine(ObjName1,peack_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Peak_1,1,WindowFind(ShortName),0,true);
if(DrawLinesChW)fObjTrendLine(ObjName2,peack_2_i[i],High[z2],Time[extri],High[z1],false,Col_Peak_1,1,0,0,false);
}
if(osma[z2]>osma[z1] && High[z2]<High[z1]){
Sig2[i]=osma[i]+Point/4;
if(DrawLinesSW)fObjTrendLine(ObjName1,peack_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Peak_2,1,WindowFind(ShortName),0,true);
if(DrawLinesChW)fObjTrendLine(ObjName2,peack_2_i[i],High[z2],Time[extri],High[z1],false,Col_Peak_2,1,0,0,false);
}
}
}
}
}
ObjName1=ShortName+"_TroghIW_"+Time[extri];
ObjName2=ShortName+"_TroghPW_"+Time[extri];
ObjectDelete(ObjName1);
ObjectDelete(ObjName2);
if(TroghNow){
if(trogh_1_i[i]!=EMPTY_VALUE){
if(trogh_2_i[i]!=EMPTY_VALUE){
if(osma[extri]<=osma[iBarShift(NULL,0,trogh_1_i[i],false)]){
z2=iBarShift(NULL,0,trogh_2_i[i],false);
z1=extri;
if(osma[z2]>osma[z1] && Low[z2]<Low[z1]){
Sig1[i]=osma[i]-Point/4;
if(DrawLinesSW)fObjTrendLine(ObjName1,trogh_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Trough_1,1,WindowFind(ShortName),0,true);
if(DrawLinesChW)fObjTrendLine(ObjName2,trogh_2_i[i],Low[z2],Time[extri],Low[z1],false,Col_Trough_1,1,0,0,false);
}
if(osma[z2]<osma[z1] && Low[z2]>Low[z1]){
Sig2[i]=osma[i]-Point/4;
if(DrawLinesSW)fObjTrendLine(ObjName1,trogh_2_i[i],osma[z2],Time[extri],osma[z1],false,Col_Trough_2,1,WindowFind(ShortName),0,true);
if(DrawLinesChW)fObjTrendLine(ObjName2,trogh_2_i[i],Low[z2],Time[extri],Low[z1],false,Col_Trough_2,1,0,0,false);
}
}
}
}
}
}
return(0);
}
//+------------------------------------------------------------------+
void fObjTrendLine(
string aObjectName, // 1 èìÿ
datetime aTime_1, // 2 âðåìÿ 1
double aPrice_1, // 3 öåíà 1
datetime aTime_2, // 4 âðåìÿ 2
double aPrice_2, // 5 öåíà 2
bool aRay=false, // 6 ëó÷
color aColor=Red, // 7 öâåò
int aWidth=1, // 8 òîëùèíà
int aWindowNumber=0, // 9 îêíî
int aStyle=0, // 10 0-STYLE_SOLID, 1-STYLE_DASH, 2-STYLE_DOT, 3-STYLE_DASHDOT, 4-STYLE_DASHDOTDOT
bool aBack=false // 11 ôîí
){
if(ObjectFind(aObjectName)!=aWindowNumber){
ObjectCreate(aObjectName,OBJ_TREND,aWindowNumber,aTime_1,aPrice_1,aTime_2,aPrice_2);
}
ObjectSet(aObjectName,OBJPROP_TIME1,aTime_1);
ObjectSet(aObjectName,OBJPROP_PRICE1,aPrice_1);
ObjectSet(aObjectName,OBJPROP_TIME2,aTime_2);
ObjectSet(aObjectName,OBJPROP_PRICE2,aPrice_2);
ObjectSet(aObjectName,OBJPROP_RAY,aRay);
ObjectSet(aObjectName,OBJPROP_COLOR,aColor);
ObjectSet(aObjectName,OBJPROP_WIDTH,aWidth);
ObjectSet(aObjectName,OBJPROP_BACK,aBack);
ObjectSet(aObjectName,OBJPROP_STYLE,aStyle);
}
void fObjDeleteByPrefix(string aPrefix){
//fObjDeleteByPrefix("");
for(int i=ObjectsTotal()-1;i>=0;i--){
if(StringFind(ObjectName(i),aPrefix,0)==0){
ObjectDelete(ObjectName(i));
}
}
}
Comments