
#property indicator_chart_window
#property  indicator_buffers 2
#property  indicator_color1  Red
#property  indicator_color2  Blue

#define TRADE_LINE 9999
#define LONG 1
#define NONE 0
#define SHORT -1

#define NEUTRAL 0
#define BUY 1
#define SELL -1

extern int RangeStartTime=8;
extern int RangeEndTime=10;
extern bool InvertBias=false;
extern bool InvertSignal=false;
extern bool IgnoreBias=false;
extern bool ShowTimeLines=true;
extern bool ShowHighLowLines=true;
extern color RangeStartColor = Lime;
extern color RangeEndColor = Yellow;
extern color HighColor=Blue;
extern color LowColor=Red;

extern int stats_font_size = 11;
extern string stats_font = "Arial";
extern color stats_font_color = White;

double   IndBuff0[];
double   IndBuff1[];
double   IndBuff2[];
double   IndBuff3[];
double   IndBuff4[];
double   IndBuff5[];
double   IndBuff6[];
double   IndBuff7[];

int      Signal,handle;
double   LocalPoint;
double open,close,high,low,mid;
bool lookForEntryShort,lookForEntryLong;
bool inATrade = false;
int tradeDirection;
int longsWon;
int longsLost;
int shortsWon;
int shortsLost;
int totalTrades;
int lastTp;
double ep, tp, sl;
datetime reftime,timeHighBroken,timeLowBroken;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
string shortName;
   inATrade = false;
   tradeDirection = NONE;
   longsWon = 0;
   longsLost = 0;
   shortsWon = 0;
   shortsLost = 0;
   totalTrades = 0;   

   IndicatorBuffers(2);
   SetIndexBuffer(0,IndBuff0);
   SetIndexBuffer(1,IndBuff1);
   SetIndexStyle(0,DRAW_ARROW,EMPTY,3);
   SetIndexStyle(1,DRAW_ARROW,EMPTY,3);
   SetIndexArrow(0,234);
   SetIndexArrow(1,233);
   LocalPoint=Point*GetDigitAdjustFactor();
   handle=WindowFind(WindowExpertName());
   lookForEntryShort=false;
   lookForEntryLong=false;
   timeHighBroken=0;
   timeLowBroken=0;
   initStatsDisplay();
