//+------------------------------------------------------------------+
//|           Crazy Arrows                                           |
//+------------------------------------------------------------------+
#property copyright "Crazy Arrows"
#property link      ""
#property version   "1.3"
#property strict

#property indicator_chart_window
#property indicator_buffers 10

#property indicator_color1 clrNONE
#property indicator_color2 clrAqua
#property indicator_color3 clrMagenta
#property indicator_width2 1
#property indicator_width3 1

#property indicator_color4 clrOrangeRed
#property indicator_color5 clrSpringGreen
#property indicator_color6 clrNONE
#property indicator_color7 clrNONE
#property indicator_color8 clrOrangeRed
#property indicator_color9 clrSpringGreen
#property indicator_style4 0
#property indicator_style5 0
#property indicator_style8 0
#property indicator_style9 0
#property indicator_width4 2
#property indicator_width5 2
#property indicator_width8 2
#property indicator_width9 2

//---- stoch settings
extern string Arrow_Settings = "-------------------------------------";
extern int    RSI_Period     = 14;
extern int    RSI_Price      = 0;
extern int    T3_Period      = 14;
extern double T3_Hot         = 0.7;

//---- input parameters
bool               T3Original      = false;

extern string Slow_Moving_Average_Settings = "-------------------------------------";
extern int    MA_Period       = 200;
extern int    MA_Type         = 1;
int           MAAppliedPrice  = 0;

extern string Fast_Moving_Average_Settings = "-------------------------------------";
extern int    MA_Period_      = 100;
extern int    MA_Type_        = 1;
int           MAAppliedPrice_ = 0;

double t3rsi[];
double trend[];

double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double MA1[];
double ExtMapBuffer4[];
double ExtMapBuffer5[];
double ExtMapBuffer6[];

int    MAMode, MAMode2;
string strMAType, strMAType2;

double upArrow[];
double dnArrow[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   string short_name;
   short_name = "Crazy Arrows";
   IndicatorShortName(short_name);

   SetIndexBuffer(0, t3rsi);
   SetIndexStyle(0, DRAW_NONE);
   
   SetIndexBuffer(1, dnArrow);
   SetIndexStyle(1, DRAW_ARROW);
   SetIndexArrow(1, 225);
   
   SetIndexBuffer(2, upArrow);
   SetIndexStyle(2, DRAW_ARROW);
   SetIndexArrow(2, 226);

   SetIndexBuffer(3, ExtMapBuffer3);
   SetIndexStyle(3, DRAW_LINE);

   SetIndexBuffer(4, ExtMapBuffer2);
   SetIndexStyle(4, DRAW_LINE);

   SetIndexBuffer(5, ExtMapBuffer1);
   SetIndexStyle(5, DRAW_NONE);

   SetIndexBuffer(6, MA1);
   SetIndexStyle(6, DRAW_NONE);

   SetIndexBuffer(7, ExtMapBuffer6);
   SetIndexStyle(7, DRAW_LINE);

   SetIndexBuffer(8, ExtMapBuffer5);
   SetIndexStyle(8, DRAW_LINE);

   SetIndexBuffer(9, ExtMapBuffer4);
   SetIndexStyle(9, DRAW_NONE);

   switch (MA_Type)
   {
      case 1:  strMAType = "EMA";  MAMode = MODE_EMA;  break;
      case 2:  strMAType = "SMMA"; MAMode = MODE_SMMA; break;
      case 3:  strMAType = "LWMA"; MAMode = MODE_LWMA; break;
      default: strMAType = "SMA";  MAMode = MODE_SMA;  break;
   }

   switch (MA_Type_)
   {
      case 1:  strMAType2 = "EMA";  MAMode2 = MODE_EMA;  break;
      case 2:  strMAType2 = "SMMA"; MAMode2 = MODE_SMMA; break;
      case 3:  strMAType2 = "LWMA"; MAMode2 = MODE_LWMA; break;
      default: strMAType2 = "SMA";  MAMode2 = MODE_SMA;  break;
   }

   return(0);
}

