#property copyright "MAX888 && PavelG && Pavka69 && Barrel && UserUserov"
#property link      "http://forum.tradelikeapro.ru/index.php?topic=4731.0"

#property version   "1.00"
#property strict
#property indicator_buffers 14
#property indicator_chart_window
//*
#property indicator_color1 clrNONE     //fractals high, current TF
#property indicator_color2 clrNONE     //fractals low, current TF
#property indicator_color3 clrAqua     //line high, current TF
#property indicator_color4 clrOrange   //line low, current TF
#property indicator_color5 clrNONE     //fractals high, higher TF
#property indicator_color6 clrNONE      //fractals low, higher TF
#property indicator_color7 clrBlue     //line high, higher TF
#property indicator_color8 clrRed      //line low, higher TF
#property indicator_color9 clrAqua     //NoTrade high arrows, current TF
#property indicator_color10 clrOrange  //NoTrade low arrows, current TF
#property indicator_color11 clrBlue    //NoTrade high arrows, higher TF
#property indicator_color12 clrRed     //NoTrade low arrow, higher TF
#property indicator_color13 clrLime     //Long entry points
#property indicator_color14 clrRed     //Short entry points

/*/
#property indicator_color1 clrAqua     //fractals high, current TF
#property indicator_color2 clrOrange     //fractals low, current TF
#property indicator_color3 clrAqua     //line high, current TF
#property indicator_color4 clrOrange   //line low, current TF
#property indicator_color5 clrBlue     //fractals high, higher TF
#property indicator_color6 clrRed      //fractals low, higher TF
#property indicator_color7 clrBlue     //line high, higher TF
#property indicator_color8 clrRed      //line low, higher TF
#property indicator_color9 clrAqua     //NoTrade high arrows, current TF
#property indicator_color10 clrOrange  //NoTrade low arrows, current TF
#property indicator_color11 clrBlue    //NoTrade high arrows, higher TF
#property indicator_color12 clrRed     //NoTrade low arrow, higher TF
//*/
enum EMaxSlopeOptions{
   MSO_HISTORICAL_MAX      = 0,  //Search for better fractal
   MSO_NO_TRADE            = 1,  //Mark as NoTrade
};
enum ENoTradeMode {
   RESPECT_BOTH            = 0,  //Respect both lines
   RESPECT_HIGH            = 1,  //Respect higher TF
   RESPECT_CURRENT         = 2,  //Respect current TF
   RESPECT_SIGNAL          = 3,  //Respect crossed line
   IGNORE                  = 4,  //Ignore both
};
enum EEntryMode {
   CURRENT_TF              = 0,  //Price crosses CTF line
   HIGHER_TF               = 1,  //Price crosses HTF line
   FURTHER_LINE            = 2,  //Price crosses further line
   NEARER_LINE             = 3,  //Price crosses nearer line
   BOTH_LINES_ONE_CANDLE   = 4,  //Candle crosses both lines
   CURRENT_TF_WHEN_NEARER  = 5,  //Current TF when nearer
   HIGHER_TF_WHEN_NEARER   = 6,  //Higher TF when nearer
   EITHER                  = 7,  //Price crosses either line
};
//--- input parameters
extern int              DistanceFromTheBarPips     = 15;                //Distance from high/low to draw arrows and the line, pips
extern int              NumberOfBars               = 1000;              //Number of bars to scan back for suitable line attachment
extern ENUM_TIMEFRAMES  HigherTimeFrame            = PERIOD_H4;         //Higher timeframe to calculate
extern double           MaxSlope                   = 0.1;               //Maximum acceptable slope, pips per minute 
extern EMaxSlopeOptions MaxSlopeFix                = MSO_NO_TRADE;      //How to deal with MaxSlope limit breach
extern ENoTradeMode     NoTradeMode                = RESPECT_BOTH;      //Entry: how to handle NoTrade
extern EEntryMode       EntryMode                  = FURTHER_LINE;      //Entry: what makes a signal
extern bool             AlertsOn                   = false;             //Alerts
extern bool             AlertsEmail                = false;             //Email
extern bool             AlertsPush                 = false;             //Push

#include <ChartObjects/ChartObjectsLines.mqh>

int pointsInPip = 1;
int higherTFMultiplicity;
double distanceFromTheBars;
double maxSlope;

//--- buffers
double CTFHigh[];
double CTFLow[];
double CTFLineLevelHigh[];
double CTFLineLevelLow[];
double HTFHigh[];
double HTFLow[];
double HTFLineLevelHigh[];
double HTFLineLevelLow[];
//No Trade buffers
double CTFNoTradeHigh[];
double CTFNoTradeLow[];
double HTFNoTradeHigh[];
double HTFNoTradeLow[];

double LongEntry[];
double ShortEntry[];
double Alerted[];

//for lines on current time frame
int indexCTFHighFirst = 0;
int indexCTFHighSecond = 0;
int indexCTFLowFirst = 0;
int indexCTFLowSecond = 0;
//for lines on higher time frame
int indexHTFHighFirst = 0;
int indexHTFHighSecond = 0;
int indexHTFLowFirst = 0;
int indexHTFLowSecond = 0;