//----
   

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   int i;
   string name;
   
   for(i=ObjectsTotal()-1;i>=0;i--)
   {
      name=ObjectName(i);
      if(StringSubstr(name,0,2)=="1_")
         ObjectDelete(name);
   }
   Comment(" ");
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int limit,counted_bars=IndicatorCounted();
   int shift,dayshift,lowestbar,highestbar;
   string name;
   datetime end;
   double stoch,macd[8];

   if(counted_bars>0) counted_bars--;
   limit=Bars-1-counted_bars;

   for(int bar=limit; bar>=0; bar--)
   {
      shift=iBarShift(NULL,PERIOD_H1,Time[bar]);
      dayshift=iBarShift(NULL,PERIOD_D1,Time[bar]);
      if(IsNewBar(PERIOD_H1,shift))
      {
         if(TimeHour(Time[bar])==RangeStartTime)
         {
            open=Open[bar];
            if(ShowTimeLines)
            {
               name="1_S_" +TimeToStr(Time[bar]);
               drawLine(name,OBJ_VLINE,0,RangeStartColor,Time[bar],open);
            }            
         }
         else if(TimeHour(Time[bar])==RangeEndTime)
         {
            if(ShowTimeLines)
            {
               name="1_E_" +TimeToStr(Time[bar]);
               drawLine(name,OBJ_VLINE,0,RangeEndColor,Time[bar],open);
            }
            close=Close[bar+1];
            highestbar=iHighest(NULL,PERIOD_H1,MODE_HIGH,RangeEndTime-RangeStartTime,shift+1);
            high=iHigh(NULL,PERIOD_H1,highestbar);
            lowestbar=iLowest(NULL,PERIOD_H1,MODE_LOW,RangeEndTime-RangeStartTime,shift+1);
            low=iLow(NULL,PERIOD_H1,lowestbar);
            end=iTime(NULL,PERIOD_D1,dayshift)+86400;
            reftime=Time[bar];
            if(ShowHighLowLines)
            {
               name="1_H_" +TimeToStr(Time[bar]);
               drawLine(name,OBJ_TREND,0,HighColor,iTime(NULL,PERIOD_H1,highestbar),high,end,high);
               name="1_L_" +TimeToStr(Time[bar]);
               drawLine(name,OBJ_TREND,0,LowColor,iTime(NULL,PERIOD_H1,lowestbar),low,end,low);
            }
            if(IgnoreBias)
            {
               lookForEntryShort=true;            
               lookForEntryLong=true;
            }
            else
            {
               if(close<open)
                  lookForEntryShort=true;
               else if(close>open)
                  lookForEntryLong=true;
               if(InvertBias)
               {
                  lookForEntryShort=!lookForEntryShort;
                  lookForEntryLong=!lookForEntryLong;
               }
            }
            continue;
         }
      }
      if (!inATrade) {
         if((lookForEntryShort || lookForEntryLong) && IsNewBar(PERIOD_M1,bar))
         {
            stoch = iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_MAIN,bar+1);
         
            //macd[0]=iCustom(NULL,0,"MACD_4CZ",5,34,0,bar+1);   //green
            //macd[1]=iCustom(NULL,0,"MACD_4CZ",5,34,1,bar+1);   //darkgreen
            //macd[2]=iCustom(NULL,0,"MACD_4CZ",5,34,2,bar+1);   //red
            //macd[3]=iCustom(NULL,0,"MACD_4CZ",5,34,3,bar+1);   //maroon
            //macd[4]=iCustom(NULL,0,"MACD_4CZ",5,34,0,bar+2);
            //macd[5]=iCustom(NULL,0,"MACD_4CZ",5,34,1,bar+2);
            //macd[6]=iCustom(NULL,0,"MACD_4CZ",5,34,2,bar+2);
            //macd[7]=iCustom(NULL,0,"MACD_4CZ",5,34,3,bar+2);
            double atr=iATR(NULL,0,5,bar);

            if(HighBoundaryBroken(bar) || LowBoundaryBroken(bar))
            {
               if(timeHighBroken>timeLowBroken)
               {
                  lookForEntryShort=false;
                  lookForEntryLong=true;
               }
               else if(timeHighBroken<timeLowBroken)
               {
                  lookForEntryShort=true;
                  lookForEntryLong=false;
               }
         
            }
            //changed from green -> darkgreen?         
            if(macd[1]>0 && macd[5]==0 && macd[0]==0 && macd[4]>0)
            {
               if(stoch>50 && lookForEntryShort && (High[bar+1]<high || IgnoreBias))
               {
                  lastTp = findLastSwingHigh(bar+1);
                  sl = High[lastTp] + 0.0001;
                  ep = (High[bar+1] + Low[bar+1])/ 2.0;
                  tp = ep - 3.0 * (sl - ep);
               
                  name="1_H_EP" + TimeToStr(Time[bar+1]);
                  drawLine(name,TRADE_LINE,0,Green,iTime(NULL,PERIOD_H1,highestbar), ep,end,ep);
                  name="1_H_SL" + TimeToStr(Time[bar+1]);
                  drawLine(name,TRADE_LINE,0, Red,iTime(NULL,PERIOD_H1,highestbar), sl, end, sl);
                  name="1_H_TP" + TimeToStr(Time[bar+1]);
                  drawLine(name,TRADE_LINE, 0, Red,iTime(NULL,PERIOD_H1,highestbar), tp, end, tp);
                  inATrade = true;
                  tradeDirection = SHORT;
                  totalTrades++;
                  Print("TRADE #" + totalTrades + ": SHORT (SL, EP, TP) => (" + DoubleToStr(sl,5) + ", " + DoubleToStr(ep,5) + ", " + DoubleToStr(tp,5) + ")"); 
                  
                  if(InvertSignal)
                     IndBuff1[bar]=Low[bar]-atr;
                  else
                     IndBuff0[bar]=High[bar]+atr;
                  lookForEntryShort=false;
               }
            }
            //changed from marron -> red?
            else if(macd[2]<0 && macd[6]==0 && macd[3]==0 && macd[7]<0)
            {
               if(stoch<50 && lookForEntryLong && (Low[bar+1]>low || IgnoreBias))
               {
                  lastTp = findLastSwingLow(bar+1);
                  sl = Low[lastTp] + 0.0001;
                  ep = (High[bar+1] + Low[bar+1])/ 2.0;
                  tp = ep + 3.0 * (ep - sl);
               
                  
               
                  name="1_H_EP" + TimeToStr(Time[bar+1]);
                  drawLine(name,TRADE_LINE,0,Green,iTime(NULL,PERIOD_H1,highestbar), ep,end,ep);
                  name="1_H_SL" + TimeToStr(Time[bar+1]);
                  drawLine(name,TRADE_LINE,0, Red,iTime(NULL,PERIOD_H1,highestbar), sl, end, sl);
                  name="1_H_TP" + TimeToStr(Time[bar+1]);
                  drawLine(name,TRADE_LINE, 0, Red,iTime(NULL,PERIOD_H1,highestbar), tp, end, tp);

                  inATrade = true;
                  tradeDirection = LONG;
                  totalTrades++;
                  Print("TRADE #" + totalTrades + ": LONG (SL, EP, TP) => (" + DoubleToStr(sl,5) + ", " + DoubleToStr(ep,5) + ", " + DoubleToStr(tp,5) + ")");             
                  if(InvertSignal)
                     IndBuff0[bar]=High[bar]+atr;
                  else
                     IndBuff1[bar]=Low[bar]-atr;
                  lookForEntryLong=false;
               }
            }
         }
      } else { // we are in a trade.
         if ( IsNewBar(PERIOD_M1,bar) ) {
            
            switch(tradeDirection) {
            case SHORT:               
               if (Low[bar+1] <= tp) {
                  inATrade = false;
                  tradeDirection = NONE;
                  Print("TRADE #" + totalTrades + ": SHORT WINNER  Closed at " + DoubleToStr(Low[bar+1], 5));
                  shortsWon++;                  
               } else if (High[bar+1] >= sl) {
                  inATrade = false;
                  tradeDirection = NONE;
                  Print("TRADE #" + totalTrades + ": SHORT LOSER Closed at " + DoubleToStr(High[bar+1], 5));                  
                  shortsLost++;
               }
               updateStatsDisplay();
            break;
            case LONG:               
               if (High[bar+1] >= tp) {
                  inATrade = false;
                  tradeDirection = NONE;
                  Print("TRADE #" + totalTrades + ": LONG WINNER Closed at " + DoubleToStr(High[bar+1], 5));                                    
                  longsWon++;               
               } else if (Low[bar+1] <= sl) {
                  inATrade = false;
                  tradeDirection = NONE;
                  Print("TRADE #" + totalTrades + ": LONG LOSER Closed at " + DoubleToStr(Low[bar+1], 5));                                    
                  longsLost++;
               }
               updateStatsDisplay();
            break;
            case NONE:
            default:
            break;
            }
            
         }
      } // inATrade
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+
int GetDigitAdjustFactor()
{
   if(Digits==5 || Digits==3)
      return(10);
   else
      return(1);
}

