//+------------------------------------------------------------------+
//|                                                    MA ribbon.mq4 |
//|                                               mladenfx@gmail.com |
//|                                                                  |
//| original idea by Jose Silva                                      |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1  clrCrimson  //C'97,48,48'  /////C'217,240,242'   //C'215,255,225'
#property indicator_color2  clrDarkGray  //C'36,62,62'             ///C'240,235,183'    ///OldLace   //Gainsboro
#property indicator_color3  clrTeal
#property indicator_color4  clrChocolate

//
//
//

extern ENUM_TIMEFRAMES    TimeFrame = PERIOD_CURRENT; // Time frame
extern int                MA1Period = 9;
extern ENUM_MA_METHOD     MA1Method = MODE_EMA;
extern ENUM_APPLIED_PRICE MA1Price  = PRICE_WEIGHTED;
extern int                MA1Shift  = 1;
extern int                MA2Period = 1;
extern ENUM_MA_METHOD     MA2Method = MODE_EMA;
extern ENUM_APPLIED_PRICE MA2Price  = PRICE_WEIGHTED;
extern int                MA2Shift  = 0;
extern int                FillWidth = 9;
extern int                LineWidth = 9;
extern bool               Interpolate = true;           // Interpolate in mtf mode
//template code start1
extern string             button_note1          = "------------------------------";
extern ENUM_BASE_CORNER   btn_corner            = CORNER_LEFT_UPPER; // chart btn_corner for anchoring
extern string             btn_text              = "MA";
extern string             btn_Font              = "Impact";
extern int                btn_FontSize          = 10;                             //btn__font size
extern color              btn_text_ON_color     = clrWhite;
extern color              btn_text_OFF_color    = C'120,120,120';
extern color              btn_background_color  = clrDimGray;
extern color              btn_border_color      = clrBlack;
extern int                button_x              = 900;                                     //btn__x
extern int                button_y              = 20;                                     //btn__y
extern int                btn_Width             = 60;                                 //btn__width
extern int                btn_Height            = 20;                                //btn__height
extern string             UniqueButtonID        = "MAs";
extern string             button_note2          = "------------------------------";

bool                      show_data             = true;
string IndicatorName, IndicatorObjPrefix;

double buffer1[],buffer2[],buffer3[],buffer4[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,0,MA1Period,MA1Method,MA1Price,MA1Shift,MA2Period,MA2Method,MA2Price,MA2Shift,FillWidth,LineWidth,Interpolate,button_note1,btn_corner,btn_text,btn_Font,btn_FontSize,btn_text_ON_color,btn_text_OFF_color,btn_background_color,btn_border_color,button_x,button_y,btn_Width,btn_Height,UniqueButtonID,button_note2,_buff,_ind)

//------------------------------------------------------------------
//
//------------------------------------------------------------------
string GenerateIndicatorName(const string target) //don't change anything here
{
   string name = target;
   int try = 2;
   while (WindowFind(name) != -1)
   {
      name = target + " #" + IntegerToString(try++);
   }
   return name;
}
//+------------------------------------------------------------------------------------------------------------------+
string buttonId;

int OnInit()
{
   IndicatorName = GenerateIndicatorName(btn_text);
   IndicatorObjPrefix = "__" + IndicatorName + "__";
   IndicatorShortName(IndicatorName);
   IndicatorDigits(Digits);
   
   double val;
   if (GlobalVariableGet(IndicatorName + "_visibility", val))
      show_data = val != 0;

   ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_MOVE, 1);
   buttonId = IndicatorObjPrefix + UniqueButtonID;
   createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, btn_background_color, btn_border_color, btn_text_ON_color);
   ObjectSetInteger(ChartID(), buttonId, OBJPROP_YDISTANCE, button_y);
   ObjectSetInteger(ChartID(), buttonId, OBJPROP_XDISTANCE, button_x);

// put init() here
   init2();
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------------------------------------------------------+
//don't change anything here
void createButton(string buttonID,string buttonText,int width,int height,string font,int fontSize,color bgColor,color borderColor,color txtColor)
{
      ObjectDelete    (ChartID(),buttonID);
      ObjectCreate    (ChartID(),buttonID,OBJ_BUTTON,0,0,0);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_COLOR,txtColor);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_BGCOLOR,bgColor);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_BORDER_COLOR,borderColor);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_XSIZE,width);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_YSIZE,height);
      ObjectSetString (ChartID(),buttonID,OBJPROP_FONT,font);
      ObjectSetString (ChartID(),buttonID,OBJPROP_TEXT,buttonText);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_FONTSIZE,fontSize);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_SELECTABLE,0);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_CORNER,btn_corner);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_HIDDEN,1);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_XDISTANCE,9999);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_YDISTANCE,9999);
}
//+------------------------------------------------------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll(ChartID(), IndicatorObjPrefix);

//put deinit() here
	return(0);
}
//+------------------------------------------------------------------------------------------------------------------+
//don't change anything here
bool recalc = true;

