//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-tsd.com"
//------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1  LimeGreen 
#property indicator_color2  Orange
#property indicator_color3  Aqua
#property indicator_color4  Magenta
#property indicator_width1  2
#property indicator_width2  2

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame       = PERIOD_CURRENT;
extern double             FastLimit       = 0.5;
extern double             SlowLimit       = 0.05;
extern ENUM_APPLIED_PRICE Price           = PRICE_MEDIAN;
extern int                PriceFilter     = 1;
extern ENUM_MA_METHOD     PriceFilterMode = MODE_EMA;
extern bool               alertsOn        = true;
extern bool               alertsOnCurrent = false;
extern bool               alertsMessage   = true;
extern bool               alertsSound     = true;
extern bool               alertsNotify    = false;
extern bool               alertsEmail     = false;
extern string             soundFile       = "alert2.wav";

extern int                arrowthickness  = 1;
extern bool               ArrowsOnFirstBar= true;

//
//
//
//
//

double mama[];
double fama[];
double arrUp[];
double arrDn[];
double trend[];
string indicatorFileName;
bool   returnBars;
int    timeFrame;

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,mama);
   SetIndexBuffer(1,fama);
   SetIndexBuffer(2,arrUp);  SetIndexStyle(2,DRAW_ARROW,0,arrowthickness); SetIndexArrow(2,233);
   SetIndexBuffer(3,arrDn);  SetIndexStyle(3,DRAW_ARROW,0,arrowthickness); SetIndexArrow(3,234);
   SetIndexBuffer(4,trend); 
      indicatorFileName = WindowExpertName();
      returnBars        = TimeFrame==-99;
      TimeFrame         = MathMax(TimeFrame,_Period);
   return(0);
}
int deinit() { return(0); }

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

double work[][14];
#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 _sa       13

#define Pi 3.14159265358979323846264338327950288

//
//
//
//
//

int start()
{
   double rad2degree = 180.0/Pi;
   int    i,r,counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = MathMin(Bars-counted_bars,Bars-1);
            if (ArrayRange(work,0)!=Bars) ArrayResize(work,Bars);
            if (returnBars) { mama[0] = limit+1; return(0); }
            if (TimeFrame!=Period())
            {
               int shift = -1; if (ArrowsOnFirstBar) shift=1;
               limit = (int)MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
               for (i=limit; i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);       
                  int x = iBarShift(NULL,TimeFrame,Time[i+shift]);       
                     mama[i]  = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,FastLimit,SlowLimit,Price,PriceFilter,PriceFilterMode,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,0,y);
                     fama[i]  = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,FastLimit,SlowLimit,Price,PriceFilter,PriceFilterMode,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,1,y);
                  if (x!=y)
                  {
                     arrUp[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,FastLimit,SlowLimit,Price,PriceFilter,PriceFilterMode,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,2,y);
                     arrDn[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,FastLimit,SlowLimit,Price,PriceFilter,PriceFilterMode,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,3,y);
                  }   
                  else
                  {
                     arrUp[i] = EMPTY_VALUE;
                     arrDn[i] = EMPTY_VALUE;
                  }
               }
               return(0);
            }

   //
   //
   //
   //
   //

   for(i=limit, r=Bars-i-1; i>=0; i--,r++)
   {
      work[r][_price]     = iMA(NULL,0,PriceFilter,0,PriceFilterMode,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);
      work[r][_sa] = Alpha;
	
      //
      //
      //
      //
      //

      mama[i]  =     work[r][_sa]*work[r][_price] + (1.0-    work[r][_sa])*mama[i+1];
      fama[i]  = 0.5*work[r][_sa]*mama[i]         + (1.0-0.5*work[r][_sa])*fama[i+1];
      trend[i] = trend[i+1];
      if (fama[i]<mama[i]) trend[i] = 1;
      if (fama[i]>mama[i]) trend[i] =-1;
      
      //
      //
      //
      //
      //
      
      arrUp[i] = EMPTY_VALUE;
      arrDn[i] = EMPTY_VALUE;
      if (trend[i]!= trend[i+1])
      if (trend[i] == 1)
            arrUp[i] = mama[i] - iATR(NULL,0,20,i)/2;
      else  arrDn[i] = mama[i] + iATR(NULL,0,20,i)/2;
      
   }
   
   //
   //
   //
   //
   //
   
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;
      if (trend[whichBar] != trend[whichBar+1])
      if (trend[whichBar] == 1)
            doAlert("crossing fama up");
      else  doAlert("crossing fama down");       
   }
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));
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          message =  StringConcatenate(Symbol()," ",timeFrameToString(TimeFrame)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," mama ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol()," mama  "),message);
             if (alertsSound)   PlaySound(soundFile);
      }
}
      

