//+------------------------------------------------------------------+
//|                                   FX Compass Fib auto-trader.mq4 |
//|                                  Copyright © 2009, Steve Hopwood |
//|                              http://www.hopwood3.freeserve.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2009, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#property show_inputs
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define  up "Up"
#define  down "Down"
#define  flat "Flat"
/*



start()
void DisplayUserFeedback()
void CalculateTradeLevels()


----Fib----
void GetSwing()
void DrawFib()

----Trading----
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
bool TradingTimesCheck()
void LookForTradeOpportunities()
bool StopTradingCheck()

----Trend spotting
void ReadRsi()
double iLsma(int LSMAPeriod,int shift)
void GetTradeDirectionFromTrend()


----Trade management----
bool DoesTradeExist()


1. Fib the previous days high to low as you do.
2. Price through 0 or 100 Fib, enter trade with 138.2 Fib as target.
3. If price reverses back into the inner Fibs and hits the 23.6 or 78.6 then first trade is closed and a 
   reverse trade is triggered with the 50 Fib as the target. Rince and Repeat each day each pair.
4. If first trade completes and price continues to the 200 Fib (especially with a candle close beyond the level) 
   cancel all orders = continuation of trend. Start again tomorrow.
   
In its simplest form, Strikes on 0 and 100 trigger targets of 138 extension with the SL being a reverse 
trade at 23.6 or 78.6 with the 50 as the target. The EA needs to get ready when price enters the 0 to 23.6 area 
or the 100 to 78.6 area for a trade in either direction according to the next trigger.

Ranging markets can do some damage, but I have found the success rate over 75% and the RR is excellent as 
the recovery trade kicks in if the initial trade fails.
*/

//changes
//in LookForTradeOpportunities
// DoesTradeExist - Query of the function occurs only once
// condition of a Trade are exists a Order or type > 5 

extern string  gi = "____General inputs----";
extern double  Lot = 3;
extern int     MagicNumber = 0;
extern bool    CriminalIsECN = false;
extern int     PendingPipsDistance = 100;
extern color   FiboColour = Blue;
extern string  rsi = "----Rsi----";
extern bool    UseRsi = true;
extern string  ls = "----LSMA----";
extern bool    UseLSMA = true;
extern int     LSMA_Period = 14;
extern string  tt = "----Trading hours----";
extern string  Trade_Hours = "Set Morning & Evening Hours";
extern string  Trade_Hoursi = "Use 24 hour, local time clock";
extern string  Trade_Hours_M = "Morning Hours 0-12";
extern  int    start_hourm = 0;
extern  int    end_hourm = 12;
extern string  Trade_Hours_E = "Evening Hours 12-24";
extern  int    start_houre = 12;
extern  int    end_houre = 24;

extern string  mis = "----Odds and ends----";
extern int     DisplayGapSize = 30;
   

//Fib variables
double         SwingHigh, SwingLow;
double         BreakoutBuyLevel, BreakoutSellLevel, RetraceBuyLevel, RetraceSellLevel, StopTradingHighLevel, StopTradingLowLevel;
double         BreakoutBuyTP, BreakoutSellTP, RetraceBuyTP, RetraceSellTP;

//Misc
int            OldBars; 
int            TicketNo;//Holds the ticket number of the most recent open trade eg the last in a sequence of 3
bool           RobotDisabled;
string         Gap, DisabledMessage, ScreenMessage;
double         RsiVal;
string         TradeComment, trend;


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----
   
   if (Digits == 2 || Digits == 4)
   {
      
   }//if (Digits == 2 || Digits == 4)
   
//----
   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   
   
    OldBars = 0;
    start();

   
   return(0);
}