void handleButtonClicks()
{
   if (ObjectGetInteger(ChartID(), buttonId, OBJPROP_STATE))
   {
      ObjectSetInteger(ChartID(), buttonId, OBJPROP_STATE, false);
      show_data = !show_data;
      GlobalVariableSet(IndicatorName + "_visibility", show_data ? 1.0 : 0.0);
      recalc = true;
      start();
   }
}
//+------------------------------------------------------------------------------------------------------------------+
void OnChartEvent(const int id, //don't change anything here
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   handleButtonClicks();
}
int start()
{
   handleButtonClicks();
   recalc = false;
   //put start () here
   start2();
   
      if (show_data)
         {
           ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_ON_color);
           SetIndexStyle(0,DRAW_HISTOGRAM);
           SetIndexStyle(1,DRAW_HISTOGRAM);    
           SetIndexStyle(2,DRAW_LINE);
           SetIndexStyle(3,DRAW_LINE);        
         }
      else
         {
           ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_OFF_color);
           for (int banzai2=0; banzai2<indicator_buffers; banzai2++)
               SetIndexStyle(banzai2,DRAW_NONE);
         }
   return(0);
}
int init2()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,buffer3); SetIndexStyle(0,DRAW_HISTOGRAM,EMPTY,FillWidth);
   SetIndexBuffer(1,buffer4); SetIndexStyle(1,DRAW_HISTOGRAM,EMPTY,FillWidth);
   SetIndexBuffer(2,buffer1); SetIndexStyle(2,DRAW_LINE,EMPTY,LineWidth); 
   SetIndexBuffer(3,buffer2); SetIndexStyle(3,DRAW_LINE,EMPTY,LineWidth);
   SetIndexBuffer(4,count);
      
      //
      //
      //
      //
      //
      
      MA1Method         = MathMin(MathMax(MA1Method,0),4);
      MA2Method         = MathMin(MathMax(MA2Method,0),4);
      indicatorFileName = WindowExpertName();
      TimeFrame         = MathMax(TimeFrame,_Period);
      SetIndexShift(0,MA1Shift * TimeFrame/_Period);  
      SetIndexShift(1,MA2Shift * TimeFrame/_Period); 
      SetIndexShift(2,MA1Shift * TimeFrame/_Period);  
      SetIndexShift(3,MA2Shift * TimeFrame/_Period); 
      
      IndicatorShortName(timeFrameToString(TimeFrame)+" MA Ribbon filled"); 
return(0);
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int start2()
{
  int limit,i,counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
           limit=MathMin(Bars-counted_bars,Bars-1); count[0] = limit;
           if (MA1Shift < 0) limit = fmax(limit,-MA1Shift);
           if (MA2Shift < 0) limit = fmax(limit,-MA2Shift);

   //
   //
   //
   //
   //

   if (TimeFrame == Period())
   {
     for(i=limit; i>=0; i--)
     {
        if (MA1Method<4) 
              buffer1[i] = iMA(NULL,0,MA1Period,MA1Shift,MA1Method,MA1Price,i);
        else  buffer1[i] = iLsma(iMA(NULL,0,1,MA1Shift,MODE_SMA,MA1Price,i),MA1Period,i,0);
        if (MA2Method<4) 
              buffer2[i] = iMA(NULL,0,MA2Period,MA2Shift,MA2Method,MA2Price,i);
        else  buffer2[i] = iLsma(iMA(NULL,0,1,MA2Shift,MODE_SMA,MA2Price,i),MA2Period,i,1);
        buffer3[i] = buffer1[i];
        buffer4[i] = buffer2[i];
     }
   return(0);
   }
   
   //
   //
   //
   //
   //
   
   limit = (int)MathMax(limit,MathMin(Bars-1,_mtfCall(4,0)*TimeFrame/_Period));
   for (i=limit;i>=0;i--)
   {
      int y = iBarShift(NULL,TimeFrame,Time[i]);
         buffer1[i] = _mtfCall(2,y);
         buffer2[i] = _mtfCall(3,y);
         buffer3[i] = buffer1[i];
         buffer4[i] = buffer2[i];

         //
         //
         //
         //
         //
      
            if (!Interpolate || y==iBarShift(NULL,TimeFrame,Time[i-1])) continue;

         //
         //
         //
         //
         //

         int n,k; datetime time = iTime(NULL,TimeFrame,y);
            for(n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            for(k = 1; k < n && (i+n)<Bars && (i+k)<Bars; k++)
            {
               buffer1[i+k] = buffer1[i] + (buffer1[i+n]-buffer1[i])*k/n;
               buffer2[i+k] = buffer2[i] + (buffer2[i+n]-buffer2[i])*k/n;
               buffer3[i+k] = buffer1[i+k];
               buffer4[i+k] = buffer2[i+k];
            }
   }
   return(0);
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workLsma[][2];
double iLsma(double price, double period, int r, int instanceNo=0)
{
   if (ArrayRange(workLsma,0)!= Bars) ArrayResize(workLsma,Bars); r = Bars-r-1;

   //
   //
   //
   //
   //
   
      period = MathMax(period,1);
      workLsma[r][instanceNo] = price;
         double lwmw = period; double lwma = lwmw*price;
         double sma  = price;
         for(int k=1; k<period && (r-k)>=0; k++)
         {
            double weight = period-k;
                   lwmw  += weight;
                   lwma  += weight*workLsma[r-k][instanceNo];  
                   sma   +=        workLsma[r-k][instanceNo];
         }             
   
   return(3.0*lwma/lwmw-2.0*sma/period);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

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("");
}


