//+---------------------+
//| LSMA                |
//| Optimized for speed |
//| by Robert Hill      |
//|                     |
//| Added Arrows at     |
//| cross of 0 line     |
//| and Level Lines     |
//+---------------------+
#property  copyright "Copyright 2005 Ron Thompson"
#property  link      "http://www.forexmt4.com/"


// indicator settings
#property  indicator_separate_window

// buffers
#property indicator_buffers   2
#property indicator_color1  Aqua
#property indicator_color2  Red
#property indicator_width1  1
#property indicator_width2  1

// user input
extern int xbars = 500;
extern int PeriodGo = 1;
extern int PeriodStop = 200;
extern int UseOpenPrice = 1;

extern double LevelLinesPercent = 75;


extern string  m = "--Moving Average Types--";
extern string  m0 = " 0 = SMA";
extern string  m1 = " 1 = EMA";
extern string  m2 = " 2 = SMMA";
extern string  m3 = " 3 = LWMA";
extern int     MA_Type=0;
extern int     MA_Period = 21;

extern color BuyColor = Green;
extern color SellColor = Red;
extern int distBelow = 5;
extern int distAbove = 50;


// bar counting
datetime bartime=0;


// Objects
int     uniq=0;
string Object_ID = "LSMA200VFastA_";

// LSMA
int per;

// buffers
double buff1[];
double MA_Buffer[];
double sumX[];  // Collect sum for each period
double sumX2[];
double sumY[];
double sumXY[];

// Collect wt for each period 
double wt[];  //LSMA current value
double wtp[];  //LSMA previous value

int MAType;
double myPoint;

string Id = "VoteA";
double Buy1, Buy2, Sell1, Sell2;

//+-----------+
//| Init      |
//+-----------+
int init()
  {
   // 233 up arrow
   // 234 down arrow
   // 158 little dot
   // 159 big dot
   // 168 open square
   // 120 box with X
   
   double tmp;
   myObjectsDeleteAll();

//---- Add 2 additional buffers as helpers used for counting.
// 1 for plotting, 7 helper
   IndicatorBuffers(8);
   SetIndexBuffer(0,buff1);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(1, MA_Buffer);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexBuffer(2, sumX);
   SetIndexBuffer(3, sumX2);
   SetIndexBuffer(4, sumY);
   SetIndexBuffer(5, sumXY);
   SetIndexBuffer(6, wt);
   SetIndexBuffer(7, wtp);
   
   tmp = PeriodStop * LevelLinesPercent / 100.0;
   Buy1 = 0.0;
   Buy2 = -tmp;
   Sell1 = 0.0;
   Sell2 = tmp;
   SetLevelStyle(STYLE_DASH, 1, Gray);
   SetLevelValue(0,Buy2);
   SetLevelValue(1, Sell2);
   SetLevelValue(2, 0.0);
   
   //SetIndexArrow(0,159);
   
   myPoint = SetPoint();
   if (MA_Type > 3) MAType = 0;
      
   Print("Init complete");
  }


//+-----------+
//| DE-Init   |
//+-----------+
int deinit()
  {
   myObjectsDeleteAll();
   
   Print("DE-Init complete");
  }


//+-----------+
//| Each Tick |
//+-----------+
int start()
  {   
   int    pos;

   int    vote;



   // draw once at open of bar 
//   if(bartime==Time[0]) return(0);
//   bartime=Time[0];

   myObjectsDeleteAll();
   uniq=0;
   
   for(pos = xbars; pos >= 0; pos--)
   {
      vote=0;
      calcLSMAs(pos);
      calcLSMAsPrev(pos);

      for (int j = PeriodGo; j <= PeriodStop; j++)
      {
        if(wt[j]<wtp[j]) vote++;
        if(wt[j]>wtp[j]) vote--;
      }
   
        
      buff1[pos]=vote;
      //draw number on chart

// Down Arrow

      if (buff1[pos + 1] >= Sell1 && buff1[pos] <= Sell1)
      {
   		ObjectCreate(Id+uniq, OBJ_TEXT, 0, Time[pos],Low[pos]-distBelow*Point );
         ObjectSetText(Id+uniq, CharToStr(242), 10, "Wingdings", SellColor);
         uniq++;
      }
      if (buff1[pos + 1] >= Sell2 && buff1[pos] <= Sell2)
      {
   		ObjectCreate(Id+uniq, OBJ_TEXT, 0, Time[pos],Low[pos]-distBelow*Point );
         ObjectSetText(Id+uniq, CharToStr(234), 10, "Wingdings", SellColor);
         uniq++;
      }
      
// Up Arrow
      if (buff1[pos+1] <= Buy1 && buff1[pos] >= Buy1)
      {
   		ObjectCreate(Id+uniq, OBJ_TEXT, 0, Time[pos],High[pos]+distAbove*Point );
         ObjectSetText(Id+uniq, CharToStr(241), 10, "Wingdings", BuyColor);
         uniq++;
      }
      if (buff1[pos+1] <= Buy2 && buff1[pos] >= Buy2)
      {
   		ObjectCreate(Id+uniq, OBJ_TEXT, 0, Time[pos],High[pos]+distAbove*Point );
         ObjectSetText(Id+uniq, CharToStr(233), 10, "Wingdings", BuyColor);
         uniq++;
      }

     }//for pos
     
ArraySetAsSeries(buff1, true);
   for(pos = xbars; pos >= 0; pos--)
   {
     MA_Buffer[pos] = iMAOnArray(buff1,0,MA_Period, 0, MAType, pos );
   }

  }//start

