This script finds DeMark pivot points, displays them on the chart and indicates their dimensions.
This script has practically the same functionality as KeyFinder. It doesn’t have any visual differences except the button which deletes the script and all associated objects from the chart.
Fig. 1. RTS index futures chart after applying KeyFinder 2.0 script
Although the script hasn’t been changed both visually and functionally, it’s code has been significantly modified.
CKeyFinder class has been created for the script.
Fig. 2. CKeyFinder class
The code of the class is provided below. As I tried to make comments as detailed as possible, you shouldn’t face any problems.
//+------------------------------------------------------------------+ //| KeyFinder.mqh | //| Trofimov Pavel | //| trofimovpp@mail.ru | //+------------------------------------------------------------------+ #property copyright "Trofimov Pavel" #property link "trofimovpp@mail.ru" //+------------------------------------------------------------------+ //| Class for KeyFinder 2.0 | //+------------------------------------------------------------------+ class CKeyFinder { private: // Class variables int MinDimension; //Minimum dimension of points int MaxBars; //The number of bars to process protected: // Class methods for internal use // Determining the upper points dimensions int getHighDimension(MqlRates &tmpRates[],int tmp_i,int tmp_iCod); // Determining the lower points dimensions int getLowDimension(MqlRates &tmpRates[],int tmp_i,int tmp_iCod); public: // Class constructor CKeyFinder(); // Class destructor ~CKeyFinder(); // Property method for getting the dimension int GetMinDimension(); // Property method for setting the dimension void SetMinDimension(int temp_Val); // Property method for getting the number of bars to process int GetMaxBars(); // Property method for setting the number of bars to process void SetMaxBars(int temp_Val); // Method for finding upper pivot points void FindUpKeyPoints(int temp_iCod,MqlRates &temp_rates[]); // Method for finding lower pivot points void FindLowKeyPoints(int temp_iCod,MqlRates &temp_rates[]); // Clearing the chart from the script objects. int CleanChart(); }; //+------------------------------------------------------------------+ //| Determining the upper point dimension | //+------------------------------------------------------------------+ int CKeyFinder::getHighDimension(MqlRates &tmpRates[],int tmp_i,int tmp_iCod)// The method receives an array of MqlRates type data, a number of a processed bar in the array and a maximum index of the array { int k=1; while((tmpRates[tmp_i].high>tmpRates[tmp_i+k].high) && (tmpRates[tmp_i].high>tmpRates[tmp_i-k].high) && ((tmp_i+k)<(tmp_iCod)) && ((tmp_i-k)>0)) k++; if(((tmp_i+k)==tmp_iCod) || ((tmp_i-k)==0)) k=-1; return(k); }; //+------------------------------------------------------------------+ //| Determining the lower point dimension | //+------------------------------------------------------------------+ int CKeyFinder::getLowDimension(MqlRates &tmpRates[],int tmp_i,int tmp_iCod)// The method receives an array of MqlRates type data, a number of a processed bar in the array and a maximum index of the array { int k=1; while((tmpRates[tmp_i].low<tmpRates[tmp_i+k].low) && (tmpRates[tmp_i].low<tmpRates[tmp_i-k].low) && ((tmp_i+k)<(tmp_iCod)) && ((tmp_i-k)>0)) k++; if(((tmp_i+k)==tmp_iCod) || ((tmp_i-k)==0)) k=-1; return(k); }; //+------------------------------------------------------------------+ //| Method GetMinDimension | //+------------------------------------------------------------------+ int CKeyFinder::GetMinDimension(){return(MinDimension);}; //+------------------------------------------------------------------+ //| Method SetMinDimension | //+------------------------------------------------------------------+ void CKeyFinder::SetMinDimension(int temp_Val) { if(temp_Val>1) MinDimension=temp_Val; else { MessageBox("The set dimension is too low."+"\n"+"The default dimension of 5 will be used","Warning!",MB_OK+MB_ICONWARNING); MinDimension=5; }; }; //+------------------------------------------------------------------+ //| Method GetMaxBars | //+------------------------------------------------------------------+ int CKeyFinder::GetMaxBars() {return(MaxBars);}; //+------------------------------------------------------------------+ //| Method SetMaxBars | //+------------------------------------------------------------------+ void CKeyFinder::SetMaxBars(int temp_Val) { // Checking the availability of history for the set number of bars int SMaxBars=Bars(Symbol(),0); if(SMaxBars<temp_Val) { temp_Val=SMaxBars;// Setting the maximum available number of bars MessageBox("The MaxBars parameter is too high."+"\n"+"Only "+IntegerToString(temp_Val)+" bars will be used for calculation.","Warning!",MB_OK+MB_ICONWARNING); }; // Checking if the number of bars is not too low if(temp_Val<(2*MinDimension)) { MessageBox("The set number of bars is too low."+"\n"+"The default number of 300 will be used","Warning!",MB_OK+MB_ICONWARNING); temp_Val=300; }; MaxBars=temp_Val; }; //+------------------------------------------------------------------+ //| Method FindKeyPoints - Finding upper key points | //+------------------------------------------------------------------+ void CKeyFinder::FindUpKeyPoints(int temp_iCod,MqlRates &temp_rates[])// The method receives an index of the maximum array element and the MqlRates array { int HD=1; //initializing points dimensions for(int i=temp_iCod-MinDimension; i>(MinDimension-1); i--)// A loop from the last bar - MinDimension to the zero bar + MinDimension { HD=getHighDimension(temp_rates,i,temp_iCod);//Getting points dimensions if((HD>=MinDimension) || (HD==-1)) {//Creating a mark if MinDimension condition is met string Ob_Name="KF_Label"+IntegerToString(i); if(HD!=-1) { ObjectCreate(0,Ob_Name,OBJ_TEXT,0,temp_rates[i].time,temp_rates[i].high); ObjectSetInteger(0,Ob_Name,OBJPROP_ANCHOR,0,ANCHOR_LOWER); ObjectSetString(0,Ob_Name,OBJPROP_TEXT,0,IntegerToString(HD)); ObjectSetInteger(0,Ob_Name,OBJPROP_COLOR,clrRed); } else { //If the dimension can't be determined, use a ball mark ObjectCreate(0,Ob_Name,OBJ_ARROW,0,temp_rates[i].time,temp_rates[i].high); ObjectSetInteger(0,Ob_Name,OBJPROP_ARROWCODE,0,159); ObjectSetInteger(0,Ob_Name,OBJPROP_ANCHOR,0,ANCHOR_BOTTOM); ObjectSetInteger(0,Ob_Name,OBJPROP_COLOR,clrRed); }; }; }; }; //+------------------------------------------------------------------+ //| Method FindLowKeyPoints - Finding lower key points | //+------------------------------------------------------------------+ void CKeyFinder::FindLowKeyPoints(int temp_iCod,MqlRates &temp_rates[])// The method receives an index of the maximum array element and the MqlRates array { int LD=1;//initializing points dimensions bool iCreate; for(int i=temp_iCod-MinDimension; i>(MinDimension-1); i--)// A loop from the last bar - MinDimension to the zero bar + MinDimension { LD=getLowDimension(temp_rates,i,temp_iCod); if((LD>=MinDimension) || (LD==-1)) { string Ob_Name="KF_Label"+IntegerToString(i)+"_1";//Avoiding the bars there Low and High can be key points if(LD!=-1) { iCreate=ObjectCreate(0,Ob_Name,OBJ_TEXT,0,temp_rates[i].time,temp_rates[i].low); if(iCreate) { ObjectSetInteger(0,Ob_Name,OBJPROP_ANCHOR,0,ANCHOR_UPPER); ObjectSetString(0,Ob_Name,OBJPROP_TEXT,0,IntegerToString(LD)); ObjectSetInteger(0,Ob_Name,OBJPROP_COLOR,clrGreen); } else Comment("Cannot create the object"); } else { iCreate=ObjectCreate(0,Ob_Name,OBJ_ARROW,0,temp_rates[i].time,temp_rates[i].low); if(iCreate) { ObjectSetInteger(0,Ob_Name,OBJPROP_ARROWCODE,0,159); ObjectSetInteger(0,Ob_Name,OBJPROP_ANCHOR,0,ANCHOR_TOP); ObjectSetInteger(0,Ob_Name,OBJPROP_COLOR,clrGreen); } else Comment("Cannot create the object"); }; }; }; }; //+------------------------------------------------------------------+ //| Method CleanChart - Clearing the chart from objects | //+------------------------------------------------------------------+ int CKeyFinder::CleanChart(void) { string Label="KF_Label"; int obj_total=ObjectsTotal(0,0,-1),n=0; for(int obj=obj_total-1; obj>=0; obj--) //Clearing the objects created by the script by the name mask { string objname=ObjectName(0,obj,0,-1); if(StringFind(objname,Label)>=0) ObjectDelete(0,objname); n++; } return(n); } //+------------------------------------------------------------------+ //| Class constructor | //+------------------------------------------------------------------+ CKeyFinder::CKeyFinder(){}; //+------------------------------------------------------------------+ //| Class destructor | //+------------------------------------------------------------------+ CKeyFinder::~CKeyFinder(){}; //+---------------------------------------------------------------------+
Because most of the code has been moved to the class, the main script code is very compact.
//+------------------------------------------------------------------+ //| KeyFinder2.mq5 | //| Trofimov Pavel | //| trofimovpp@mail.ru | //+------------------------------------------------------------------+ #property copyright "Trofimov Pavel" #property link "trofimovpp@mail.ru" #property version "2.00" #property description "Warning! This algorithm uses loops for calculations!" #property description "It is recommended so set not more than 1000 to process!" #property script_show_inputs //--- input parameters input int MinDimesion=5; //Minimum dimension of points input int MaxBars=300; //The number of bars to process #include "KeyFinder.mqh" #include <ChartObjects\ChartObjectsTxtControls.mqh> //+------------------------------------------------------------------+ //| Script variables | //+------------------------------------------------------------------+ CKeyFinder m_keyfinder; //Declaring СKeyFinder class variable CChartObjectButton m_button_close; //Declaring CChartObjectButton class variable //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //-Initializing variables MqlRates rates_array[]; string Com="\n\n\n"; int iCod=CopyRates(Symbol(),Period(),0,MaxBars,rates_array);// The number of elements in MqlRates array that we were able to copy int sy=10;//Button position if(ChartGetInteger(0,CHART_SHOW_OHLC)) sy+=16; //-Setting the necessary parameters m_keyfinder.SetMaxBars(MaxBars); m_keyfinder.SetMinDimension(MinDimesion); m_keyfinder.CleanChart();//Clearing the chart from objects in case of a second use iCod=iCod-1;//An index of the maximum element in rates_array[] Com+="Working...Please, wait!"; //-Creating the button and setting its properties m_button_close.Create(0,"ButtonClose",0,10,sy,100,20); m_button_close.Description("Close Script"); m_button_close.Color(Blue); m_button_close.FontSize(8); Comment(Com); //-Processing the bars using the CKeyFinder class methods if(iCod>0) { m_keyfinder.FindUpKeyPoints(iCod,rates_array);//Searching for upper key points Com+="\nUpper points have been processed.\n"; Comment(Com); m_keyfinder.FindLowKeyPoints(iCod,rates_array);//Searching for lower key points Comment("\n\n\nProcessing is complete"); } else Comment("\n\n\nNo bars to process!!!"); m_button_close.State(false); //-Looping the script until the button is pressed while(!(m_button_close.State())) { //--- redraw chart ChartRedraw(); Sleep(250); }; //-Clearing the chart by a press of the button m_keyfinder.CleanChart(); Comment(""); }
And finally, I provided several helpful links and explanations:
- How to load the code directly from MetaEditor
- To use the script in MetaTrader 4 you need to change the extension of the file KeyFinder2.mq5 to mq4 and recompile it in MetaEditor. The KeyFinder.mqh file containing the class code should be stored in the same folder (for example, MQL5\Scripts) as the main script file.
I am looking forward to reading your comments, feedback and suggestions. Good luck in trading!