void DisplayUserFeedback()
{
      ScreenMessage = "";
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
      //Code for time to bar-end display from Candle Time by Nick Bilak
      double i;
      int m,s,k;
      m=Time[0]+Period()*60-CurTime();
      i=m/60.0;
      s=m%60;
      m=(m-m%60)/60;
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, m + " minutes " + s + " seconds left to bar end", NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "PendingPipsDistance: ", PendingPipsDistance, NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Magic number: ", MagicNumber, NL);
      if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = true", NL);
      else ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = false", NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), NL);
      if (UseRsi)
      {
         ReadRsi();
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "RsiVal: ", RsiVal, NL);
      }//if (UseRsi)
      if (UseLSMA)
      {
         GetTradeDirectionFromTrend();
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "LSMA shows current trend is ", trend, NL);
      }//if (UseLSMA)
      
      ScreenMessage = StringConcatenate(ScreenMessage,NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading hours: ", NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Start_hourm:  ", DoubleToStr(start_hourm, 2), NL );
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "End_hourm:  ", DoubleToStr(end_hourm, 2), NL );
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Start_houre:  ", DoubleToStr(start_houre, 2), NL );
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "End_houre:   ", DoubleToStr(end_houre, 2), NL, NL );
      
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Swing high: ", DoubleToStr(SwingHigh,Digits),NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Swing low: ", DoubleToStr(SwingLow,Digits),NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Breakout buy level: ", DoubleToStr(BreakoutBuyLevel,Digits));
      ScreenMessage = StringConcatenate(ScreenMessage, "  TP: ", DoubleToStr(BreakoutBuyTP,Digits), "  SL: ", DoubleToStr(RetraceSellLevel, Digits), NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Breakout sell level: ", DoubleToStr(BreakoutSellLevel,Digits));
      ScreenMessage = StringConcatenate(ScreenMessage, "  TP: ", DoubleToStr(BreakoutSellTP,Digits), "  SL: ", DoubleToStr(RetraceBuyLevel,Digits),NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Retrace buy level: ", DoubleToStr(RetraceBuyLevel,Digits));
      ScreenMessage = StringConcatenate(ScreenMessage, "  TP: ", DoubleToStr(RetraceBuyTP,Digits), "  SL: ", DoubleToStr(BreakoutSellLevel,Digits),NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Retrace sell level: ", DoubleToStr(RetraceSellLevel,Digits));
      ScreenMessage = StringConcatenate(ScreenMessage, "  TP: ", DoubleToStr(RetraceSellTP,Digits), "  SL: ", DoubleToStr(BreakoutBuyLevel,Digits),NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop trading high: ", DoubleToStr(StopTradingHighLevel,Digits),NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop trading low: ", DoubleToStr(StopTradingLowLevel,Digits),NL);
      
      
      
      Comment(ScreenMessage);

}//void DisplayUserFeedback()



//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   ObjectDelete("SH_Fibo");
   Comment("");
   
//----
   return(0);
}

void DrawFib()
{

      
      double HighPrice, LowPrice;
      datetime OpenTime, CloseTime;
      string tf;
      
      HighPrice = SwingHigh;
      OpenTime = iTime(NULL, PERIOD_D1, 1);
      LowPrice = SwingLow;
      CloseTime = iTime(NULL, PERIOD_D1, 1);
         
      
            
      
            
      ObjectCreate("SH_Fibo",OBJ_FIBO,0,OpenTime,HighPrice,CloseTime,LowPrice);
      ObjectSet("SH_Fibo", OBJPROP_STYLE, STYLE_DASH);
      ObjectSet("SH_Fibo", OBJPROP_COLOR, FiboColour);
      ObjectSet("SH_Fibo", OBJPROP_LEVELCOLOR, FiboColour);
      ObjectSet("SH_Fibo", OBJPROP_WIDTH, 1);
      ObjectSet("SH_Fibo", OBJPROP_FIBOLEVELS, 9);
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+0, 0);
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+1, 100);
      
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+0, 0.236);//Retrace buy
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+1, -0.382);//Breakout targer
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+2, 0);//Low
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+3, 0.786);//Retrace sell
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+4, 1.382);//Breakout targer
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+5, 0.50);//Pivot/retrace target
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+6, 2);//stop trading level
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+7, -1);//stop trading level
      ObjectSet("SH_Fibo", OBJPROP_FIRSTLEVEL+8, 1);//High
      
      
      ObjectSetFiboDescription("SH_Fibo", 0, " Retrace buy (23.6)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 1, " TP (-38.2)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 2, " Low. Breakout sell (0)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 3, " Retrace sell (78.6)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 4, " Tp (138.2)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 5, " Pivot/TP (50)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 6, " Stop trading (200)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 7, " Stop trading (-100)"+ "  %$");
      ObjectSetFiboDescription("SH_Fibo", 8, " High. Breakout buy (100)"+ "  %$");
      
      
}//End void DrawFib()


bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
{
   
   
   if (!IsTradeAllowed() ) return(false);
   
   int slippage = 10;
   if (Digits == 3 || Digits == 5) slippage = 100;
   
   color col = Red;
   if (type == OP_BUY) col = Green;
   
   if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, 0, col);
   
   
   //Is a 2 stage criminal
   if (CriminalIsECN)
   {
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, 0, col);
	   if (stop != 0)
	   {
		   if (ticket > 0)
		   bool result = OrderModify(ticket, OrderOpenPrice(), stop, take, 0, CLR_NONE);
		   if (!result)
		   {
		       int err=GetLastError();
             Print(Symbol(), " ", type," SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
		   }//if (!result)			  
	   }//if (Sl != 0)
      
      
   }//if (CriminalIsECN)
   
   //Error trapping for both
   if (ticket < 0)
   {
      string stype;
      if (type == OP_BUY) stype = "OP_BUY";
      if (type == OP_SELL) stype = "OP_SELL";
      err=GetLastError();
      //Alert(Symbol(), " ", stype," Simone fib order send failed with error(",err,"): ",ErrorDescription(err));
      //Print(Symbol(), " ", stype," FX Compass order send failed with error(",err,"): ",ErrorDescription(err));
      Print(Symbol(), " ", comment," FX Compass order send failed with error(",err,"): ",ErrorDescription(err));
      return(false);
   }//if (ticket < 0)  
   
   //Got this far, so trade send succeeded
   return(true);
   
}//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)

bool DoesTradeExist()
{
   TicketNo = 0;
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
      {
         TicketNo = OrderTicket();//Tells the robot which is the most recent trade in a sequence
         return(true);
      }//if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   return(false);
   
}//bool DoesTradeExist()

void GetSwing()
{

   SwingHigh = iHigh(NULL, PERIOD_D1, 1);
   SwingLow = iLow(NULL, PERIOD_D1, 1);
   

    
   CalculateTradeLevels();
   
   
   
}//void GetSwing()


void CalculateTradeLevels()
{
   
   double extent = SwingHigh - SwingLow;

   BreakoutBuyLevel = SwingHigh;
   BreakoutSellLevel = SwingLow;
   RetraceBuyLevel = NormalizeDouble(SwingLow + (extent * 23.6 / 100), Digits); 
   RetraceSellLevel = NormalizeDouble(SwingLow + (extent * 78.6 / 100), Digits); 
   StopTradingHighLevel = NormalizeDouble(SwingHigh + extent, Digits); 
   StopTradingLowLevel = NormalizeDouble(SwingLow - extent, Digits); 
   BreakoutBuyTP = NormalizeDouble(SwingLow + (extent * 138.2 / 100), Digits); 
   RetraceBuyTP = NormalizeDouble(SwingLow + (extent * 50 / 100), Digits); 
   RetraceSellTP = RetraceBuyTP;
   BreakoutSellTP = NormalizeDouble(SwingLow - (extent * 38.2 / 100), Digits); 
   
   
   /*for (int cc = 0; cc < ArraySize(LongFibLevels); cc++)
double         BreakoutBuyTP, BreakoutSellTP, RetraceBuyTP, RetraceSellTP;

   {
      LongTargetLevel[cc] = NormalizeDouble(SwingLow + (extent * LongFibLevels[cc] / 100), Digits);            
   }//for (int cc = 0; cc < ArraySize(LongFibLevels); cc++)
            
   for (cc = 0; cc < ArraySize(ShortFibLevels); cc++)
   {
      ShortTargetLevel[cc] = NormalizeDouble(SwingLow - (extent * ShortFibLevels[cc] / 100), Digits);            
   }//for (cc = 0; cc <= ArraySize(ShortFibLevels); cc++)
   */
   
}//End void CalculateTradeLevels()

