//+------------------------------------------------------------------+
//|                                        AbsoluteStrength_v1.1.mq4 |
//|                           Copyright © 2006, TrendLaboratory Ltd. |
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |
//|                                       E-mail: igorad2004@list.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, TrendLaboratory Ltd."
#property link      "http://finance.groups.yahoo.com/group/TrendLaboratory"

#property indicator_separate_window
#property indicator_buffers   4
#property indicator_color1    LightBlue
#property indicator_width1    2 
#property indicator_color2    Tomato
#property indicator_width2    2
#property indicator_color3    Aqua
#property indicator_width3    1
#property indicator_style3    3 
#property indicator_color4    Orange
#property indicator_width4    1 
#property indicator_style4    3
//---- input parameters
extern string    TimeFrame  = "Current time frame";
extern int       Mode       =  0; // 0-RSI method; 1-Stoch method; 2-ADX method
extern int       Length     = 10; // Period of evaluation
extern int       Smooth     =  5; // Period of smoothing
extern int       Signal     =  5; // Period of Signal Line
extern int       Price      =  0; // Price mode : 0-Close,1-Open,2-High,3-Low,4-Median,5-Typical,6-Weighted
extern int       ModeMA     =  4; // Mode of Moving Average
extern double    T3Hot        = 0.9;
extern bool      T3Original   = true;
extern int       AdaptPeriod  = 25;
extern double    OverBought =  0; // OverBought Level
extern double    OverSold   =  0; // OverSold Level 
extern bool      alertsOn        = false;
extern bool      alertsOnCurrent = true;
extern bool      alertsMessage   = true;
extern bool      alertsSound     = false;
extern bool      alertsEmail     = false;
  
double Bulls[];
double Bears[];
double AvgBulls[];
double AvgBears[];
double SmthBulls[];
double SmthBears[];
double SigBulls[];
double SigBears[];

