//+------------------------------------------------------------------+
//|                                                                  |
//|                                               RaitisCyFilter.mq4 |
//|                                                                  |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2011, Raitis"
#property link      "esterkin2313@inbox.lv"

#property indicator_separate_window
#property indicator_minimum 0.0
#property indicator_maximum 1.0
#property indicator_buffers 2
#property indicator_color1 LimeGreen
#property indicator_color2 DarkOrange

extern string TimeFrame = "current time frame";
extern int SmoothPeriod = 5;
extern int SmoothPhase = 0;
extern bool alertsOn = FALSE;
extern bool alertsOnCurrent = FALSE;
extern bool alertsMessage = FALSE;
extern bool alertsSound = FALSE;
extern bool alertsEmail = FALSE;
double g_ibuf_112[];
double g_ibuf_116[];
double g_ibuf_120[];
int g_timeframe_124;
bool gi_128 = FALSE;
bool gi_132 = FALSE;
string gs_136;
string gs_nothing_144 = "nothing";
datetime g_time_152;
string gsa_156[] = {"M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1", "MN"};
int gia_160[] = {1, 5, 15, 30, 60, 240, 1440, 10080, 43200};
double gda_164[][30];

int init() {
   IndicatorBuffers(3);
   SetIndexBuffer(0, g_ibuf_112);
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(1, g_ibuf_116);
   SetIndexStyle(1, DRAW_HISTOGRAM);
   SetIndexBuffer(2, g_ibuf_120);
   if (TimeFrame == "calculate") {
      gi_128 = TRUE;
      return (0);
   }
   if (TimeFrame == "getBarsCount") {
      gi_132 = TRUE;
      return (0);
   }
   g_timeframe_124 = stringToTimeFrame(TimeFrame);
   gs_136 = WindowExpertName();
   IndicatorShortName(timeFrameToString(g_timeframe_124) + "RaitisCyFilter");
   return (0);
}

int start() {
   double ld_12;
   double ld_20;
   double ld_28;
   int l_shift_36;
   int li_0 = IndicatorCounted();
   if (li_0 < 0) return (-1);
   if (li_0 > 0) li_0--;
   int li_8 = MathMin(Bars - li_0, Bars - 1);
   if (gi_132) {
      g_ibuf_112[0] = li_8 + 1;
      return (0);
   }
   if (gi_128 || g_timeframe_124 == Period()) {
      for (int li_4 = li_8; li_4 >= 0; li_4--) {
         ld_12 = iSmooth(High[li_4 + 1], SmoothPeriod, SmoothPhase, li_4 + 1, 0);
         ld_20 = iSmooth(Low[li_4 + 1], SmoothPeriod, SmoothPhase, li_4 + 1, 10);
         ld_28 = iSmooth(Close[li_4], SmoothPeriod, SmoothPhase, li_4, 20);
         g_ibuf_116[li_4] = EMPTY_VALUE;
         g_ibuf_112[li_4] = EMPTY_VALUE;
         g_ibuf_120[li_4] = g_ibuf_120[li_4 + 1];
         if (ld_28 > ld_12) g_ibuf_120[li_4] = -1;
         if (ld_28 < ld_20) g_ibuf_120[li_4] = 1;
         if (g_ibuf_120[li_4] == 1.0) g_ibuf_116[li_4] = 1;
         if (g_ibuf_120[li_4] == -1.0) g_ibuf_112[li_4] = 1;
      }
      manageAlerts();
      return (0);
   }
   li_8 = MathMax(li_8, MathMin(Bars, iCustom(NULL, g_timeframe_124, gs_136, "getBarsCount", 0, 0) * g_timeframe_124 / Period()));
   for (li_4 = li_8; li_4 >= 0; li_4--) {
      l_shift_36 = iBarShift(NULL, g_timeframe_124, Time[li_4]);
      g_ibuf_116[li_4] = EMPTY_VALUE;
      g_ibuf_112[li_4] = EMPTY_VALUE;
      g_ibuf_120[li_4] = iCustom(NULL, g_timeframe_124, gs_136, "calculate", SmoothPeriod, SmoothPhase, 2, l_shift_36);
      if (g_ibuf_120[li_4] == 1.0) g_ibuf_116[li_4] = 1;
      if (g_ibuf_120[li_4] == -1.0) g_ibuf_112[li_4] = 1;
   }
   manageAlerts();
   return (0);
}