void drawLine(string name, int type, int window, color col, datetime time1, double price1, datetime time2=0, double price2=0, datetime time3=0, double price3=0)
{
   if(ObjectFind(name) != -1)
   {
      ObjectDelete(name);
   }
   int objType = type;
   if (type == TRADE_LINE) objType = OBJ_TREND;
   
   ObjectCreate(name, objType, window, time1, price1, time2, price2);
   ObjectSet(name, OBJPROP_RAY, false);
   ObjectSet(name, OBJPROP_COLOR, col);
   if(type==OBJ_VLINE || type == TRADE_LINE)
      ObjectSet(name, OBJPROP_STYLE, STYLE_DOT);
    
      

}


double findLastSwingLow(int entryBar) {   
   int i = (entryBar + 1); 
   while ( TimeHour( Time[i] ) != RangeStartTime ) {
      if (Low[i+i] >  Low[i] && Low[i] < Low[i-1] && Low[i] < Low[entryBar]) break;
      else i++; 
   }
   return(i);
}

double findLastSwingHigh(int entryBar) {   
   int i = (entryBar + 1); 
   while ( TimeHour( Time[i] ) != RangeStartTime ) {
      if (High[i+i] <  High[i] && High[i] > High[i-1] && High[i] > High[entryBar]) break;
      else i++; 
   }
   return(i);
}