bool TradingTimesCheck()
{

      //Trading times
   int hour = TimeHour(TimeLocal() );
   
   if (end_hourm < start_hourm)
	{
		end_hourm += 24;
	}
	

	if (end_houre < start_houre)
	{
		end_houre += 24;
	}
	
	bool ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);

	// adjust for past-end-of-day cases
	// eg in AUS, USDJPY trades 09-17 and 22-06
	// so, the above check failed, check if it is because of this condition
	if (!ok2Trade && hour < 12)
	{
 		hour += 24;
		ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);
		
		// so, if the trading hours are 11pm - 6am and the time is between  midnight to 11am, (say, 5am)
		// the above code will result in comparing 5+24 to see if it is between 23 (11pm) and 30(6+24), which it is...
	}


   // check for end of day by looking at *both* end-hours

   if (hour >= MathMax(end_hourm, end_houre))
   {      
      return(false);
   }//if (hour >= MathMax(end_hourm, end_houre))

   return(true);

}//End bool TradingTimesCheck()

void ReadRsi()
{

   RsiVal = iRSI(NULL, 0, 14, PRICE_CLOSE, 0);

}//End void ReadRsi()


void LookForTradeOpportunities()
{

   bool SendTrade = true;
   double stop, take, price;
   int type = 100;

   //Rsi check
   if (UseRsi)
   {
      ReadRsi();
      if (RsiVal < 55 && RsiVal > 45) return;
   }//if (UseRsi)
 
   if (UseLSMA)
   {
      GetTradeDirectionFromTrend();
      if (trend == flat) return;
   }//if (UseLSMA)
   
   RefreshRates();
   //Long breakout
   if (Ask > BreakoutBuyLevel && Open[0] < BreakoutBuyLevel)
   {
      type = OP_BUY;
      if (UseRsi && RsiVal < 55) 
      {
         SendTrade = false;
         return;         
      }//if (UseRsi && RsiVal < 55) 
      if (UseLSMA)
      {
         if (trend != up) return;
      }//if (UseLSMA)
   
      stop = RetraceSellLevel;
      take = BreakoutBuyTP;
      price = Ask;
      TradeComment = "Breakout Buy";
   }//if (Ask > BreakoutBuyLevel && Open[0] < BreakoutBuyLevel)
   

   //Long retrace
   if (Ask > RetraceBuyLevel && Ask < RetraceBuyTP && Open[0] < RetraceBuyLevel)
   {
      type = OP_BUY;
      if (UseRsi && RsiVal < 55) 
      {
         SendTrade = false;
         return;         
      }//if (UseRsi && RsiVal < 55) 
      if (UseLSMA)
      {
         if (trend != up) return;
      }//if (UseLSMA)
      
      stop = BreakoutSellLevel;
      take = BreakoutBuyTP;
      price = Ask;
      TradeComment = "Retrace Buy";
   }//if (Ask > RetraceBuyLevel && Ask < RetraceBuyTP && Open[0] < RetraceBuyLevel)
   
   //Short breakout
   if (Bid < BreakoutSellLevel && Open[0] > BreakoutSellLevel)
   {
      type = OP_SELL;
      if (UseRsi && RsiVal > 45) 
      {
         SendTrade = false;
         return;         
      }//if (UseRsi && RsiVal < 55) 
      if (UseLSMA)
      {
         if (trend != down) return;
      }//if (UseLSMA)
   
      stop = RetraceBuyLevel;
      take = BreakoutSellTP;
      price = Bid;
      TradeComment = "Breakout Sell";
   }//if (Bid < BreakoutSellLevel && Open[0] > BreakoutSellLevel)
   

   //Short retrace
   if (Bid < RetraceSellLevel && Bid > RetraceSellTP && Open[0] > RetraceSellLevel)
   {
      type = OP_SELL;
      if (UseRsi && RsiVal > 45) 
      {
         SendTrade = false;
         return;         
      }//if (UseRsi && RsiVal < 55) 
      if (UseLSMA)
      {
         if (trend != down) return;
      }//if (UseLSMA)
   
      stop = BreakoutBuyLevel;
      take = RetraceSellTP;
      price = Bid;
      TradeComment = "Retrace Sell";
   }//if (Bid < RetraceSellLevel && Bid > RetraceSellTP && Open[0] > RetraceSellLevel)
   
   //no Trade if Order exitst or if the if-conditional (above) isn't met
   if (DoesTradeExist() == true || type == 100) SendTrade = false;

   if (SendTrade) SendSingleTrade(type, TradeComment, Lot, price, stop, take);

}//End void LookForTradeOpportunities()