void manageAlerts() {
   int li_0;
   if ((!gi_128) && alertsOn) {
      if (alertsOnCurrent) li_0 = 0;
      else li_0 = 1;
      li_0 = iBarShift(NULL, 0, iTime(NULL, g_timeframe_124, li_0));
      if (g_ibuf_120[li_0] != g_ibuf_120[li_0 + 1]) {
         if (g_ibuf_120[li_0] == 1.0) {
            doAlert(li_0, "up");
            return;
         }
         doAlert(li_0, "down");
      }
   }
}

void doAlert(int ai_0, string as_4) {
   string l_str_concat_12;
   if (gs_nothing_144 != as_4 || g_time_152 != Time[ai_0]) {
      gs_nothing_144 = as_4;
      g_time_152 = Time[ai_0];
      l_str_concat_12 = StringConcatenate(Symbol(), " at ", TimeToStr(TimeLocal(), TIME_SECONDS), " RaitisCyFilter direction changed to", as_4);
      if (alertsMessage) Alert(l_str_concat_12);
      if (alertsEmail) SendMail(StringConcatenate(Symbol(), "RaitisCyFilter"), l_str_concat_12);
      if (alertsSound) PlaySound("alert2.wav");
   }
}

int stringToTimeFrame(string as_0) {
   as_0 = stringUpperCase(as_0);
   for (int ai_8 = ArraySize(gia_160) - 1; ai_8 >= 0; ai_8--)
      if (as_0 == gsa_156[ai_8] || as_0 == "" + gia_160[ai_8]) return (MathMax(gia_160[ai_8], Period()));
   return (Period());
}

string timeFrameToString(int ai_0) {
   for (int li_4 = ArraySize(gia_160) - 1; li_4 >= 0; li_4--)
      if (ai_0 == gia_160[li_4]) return (gsa_156[li_4]);
   return ("");
}

string stringUpperCase(string as_0) {
   int li_20;
   string ls_ret_8 = as_0;
   for (int li_16 = StringLen(as_0) - 1; li_16 >= 0; li_16--) {
      li_20 = StringGetChar(ls_ret_8, li_16);
      if ((li_20 > '`' && li_20 < '{') || (li_20 > 'ß' && li_20 < 256)) ls_ret_8 = StringSetChar(ls_ret_8, li_16, li_20 - 32);
      else
         if (li_20 > -33 && li_20 < 0) ls_ret_8 = StringSetChar(ls_ret_8, li_16, li_20 + 224);
   }
   return (ls_ret_8);
}