//+------------------------------------------------------------------+
double RSI(int i = 0)
{
   return(iRSI(NULL, 0, RSI_Period, RSI_Price, i));
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   double MA_Cur, MA_Prev;
   int limit;
   int counted_bars = IndicatorCounted();
   
   if (counted_bars < 0) return(-1);
   if (counted_bars > 0) counted_bars--;
   limit = Bars - counted_bars;

   for(int i = limit - 1; i >= 0; i--)
   {
      if (MA_Type == 4)
      {
         MA_Cur  = LSMA(MA_Period, MAAppliedPrice, i);
         MA_Prev = LSMA(MA_Period, MAAppliedPrice, i + 1);
      }
      else
      {
         MA_Cur  = iMA(NULL, 0, MA_Period, 0, MAMode, MAAppliedPrice, i);
         MA_Prev = iMA(NULL, 0, MA_Period, 0, MAMode, MAAppliedPrice, i + 1);
      }

      ExtMapBuffer3[i] = MA_Cur;
      ExtMapBuffer2[i] = MA_Cur;
      ExtMapBuffer1[i] = MA_Cur;

      if (MA_Prev > MA_Cur)
      {
         ExtMapBuffer2[i] = EMPTY_VALUE;
      }
      else if (MA_Prev < MA_Cur)
      {
         ExtMapBuffer1[i] = EMPTY_VALUE;
      }
      else
      {
         ExtMapBuffer1[i] = EMPTY_VALUE;
         ExtMapBuffer2[i] = EMPTY_VALUE;
      }
   }

   double MA_Cur2, MA_Prev2;
   int limit2;
   int counted_bars2 = IndicatorCounted();
   
   if (counted_bars2 < 0) return(-1);
   if (counted_bars2 > 0) counted_bars2--;
   limit2 = Bars - counted_bars2;

   for(int i2 = limit2 - 1; i2 >= 0; i2--)
   {
      if (MA_Type_ == 4)
      {
         MA_Cur2  = LSMA2(MA_Period_, MAAppliedPrice_, i2);
         MA_Prev2 = LSMA2(MA_Period_, MAAppliedPrice_, i2 + 1);
      }
      else
      {
         MA_Cur2  = iMA(NULL, 0, MA_Period_, 0, MAMode2, MAAppliedPrice_, i2);
         MA_Prev2 = iMA(NULL, 0, MA_Period_, 0, MAMode2, MAAppliedPrice_, i2 + 1);
      }

      ExtMapBuffer6[i2] = MA_Cur2;
      ExtMapBuffer5[i2] = MA_Cur2;
      ExtMapBuffer4[i2] = MA_Cur2;

      if (MA_Prev2 > MA_Cur2)
      {
         ExtMapBuffer5[i2] = EMPTY_VALUE;
      }
      else if (MA_Prev2 < MA_Cur2)
      {
         ExtMapBuffer4[i2] = EMPTY_VALUE;
      }
      else
      {
         ExtMapBuffer4[i2] = EMPTY_VALUE;
         ExtMapBuffer5[i2] = EMPTY_VALUE;
      }
   }

   for(int j = MathMax(Bars - 1 - IndicatorCounted(), 1); j >= 0; j--)
   {
      t3rsi[j] = iT3(RSI(j), T3_Period, T3_Hot, T3Original, j);
      MA1[j]   = iMA(NULL, 0, 1, 0, MODE_SMA, PRICE_CLOSE, j);

      if(t3rsi[j] > RSI(j + 1) && t3rsi[j] < 50 && MA1[j] < ExtMapBuffer3[j])
      {
         if(MA1[j] < ExtMapBuffer6[j])
         {
            upArrow[j] = High[j] + iATR(NULL, 0, 5, j) / 3;
         }
      }
      else if(t3rsi[j] < RSI(j + 1) && t3rsi[j] > 50 && MA1[j] > ExtMapBuffer3[j])
      {
         if(MA1[j] > ExtMapBuffer6[j])
         {
            dnArrow[j] = Low[j] - iATR(NULL, 0, 5, j) / 3;
         }
      }
   }

   return(0);
}

