//+------------------------------------------------------------------+
//|                                         smPriceBoat Signals_vX
//+------------------------------------------------------------------+
#property copyright "Copyright 20.06.2020, SwingMan"
#property strict

/*--------------------------------------------------------------------
12.06.2020  - v1.0   - first version
--------------------------------------------------------------------*/

#property indicator_chart_window

#property indicator_buffers 12

#property indicator_color1 clrYellow //Trend fast
#property indicator_color2 clrLime
#property indicator_color3 clrRed
#property indicator_color4 clrYellow //Trend slow
#property indicator_color5 clrAqua   //Fractals
#property indicator_color6 clrRed

#property indicator_width1 3  //Trend
#property indicator_width2 3
#property indicator_width3 3
#property indicator_width4 4
#property indicator_width5 1  //Fractals
#property indicator_width6 1


enum ENUM_PATTERNS
  {
   ALL,
   Fractals,
   Smash_Bar,
   Retrace_Bar
  };

//+------------------------------------------------------------------+
//---- indicator parameters
//+------------------------------------------------------------------+
sinput string ____Patterns="========================================";
input ENUM_PATTERNS Draw_Patterns=ALL;
int maxBars=1500;
//--- Trend
sinput string ____Trend="========================================";
extern int MovingAverage_Period_Fast           =10;
extern int MovingAverage_Period_Slow           =110;
input ENUM_MA_METHOD MovingAverage_Method=MODE_SMA;
ENUM_APPLIED_PRICE MA_Price_1      =PRICE_CLOSE;
ENUM_APPLIED_PRICE MA_Price_2      =PRICE_OPEN;
//--- Fractals
sinput string ____Fractals="========================================";
//sinput string sArrows="ARROWS (217,218) or (164,164)"; //=================================
extern int ArrowCodeFractal_UP=217;
extern int ArrowCodeFractal_DN=218;
extern int ArrowWidthFractals  =1;
extern color ArrowColorFractal_UP=clrAqua;
extern color ArrowColorFractal_DN=clrOrange;
sinput string ____Smash_Bar="========================================";
extern int ArrowCodeSmash_UP=221;
extern int ArrowCodeSmash_DN=222;
extern int ArrowWidthSmash  =0;
extern color ArrowColorSmash_UP=clrLime;
extern color ArrowColorSmash_DN=clrMagenta;
sinput string ____Retrace_Bar="========================================";
extern int ArrowCodeRetrace_UP=233;
extern int ArrowCodeRetrace_DN=234;
extern color ArrowColorRetrace_UP=clrTurquoise;
extern color ArrowColorRetrace_DN=clrRed;
extern int ArrowWidthRetrace  =0;
sinput string ____Entry_Level="========================================";
extern int ArrowCodeEntry=164;
extern color ArrowColorEntry_UP=clrAqua;
extern color ArrowColorEntry_DN=clrYellow;
extern int ArrowWidthEntry  =2;
extern bool ShowComment=true;
sinput string ____ATR="========================================";
input int ATR_Period=55;
input int ATR_Factor=1;
//+------------------------------------------------------------------+
//int Period_Shift             =0;

//--- constants
string CR="\n";
string sObj="pboat_";

//---- buffers
//--- Moving Averages for trend
double LineMedian[], TrendUP[],TrendDOWN[],MainTrend[],SlowTrend[];
double mavg1[],mavg2[];
double atr[];
//int atrPeriod=55;