double iSmooth(double ad_0, double ad_8, double ad_16, int ai_24, int ai_28 = 0) {
   double ld_80;
   double ld_88;
   if (ArrayRange(gda_164, 0) != Bars) ArrayResize(gda_164, Bars);
   int li_32 = Bars - ai_24 - 1;
   if (li_32 == 0) {
      for (int l_count_36 = 0; l_count_36 < 7; l_count_36++) gda_164[0][l_count_36 + ai_28] = ad_0;
      while (l_count_36 < 10) {
         gda_164[0][l_count_36 + ai_28] = 0;
         l_count_36++;
      }
      return (ad_0);
   }
   double ld_40 = MathMax(MathLog(MathSqrt((ad_8 - 1.0) / 2.0)) / MathLog(2.0) + 2.0, 0);
   double ld_48 = MathMax(ld_40 - 2.0, 0.5);
   double ld_56 = ad_0 - (gda_164[li_32 - 1][ai_28 + 5]);
   double ld_64 = ad_0 - (gda_164[li_32 - 1][ai_28 + 6]);
   gda_164[li_32][ai_28 + 7] = 0;
   if (MathAbs(ld_56) > MathAbs(ld_64)) gda_164[li_32][ai_28 + 7] = MathAbs(ld_56);
   if (MathAbs(ld_56) < MathAbs(ld_64)) gda_164[li_32][ai_28 + 7] = MathAbs(ld_64);
   gda_164[li_32][ai_28 + 8] = gda_164[li_32 - 1][ai_28 + 8] + (gda_164[li_32][ai_28 + 7] - (gda_164[li_32 - 10][ai_28 + 7])) / 10.0;
   double ld_72 = MathMin(MathMax(4.0 * ad_8, 30), 150);
   if (li_32 < ld_72) {
      ld_80 = gda_164[li_32][ai_28 + 8];
      for (l_count_36 = 1; l_count_36 < ld_72 && li_32 - l_count_36 >= 0; l_count_36++) ld_80 += gda_164[li_32 - l_count_36][ai_28 + 8];
      ld_80 /= l_count_36;
   } else ld_80 = ((gda_164[li_32 - 1][ai_28 + 9]) * ld_72 - (gda_164[li_32 - toInt(ld_72)][ai_28 + 8]) + (gda_164[li_32][ai_28 + 8])) / ld_72;
   gda_164[li_32][ai_28 + 9] = ld_80;
   if (gda_164[li_32][ai_28 + 9] > 0.0) ld_88 = (gda_164[li_32][ai_28 + 7]) / (gda_164[li_32][ai_28 + 9]);
   else ld_88 = 0;
   if (ld_88 > MathPow(ld_40, 1.0 / ld_48)) ld_88 = MathPow(ld_40, 1.0 / ld_48);
   if (ld_88 < 1.0) ld_88 = 1.0;
   double ld_96 = MathPow(ld_88, ld_48);
   double ld_104 = MathSqrt((ad_8 - 1.0) / 2.0) * ld_40;
   double ld_112 = MathPow(ld_104 / (ld_104 + 1.0), MathSqrt(ld_96));
   if (ld_56 > 0.0) gda_164[li_32][ai_28 + 5] = ad_0;
   else gda_164[li_32][ai_28 + 5] = ad_0 - ld_112 * ld_56;
   if (ld_64 < 0.0) gda_164[li_32][ai_28 + 6] = ad_0;
   else gda_164[li_32][ai_28 + 6] = ad_0 - ld_112 * ld_64;
   double ld_120 = MathMax(MathMin(ad_16, 100), -100) / 100.0 + 1.5;
   double ld_128 = (ad_8 - 1.0) / 2.0 / ((ad_8 - 1.0) / 2.0 + 2.0);
   double ld_136 = MathPow(ld_128, ld_96);
   gda_164[li_32][ai_28 + 0] = ad_0 + ld_136 * (gda_164[li_32 - 1][ai_28 + 0] - ad_0);
   gda_164[li_32][ai_28 + 1] = (ad_0 - (gda_164[li_32][ai_28 + 0])) * (1 - ld_128) + ld_128 * (gda_164[li_32 - 1][ai_28 + 1]);
   gda_164[li_32][ai_28 + 2] = gda_164[li_32][ai_28 + 0] + ld_120 * (gda_164[li_32][ai_28 + 1]);
   gda_164[li_32][ai_28 + 3] = (gda_164[li_32][ai_28 + 2] - (gda_164[li_32 - 1][ai_28 + 4])) * MathPow(1 - ld_136, 2) + MathPow(ld_136, 2) * (gda_164[li_32 - 1][ai_28 +
      3]);
   gda_164[li_32][ai_28 + 4] = gda_164[li_32 - 1][ai_28 + 4] + (gda_164[li_32][ai_28 + 3]);
   return (gda_164[li_32][ai_28 + 4]);
}

int toInt(double ad_0) {
   return (ad_0);
}