CChartObjectTrend ctfLineHigh, ctfLineLow, htfLineHigh, htfLineLow;


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){
//---- indicators
   Print("Init invoked with parameters: Distance=", DistanceFromTheBarPips, ", Number=", NumberOfBars, ", HigherTF=", EnumToString(HigherTimeFrame), ", MaxSlope=", MaxSlope, ", MaxSlopeFix=", EnumToString(MaxSlopeFix), ", NoTradeMode=", EnumToString(NoTradeMode), ", EntryMode=", EnumToString(EntryMode));
   if(HigherTimeFrame <= _Period) {
      Print("Higher timeframe must be greater than current!");
      return (INIT_FAILED);
   }
      
   IndicatorDigits(Digits);
   IndicatorBuffers(15);
   SetIndexStyle(0, DRAW_ARROW, EMPTY, EMPTY, indicator_color1);
   SetIndexArrow(0, 217);
   SetIndexBuffer(0, CTFHigh);
   SetIndexEmptyValue(0, 0.0);
   SetIndexLabel(0, "Current TF High fractal");
   SetIndexStyle(1, DRAW_ARROW, EMPTY, EMPTY, indicator_color2);
   SetIndexArrow(1, 218);
   SetIndexBuffer(1, CTFLow);
   SetIndexEmptyValue(1, 0.0);
   SetIndexLabel(1, "Current TF Low fractal");
   
   SetIndexStyle(2, DRAW_ARROW, EMPTY, EMPTY, indicator_color3);
   SetIndexArrow(2, 159);
   SetIndexBuffer(2, CTFLineLevelHigh);
   SetIndexEmptyValue(2, 0.0);
   SetIndexLabel(2, "Current TF Line level High");
   SetIndexStyle(3, DRAW_ARROW, EMPTY, EMPTY, indicator_color4);
   SetIndexArrow(3, 159);
   SetIndexBuffer(3, CTFLineLevelLow);
   SetIndexEmptyValue(3, 0.0);
   SetIndexLabel(3, "Current TF Line level Low");
   
   SetIndexStyle(4, DRAW_ARROW, EMPTY, 2, indicator_color5);
   SetIndexArrow(4, 217);
   SetIndexBuffer(4, HTFHigh);
   SetIndexEmptyValue(4, 0.0);
   SetIndexLabel(4, "Higher TF High fractal");
   SetIndexStyle(5, DRAW_ARROW, EMPTY, 2, indicator_color6);
   SetIndexArrow(5, 218);
   SetIndexBuffer(5, HTFLow);
   SetIndexEmptyValue(5, 0.0);
   SetIndexLabel(5, "Higher TF Low fractal");

   SetIndexStyle(6, DRAW_ARROW, EMPTY, 1, indicator_color7);
   SetIndexArrow(6, 159);
   SetIndexBuffer(6, HTFLineLevelHigh);
   SetIndexEmptyValue(6, 0.0);
   SetIndexLabel(6, "Higher TF Line level High");
   SetIndexStyle(7, DRAW_ARROW, EMPTY, 1, indicator_color8);
   SetIndexArrow(7, 159);
   SetIndexBuffer(7, HTFLineLevelLow);
   SetIndexEmptyValue(7, 0.0);
   SetIndexLabel(7, "Higher TF Line level Low");
   
   SetIndexStyle(8, DRAW_ARROW, EMPTY, 1, indicator_color9);
   SetIndexArrow(8, 251);
   SetIndexBuffer(8, CTFNoTradeHigh);
   SetIndexEmptyValue(8, 0.0);
   SetIndexLabel(8, "Current TF No Trade High");
   SetIndexStyle(9, DRAW_ARROW, EMPTY, 1, indicator_color10);
   SetIndexArrow(9, 251);
   SetIndexBuffer(9, CTFNoTradeLow);
   SetIndexEmptyValue(9, 0.0);
   SetIndexLabel(9, "Current TF No Trade Low");
   
   SetIndexStyle(10, DRAW_ARROW, EMPTY, 3, indicator_color11);
   SetIndexArrow(10, 251);
   SetIndexBuffer(10, HTFNoTradeHigh);
   SetIndexEmptyValue(10, 0.0);
   SetIndexLabel(10, "Higher TF No Trade High");
   SetIndexStyle(11, DRAW_ARROW, EMPTY, 3, indicator_color12);
   SetIndexArrow(11, 251);
   SetIndexBuffer(11, HTFNoTradeLow);
   SetIndexEmptyValue(11, 0.0);
   SetIndexLabel(11, "Higher TF No Trade Low");

   SetIndexStyle(12, DRAW_ARROW, EMPTY, 3, indicator_color13);
   SetIndexArrow(12, 233);
   SetIndexBuffer(12, LongEntry);
   SetIndexEmptyValue(12, 0.0);
   SetIndexLabel(12, "Long Entry");
   SetIndexStyle(13, DRAW_ARROW, EMPTY, 3, indicator_color14);
   SetIndexArrow(13, 234);
   SetIndexBuffer(13, ShortEntry);
   SetIndexEmptyValue(13, 0.0);
   SetIndexLabel(13, "Short Entry");

   SetIndexBuffer(14, Alerted);
   
   higherTFMultiplicity = HigherTimeFrame / _Period;
   pointsInPip = (Digits == 3 || Digits == 5) ? 10 : 1;
   distanceFromTheBars = pointsInPip * DistanceFromTheBarPips * Point;
   maxSlope = pointsInPip * MaxSlope * Point;
   MathSrand((int)TimeCurrent());
   int id = MathRand();
      
   ctfLineHigh.Create(0, "FisherCTFLineHigh" + IntegerToString(id), 0, TimeCurrent(), 0, TimeCurrent(), 0);
   ctfLineHigh.Color(clrAqua);
   ctfLineHigh.RayLeft(false);
   ctfLineHigh.RayRight(true);
   ctfLineHigh.Hidden(false);

   ctfLineLow.Create(0, "FisherCTFLineLow" + IntegerToString(id), 0, TimeCurrent(), 0, TimeCurrent(), 0);
   ctfLineLow.Color(clrOrange);
   ctfLineLow.RayLeft(false);
   ctfLineLow.RayRight(true);
   ctfLineLow.Hidden(false);

   htfLineHigh.Create(0, "FisherHTFLineHigh" + IntegerToString(id), 0, TimeCurrent(), 0, TimeCurrent(), 0);
   htfLineHigh.Color(clrBlue);
   htfLineHigh.Width(2);
   htfLineHigh.RayLeft(false);
   htfLineHigh.RayRight(true);
   htfLineHigh.Hidden(false);

   htfLineLow.Create(0, "FisherTFLineLow" + IntegerToString(id), 0, TimeCurrent(), 0, TimeCurrent(), 0);
   htfLineLow.Color(clrRed);
   htfLineLow.Width(2);
   htfLineLow.RayLeft(false);
   htfLineLow.RayRight(true);
   htfLineLow.Hidden(false);
//----
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[]){
//   Print("rates_total=", rates_total, ", prev_calculated=", prev_calculated);
   int limit = rates_total - prev_calculated;
   if(prev_calculated < 4)
      limit -= 4 - prev_calculated;
   if(limit > 0) {
      if(prev_calculated == 0) {
         ArrayInitialize(CTFHigh, 0.0);
         ArrayInitialize(CTFLow, 0.0);
         ArrayInitialize(CTFLineLevelHigh, 0.0);
         ArrayInitialize(CTFLineLevelLow, 0.0);
         ArrayInitialize(HTFHigh, 0.0);
         ArrayInitialize(HTFLow, 0.0);
         ArrayInitialize(HTFLineLevelHigh, 0.0);
         ArrayInitialize(HTFLineLevelLow, 0.0);
         ArrayInitialize(CTFNoTradeHigh, 0.0);
         ArrayInitialize(CTFNoTradeLow, 0.0);
         ArrayInitialize(HTFNoTradeHigh, 0.0);
         ArrayInitialize(HTFNoTradeLow, 0.0);
         ArrayInitialize(LongEntry, 0.0);
         ArrayInitialize(ShortEntry, 0.0);
         ArrayInitialize(Alerted, 0.0);
         indexCTFHighFirst = -1;
         indexCTFHighSecond = -1;
         indexCTFLowFirst = -1;
         indexCTFLowSecond = -1;
         indexHTFHighFirst = -1;
         indexHTFHighSecond = -1;
         indexHTFLowFirst = -1;
         indexHTFLowSecond = -1;
      } else {
         indexCTFHighFirst += limit;
         indexCTFHighSecond += limit;
         indexCTFLowFirst += limit;
         indexCTFLowSecond += limit;
         indexHTFHighFirst += limit;
         indexHTFHighSecond += limit;
         indexHTFLowFirst += limit;
         indexHTFLowSecond += limit;
      }
   
   //------------------------------------------------------
   // Higher timeframe is an outer cycle
   //------------------------------------------------------
      if(limit + 4 * higherTFMultiplicity > rates_total)
         limit = rates_total - 4 * higherTFMultiplicity;
      
      //prepare buffers to keep the indexes of the highest and lowest of the synthetic "bars" 
      int htfIndexHighTmp[];
      int htfIndexLowTmp[];
      ArrayResize(htfIndexHighTmp, limit/higherTFMultiplicity + 3);
      ArrayResize(htfIndexLowTmp, limit/higherTFMultiplicity + 3);
      
      for(int i = 0; i <= limit/higherTFMultiplicity + 2; i++) {
         htfIndexHighTmp[i] = FindHTFHigh(high, i);
         htfIndexLowTmp[i] = FindHTFLow(low, i);            
      }   
      for(int i = limit / higherTFMultiplicity; i >= 0; i--) {
   //--------high----------
         if(high[htfIndexHighTmp[i + 1]] > high[htfIndexHighTmp[i]] && high[htfIndexHighTmp[i + 1]] >= high[htfIndexHighTmp[i + 2]]) {
            HTFHigh[htfIndexHighTmp[i + 1]] = high[htfIndexHighTmp[i + 1]] + distanceFromTheBars;
            if(indexHTFHighFirst > -1) { //first fractal already found
               if(indexHTFHighSecond == -1 || HTFHigh[htfIndexHighTmp[i + 1]] < HTFHigh[indexHTFHighFirst]){ // if new high fractal is lower than the last one
                  indexHTFHighSecond = indexHTFHighFirst;
               } else { //not so simple, will have to search back up to NumberOfBars to find a fractal that is higher than the new one
                  bool found = false;
                  for(int j = indexHTFHighSecond; j < NumberOfBars * higherTFMultiplicity && j < rates_total; j++) {
                     if(HTFHigh[j] != 0 && HTFHigh[j] > HTFHigh[htfIndexHighTmp[i + 1]]) {
                        indexHTFHighSecond = j;
                        found = true;
                        break;
                     }
                  }
                  if(!found) {
                     indexHTFHighSecond = ArrayMaximum(high, (int)MathMin(NumberOfBars * higherTFMultiplicity, rates_total) - indexHTFHighSecond, indexHTFHighSecond);
                  }
               }
            }
            indexHTFHighFirst = htfIndexHighTmp[i + 1];
         }
         if(IsHTFHighLineReady()) {
            double slope = (HTFHigh[indexHTFHighSecond] - HTFHigh[indexHTFHighFirst])/(indexHTFHighSecond - indexHTFHighFirst) / Period();
            bool slopeNoTrade = false;
            if(slope > maxSlope) {
               if(prev_calculated != 0)
                  Print("Max slope of " + DoubleToStr(MaxSlope, 1) + " pips is breached for the higher timeframe High, the slope is " + DoubleToStr(slope / Point / pointsInPip, 4));
               switch(MaxSlopeFix) {
               case MSO_HISTORICAL_MAX:
                  indexHTFHighSecond = ArrayMaximum(high, (int)MathMin(NumberOfBars * higherTFMultiplicity, rates_total) - indexHTFHighSecond, indexHTFHighSecond);
                  break;
               case MSO_NO_TRADE:
                  slopeNoTrade = true;
                  break;
               }
            }
   
            if(htfLineHigh.GetInteger(OBJPROP_TIME2) != time[indexHTFHighFirst])
               MoveLine(htfLineHigh, time[indexHTFHighSecond], HTFHigh[indexHTFHighSecond], time[indexHTFHighFirst], HTFHigh[indexHTFHighFirst]);
            for(int ii = i * higherTFMultiplicity; ii <= (i + 1) * higherTFMultiplicity && ii <= limit; ii++){
               HTFLineLevelHigh[ii] = GetLineLevel(indexHTFHighSecond, HTFHigh[indexHTFHighSecond], indexHTFHighFirst, HTFHigh[indexHTFHighFirst], ii);//ObjectGetValueByShift(htfLineHigh.Name(), ii);
               if(slopeNoTrade || HTFHigh[indexHTFHighSecond] < HTFHigh[indexHTFHighFirst]) 
                  HTFNoTradeHigh[ii] = HTFLineLevelHigh[ii];
            }
         }
   //--------low----------
         if(low[htfIndexLowTmp[i + 1]] < low[htfIndexLowTmp[i]] && low[htfIndexLowTmp[i + 1]] <= low[htfIndexLowTmp[i + 2]]) {
            HTFLow[htfIndexLowTmp[i + 1]] = low[htfIndexLowTmp[i + 1]] - distanceFromTheBars;
            if(indexHTFLowFirst > -1) { //first fractal already found
               if(indexHTFLowSecond == -1 || HTFLow[htfIndexLowTmp[i + 1]] > HTFLow[indexHTFLowFirst]){ // if new low fractal is higher than the last one
                  indexHTFLowSecond = indexHTFLowFirst;
               } else { //not so simple, will have to search back up to NumberOfBars to find a fractal that is lower than the new one
                  bool found = false;
                  for(int j = indexHTFLowSecond; j < NumberOfBars * higherTFMultiplicity && j < rates_total; j++) {
                     if(HTFLow[j] != 0 && HTFLow[j] < HTFLow[htfIndexLowTmp[i + 1]]) {
                        indexHTFLowSecond = j;
                        found = true;
                        break;
                     }
                  }
                  if(!found) {
                     indexHTFLowSecond = ArrayMinimum(low, (int)MathMin(NumberOfBars * higherTFMultiplicity, rates_total) - indexHTFLowSecond, indexHTFLowSecond);
                  }
               }
            }
            indexHTFLowFirst = htfIndexLowTmp[i + 1];
         }
         if(IsHTFLowLineReady()) {
            double slope = (HTFLow[indexHTFLowFirst] - HTFLow[indexHTFLowSecond])/(indexHTFLowSecond - indexHTFLowFirst) / Period();
            bool slopeNoTrade = false;
            if(slope > maxSlope) {
               if(prev_calculated != 0)
                  Print("Max slope of " + DoubleToStr(MaxSlope, 1) + " pips is breached for the higher timeframe Low, the slope is " + DoubleToStr(slope / Point / pointsInPip, 4));
               switch(MaxSlopeFix) {
               case MSO_HISTORICAL_MAX:
                  indexHTFLowSecond = ArrayMinimum(low, (int)MathMin(NumberOfBars * higherTFMultiplicity, rates_total) - indexHTFLowSecond, indexHTFLowSecond);
                  break;
               case MSO_NO_TRADE:
                  slopeNoTrade = true;
                  break;
               }
            }
            if(htfLineLow.GetInteger(OBJPROP_TIME2) != time[indexHTFLowFirst])
               MoveLine(htfLineLow, time[indexHTFLowSecond], HTFLow[indexHTFLowSecond], time[indexHTFLowFirst], HTFLow[indexHTFLowFirst]);
            for(int ii = i * higherTFMultiplicity; ii <= (i + 1) * higherTFMultiplicity && ii <= limit; ii++){
               HTFLineLevelLow[ii] = GetLineLevel(indexHTFLowSecond, HTFLow[indexHTFLowSecond], indexHTFLowFirst, HTFLow[indexHTFLowFirst], ii);//ObjectGetValueByShift(htfLineLow.Name(), ii);
               if(slopeNoTrade || HTFLow[indexHTFLowSecond] > HTFLow[indexHTFLowFirst]) 
                  HTFNoTradeLow[ii] = HTFLineLevelLow[ii];
            }
         }
      //----------------------
      // current TF - inner cycle
      //----------------------
         //Print("CTF cycle from ", MathMin((i + 1) * higherTFMultiplicity, limit) - 1, " to ", i * higherTFMultiplicity, " inclusive");
         for(int ii = MathMin((i + 1) * higherTFMultiplicity, limit) - 1; ii >= i * higherTFMultiplicity; ii--) {
      //--------high----------
            if(high[ii + 2] > high[ii + 1] && high[ii + 2] >= high[ii + 3]) { //new low fractal
               CTFHigh[ii + 2] = high[ii + 2] + distanceFromTheBars;
               if(indexCTFHighFirst > -1) { //first fractal
                  if(indexCTFHighSecond == -1 || CTFHigh[ii + 2] <= CTFHigh[indexCTFHighFirst]){ // if new high fractal is lower than the last one
                     indexCTFHighSecond = indexCTFHighFirst;
                  } else { //not so simple, will have to search back up to NumberOfBars to find a fractal that is higher than the new one
                     bool found = false;
                     for(int j = indexCTFHighSecond; j < NumberOfBars && j < rates_total; j++) {
                        if(CTFHigh[j] != 0 && CTFHigh[j] > CTFHigh[ii + 2]) {
                           indexCTFHighSecond = j;
                           found = true;
                           break;
                        }
                     }
                     if(!found)
                        indexCTFHighSecond = ArrayMaximum(high, NumberOfBars - indexCTFHighSecond, indexCTFHighSecond);
                  }
               }
               indexCTFHighFirst = ii + 2;
               //Print("High: i=", i, ", ii=", ii, ", first=", indexCTFHighFirst, ", second=", indexCTFHighSecond);
            }
            if(IsCTFHighLineReady()) {
               //Print("High >>> first=", indexCTFHighFirst, ", second=", indexCTFHighSecond);
               double slope = (CTFHigh[indexCTFHighSecond] - CTFHigh[indexCTFHighFirst])/(indexCTFHighSecond - indexCTFHighFirst) / Period();
               bool slopeNoTrade = false;
               if(slope > maxSlope) {
                  if(prev_calculated != 0)
                     Print("Max slope of " + DoubleToStr(MaxSlope, 1) + " pips is breached for the current timeframe High, the slope is " + DoubleToStr(slope / Point / pointsInPip, 4));
                  switch(MaxSlopeFix) {
                  case MSO_HISTORICAL_MAX:
                     indexCTFHighSecond = ArrayMaximum(high, NumberOfBars - indexCTFHighSecond, indexCTFHighSecond);
                     break;
                  case MSO_NO_TRADE:
                     slopeNoTrade = true;
                     break;
                  }
               }
               if(ctfLineHigh.GetInteger(OBJPROP_TIME2) != time[indexCTFHighFirst])
                  MoveLine(ctfLineHigh, time[indexCTFHighSecond], CTFHigh[indexCTFHighSecond], time[indexCTFHighFirst], CTFHigh[indexCTFHighFirst]);
               CTFLineLevelHigh[ii] = GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii);//ObjectGetValueByShift(ctfLineHigh.Name(), ii);
               if(slopeNoTrade || CTFHigh[indexCTFHighSecond] < CTFHigh[indexCTFHighFirst]) 
                  CTFNoTradeHigh[ii] = CTFLineLevelHigh[ii];
            }
      //--------low----------
            if(low[ii + 2] < low[ii + 1] && low[ii + 2] <= low[ii + 3]){ //new low fractal
               CTFLow[ii + 2] = low[ii + 2] - distanceFromTheBars;
               if(indexCTFLowFirst > -1) { //first fractal
                  bool found = false;
                  if(indexCTFLowSecond == -1 || CTFLow[ii + 2] >= CTFLow[indexCTFLowFirst]){ // if new low fractal is higher than the last one
                     indexCTFLowSecond = indexCTFLowFirst;
                     found = true;
                  } else { //not so simple, will have to search back up to NumberOfBars to find a fractal that is lower than the new one
                     for(int j = indexCTFLowSecond; j < NumberOfBars && j < rates_total; j++) {
                        if(CTFLow[j] != 0 && CTFLow[j] < CTFLow[ii + 2]) {
                           indexCTFLowSecond = j;
                           found = true;
                           break;
                        }
                     }
                     if(!found) {
                        indexCTFLowSecond = ArrayMinimum(low, NumberOfBars - indexCTFLowSecond, indexCTFLowSecond);
                     }
                  }
               }
               indexCTFLowFirst = ii + 2;
               //Print("Low: i=", i, ", ii=", ii, ", first=", indexCTFLowFirst, ", second=", indexCTFLowSecond);
            }
            if(IsCTFLowLineReady()) {
               //Print("Low >>> first=", indexCTFLowFirst, ", second=", indexCTFLowSecond);
               double slope = (CTFLow[indexCTFLowFirst] - CTFLow[indexCTFLowSecond])/(indexCTFLowSecond - indexCTFLowFirst) / Period();
               bool slopeNoTrade = false;
               if(slope > maxSlope) {
                  if(prev_calculated != 0)
                     Print("Max slope of " + DoubleToStr(MaxSlope, 1) + " pips is breached for the current timeframe Low, the slope is " + DoubleToStr(slope / Point / pointsInPip, 4));
                  switch(MaxSlopeFix) {
                  case MSO_HISTORICAL_MAX:
                     indexCTFLowSecond = ArrayMinimum(low, NumberOfBars - indexCTFLowSecond, indexCTFLowSecond);
                     break;
                  case MSO_NO_TRADE:
                     slopeNoTrade = true;
                     break;
                  }
               }
               if(ctfLineLow.GetInteger(OBJPROP_TIME2) != time[indexCTFLowFirst])
                  MoveLine(ctfLineLow, time[indexCTFLowSecond], CTFLow[indexCTFLowSecond], time[indexCTFLowFirst], CTFLow[indexCTFLowFirst]);
               CTFLineLevelLow[ii] = GetLineLevel(indexCTFLowSecond, CTFLow[indexCTFLowSecond], indexCTFLowFirst, CTFLow[indexCTFLowFirst], ii);//ObjectGetValueByShift(ctfLineLow.Name(), ii);
               if(slopeNoTrade || CTFLow[indexCTFLowSecond] > CTFLow[indexCTFLowFirst]) 
                  CTFNoTradeLow[ii] = CTFLineLevelLow[ii];
            }
            CheckForEntryPoints(high, low, ii);
         }
         
      }
   } else {
      CheckForEntryPoints(high, low, 0);
   }
   if(Alerted[0] ==  0.0) {
      string message = NULL;
      if(ShortEntry[0] != 0.0)
         message =  "Fishing: " + TimeFrameToString(Period())  + " " + Symbol() + " at " + TimeToStr(TimeLocal(),TIME_SECONDS) + " Short Entry!";
      if(LongEntry[0] != 0.0)
         message =  "Fishing: " + TimeFrameToString(Period())  + " " + Symbol() + " at " + TimeToStr(TimeLocal(),TIME_SECONDS) + " Long Entry!";
      if(message != NULL) {       
         if (AlertsOn) { 
            Alert(message);
            PlaySound("alert2.wav");
         }
         if (AlertsEmail)   SendMail(StringConcatenate(Symbol()," Fishing"),message);
         if (AlertsPush)   SendNotification(message);
         Alerted[0] = 1;               
      }
   }