//--- Fractals 1/1
double FractalsUP[],FractalsDOWN[],AllFractalsUP[],AllFractalsDOWN[];
int Equals=3; //5;
int nLeftUp=1; //2;
int nRightUp=1; //2;
int nLeftDown=1; //2;
int nRightDown=1; //2;
int pos=0,cntup=0,cntdown=0,cnt=0;
int r=0,l=0,e=0;
int fup=0,fdown=0;
//--- Smash Bar, Retrace Bar
double SmashUP[],SmashDOWN[];
double RetraceUP[],RetraceDOWN[];
//--- Entrys
double AllEntrys[],EntryUP[],EntryDOWN[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   if(ShowComment==true)
     {
      string sName=WindowExpertName()+" ("+(string)MovingAverage_Period_Fast+","+(string)MovingAverage_Period_Slow+") ";
      Comment(sName,CR,"=====================");
     }

   ChartSetInteger(0,CHART_SHOW_GRID,false);
   maxBars=Bars-MovingAverage_Period_Slow;
   Draw_Symbol_Timeframe();
//---

   int iBuff=-1;
//---- indicators Trend -------------------------------
   iBuff++;
   SetIndexBuffer(iBuff,LineMedian);
   SetIndexLabel(iBuff,NULL);
   SetIndexDrawBegin(iBuff,MovingAverage_Period_Fast);

   iBuff++;
   SetIndexBuffer(iBuff,TrendUP);
   SetIndexLabel(iBuff,"UP"+" ("+(string)MovingAverage_Period_Fast+") ");
   SetIndexDrawBegin(iBuff,MovingAverage_Period_Fast);

   iBuff++;
   SetIndexBuffer(iBuff,TrendDOWN);
   SetIndexLabel(iBuff,"DOWN"+" ("+(string)MovingAverage_Period_Fast+") ");
   SetIndexDrawBegin(iBuff,MovingAverage_Period_Fast);

   iBuff++;
   SetIndexBuffer(iBuff,SlowTrend);
   SetIndexLabel(iBuff,"SlowTrend"+" ("+(string)MovingAverage_Period_Slow+") ");
   SetIndexDrawBegin(iBuff,MovingAverage_Period_Slow);

//---- indicators Fractals 1/1 ------------------------------- Fractals 1/1
   iBuff++;
   SetIndexBuffer(iBuff,FractalsUP);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthFractals,ArrowColorFractal_UP);
   SetIndexArrow(iBuff,ArrowCodeFractal_UP);

   iBuff++;
   SetIndexBuffer(iBuff,FractalsDOWN);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthFractals,ArrowColorFractal_DN);
   SetIndexArrow(iBuff,ArrowCodeFractal_DN);

//---- indicators Smash Bar -------------------------------
   iBuff++;
   SetIndexBuffer(iBuff,SmashUP);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthSmash,ArrowColorSmash_UP);
   SetIndexArrow(iBuff,ArrowCodeSmash_UP);

   iBuff++;
   SetIndexBuffer(iBuff,SmashDOWN);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthSmash,ArrowColorSmash_DN);
   SetIndexArrow(iBuff,ArrowCodeSmash_DN);

//---- indicators Retrace Bar -------------------------------
   iBuff++;
   SetIndexBuffer(iBuff,RetraceUP);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthRetrace,ArrowColorRetrace_UP);
   SetIndexArrow(iBuff,ArrowCodeRetrace_UP);

   iBuff++;
   SetIndexBuffer(iBuff,RetraceDOWN);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthRetrace,ArrowColorRetrace_DN);
   SetIndexArrow(iBuff,ArrowCodeRetrace_DN);

//---- indicators Entry Level -------------------------------
   iBuff++;
   SetIndexBuffer(iBuff,EntryUP);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthEntry,ArrowColorEntry_UP);
   SetIndexArrow(iBuff,ArrowCodeEntry);

   iBuff++;
   SetIndexBuffer(iBuff,EntryDOWN);
   SetIndexStyle(iBuff,DRAW_ARROW,0,ArrowWidthEntry,ArrowColorEntry_DN);
   SetIndexArrow(iBuff,ArrowCodeEntry);


//--- more buffers ------------------------------
   int newBuffers=7;
   IndicatorBuffers(iBuff+1+newBuffers);

   iBuff++;
   SetIndexBuffer(iBuff,mavg1);           //#1
   iBuff++;
   SetIndexBuffer(iBuff,mavg2);           //#2
   iBuff++;
   SetIndexBuffer(iBuff,AllFractalsUP);   //#3
   iBuff++;
   SetIndexBuffer(iBuff,AllFractalsDOWN); //#4
   iBuff++;
   SetIndexBuffer(iBuff,atr);             //#5
   iBuff++;
   SetIndexBuffer(iBuff,MainTrend);       //#6
   iBuff++;
   SetIndexBuffer(iBuff,AllEntrys);       //#7