//+------------------------------------------------------------------+
//| T3 Moving Average                                                |
//+------------------------------------------------------------------+
double workT3[][6];
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 forInstance = 0)
{
   if (ArrayRange(workT3, 0) != Bars)
      ArrayResize(workT3, Bars);
   if (ArrayRange(workT3Coeffs, 0) < (forInstance + 1))
      ArrayResize(workT3Coeffs, forInstance + 1);

   if (workT3Coeffs[forInstance][_period] != period)
   {
      workT3Coeffs[forInstance][_period] = period;
      double a = hot;
      workT3Coeffs[forInstance][_c1] = -a * a * a;
      workT3Coeffs[forInstance][_c2] = 3 * a * a + 3 * a * a * a;
      workT3Coeffs[forInstance][_c3] = -6 * a * a - 3 * a - 3 * a * a * a;
      workT3Coeffs[forInstance][_c4] = 1 + 3 * a + a * a * a + 3 * a * a;
      if (original)
         workT3Coeffs[forInstance][_alpha] = 2.0 / (1.0 + period);
      else
         workT3Coeffs[forInstance][_alpha] = 2.0 / (2.0 + (period - 1.0) / 2.0);
   }

   int buffer = forInstance * 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[forInstance][_alpha] * (price                     - workT3[r-1][0 + buffer]);
      workT3[r][1 + buffer] = workT3[r-1][1 + buffer] + workT3Coeffs[forInstance][_alpha] * (workT3[r][0 + buffer]     - workT3[r-1][1 + buffer]);
      workT3[r][2 + buffer] = workT3[r-1][2 + buffer] + workT3Coeffs[forInstance][_alpha] * (workT3[r][1 + buffer]     - workT3[r-1][2 + buffer]);
      workT3[r][3 + buffer] = workT3[r-1][3 + buffer] + workT3Coeffs[forInstance][_alpha] * (workT3[r][2 + buffer]     - workT3[r-1][3 + buffer]);
      workT3[r][4 + buffer] = workT3[r-1][4 + buffer] + workT3Coeffs[forInstance][_alpha] * (workT3[r][3 + buffer]     - workT3[r-1][4 + buffer]);
      workT3[r][5 + buffer] = workT3[r-1][5 + buffer] + workT3Coeffs[forInstance][_alpha] * (workT3[r][4 + buffer]     - workT3[r-1][5 + buffer]);
   }

   return(workT3Coeffs[forInstance][_c1] * workT3[r][5 + buffer] +
          workT3Coeffs[forInstance][_c2] * workT3[r][4 + buffer] +
          workT3Coeffs[forInstance][_c3] * workT3[r][3 + buffer] +
          workT3Coeffs[forInstance][_c4] * workT3[r][2 + buffer]);
}

//+------------------------------------------------------------------+
//| LSMA                                                             |
//+------------------------------------------------------------------+
double LSMA(int Rperiod, int prMode, int shift)
{
   int length = Rperiod;
   double sum = 0;
   
   for(int i = length; i >= 1; i--)
   {
      double lengthvar = (length + 1.0) / 3.0;
      double pr;
      switch (prMode)
      {
         case 0: pr = Close[length - i + shift]; break;
         case 1: pr = Open[length - i + shift]; break;
         case 2: pr = High[length - i + shift]; break;
         case 3: pr = Low[length - i + shift]; break;
         case 4: pr = (High[length - i + shift] + Low[length - i + shift]) / 2.0; break;
         case 5: pr = (High[length - i + shift] + Low[length - i + shift] + Close[length - i + shift]) / 3.0; break;
         case 6: pr = (High[length - i + shift] + Low[length - i + shift] + Close[length - i + shift] + Close[length - i + shift]) / 4.0; break;
         default: pr = Close[length - i + shift]; break;
      }
      sum += (i - lengthvar) * pr;
   }
   
   return(sum * 6.0 / (length * (length + 1.0)));
}

//+------------------------------------------------------------------+
//| LSMA2                                                            |
//+------------------------------------------------------------------+
double LSMA2(int Rperiod, int prMode, int shift)
{
   int length = Rperiod;
   double sum = 0;
   
   for(int i = length; i >= 1; i--)
   {
      double lengthvar = (length + 1.0) / 3.0;
      double pr;
      switch (prMode)
      {
         case 0: pr = Close[length - i + shift]; break;
         case 1: pr = Open[length - i + shift]; break;
         case 2: pr = High[length - i + shift]; break;
         case 3: pr = Low[length - i + shift]; break;
         case 4: pr = (High[length - i + shift] + Low[length - i + shift]) / 2.0; break;
         case 5: pr = (High[length - i + shift] + Low[length - i + shift] + Close[length - i + shift]) / 3.0; break;
         case 6: pr = (High[length - i + shift] + Low[length - i + shift] + Close[length - i + shift] + Close[length - i + shift]) / 4.0; break;
         default: pr = Close[length - i + shift]; break;
      }
      sum += (i - lengthvar) * pr;
   }
   
   return(sum * 6.0 / (length * (length + 1.0)));
}
//+------------------------------------------------------------------+