void initStatsDisplay() {
   ObjectCreate("1_stats", OBJ_LABEL, 0, 0, 0);
   ObjectSetText("1_stats", "init", stats_font_size, stats_font, stats_font_color);
   ObjectSet("1_stats", OBJPROP_CORNER, 0);
   ObjectSet("1_stats", OBJPROP_XDISTANCE, 20);
   ObjectSet("1_stats", OBJPROP_YDISTANCE, 40);   
   
}

void updateStatsDisplay() {
   int sn = shortsWon + shortsLost;
   int ln = longsWon + longsLost;
   
   string msg = "Total: " + totalTrades + "  Shorts: (" + sn + ", " + shortsWon + ", " + shortsLost + 
      ") Longs: (" + ln + ", " + longsWon + ", " + longsLost + ")";
   ObjectSetText("1_stats", msg, stats_font_size, stats_font, stats_font_color);
}



bool IsNewBar(int thePeriod, int shift=0)
{
static datetime barTime1440=0, barTime240=0, barTime60=0, barTime30=0, barTime15=0, barTime5=0, barTime1=0;

   switch(thePeriod)
   {
      case PERIOD_D1:
         if(barTime1440<iTime(Symbol(),PERIOD_D1,shift))
         {
            barTime1440=iTime(Symbol(),PERIOD_D1,shift);
            return(true);
         }
         break;
      case PERIOD_H4:
         if(barTime240<iTime(Symbol(),PERIOD_H4,shift))
         {
            barTime240=iTime(Symbol(),PERIOD_H4,shift);
            return(true);
         }
         break;
      case PERIOD_H1:
         if(barTime60<iTime(Symbol(),PERIOD_H1,shift))
         {
            barTime60=iTime(Symbol(),PERIOD_H1,shift);
            return(true);
         }
         break;
      case PERIOD_M30:
         if(barTime30<iTime(Symbol(),PERIOD_M30,shift))
         {
            barTime30=iTime(Symbol(),PERIOD_M30,shift);
            return(true);
         }
         break;
      case PERIOD_M15:
         if(barTime15<iTime(Symbol(),PERIOD_M15,shift))
         {
            barTime15=iTime(Symbol(),PERIOD_M15,shift);
            return(true);
         }
         break;
      case PERIOD_M5:
         if(barTime5<iTime(Symbol(),PERIOD_M5,shift))
         {
            barTime5=iTime(Symbol(),PERIOD_M5,shift);
            return(true);
         }
         break;
      case PERIOD_M1:
         if(barTime1<iTime(Symbol(),PERIOD_M1,shift))
         {
            barTime1=iTime(Symbol(),PERIOD_M1,shift);
            return(true);
         }
         break;
   }
   return(false);
}
bool HighBoundaryBroken(int bar)
{
   int start,end,index;
   double price;
   
   start=iBarShift(NULL,0,reftime);
   index=iHighest(NULL,0,MODE_HIGH,start-bar,bar);
   price=High[index];
   if(price>high)
   {
      timeHighBroken=Time[bar];
      return(true);
   }
   
   return(false);
}
bool LowBoundaryBroken(int bar)
{
   int start,end,index;
   double price;
   
   start=iBarShift(NULL,0,reftime);
   index=iLowest(NULL,0,MODE_LOW,start-bar,bar);
   price=Low[index];
   if(price<low)
   {
      timeLowBroken=Time[bar];
      return(true);
   }
   return(false);
}