// Calculate all LSMAs for the previous candle
void calcLSMAsPrev(int mybar)
  {
   int    i;
   double Val = 0;
   double c, m, yint, mywt;

// Clear working buffers
   for(i = 0; i <= PeriodStop  ; i++)
   {
	  sumX[i] = 0;
	  sumY[i] = 0;
	  sumXY[i] = 0;
	  sumX2[i] = 0;
//	  sumY2[i] = 0;
	}

// Then calculate all sums realizing that
// The sum for period 1 is the current value
// the sum for period 2 is the sum for period 1 + the previous value
// the sum for period 3 is the sum for period 2 + the previous value

   for(i = 1; i <= PeriodStop  ; i++)
   {
      if (UseOpenPrice == 1)
        Val = Open[mybar+i];
      else
        Val = Close[mybar+i+1];
      sumY[i] = sumY[i-1] + Val;
//      sumY2[i] = sumY[i] * sumY[i];
      sumX[i] = sumX[i-1] + i;
      sumX2[i] = sumX[i] + i * i;
      sumXY[i] = sumX[i] + sumY[i];
   }
      
// Then calculate the LSMA value for each period 

   for(i = 1; i <= PeriodStop  ; i++)
   {
     c=sumX2[i] * i - sumX2[i];
     if(c==0.0) c = .0000001;
     
     m = (sumXY[i] * i - sumX[i] * sumY[i]) /c;
     yint=(sumY[i] - sumX[i] * m) / i;
     mywt = yint + m * i;

// Round value to nearest pip for accurate compares later

     mywt = MathFloor(mywt/myPoint)*myPoint;
     wtp[i] = mywt;
   }
}         


// Calculate all LSMAs for the current candle
void calcLSMAs(int mybar)
  {
   int    i;
   double Val = 0;
   double c, m, yint, mywt;
   
   

// Clear working buffers
   for(i = 0; i <= PeriodStop  ; i++)
   {
	sumX[i] = 0;
	sumY[i] = 0;
	sumXY[i] = 0;
	sumX2[i] = 0;
//	sumY2[i] = 0;
	}

// Then calculate all sums realizing that
// The sum for period 1 is the current value
// the sum for period 2 is the sum for period 1 + the previous value
// the sum for period 3 is the sum for period 2 + the previous value
   for(i = 1; i <= PeriodStop  ; i++)
   {
      if (UseOpenPrice == 1)
        Val = Open[mybar+i-1];
      else
        Val = Close[mybar+i];
      sumY[i] = sumY[i-1] + Val;
//      sumY2[i] = sumY[i] * sumY[i];
      sumX[i] = sumX[i-1] + i;
      sumX2[i] = sumX[i] + i * i;
      sumXY[i] = sumX[i] + sumY[i];
   }
      
// Then calculate the LSMA value for each period 

   for(i = 1; i <= PeriodStop  ; i++)
   {
     c=sumX2[i] * i - sumX2[i];
     if(c==0.0) c = .0000001;
     
     m = (sumXY[i] * i - sumX[i] * sumY[i]) /c;
     yint=(sumY[i] - sumX[i] * m) / i;
     mywt = yint + m * i;

// Round value to nearest pip for accurate compares later

     mywt = MathFloor(mywt/myPoint)*myPoint;
     wt[i] = mywt;
   }
}         

void myObjectsDeleteAll()
{
   int obj = ObjectsTotal(OBJ_TEXT);
   int i, limit;
   string objName;
   
   if (obj > 0)
   {
      for (i = obj; i >= 0;i--)
      {
         objName = ObjectName(i);
         if (StringFind(objName,Object_ID, 0) >= 0) ObjectDelete(objName);
      }
   }
   
   limit=1500;
   for(i=limit; i>=0; i--) ObjectDelete(Id+i);
	
}

double SetPoint()
{
   double mPoint;
   
   if (Digits < 4)
      mPoint = 0.01;
   else
      mPoint = 0.0001;
   
   return(mPoint);
}

 

