//+---------------------+
//| 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   1
#property indicator_color1  Black

// user input
extern int xbars = 500;
extern int PeriodGo = 1;
extern int PeriodStop = 200;

extern double LevelLinesPercent = 75;
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 = "LSMA200VFast_";

// LSMA
int per;

// buffers
double buff1[];
double sumX[];  // Collect sum for each period
double sumX2[];
double sumY[];
double sumY2[];
double sumXY[];

// Collect wt for each period 
double wt[];  //LSMA current value
double wtp[];  //LSMA previous value

double myPoint;

string Id = "Vote";
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, sumX);
   SetIndexBuffer(2, sumX2);
   SetIndexBuffer(3, sumY);
   SetIndexBuffer(4, sumY2);
   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();

   
   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

  }//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++)
   {
      Val = Open[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;
     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++)
   {
      Val = Open[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;
     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);
}

 