bool StopTradingCheck()
{

   if (Open[0] > StopTradingHighLevel) return(true);
   if (Open[0] < StopTradingLowLevel) return(true);
   
   return(false);

}//End bool StopTradingCheck()


double iLsma(int LSMAPeriod,int shift)
{
   //Code to calculate LSMA value. Copied from MrPip's work. Many thanks, MrPip
   
   double wt;
   
   double ma1=iMA(NULL,0,LSMAPeriod,0,MODE_SMA ,PRICE_CLOSE,shift);
   double ma2=iMA(NULL,0,LSMAPeriod,0,MODE_LWMA,PRICE_CLOSE,shift);
   wt = MathFloor((3.0*ma2-2.0*ma1)/Point) * Point;
   return(wt);
}//double iLsma(int LSMAPeriod,int shift)  

void GetTradeDirectionFromTrend()
{
   trend = flat;
   double lsma_cur, lsma_prev;
   
   lsma_cur = iLsma(LSMA_Period, 1);
   lsma_prev = iLsma(LSMA_Period, 2);
   if (lsma_cur > lsma_prev) trend = up;
   if (lsma_cur < lsma_prev) trend = down;
   
   

}//End void GetTradeDirectionFromTrend()



//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   static bool StopTrading;

   
   if (RobotDisabled )
   {
      Comment("The robot has been suspended. Reason: ", DisabledMessage);
      return;
   }//if (RobotDisabled )
 
   
   if(OldBars != iBars(NULL, PERIOD_D1) ) 
   {
      ObjectDelete("SH_Fibo");
      GetSwing();
      DrawFib();
      OldBars = iBars(NULL, PERIOD_D1);
      StopTrading = false;   
   }//if(OldBars != Bars && NoOfTrades == 0) 

   //Check trading hours
   bool TradeHours = TradingTimesCheck();
   if (!TradeHours)
   {
      Comment("Outside trading hours\nstart_hourm-end_hourm: ", start_hourm, "-",end_hourm, "\nstart_houre-end_houre: ", start_houre, "-",end_houre);
      return;
   }//if (hour < start_hourm)
   
   if (StopTrading)
   {
      Comment(Gap, "Not trading any more today");
      return;
   }//if (StopTrading)
   

   
   //Stop trading check
   StopTrading = StopTradingCheck();

   
   //Look for trading opportunities
   LookForTradeOpportunities();
   

   DisplayUserFeedback();
   
   
//----
   return(0);
}
//+------------------------------------------------------------------+5


