//+------------------------------------------------------------------+
//|                                            Murrey_Math_MT_VG.mq4 |
//|                       Copyright © 2004, Vladislav Goshkov (VG).  |
//|                                   2011, MEDS             |
//|                                           4vg@mail.ru            |
//+------------------------------------------------------------------+
#property copyright "Vladislav Goshkov (VG)."
#property link      "4vg@mail.ru"

#property indicator_buffers 2
#property indicator_chart_window
#property indicator_color1 White
#property indicator_color2 White
#property indicator_width1 2
#property indicator_width2 2


extern string     UniqueID                      = "MEDS_MML";
extern bool       UseOriginalCalcs              = false;              //Set True to use VG MML calculation
extern bool       UseFractalMultiplier          = true;              //Use multiplier to ensure fractal is ALWAYS 10000
extern bool       UseCloseForRangeCalcs         = false;              //Original Murrey rules do not use wicks to calculate ranges
extern int        P                             = 192;               
extern int        MMPeriod                      = 0;                 //Use current timeframe
extern int        NumBars                       = 800;
extern bool       Debug                         = false;


extern color      clr_m_2_8 = Yellow;         extern int    wdth_m_2_8 = 2;		//  [-2]/8
extern color      clr_m_1_8 = HotPink;        extern int    wdth_m_1_8 = 2;		//  [-1]/8
extern color      clr_0_8   = DeepSkyBlue;    extern int    wdth_0_8   = 2;		//  [0]/8 
extern color      clr_1_8   = DarkOrange;     extern int    wdth_1_8   = 2;		//  [1]/8 
extern color      clr_2_8   = Red;            extern int    wdth_2_8   = 1;		//  [2]/8 
extern color      clr_3_8   = Green;          extern int    wdth_3_8   = 1;		//  [3]/8 
extern color      clr_4_8   = Blue;           extern int    wdth_4_8   = 2;		//  [4]/8 
extern color      clr_5_8   = Green;          extern int    wdth_5_8   = 1;		//  [5]/8 
extern color      clr_6_8   = Red;            extern int    wdth_6_8   = 1;		//  [6]/8 
extern color      clr_7_8   = DarkOrange;     extern int    wdth_7_8   = 2;		//  [7]/8 
extern color      clr_8_8   = DeepSkyBlue;    extern int    wdth_8_8   = 2;		//  [8]/8 
extern color      clr_p_1_8 = HotPink;        extern int    wdth_p_1_8 = 2;		//  [+1]/8
extern color      clr_p_2_8 = Yellow;         extern int    wdth_p_2_8 = 2;		//  [+2]/8

bool fractalDone = false;
bool    Redraw;
double  buffer1[], buffer2[];
double  dmml = 0, dvtl = 0,
        sum  = 0,
        v1 = 0,  v2 = 0,
        mn = 0,  mx = 0, mmx,
        mml[13], x[7], y[7], 
        octave = 0, fractal = 0, range   = 0,
        finalH  = -100000000, finalL  = 999999999;
string  ln_txt[13],  buff_str = "",  buff_str1 = "",buff_str2 = "",RedrawDate;
int     bn_Lo   = -1, bn_Hi   = -1, bn_v1   = 0, bn_v2   = 0,
        OctLinesCnt = 13,
        clr[13], wdth[13], shft = 0,
        nTime = 0, CurPeriod = 0, nDigits = 0,
        i = 0;
int 	  NewPeriod=0;
int 	  MMmultiplier ; //use this to push a pair into a different fractal
   
