//+------------------------------------------------------------------+
//|                                                    mama macd.mq4 |
//|                                                                  |
//|                                                  mama by Mladen  |
//|                                                  mod by mrtools  |
//+------------------------------------------------------------------+

#property copyright "www.forex-tsd.com"
#property link      "www.forex-tsd.com"

#property  indicator_separate_window
#property  indicator_buffers   6
#property  indicator_color1    LimeGreen
#property  indicator_color2    Red
#property  indicator_color3    Red
#property  indicator_color4    LimeGreen
#property  indicator_color5    DarkSlateGray   
#property  indicator_color6    DeepPink
#property  indicator_width1    3
#property  indicator_width2    3
#property  indicator_width3    3
#property  indicator_width4    3
#property  indicator_width5    3
#property  indicator_width6    2
#property indicator_levelcolor Gold

//
//
//
//
//

extern string TimeFrame        = "Current time frame";
extern double FastLimit        = 0.5;
extern double SlowLimit        = 0.05;
extern double SignalPeriod     = 10;
extern int    Price            = PRICE_MEDIAN;
extern bool   Interpolate      = true;
extern bool   HistogramOnSlope = true;

extern bool   alertsOn         = false;
extern bool   alertsOnSlope    = true;
extern bool   alertsOnCurrent  = true;
extern bool   alertsMessage    = true;
extern bool   alertsSound      = false;
extern bool   alertsEmail      = false;


//
//
//
//
//

double mafa[];
double signal[];
double mama[];
double fama[];
double mafahuu[];
double mafahud[];
double mafahdd[];
double mafahdu[];
double trend[];
double slope[];

//
//
//
//
//

string indicatorFileName;
bool   returnBars;
bool   calculateValue;
int    timeFrame;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   
    IndicatorBuffers(8);  
    SetIndexBuffer(0,mafahuu); SetIndexStyle(0,DRAW_HISTOGRAM);
    SetIndexBuffer(1,mafahud); SetIndexStyle(1,DRAW_HISTOGRAM);
    SetIndexBuffer(2,mafahdd); SetIndexStyle(2,DRAW_HISTOGRAM);
    SetIndexBuffer(3,mafahdu); SetIndexStyle(3,DRAW_HISTOGRAM);
    SetIndexBuffer(4,mafa);
    SetIndexBuffer(5,signal);
    SetIndexBuffer(6,mama);
    SetIndexBuffer(7,fama);
    
    SetLevelValue(0,0);
    
        //
        //
        //
        //
        //
         
         
         indicatorFileName = WindowExpertName();
         calculateValue    = TimeFrame == "calculateValue"; if (calculateValue) { return(0); }
         returnBars        = TimeFrame == "returnBars";     if (returnBars)     { return(0); }
         timeFrame         = stringToTimeFrame(TimeFrame);

        //
        //
        //
        //
        //
   
   IndicatorShortName(timeFrameToString(timeFrame)+"  mama macd ("+DoubleToStr(FastLimit,2)+","+DoubleToStr(SlowLimit,2)+")"); 
return(0);
}
      
int deinit() { return(0); }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double work[][13];
#define _price     0
#define _smooth    1
#define _detrender 2
#define _period    3
#define _phase     4
#define _Q1        5
#define _I1        6
#define _JI        7
#define _JQ        8
#define _Q2        9
#define _I2       10
#define _Re       11
#define _Im       12

#define Pi 3.14159265358979323846264338327950288

//
//
//
//
//