//   if(ShortEntry[0] != 0)
//      Print("Short entry!!!");
//   if(LongEntry[0] != 0)
//      Print("Long entry!!!");
   return(rates_total);
}
//+------------------------------------------------------------------+
void MoveLine(CChartObjectTrend &_line, long _time1, double _price1, long _time2, double _price2) {
   _line.SetInteger(OBJPROP_TIME1, _time1);
   _line.SetDouble(OBJPROP_PRICE1, _price1);
   _line.SetInteger(OBJPROP_TIME2, _time2);
   _line.SetDouble(OBJPROP_PRICE2, _price2);
}

double GetLineLevel(int _index1, double _price1, int _index2, double _price2, int _shift) {
   return(_price2 + (_shift - _index2) * (_price1 - _price2) / (_index1 - _index2));
}

int FindHTFHigh(const double &high[], int i) {
   return ArrayMaximum(high, higherTFMultiplicity, i * higherTFMultiplicity);;
}

int FindHTFLow(const double &low[], int i) {
   return ArrayMinimum(low, higherTFMultiplicity, i * higherTFMultiplicity);
}
bool IsHTFLowLineReady() {
   return (indexHTFLowFirst > -1 && indexHTFLowSecond > -1);
}
bool IsHTFHighLineReady() {
   return (indexHTFHighFirst > -1 && indexHTFHighSecond > -1);
}
bool IsCTFLowLineReady() {
   return (indexCTFLowFirst > -1 && indexCTFLowSecond > -1);
}
bool IsCTFHighLineReady() {
   return (indexCTFHighFirst > -1 && indexCTFHighSecond > -1);
}
void CheckForEntryPoints(const double &high[], const double &low[], int ii){
//----------------------
// Entry points
//----------------------
   bool noTradeLong = false;
   bool noTradeShort  = false;
   switch(NoTradeMode) {
   case RESPECT_BOTH:
      noTradeLong = HTFNoTradeHigh[ii] != 0 || CTFNoTradeHigh[ii] != 0;
      noTradeShort  = HTFNoTradeLow[ii] != 0 || CTFNoTradeLow[ii] != 0;
      break;
   case RESPECT_HIGH:
      noTradeLong = HTFNoTradeHigh[ii] != 0;
      noTradeShort  = HTFNoTradeLow[ii] != 0;
      break;
   case RESPECT_CURRENT:
      noTradeLong = CTFNoTradeHigh[ii] != 0;
      noTradeShort  = CTFNoTradeLow[ii] != 0;
      break;
   }
   if(!noTradeLong && LongEntry[ii] == 0) {
      switch(EntryMode) {
      case CURRENT_TF:
         if(IsCTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeHigh[ii] == 0) && high[ii] > CTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii + 1))
            LongEntry[ii] = CTFLineLevelHigh[ii];
         break;
      case HIGHER_TF:
         if(IsHTFHighLineReady())
            Print("ii = ", ii, ", indexHTFHighSecond = ", indexHTFHighSecond, ", indexHTFHighFirst = ", indexHTFHighFirst, ", high higher = ", high[ii] > HTFLineLevelHigh[ii], ", prev lower = ", high[ii + 1] < GetLineLevel(indexHTFHighSecond, HTFHigh[indexHTFHighSecond], indexHTFHighFirst, HTFHigh[indexHTFHighFirst], ii + 1));
         if(IsHTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeHigh[ii] == 0) && high[ii] > HTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexHTFHighSecond, HTFHigh[indexHTFHighSecond], indexHTFHighFirst, HTFHigh[indexHTFHighFirst], ii + 1))
            LongEntry[ii] = HTFLineLevelHigh[ii];
         break;
      case FURTHER_LINE:
         if(HTFLineLevelHigh[ii] > CTFLineLevelHigh[ii]) {
            if(IsHTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeHigh[ii] == 0) && high[ii] > HTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexHTFHighSecond, HTFHigh[indexHTFHighSecond], indexHTFHighFirst, HTFHigh[indexHTFHighFirst], ii + 1))
               LongEntry[ii] = HTFLineLevelHigh[ii];
         } else {
            if(IsCTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeHigh[ii] == 0) && high[ii] > CTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii + 1))
               LongEntry[ii] = CTFLineLevelHigh[ii];
         }
         break;
      case NEARER_LINE:
         if(HTFLineLevelHigh[ii] > CTFLineLevelHigh[ii]) {
            if(IsCTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeHigh[ii] == 0) && high[ii] > CTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii + 1))
               LongEntry[ii] = CTFLineLevelHigh[ii];
         } else {
            if(IsHTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeHigh[ii] == 0) && high[ii] > HTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexHTFHighSecond, HTFHigh[indexHTFHighSecond], indexHTFHighFirst, HTFHigh[indexHTFHighFirst], ii + 1))
               LongEntry[ii] = HTFLineLevelHigh[ii];
         }
         break;
      case BOTH_LINES_ONE_CANDLE:
         if(IsCTFHighLineReady() && IsHTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || (CTFNoTradeHigh[ii] == 0 && HTFNoTradeHigh[ii] == 0)) && high[ii] > MathMax(CTFLineLevelHigh[ii], HTFLineLevelHigh[ii]) && low[ii] <= MathMin(CTFLineLevelHigh[ii], HTFLineLevelHigh[ii]))
            LongEntry[ii] = MathMax(CTFLineLevelHigh[ii], HTFLineLevelHigh[ii]);
         break;
      case CURRENT_TF_WHEN_NEARER:
         if(IsCTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeHigh[ii] == 0) && CTFLineLevelHigh[ii] <= HTFLineLevelHigh[ii] && high[ii] > CTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii + 1))
         LongEntry[ii] = CTFLineLevelHigh[ii];
         break;
      case HIGHER_TF_WHEN_NEARER:
         if(IsHTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeHigh[ii] == 0) && HTFLineLevelHigh[ii] <= CTFLineLevelHigh[ii] && high[ii] > HTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii + 1))
            LongEntry[ii] = HTFLineLevelHigh[ii];
         break;
      case EITHER:
         if(IsHTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeHigh[ii] == 0) && high[ii] > HTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexHTFHighSecond, HTFHigh[indexHTFHighSecond], indexHTFHighFirst, HTFHigh[indexHTFHighFirst], ii + 1))
            LongEntry[ii] = HTFLineLevelHigh[ii];
         else if(IsCTFHighLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeHigh[ii] == 0) && high[ii] > CTFLineLevelHigh[ii] && high[ii + 1] < GetLineLevel(indexCTFHighSecond, CTFHigh[indexCTFHighSecond], indexCTFHighFirst, CTFHigh[indexCTFHighFirst], ii + 1))
            LongEntry[ii] = CTFLineLevelHigh[ii];
         break;
      }
   }
   
   if(!noTradeShort && ShortEntry[ii] == 0) {
      switch(EntryMode) {
      case CURRENT_TF:
         if(IsCTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeLow[ii] == 0) && low[ii] < CTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexCTFLowSecond, CTFLow[indexCTFLowSecond], indexCTFLowFirst, CTFLow[indexCTFLowFirst], ii + 1))
            ShortEntry[ii] = CTFLineLevelLow[ii];
         break;
      case HIGHER_TF:
         if(IsHTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeLow[ii] == 0) && low[ii] < HTFLineLevelLow[ii] && low[ii + 1] >  GetLineLevel(indexHTFLowSecond, HTFLow[indexHTFLowSecond], indexHTFLowFirst, HTFLow[indexHTFLowFirst], ii + 1))
            ShortEntry[ii] = HTFLineLevelLow[ii];
         break;
      case FURTHER_LINE:
         if(HTFLineLevelLow[ii] < CTFLineLevelLow[ii]) {
            if(IsHTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeLow[ii] == 0) && low[ii] < HTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexHTFLowSecond, HTFLow[indexHTFLowSecond], indexHTFLowFirst, HTFLow[indexHTFLowFirst], ii + 1))
               ShortEntry[ii] = HTFLineLevelLow[ii];
         } else {
            if(IsCTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeLow[ii] == 0) && low[ii] < CTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexCTFLowSecond, CTFLow[indexCTFLowSecond], indexCTFLowFirst, CTFLow[indexCTFLowFirst], ii + 1))
               ShortEntry[ii] = CTFLineLevelLow[ii];
         }
         break;
      case NEARER_LINE:
         if(HTFLineLevelLow[ii] < CTFLineLevelLow[ii]) {
            if(IsCTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeLow[ii] == 0) && low[ii] < CTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexCTFLowSecond, CTFLow[indexCTFLowSecond], indexCTFLowFirst, CTFLow[indexCTFLowFirst], ii + 1))
               ShortEntry[ii] = CTFLineLevelLow[ii];
         } else {
            if(IsHTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeLow[ii] == 0) && low[ii] < HTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexHTFLowSecond, HTFLow[indexHTFLowSecond], indexHTFLowFirst, HTFLow[indexHTFLowFirst], ii + 1))
               ShortEntry[ii] = HTFLineLevelLow[ii];
         }
         break;
      case BOTH_LINES_ONE_CANDLE:
         if(IsCTFLowLineReady() && IsHTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || (CTFNoTradeLow[ii] == 0 && HTFNoTradeLow[ii] == 0)) && low[ii] < MathMin(CTFLineLevelLow[ii], HTFLineLevelLow[ii]) && high[ii] >= MathMax(CTFLineLevelLow[ii], HTFLineLevelLow[ii]))
            ShortEntry[ii] = MathMin(CTFLineLevelLow[ii], HTFLineLevelLow[ii]);
         break;
      case CURRENT_TF_WHEN_NEARER:
         if(IsCTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeLow[ii] == 0) && CTFLineLevelLow[ii] >= HTFLineLevelLow[ii] && low[ii] < CTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexCTFLowSecond, CTFLow[indexCTFLowSecond], indexCTFLowFirst, CTFLow[indexCTFLowFirst], ii + 1))
         ShortEntry[ii] = CTFLineLevelLow[ii];
         break;
      case HIGHER_TF_WHEN_NEARER:
         if(IsHTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeLow[ii] == 0) && HTFLineLevelLow[ii] >= CTFLineLevelLow[ii] && low[ii] < HTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexHTFLowSecond, HTFLow[indexHTFLowSecond], indexHTFLowFirst, HTFLow[indexHTFLowFirst], ii + 1))
            ShortEntry[ii] = HTFLineLevelLow[ii];
         break;
      case EITHER:
         if(IsHTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || HTFNoTradeLow[ii] == 0) && low[ii] < HTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexHTFLowSecond, HTFLow[indexHTFLowSecond], indexHTFLowFirst, HTFLow[indexHTFLowFirst], ii + 1))
            ShortEntry[ii] = HTFLineLevelLow[ii];
         else if(IsCTFLowLineReady() && (NoTradeMode != RESPECT_SIGNAL || CTFNoTradeLow[ii] == 0) && low[ii] < CTFLineLevelLow[ii] && low[ii + 1] > GetLineLevel(indexCTFLowSecond, CTFLow[indexCTFLowSecond], indexCTFLowFirst, CTFLow[indexCTFLowFirst], ii + 1))
            ShortEntry[ii] = CTFLineLevelLow[ii];
         break;
      }
   }
}
string TimeFrameToString(int tf)
{
   switch(tf){
      case PERIOD_CURRENT: return ("Current time frame");
      case PERIOD_M1:  return ("M1");
      case PERIOD_M5:  return ("M5");
      case PERIOD_M15: return ("M15");
      case PERIOD_M30: return ("M30");
      case PERIOD_H1:  return ("H1");
      case PERIOD_H4:  return ("H4");
      case PERIOD_D1:  return ("D1");
      case PERIOD_W1:  return ("W1");
      case PERIOD_MN1: return ("MN");
   }
   return (IntegerToString(tf));
}