//---- Fractals
   cntup=nLeftUp+nRightUp+Equals+1;
   cntdown=nLeftDown+Equals+1;
   if(cntup>=cntdown)
      cnt=cntup;
   if(cntup<cntdown)
      cnt=cntdown;
//----
   IndicatorDigits(Digits);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   ObjectsDeleteAll(0,sObj);
   Comment("");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
//int start()
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],
                const double &open[],const double &high[],const double &low[],const double &close[],
                const long &tick_volume[],const long &volume[],const int &spread[])
  {
//----
   int    i, Counted_bars=IndicatorCounted();

   i=Bars-Counted_bars-1;           // first bar
   int iBar=0;

//             *******************************************
//                   1. Trend = Cross Open/Close
//             *******************************************
   while(i>=0)
     {
      TrendUP[i  ]=EMPTY_VALUE;
      TrendDOWN[i]=EMPTY_VALUE;
      MainTrend[i]=0;

      //--- Trend
      double MAmedian=iMA(NULL,0,MovingAverage_Period_Fast,0,MovingAverage_Method,PRICE_MEDIAN,i);
      double MA_0=iMA(NULL,0,MovingAverage_Period_Fast,0,MovingAverage_Method,MA_Price_1,i);
      double MA_2=iMA(NULL,0,MovingAverage_Period_Fast,0,MovingAverage_Method,MA_Price_2,i);

      LineMedian[i]=MAmedian;

      SlowTrend[i]=iMA(NULL,0,MovingAverage_Period_Slow,0,MovingAverage_Method,PRICE_MEDIAN,i);

      if(MA_0>=MA_2)  //-- Close>Open
        {
         TrendUP[i]=MAmedian;
         MainTrend[i]=1;
        }
      else
         if(MA_0<MA_2)  //-- Close<Open
           {
            TrendDOWN[i]=MAmedian;
            MainTrend[i]=-1;
           }

      //--- ATR
      atr[i]=ATR_Factor*iATR(NULL,0,ATR_Period,i);

      //--- Entrys
      AllEntrys[i]=EMPTY_VALUE;
      EntryUP[i]  =EMPTY_VALUE;
      EntryDOWN[i]=EMPTY_VALUE;

      i--;
     }

//             *******************************************
//                   2.1 Fractals
//             *******************************************
   if(Draw_Patterns==ALL || Draw_Patterns==Fractals)
     {
      Get_Fractals();
      //for(int iBar=maxBars; iBar>=0; iBar--)
      //  {
      for(int iB=maxBars; iB>=0; iB--)
        {
         iBar=iB+1;
         //-- UP trend
         if(MainTrend[iBar]==1 && AllFractalsUP[iBar]!=EMPTY_VALUE && High[iBar]>SlowTrend[iBar])
           {
            FractalsUP[iBar]=AllFractalsUP[iBar];
            AllEntrys[iBar]=1;
           }
         else
            //-- DOWN trend
            if(MainTrend[iBar]==-1 && AllFractalsDOWN[iBar]!=EMPTY_VALUE && Low[iBar]<SlowTrend[iBar])
              {
               FractalsDOWN[iBar]=AllFractalsDOWN[iBar];
               AllEntrys[iBar]=-1;
              }
        }
     }

//             *******************************************
//                   2.2 Smash Bar
//             *******************************************
   if(Draw_Patterns==ALL || Draw_Patterns==Smash_Bar)
     {
      //for(int iBar=maxBars; iBar>=0; iBar--)
      //  {
      for(int iB=maxBars; iB>=0; iB--)
        {
         iBar=iB+1;
         //-- UP trend
         if(MainTrend[iBar]==1 && Close[iBar]>High[iBar+1] && High[iBar]>SlowTrend[iBar])
           {
            SmashUP[iBar]=High[iBar];
            AllEntrys[iBar]=1;
           }
         else
            //-- DOWN trend
            if(MainTrend[iBar]==-1 && Close[iBar]<Low[iBar+1] && Low[iBar]<SlowTrend[iBar])
              {
               SmashDOWN[iBar]=Low[iBar];
               AllEntrys[iBar]=-1;
              }
        }
     }

//             *******************************************
//                   2.3 Retrace Bar
//             *******************************************
   if(Draw_Patterns==ALL || Draw_Patterns==Retrace_Bar)
     {
      //for(int iBar=maxBars; iBar>=0; iBar--)
      //  {
      for(int iB=maxBars; iB>=0; iB--)
        {
         iBar=iB+1;
         //-- UP trend
         if(MainTrend[iBar]==1 && Close[iBar]<Open[iBar] && High[iBar]>SlowTrend[iBar])
           {
            RetraceUP[iBar]=High[iBar];
            AllEntrys[iBar]=1;
           }
         else
            //-- DOWN trend
            if(MainTrend[iBar]==-1 && Close[iBar]>Open[iBar] && Low[iBar]<SlowTrend[iBar])
              {
               RetraceDOWN[iBar]=Low[iBar];
               AllEntrys[iBar]=-1;
              }
        }
     }

//             ===========================================
//             *******************************************
//                   3. Entry Levels
//             *******************************************
//             ===========================================
   double lastTrend=EMPTY_VALUE;
   double lastEntry=EMPTY_VALUE;

//for(int iBar=maxBars; iBar>=0; iBar--)
//  {
   for(int iB=maxBars; iB>=0; iB--)
     {
      iBar=iB+1;
      
      //-- UP trend ---------------------------------------
      if(AllEntrys[iBar]==1)
        {
         //--- first UP Entry
         if(lastTrend==EMPTY_VALUE || lastTrend==-1)
           {
            EntryUP[iBar]=High[iBar];
            lastEntry=EntryUP[iBar];
            Draw_ShortTrendLine(iBar,lastEntry,ArrowColorEntry_UP,ArrowWidthEntry);
           }
         else
            //--- more UP Entrys
            if(lastTrend==1)
              {
               if(High[iBar]-lastEntry>atr[iBar])  //##
                 {
                  EntryUP[iBar]=High[iBar];
                  lastEntry=EntryUP[iBar];
                  Draw_ShortTrendLine(iBar,lastEntry,ArrowColorEntry_UP,ArrowWidthEntry);
                 }
              }
         lastTrend=1;
        }
      else
         //-- DOWN trend ----------------------------------
         if(AllEntrys[iBar]==-1)
           {
            //--- first DOWN Entry
            if(lastTrend==EMPTY_VALUE || lastTrend==1)
              {
               EntryDOWN[iBar]=Low[iBar];
               lastEntry=EntryDOWN[iBar];
               Draw_ShortTrendLine(iBar,lastEntry,ArrowColorEntry_DN,ArrowWidthEntry);
              }
            else
               //--- more DOWN Entrys
               if(lastTrend==-1)
                 {
                  if(lastEntry-Low[iBar]>atr[iBar])   //##
                    {
                     EntryDOWN[iBar]=Low[iBar];
                     lastEntry=EntryDOWN[iBar];
                     Draw_ShortTrendLine(iBar,lastEntry,ArrowColorEntry_DN,ArrowWidthEntry);
                    }
                 }
            lastTrend=-1;
           }
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Get_Fractals()
  {
   int i=0,j=0;
   int cbars=IndicatorCounted();
//----
   if(cbars<0)
      return;
//----
   if(cbars>0)
      cbars--;
   pos=0;
//----
   if(cbars>(Bars-cnt-1))
      pos=(Bars-cnt-1);
   else
      pos=Bars -(cbars+nRightUp);
      
   if(cbars==0)
      pos-=Equals;

//----
   while(pos>=nRightUp)
     {
      AllFractalsUP[pos]  =EMPTY_VALUE;
      AllFractalsDOWN[pos]=EMPTY_VALUE;

      //===================================================
      //FRACTAL UP
      r=nRightUp; // check the right side of the fractal
      //----
      for(i=1; i<=r; i++)
        {
         if(High[pos]<=High[pos-i])
            break;
        }
      // if everything is OK on the right then i must be equal to r + 1
      if(i==r+1) //FractalsUP[pos]=High[pos];
        {
         l=nLeftUp;  // check the left side of the fractal
         e= Equals;
         //----
         for(j=1; j<=l+Equals; j++)
           {
            if(High[pos]<High[pos+j])
               break;
            //----
            if(High[pos]>High[pos+j])
               l--;
            //----
            if(High[pos]==High[pos+j])
               e--;
            //----
            if(l==0)
              {
               AllFractalsUP[pos]=High[pos];
               break;
              }
            //----
            if(e<0)
               break;
           }
        }

      //===================================================
      //FRACTAL DOWN
      r=nRightDown; // check the right side of the fractal
      //----
      for(i=1; i<=r; i++)
        {
         if(Low[pos]>=Low[pos-i])
            break;
        }
      //----
      if(i==r+1) //FractalsUP[pos]=High[pos];
        {
         l=nLeftDown;  // check the left side of the fractal
         e= Equals;
         //----
         for(j=1; j<=l+Equals; j++)
           {
            if(Low[pos]>Low[pos+j])
               break;
            //----
            if(Low[pos]<Low[pos+j])
               l--;
            //----
            if(Low[pos]==Low[pos+j])
               e--;
            //----
            if(l==0)
              {
               AllFractalsDOWN[pos]=Low[pos];
               break;
              }
            if(e<0)
               break;
           }
        }

      pos--;
     }
  }

//                **********************************
//                         FUNCTIONS
//                **********************************
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Draw_ShortTrendLine(int iBar,double value,color dColor,int iWidth)
  {
   datetime time1=Time[iBar];
   datetime time2=time1;
   int ip=1,nPeriods=3;

//--- loop on weekends!
   if(Period()<=PERIOD_D1)
     {
      do
        {
         time2=time2+Period()*60;
         if(TimeDayOfWeek(time2)!=SATURDAY && TimeDayOfWeek(time2)!=SUNDAY)
            ip++;
        }
      while(ip<=nPeriods);
     }
   else
      time2=time2+nPeriods*Period()*60;
//---

   string objName=sObj+TimeToString(time1);

   ObjectDelete(0,objName);
   ObjectCreate(0,objName,OBJ_TREND,0,time1,value,time2,value);

   ObjectSetInteger(0,objName,OBJPROP_COLOR,dColor);
   ObjectSetInteger(0,objName,OBJPROP_WIDTH,iWidth);
   ObjectSetInteger(0,objName,OBJPROP_RAY,false);
   ObjectSetInteger(0,objName,OBJPROP_HIDDEN,true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Get_PeriodName(int period)
  {
   string sPeriod="";

   switch(period)
     {
      case PERIOD_M1:
         sPeriod="M1";
         break;
      case PERIOD_M5:
         sPeriod="M5";
         break;
      case PERIOD_M15:
         sPeriod="M15";
         break;
      case PERIOD_M30:
         sPeriod="M30";
         break;
      case PERIOD_H1:
         sPeriod="H1";
         break;
      case PERIOD_H4:
         sPeriod="H4";
         break;
      case PERIOD_D1:
         sPeriod="D1";
         break;
      case PERIOD_W1:
         sPeriod="W1";
         break;
      case PERIOD_MN1:
         sPeriod="MN1";
         break;
     }
   return(sPeriod);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Draw_Symbol_Timeframe()
  {
   color dColor=clrDodgerBlue;
   int iWidth=12;
   string sText=Symbol()+" ["+Get_PeriodName(Period())+"]";

   string objName=sObj+"Symbol";

   ObjectDelete(0,objName);
   bool bObjCreate=ObjectCreate(0,objName,OBJ_LABEL,0,0,0);

   ObjectSetInteger(0,objName,OBJPROP_CORNER,CORNER_LEFT_LOWER);
   ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
   ObjectSetInteger(0,objName,OBJPROP_XDISTANCE,5);
   ObjectSetInteger(0,objName,OBJPROP_YDISTANCE,5);

   ObjectSetString(0,objName,OBJPROP_TEXT,sText);
   ObjectSetString(0,objName,OBJPROP_FONT,"Arial");

   ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,iWidth);

   ObjectSetInteger(0,objName,OBJPROP_COLOR,dColor);
   ObjectSetInteger(0,objName,OBJPROP_WIDTH,iWidth);

   ObjectSetInteger(0,objName,OBJPROP_HIDDEN,true);
  }
//+------------------------------------------------------------------+