double  lastMML,lastOctave,lastfinalH ,lastfinalL,lastDmml;
double     SetOctave                     = 0;                 //Do not use
int        OctaveMultiplier              = 0;                 //Do not use
string description = "", text = "";
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {
	del_obj();

   SetIndexStyle(0,DRAW_LINE,2);
   SetIndexBuffer(0,buffer1);
   SetIndexStyle(1,DRAW_LINE,2);
   SetIndexBuffer(1,buffer2);
   

   if(MMPeriod>0 )   {//		Set  a period appropriate to the timeframe//
      NewPeriod   = P*MathCeil(MMPeriod/Period());   
   }  
   else    { 
      NewPeriod = P; 
   }

   clr[0]  = clr_m_2_8;   wdth[0] = wdth_m_2_8; ln_txt[0]  = "                                     [-2/8]Extreme";// "extreme              
   clr[1]  = clr_m_1_8;   wdth[1] = wdth_m_1_8; ln_txt[1]  = "                                     [-1/8]Overshoot";// "overshoot          
   clr[2]  = clr_0_8;     wdth[2] = wdth_0_8;   ln_txt[2]  = "                                     [0/8]Ultimate";// "Ultimate             
   clr[3]  = clr_1_8;     wdth[3] = wdth_1_8;   ln_txt[3]  = "                                     [1/8]Weak";// "Weak, Stall and Reverse  
   clr[4]  = clr_2_8;     wdth[4] = wdth_2_8;   ln_txt[4]  = "                                     [2/8]Major";// "Pivot, Reverse - major  
   clr[5]  = clr_3_8;     wdth[5] = wdth_3_8;   ln_txt[5]  = "                                     [3/8]Top";// "Bottom of Trading Range   
   clr[6]  = clr_4_8;     wdth[6] = wdth_4_8;   ln_txt[6]  = "                                     [4/8]Pivot";// "Major S/R Pivotal Point 
   clr[7]  = clr_5_8;     wdth[7] = wdth_5_8;   ln_txt[7]  = "                                     [5/8]Bottom";// "Top of Trading Range   
   clr[8]  = clr_6_8;     wdth[8] = wdth_6_8;   ln_txt[8]  = "                                     [6/8]Major";// "Pivot, Reverse - major  
   clr[9]  = clr_7_8;     wdth[9] = wdth_7_8;   ln_txt[9]  = "                                     [7/8]Weak";// "Weak, Stall and Reverse  
   clr[10] = clr_8_8;     wdth[10]= wdth_8_8;   ln_txt[10] = "                                     [8/8]Ultimate";// "Ultimate             
   clr[11] = clr_p_1_8;   wdth[11]= wdth_p_1_8; ln_txt[11] = "                                     [+1/8]Overshoot";// "overshoot          
   clr[12] = clr_p_2_8;   wdth[12]= wdth_p_2_8; ln_txt[12] = "                                     [+2/8]Extreme";// "extremely overshoot  
   
   if (!UseOriginalCalcs)  {MMmultiplier = MathPow(10,Digits -1);}//murrey math works on pip values
   else  {MMmultiplier = 1;}
   Comment(" "); 


   return(0);
  }
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit() {
	Comment(" ");   
	del_obj();
   return(0);
  }