int start()
{
   double rad2degree = 180.0/Pi;
   int    i,r,limit,counted_bars=IndicatorCounted();

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);
         if (returnBars) { mafahuu[0] = MathMin(limit+1,Bars-1); return(0); }
            
   //
   //
   //
   //
   //
   
   if (calculateValue || timeFrame==Period())
   {
      if (ArrayRange(work,0)!=Bars) ArrayResize(work,Bars);
      if (ArrayRange(trend,0)!=Bars) ArrayResize(trend,Bars);
      if (ArrayRange(slope,0)!=Bars) ArrayResize(slope,Bars);   
      for(i=limit, r=Bars-i-1; i>=0; i--,r++)
      {
         work[r][_price]     = iMA(NULL,0,1,0,MODE_SMA,Price,i);
         work[r][_smooth]    = (4.0*work[r][_price]+3.0*work[r-1][_price]+2.0*work[r-2][_price]+work[r-3][_price])/10.0;
         work[r][_detrender] = calcComp(r,_smooth);
         work[r][_Q1]        = calcComp(r,_detrender);
         work[r][_I1]        = work[r-3][_detrender];
         work[r][_JI]        = calcComp(r,_I1);
         work[r][_JQ]        = calcComp(r,_Q1);
      
         //
         //
         //
         //
         //
      
         work[r][_I2] = 0.2*(work[r][_I1]-work[r][_JQ])                                 + 0.8*work[r-1][_I2];
         work[r][_Q2] = 0.2*(work[r][_Q1]+work[r][_JI])                                 + 0.8*work[r-1][_Q2];
         work[r][_Re] = 0.2*(work[r][_I2]*work[r-1][_I2] + work[r][_Q2]*work[r-1][_Q2]) + 0.8*work[r-1][_Re];
         work[r][_Im] = 0.2*(work[r][_I2]*work[r-1][_Q2] - work[r][_Q2]*work[r-1][_I2]) + 0.8*work[r-1][_Im];
      
         if (work[r][_Re]!= 0 && work[r][_Im]!=0) 
            work[r][_period] = 360.0/(MathArctan(work[r][_Im]/work[r][_Re])*rad2degree);
            work[r][_period] = MathMin(work[r][_period],1.50*work[r-1][_period]);
            work[r][_period] = MathMax(work[r][_period],0.67*work[r-1][_period]);
            work[r][_period] = MathMin(MathMax(work[r][_period],6),50);
            work[r][_period] = 0.2*work[r][_period]+0.8*work[r-1][_period];
      
        //
        //
        //
        //
        //
      
        if( work[r][_I1] != 0) work[r][_phase] = MathArctan(work[r][_Q1]/work[r][_I1])*rad2degree;
	
                  double DeltaPhase = MathMax(work[r-1][_phase]-work[r][_phase],1);
                  double Alpha      = MathMax(MathMin(FastLimit/DeltaPhase,FastLimit),SlowLimit);
	
          mama[i] =     Alpha*work[r][_price] + (1.0-    Alpha)*mama[i+1];
          fama[i] = 0.5*Alpha*mama[i]         + (1.0-0.5*Alpha)*fama[i+1];
          mafa[i] = mama[i]-fama[i];
          
          mafahuu[i] = EMPTY_VALUE;
          mafahud[i] = EMPTY_VALUE;
          mafahdd[i] = EMPTY_VALUE;
          mafahdu[i] = EMPTY_VALUE;
            
          //
          //
          //
          //
          //
                           
          trend[r]  = trend[r-1];
          slope[r]  = slope[r-1];
               if (mafa[i] > 0)         trend[r] =  1;
               if (mafa[i] < 0)         trend[r] = -1;
               if (mafa[i] > mafa[i+1]) slope[r] =  1;
               if (mafa[i] < mafa[i+1]) slope[r] = -1;
            
               if (HistogramOnSlope)
               {
                 if (trend[r] ==  1 && slope[r] ==  1) mafahuu[i] = mafa[i];
                 if (trend[r] ==  1 && slope[r] == -1) mafahud[i] = mafa[i];
                 if (trend[r] == -1 && slope[r] == -1) mafahdd[i] = mafa[i];
                 if (trend[r] == -1 && slope[r] ==  1) mafahdu[i] = mafa[i];
               }
               else
               {                  
                 if (trend[r] ==  1) mafahuu[i] = mafa[i];
                 if (trend[r] == -1) mafahdd[i] = mafa[i];
               }
   }
   for (i=limit; i>=0; i--) signal[i] = iMAOnArray(mafa,0,SignalPeriod,0,MODE_LWMA,i); 
   manageAlerts();
   return(0);
   } 
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));   
   if (ArrayRange(trend,0)!=Bars) ArrayResize(trend,Bars);
   if (ArrayRange(slope,0)!=Bars) ArrayResize(slope,Bars);   
      for (i=limit, r=Bars-i-1; i>=0; i--,r++)
      { 
          int y = iBarShift(NULL,timeFrame,Time[i]);
             mafa[i]   = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",FastLimit,SlowLimit,SignalPeriod,Price,4,y);
             signal[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",FastLimit,SlowLimit,SignalPeriod,Price,5,y);
             trend[r]  = trend[r-1];
             slope[r]  = slope[r-1];
               if (mafa[i] > 0)         trend[r] =  1;
               if (mafa[i] < 0)         trend[r] = -1;
               if (mafa[i] > mafa[i+1]) slope[r] =  1;
               if (mafa[i] < mafa[i+1]) slope[r] = -1;
            
               if (HistogramOnSlope)
               {
                 if (trend[r] ==  1 && slope[r] ==  1) mafahuu[i] = mafa[i];
                 if (trend[r] ==  1 && slope[r] == -1) mafahud[i] = mafa[i];
                 if (trend[r] == -1 && slope[r] == -1) mafahdd[i] = mafa[i];
                 if (trend[r] == -1 && slope[r] ==  1) mafahdu[i] = mafa[i];
               }
               else
               {                  
                 if (trend[r] ==  1) mafahuu[i] = mafa[i];
                 if (trend[r] == -1) mafahdd[i] = mafa[i];
               }
               
             if (!Interpolate || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;
             //
             //
             //
             //
             //

             datetime time = iTime(NULL,timeFrame,y);
               for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
               for(int k = 1; k < n; k++)
               {
                  mafa[i+k]   = mafa[i]   + (mafa[i+n]   - mafa[i])   * k/n;
                  signal[i+k] = signal[i] + (signal[i+n] - signal[i]) * k/n;
                    if (mafahuu[i]!= EMPTY_VALUE) mafahuu[i+k] = mafa[i+k];
                    if (mafahud[i]!= EMPTY_VALUE) mafahud[i+k] = mafa[i+k];
                    if (mafahdd[i]!= EMPTY_VALUE) mafahdd[i+k] = mafa[i+k];
                    if (mafahdu[i]!= EMPTY_VALUE) mafahdu[i+k] = mafa[i+k];
               }
      }
  manageAlerts();
return(0);
}        

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double calcComp(int r, int from)
{
   return((0.0962*work[r  ][from] + 
           0.5769*work[r-2][from] - 
           0.5769*work[r-4][from] - 
           0.0962*work[r-6][from]) * (0.075*work[r-1][_period] + 0.54));
}
  
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void manageAlerts()
{
   if (!calculateValue && alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1; whichBar = Bars-iBarShift(NULL,0,iTime(NULL,timeFrame,whichBar))-1;
      
      //
      //
      //
      //
      //
      
      if (alertsOnSlope)
      {
         if (slope[whichBar] != slope[whichBar-1])
         {
            if (slope[whichBar] == 1) doAlert(whichBar,"slope changed to up");
            if (slope[whichBar] ==-1) doAlert(whichBar,"slope changed to down");
         }         
      }
      else
      {
         if (trend[whichBar] != trend[whichBar-1])
         {
            if (trend[whichBar] == 1) doAlert(whichBar,"crossed zero line up");
            if (trend[whichBar] ==-1) doAlert(whichBar,"crossed zero line down");
         }         
      }         
   }
}   

//
//
//
//
//

void doAlert(int forBar, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[forBar]) {
          previousAlert  = doWhat;
          previousTime   = Time[forBar];

          //
          //
          //
          //
          //

          message =  StringConcatenate(Symbol()," ",timeFrameToString(timeFrame)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," mama macd ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol()," mama macd "),message);
             if (alertsSound)   PlaySound("alert2.wav");
      }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

//
//
//
//
//

int stringToTimeFrame(string tfs)
{
   tfs = StringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}

//
//
//
//
//

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//
//
//
//

string StringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int char = StringGetChar(s, length);
         if((char > 96 && char < 123) || (char > 223 && char < 256))
                     s = StringSetChar(s, length, char - 32);
         else if(char > -33 && char < 0)
                     s = StringSetChar(s, length, char + 224);
   }
   return(s);
}     