int      timeFrame;
bool     calculateValue;
bool     returnBars;
string   indicatorFileName;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
int init()
{
   IndicatorBuffers(8);
   IndicatorDigits(6);
   SetIndexBuffer(0,SmthBulls);
   SetIndexBuffer(1,SmthBears);
   SetIndexBuffer(2,SigBulls);
   SetIndexBuffer(3,SigBears);
   SetIndexBuffer(4,Bulls);
   SetIndexBuffer(5,Bears);
   SetIndexBuffer(6,AvgBulls);
   SetIndexBuffer(7,AvgBears);

         //
         //
         //
         //
         //
                  
         indicatorFileName = WindowExpertName();
         calculateValue    = (TimeFrame=="CalculateValue"); if (calculateValue) return(0);
         returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
         timeFrame         = stringToTimeFrame(TimeFrame);
         
         //
         //
         //
         //
         //

   IndicatorShortName(timeFrameToString(timeFrame)+" AbsoluteStrength("+Mode+","+Length+","+Smooth+","+Signal+",,"+ModeMA+")");
   SetIndexLabel(0,"Bulls");
   SetIndexLabel(1,"Bears");
   SetIndexLabel(2,"SignalBulls");
   SetIndexLabel(3,"SignalBears");      

   SetIndexDrawBegin(0,Length+Smooth+Signal);
   SetIndexDrawBegin(1,Length+Smooth+Signal);
   SetIndexDrawBegin(2,Length+Smooth+Signal);
   SetIndexDrawBegin(3,Length+Smooth+Signal);
   
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double trend[];
double coeff[];
int start()
{
   int 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 (returnBars) { SmthBulls[0] = limit+1; return(0); }

   //
   //
   //
   //
   //
   
   if (calculateValue || timeFrame==Period())
   {
      if (ArraySize(trend)!=Bars) ArrayResize(trend,Bars);
      if (ArraySize(coeff)!=Bars) ArrayResize(coeff,Bars);
      
      for(int shift=limit; shift>=0; shift--)
      {
         double Price1 = iMA(NULL,0,1,0,MODE_SMA,Price,shift);
         double Price2 = iMA(NULL,0,1,0,MODE_SMA,Price,shift+1); 
      
         if (Mode==0)
         {
            Bulls[shift] = 0.5*(MathAbs(Price1-Price2)+(Price1-Price2));
            Bears[shift] = 0.5*(MathAbs(Price1-Price2)-(Price1-Price2));
            continue;
         }
         if (Mode==1)
         {
            Bulls[shift] = Price1 - Low[Lowest(NULL,0,MODE_LOW,Length,shift)];
            Bears[shift] = High[Highest(NULL,0,MODE_HIGH,Length,shift)] - Price1;
            continue;
         }
         if (Mode==2)
         {
            Bulls[shift] = 0.5*(MathAbs(High[shift]-High[shift+1])+(High[shift]-High[shift+1]));
            Bears[shift] = 0.5*(MathAbs(Low[shift+1]-Low[shift])+(Low[shift+1]-Low[shift]));
         }
      }

      //
      //
      //
      //
      //
         
      for( shift=limit, r=Bars-shift-1 ; shift>=0; shift--, r++)
      {
         if (ModeMA==4)
         {
            double dev   = iStdDev(NULL,0,AdaptPeriod,0,MODE_SMA,Price,shift);
            double avg   = iSma(dev,AdaptPeriod,shift,0);
            coeff[r] = 1; if (dev!=0) coeff[r] = avg/dev;
               AvgBulls[shift] = iT3(Bulls[shift],Length*coeff[r],T3Hot,T3Original,shift,0);
               AvgBears[shift] = iT3(Bears[shift],Length*coeff[r],T3Hot,T3Original,shift,1);
         }
         else
         {
            AvgBulls[shift]=iMAOnArray(Bulls,0,Length,0,ModeMA,shift);     
            AvgBears[shift]=iMAOnArray(Bears,0,Length,0,ModeMA,shift);
         }            
      }
      for( shift=limit, r=Bars-shift-1; shift>=0; shift--,r++)
      {
         if (ModeMA==4)
         {
            SmthBulls[shift] = iT3(AvgBulls[shift],Smooth*coeff[r],T3Hot,T3Original,shift,2);
            SmthBears[shift] = iT3(AvgBears[shift],Smooth*coeff[r],T3Hot,T3Original,shift,3);
         }
         else
         {
            SmthBulls[shift]=iMAOnArray(AvgBulls,0,Smooth,0,ModeMA,shift);     
            SmthBears[shift]=iMAOnArray(AvgBears,0,Smooth,0,ModeMA,shift);
         }            
         trend[r] = trend[r-1];
            if (SmthBulls[shift]>SmthBears[shift]) trend[r] =  1;
            if (SmthBulls[shift]<SmthBears[shift]) trend[r] = -1;
      }
      for( shift=limit, r=Bars-shift-1; shift>=0; shift--,r++)
      {
         if (OverBought > 0 && OverSold > 0 )
         {
            SigBulls[shift]=OverBought/100.00*(SmthBulls[shift]+SmthBears[shift]);
            SigBears[shift]=OverSold  /100.00*(SmthBulls[shift]+SmthBears[shift]);
         }
         else
         {
            if (ModeMA==4)
            {
               SigBulls[shift] = iT3(SmthBulls[shift],Signal*coeff[r],T3Hot,T3Original,shift,4);
               SigBears[shift] = iT3(SmthBears[shift],Signal*coeff[r],T3Hot,T3Original,shift,5);
            }
            else
            {
               SigBulls[shift]=iMAOnArray(SmthBulls,0,Signal,0,ModeMA,shift);     
               SigBears[shift]=iMAOnArray(SmthBears,0,Signal,0,ModeMA,shift);
            }               
         }
      }
      manageAlerts();
      return(0);
   }
   
   //
   //
   //
   //
   //

   limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   for (int i=limit;i>=0;i--)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         SmthBulls[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",Mode,Length,Smooth,Signal,Price,ModeMA,T3Hot,T3Original,AdaptPeriod,OverBought,OverSold,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,0,y);
         SmthBears[i] = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",Mode,Length,Smooth,Signal,Price,ModeMA,T3Hot,T3Original,AdaptPeriod,OverBought,OverSold,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,1,y);
         SigBulls[i]  = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",Mode,Length,Smooth,Signal,Price,ModeMA,T3Hot,T3Original,AdaptPeriod,OverBought,OverSold,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,2,y);
         SigBears[i]  = iCustom(NULL,timeFrame,indicatorFileName,"CalculateValue",Mode,Length,Smooth,Signal,Price,ModeMA,T3Hot,T3Original,AdaptPeriod,OverBought,OverSold,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,3,y);
   }
   return(0);         
}




//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
//

double workSma[][2];
double iSma(double price, int period, int r, int instanceNo=0)
{
   if (ArrayRange(workSma,0)!= Bars) ArrayResize(workSma,Bars); instanceNo *= 2; r = Bars-r-1;

   //
   //
   //
   //
   //
      
   workSma[r][instanceNo] = price;
   if (r>=period)
          workSma[r][instanceNo+1] = workSma[r-1][instanceNo+1]+(workSma[r][instanceNo]-workSma[r-period][instanceNo])/period;
   else { workSma[r][instanceNo+1] = 0; for(int k=0; k<period && (r-k)>=0; k++) workSma[r][instanceNo+1] += workSma[r-k][instanceNo];  
          workSma[r][instanceNo+1] /= k; }
   return(workSma[r][instanceNo+1]);
}

//
//
//
//
//

double workT3[][36];
double workT3Coeffs[][6];
#define _period 0
#define _c1     1
#define _c2     2
#define _c3     3
#define _c4     4
#define _alpha  5

//
//
//
//
//

double iT3(double price, double period, double hot, bool original, int i, int instanceNo=0)
{
   if (ArrayRange(workT3,0) !=Bars)                 ArrayResize(workT3,Bars);
   if (ArrayRange(workT3Coeffs,0) < (instanceNo+1)) ArrayResize(workT3Coeffs,instanceNo+1);
   if (period<1) period=1;
   if (workT3Coeffs[instanceNo][_period] != period)
   {
     workT3Coeffs[instanceNo][_period] = period;
        double a = hot;
            workT3Coeffs[instanceNo][_c1] = -a*a*a;
            workT3Coeffs[instanceNo][_c2] = 3*a*a+3*a*a*a;
            workT3Coeffs[instanceNo][_c3] = -6*a*a-3*a-3*a*a*a;
            workT3Coeffs[instanceNo][_c4] = 1+3*a+a*a*a+3*a*a;
            if (original)
                 workT3Coeffs[instanceNo][_alpha] = 2.0/(1.0 + period);
            else workT3Coeffs[instanceNo][_alpha] = 2.0/(2.0 + (period-1.0)/2.0);
   }
   
   //
   //
   //
   //
   //
   
   int buffer = instanceNo*6;
   int r = Bars-i-1;
   if (r == 0)
      {
         workT3[r][0+buffer] = price;
         workT3[r][1+buffer] = price;
         workT3[r][2+buffer] = price;
         workT3[r][3+buffer] = price;
         workT3[r][4+buffer] = price;
         workT3[r][5+buffer] = price;
      }
   else
      {
         workT3[r][0+buffer] = workT3[r-1][0+buffer]+workT3Coeffs[instanceNo][_alpha]*(price              -workT3[r-1][0+buffer]);
         workT3[r][1+buffer] = workT3[r-1][1+buffer]+workT3Coeffs[instanceNo][_alpha]*(workT3[r][0+buffer]-workT3[r-1][1+buffer]);
         workT3[r][2+buffer] = workT3[r-1][2+buffer]+workT3Coeffs[instanceNo][_alpha]*(workT3[r][1+buffer]-workT3[r-1][2+buffer]);
         workT3[r][3+buffer] = workT3[r-1][3+buffer]+workT3Coeffs[instanceNo][_alpha]*(workT3[r][2+buffer]-workT3[r-1][3+buffer]);
         workT3[r][4+buffer] = workT3[r-1][4+buffer]+workT3Coeffs[instanceNo][_alpha]*(workT3[r][3+buffer]-workT3[r-1][4+buffer]);
         workT3[r][5+buffer] = workT3[r-1][5+buffer]+workT3Coeffs[instanceNo][_alpha]*(workT3[r][4+buffer]-workT3[r-1][5+buffer]);
      }

   //
   //
   //
   //
   //
   
   return(workT3Coeffs[instanceNo][_c1]*workT3[r][5+buffer] + 
          workT3Coeffs[instanceNo][_c2]*workT3[r][4+buffer] + 
          workT3Coeffs[instanceNo][_c3]*workT3[r][3+buffer] + 
          workT3Coeffs[instanceNo][_c4]*workT3[r][2+buffer]);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      if (alertsOnCurrent)
            int forBar = 0;
      else      forBar = 1; forBar = Bars-forBar-1;
      if (trend[forBar]!=trend[forBar-1])
      {
         if (trend[forBar]== 1) doAlert(0,"up");
         if (trend[forBar]==-1) doAlert(0,"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 =  timeFrameToString(Period())+" "+Symbol()+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" absolute strength changed trend to "+doWhat;
             if (alertsMessage) Alert(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"  absolute strength"),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)
{
   StringToUpper(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("");
}