//===================================================================+
//|                                                                  |
//| START                                                            |
//|                                                                  |
//+------------------------------------------------------------------+
int start() {
   datetime time1 = TimeLocal();
	double bestFit;
	int ExtCountedBars = IndicatorCounted();   
   if (ExtCountedBars < 0) return (-1);
   int pos = Bars - ExtCountedBars -1;

   if ( NumBars > 0 && pos > NumBars )     pos = NumBars; 

   if( (nTime != Time[pos]) || (CurPeriod != Period()) ) 
   {
	while(pos>=0)  {

	   GetRange(pos);


      //determine fractal.....Really, once is enough for this. 
	   if(!fractalDone)   {
	   	fractal = doFractal(v1,v2);
	   	fractalDone=true;
	   }//if(!fractalDone)   {
      
      double b1 = buffer1[pos];
      double b2 = buffer2[pos];
      
		if( (b2> mml[12]|| b1< mml[0]) || UseOriginalCalcs || (b2-b1 < dmml * 2 )){ 
			if(UseOriginalCalcs) {
			   CalculateXY_old(pos);
			}
			else   { 
			   CalculateXY(pos);  			
			   if (Redraw)    {
			      RedrawDate = TimeToStr( Time[pos], TIME_DATE|TIME_MINUTES);
               DrawVlines(pos);
            }
         }//else
      } //if( (b2> mml[12]|| b1< mml[0])||(b2-b1 < dmml * 4 ) || UseOriginalCalcs )
      
      if (!UseOriginalCalcs)  DrawTlines(pos);      
	   nTime    = Time[pos];
	   CurPeriod= Period();
		pos--;
	}
	text = text + "Fractal=" + fractal + " Octave=" + octave;
}
   datetime time2 = TimeLocal();
   int elapsed = time2 - time1;
if(Debug)Print( "Execution time " + TimeToStr(elapsed,TIME_MINUTES|TIME_SECONDS) + " seconds" );
	return(0);
}
//+------------------------------------------------------------------+   
void CalculateXY(int pos) {	
//+------------------------------------------------------------------+   
   range=(v2-v1);	
	sum=MathFloor(MathLog(fractal/range)/MathLog(2));	 

   DoBestFit();
   mmx = mx-mn;    

   if( (v1>=(3*mmx/16+mn)) && (v2<=(9*mmx/16+mn)) ) {x[1]=mn+mmx/2; } else x[1]=0;                                                        	
   if( (v1>=2*(mn-mmx/16))&& (v2<=(10*mmx/16+mn)) && (x[1]==0) ) {x[0]=mn+mmx/2;  } else x[0]=0;                                          
   if( (v1>=(mn+7*mmx/16))&& (v2<=(13*mmx/16+mn)) ) {x[3]=mn+3*mmx/4; }  else x[3]=0;                                                     	
   if( (v1>=(mn+6*mmx/16))&& (v2<=(18*mmx/16+mn))&& (x[3]==0) ) {x[4]=mx;   } else  x[4]=0;                                               	
   if( (v1>=2*(mn+mmx/16))&& (v2<=(14*mmx/16+mn)) && (x[0]==0) && (x[1]==0) && (x[3]==0) && (x[4]==0)) {x[2]=mn+3*mmx/4;  }  else x[2]=0; 	
   if( (x[0]+x[1]+x[2]+x[3]+x[4]) ==0 ) {x[5]=mx; }  else x[5]=0;                                                                         
	if( x[0]>0 ) {y[0]=mn;} else y[0]=0;                                                                                                   
	if( x[1]>0 )  {y[1]=mn+mmx/4;} else y[1]=0;                                                                                            
	if( x[2]>0 )  {y[2]=mn+mmx/4;} else y[2]=0;                                                                                            
	if( x[3]>0 )  {y[3]=mn+mmx/2;} else y[3]=0;                                                                                            
	if( x[4]>0 )   {y[4]=mn+mmx/2;} else y[4]=0;                                                                                           
	if( x[5]>0 )   {y[5]=mn; } else y[5]=0;                                                                                                
   
	      
   finalH = (x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6])/MMmultiplier;
   finalL = (y[0]+y[1]+y[2]+y[3]+y[4]+y[5]+y[6])/MMmultiplier;
		
   dmml = (finalH-finalL)/8;		   
   mml[0] =(finalL-dmml*2); 

   Redraw = false;

   if (mml[0] != lastMML || dmml != lastDmml || mml[12] != lastfinalH )   {
      Redraw = true;
   }
   
   for( i=1; i<OctLinesCnt; i++) {
      mml[i] = mml[i-1] + dmml;
   }//for( i=1; i<OctLinesCnt; i++) { 
   lastMML = mml[0];
   lastOctave = octave;
   lastfinalH = mml[12];
   lastDmml   = dmml;
   

	return(0);
}
//+------------------------------------------------------------------+
double doFractal(double v1, double v2)  {
//+------------------------------------------------------------------+   
   double fract;
            if( v2<=250000    && v2>25000    )     fract=100000;
   else     if( v2<=25000     && v2>2500     )     fract=10000;
   else     if( v2<=2500      && v2>250      )     fract=1000;
   else     if( v2<=250       && v2>25       )     fract=100;
   else     if( v2<=25        && v2>12.5     )     fract=12.5;
   else     if( v2<=12.5      && v2>6.25     )     fract=12.5;
   else     if( v2<=6.25      && v2>3.125    )     fract=6.25;
   else     if( v2<=3.125     && v2>1.5625   )     fract=3.125;
   else     if( v2<=1.5625    && v2>0.390625 )     fract=1.5625;
   else     if( v2<=0.390625  && v2>0        )     fract=0.1953125;
   return(fract);
}
//+------------------------------------------------------------------+
void del_obj()  {
//+------------------------------------------------------------------+
  int k=0;
  while (k<ObjectsTotal())   {
    string objname = ObjectName(k);
    if (StringSubstr(objname,0,StringLen(UniqueID)) == UniqueID)  
      ObjectDelete(objname);
    else
      k++;
  }//while (k<ObjectsTotal())      
  return(0);
}
//+------------------------------------------------------------------+
void  CreateAndSetVline(string objname, datetime date1, double price1,color pColor = 0,int pTimeframes=0, int pWidth = 0, int pBackground = 0, int pStyle = 0 )   {
//+------------------------------------------------------------------+
   ObjectCreate(objname,OBJ_VLINE,0,date1,0);
   ObjectSet(objname,OBJPROP_COLOR,pColor);
   ObjectSet(objname,OBJPROP_WIDTH,pWidth);
   ObjectSet(objname,OBJPROP_TIMEFRAMES,pTimeframes);  
   ObjectSet(objname,OBJPROP_BACK,pBackground); 
   ObjectSet(objname,OBJPROP_STYLE,pStyle);

}
//+------------------------------------------------------------------+
void  CreateAndSetTline(string objname, datetime date1, double price1,  datetime date2 , double price2,color pColor = 0,int pTimeframes=0, string pDescription="",int pWidth = 0, int pRay = 0, int pStyle = 0 )   {
//+------------------------------------------------------------------+
   ObjectCreate(objname,OBJ_TREND,0,date1,price1,date2,price2);
   ObjectSet(objname,OBJPROP_COLOR,pColor);
   ObjectSet(objname,OBJPROP_WIDTH,pWidth);
   ObjectSet(objname,OBJPROP_TIMEFRAMES,pTimeframes);  
   ObjectSet(objname,OBJPROP_RAY,pRay); 
   ObjectSet(objname,OBJPROP_STYLE,pStyle);             
   ObjectSetText(objname,pDescription);

}
//+------------------------------------------------------------------+
void DrawTlines( int pos)  {
//+------------------------------------------------------------------+   
   for( int i=0; i<OctLinesCnt; i++ ){
      buff_str  = UniqueID + i + "-" + TimeToStr( Time[pos], TIME_DATE|TIME_MINUTES);
      buff_str1 = UniqueID+""+ i + "-" + RedrawDate;   

      string buff_str3 = "v1/v2:" + DoubleToStr(v1,0)+","+DoubleToStr(v2,0)+
                         ",oct:" + DoubleToStr(octave,0)  +  
                         ",mn:" + DoubleToStr(mn,0) + 
                         ",mn+octave:" + DoubleToStr(mn+octave,0) + 
                         ",mx:" + DoubleToStr(mx,0);   
	    
      if(ObjectFind(buff_str1) == -1) {
         CreateAndSetTline( buff_str1, StrToTime(RedrawDate), mml[i],  Time[pos] , mml[i],clr[i],0, "",wdth[i], 0, 2 );	     
      }//if(ObjectFind(buff_str1) == -1) {
      else {
         ObjectSet(buff_str1, OBJPROP_TIME2, Time[pos]);
         if (i==12) ObjectSetText(buff_str1, buff_str3 );  
      }//else {
	     	         
      buff_str = UniqueID + "_txt " + i;
      if(ObjectFind(buff_str) == -1) {
         ObjectCreate(buff_str, OBJ_TEXT, 0, Time[0], shft);
         ObjectSetText(buff_str, ln_txt[i] + " " + DoubleToStr(mml[i],Digits), 8, "Arial", clr[i]);
         ObjectMove(buff_str, 0, Time[0],  mml[i]+3*Point);
         
      } //if(ObjectFind(buff_str) == -1) { 
      else {
         ObjectMove(buff_str, 0, Time[0],  mml[i]+3*Point);
         ObjectSetText(buff_str, ln_txt[i] + " " + DoubleToStr(mml[i],Digits), 8, "Arial", clr[i]);
      }//else { 
	     
   } // for( int i=1; i<=OctLinesCnt; i++ )   
   
}
//+------------------------------------------------------------------+
void DrawVlines( int pos)  {
//+------------------------------------------------------------------+  
   buff_str2 = UniqueID + " Redraw:" + RedrawDate +"pos="+pos;
   CreateAndSetVline(buff_str2, Time[pos],mml[0], DimGray,0, 0, 1,  0 );

   lastMML = mml[0];
}
//+------------------------------------------------------------------+
void GetRange(int pos)  {
//+------------------------------------------------------------------+
   if (UseCloseForRangeCalcs && !UseOriginalCalcs ) {
      bn_Lo = iLowest(NULL,0,MODE_CLOSE,NewPeriod,pos);
      bn_Hi = iHighest(NULL,0,MODE_CLOSE,NewPeriod,pos);

      v1 = Close[bn_Lo]*MMmultiplier;
      v2 = Close[bn_Hi]*MMmultiplier;	   

      buffer1[pos] = v1/MMmultiplier;         //buffer1 is the Low
      buffer2[pos] = v2/MMmultiplier;         //buffer2 is the High
   }
   else     {
      bn_Lo = iLowest(NULL,0,MODE_LOW,NewPeriod,pos);
      bn_Hi = iHighest(NULL,0,MODE_HIGH,NewPeriod,pos);

      v1 = Low[bn_Lo]*MMmultiplier;
      v2 = High[bn_Hi]*MMmultiplier;	   

      buffer1[pos] = v1/MMmultiplier;         //buffer1 is the Low
      buffer2[pos] = v2/MMmultiplier;         //buffer2 is the High
   }   
}	   
//+------------------------------------------------------------------+
void CalculateXY_old(int pos)     {
//+------------------------------------------------------------------+
   range=(v2-v1);	
	sum=MathFloor(MathLog(fractal/range)/MathLog(2));	 
   octave=fractal*(MathPow(0.5,sum));

	mn=MathFloor(v1/octave)*octave;


   if( (mn+octave)>v2 ) {
      mx=mn+octave; 
   }//if( (mn+octave)>v2 )
   else    {
      mx=mn+(2*octave);
   }//else  
   mmx = mx-mn;    

   if( (v1>=(3*mmx/16+mn))&& (v2<=(9*mmx/16+mn)))  {x[1]=mn+mmx/2; } else x[1]=0;                                                            //x[1]	
   if( (v1>=2*(mn-mmx/16))&& (v2<=(10*mmx/16+mn))  && (x[1]==0) ) {x[0]=mn+mmx/2;  } else x[0]=0;                                            //x[0]
   if( (v1>=(mn+7*mmx/16))&& (v2<=(13*mmx/16+mn))) {x[3]=mn+3*mmx/4; }  else x[3]=0;                                                         //x[3]	
   if( (v1>=(mn+6*mmx/16))&& (v2<=(18*mmx/16+mn))  && (x[3]==0) ) {x[4]=mx;   } else  x[4]=0;                                                //x[4]	
   if( (v1>=2*(mn+mmx/16))&& (v2<=(14*mmx/16+mn))  && (x[0]==0) && (x[1]==0) && (x[3]==0) && (x[4]==0)) {x[2]=mn+3*mmx/4;  }  else x[2]=0;   //x[2]	
   if( (x[0]+x[1]+x[2]+x[3]+x[4]) ==0 ) {x[5]=mx;} else x[5]=0;                                                                              //x[5]
	if( x[0]>0 ) {y[0]=mn;}       else y[0]=0;                                                                                                //y[0]                   	                     
	if( x[1]>0 ) {y[1]=mn+mmx/4;} else y[1]=0;                                                                                                //y[1]                     	                     
	if( x[2]>0 ) {y[2]=mn+mmx/4;} else y[2]=0;                                                                                                //y[2]                     	                     
	if( x[3]>0 ) {y[3]=mn+mmx/2;} else y[3]=0;                                                                                                //y[3]                      	                     
	if( x[4]>0 ) {y[4]=mn+mmx/2;} else y[4]=0;                                                                                                //y[4]                    	                     
	if( x[5]>0 ) {y[5]=mn; }      else y[5]=0;                                                                                                //y[5]
   
	      
   finalH = (x[0]+x[1]+x[2]+x[3]+x[4]+x[5])/MMmultiplier;
   finalL = (y[0]+y[1]+y[2]+y[3]+y[4]+y[5])/MMmultiplier;
		
   dmml = (finalH-finalL)/8;		   
   mml[0] =(finalL-dmml*2); //Set the bottom of the square (-2/8)
   for( i=1; i<OctLinesCnt; i++) {
      mml[i] = mml[i-1] + dmml;
   }//for( i=1; i<OctLinesCnt; i++) { 




   if (mml[0] != lastMML || dmml != lastDmml || mml[12] != lastfinalH )   {
      RedrawDate = TimeToStr( Time[pos], TIME_DATE|TIME_MINUTES);
      DrawVlines(pos);
   }
   lastMML = mml[0];
   lastOctave = octave;
   lastfinalH = mml[12];
   lastDmml   = dmml;
   DrawTlines( pos);
	return(0);
}
//+------------------------------------------------------------------+   
void DoBestFit()   {
//+------------------------------------------------------------------+   
	if (SetOctave > 0)   {
	   octave = SetOctave;
	}
	else    {
	   octave=fractal*(MathPow(0.5,sum));
      if(Debug)Print("Octave=",octave);
	}
	mn=MathFloor(v1/octave)*octave;
   if (SetOctave > 0)   {
   	for (int f = 1 ;f <= OctaveMultiplier;f++)    {
   	   if( (mn+octave*MathPow(2,f))> v2 ) {
   	      mx=mn+octave*MathPow(2,f);
   	      break; 
   	   }//if( (mn+octave)>v2 )
   	}//for (int f = 1 ;f <= OctaveMultiplier;f++) 
   }//if (SetOctave > 0)
   else  {
   	if( (mn+octave)>v2 ) {
   	   mx=mn+octave; 
   	}//if( (mn+octave)>v2 )
   	else    {
   	   mx=mn+(2*octave);
   	}//else  
   }// else
   return(0);   
}

