//+------------------------------------------------------------------+
//|                   Mystic auto trading robot by Steve Hopwood.mq4 |
//|                                  Copyright © 2010, Steve Hopwood |
//|                              http://www.hopwood3.freeserve.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define  buy "Buy"
#define  sell "Sell"
#define  up "Up"
#define  down "Down"
#define  none "None"

/*
void LookForTradingOpportunities()
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
bool DoesTradeExist()

----Indicator readings----
void ReadIndicatorValues()
double GetRsi(int tf, int period, int ap, int shift)
void GetRsiDirection()
double GetMa(int shift)
void GetMaDirection()
void GetLongCrossCandlesAgo()
void GetShortCrossCandlesAgo()

*/

extern double  Lot=0.1;
extern int     MagicNumber=0;
extern string  TradeComment="";
extern bool    CriminalIsECN=false;
extern string  tos="----TradeDirection----";
extern bool    TradeLong=true;
extern bool    TradeShort=true;
extern string  ov="Or automate the trade direction choice";
/*
extern string  tf="----Htf Rsi----";
extern bool    UseHtfRsi=false;
extern int     RsiTrendDeterminationTf=60;
extern int     RsiTrendDeterminationPeriod=14;
*/
extern string  tfr="----Rsi----";
extern int     RsiPeriod=9;
//extern int     MinRsiMovement=0;//Set to zero to turn this off
extern string  ma="----Rsi MA----";
extern int     RsiMaPeriod=5;
extern string  rsmac="Rsi/Sma cross";
extern int     MaxBarsAgoForCross=3;//If the cross happened more than this no of candles ago, the cancel the trade
extern string  tpi="----Take profit and stop loss inputs----";
extern int     TakeProfit=100;
extern int     StopLoss=50;
/*
extern string  cs="----Chart SMA----";
extern bool    UseChartSma=true;
extern int     ChartSmaPeriod=24;
*/
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;

bool           RobotSuspended;
//Rsi
double         TrendRsiVal;
double         RsiVal, PrevRsiVal;//Current tf rsi
string         RsiDirection;//Trading tf direction
string         HtfRsiTrend;//Higher tf trend

//Rsi/Sma cross
int            CrossCandlesAgo;

//Rsi Moving average
double         MaVal, PrevMaVal;
string         MaDirection;

//Chart sma
double         ChartSmaVal;

//Misc
string         Gap, ScreenMessage;
int            OldBars;
string         PipDescription=" pips";

void DisplayUserFeedback()
{
   
   if (IsTesting() && !IsVisualMode()) return;

   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL );
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   if (TradeLong) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Waiting for a Buy trade opportunity", NL);
   if (TradeShort) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Waiting for a Short trade opportunity", NL);
   if (!TradeLong && !TradeShort) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Not trading", NL);
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Take profit: ", TakeProfit, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop loss: ", StopLoss, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Magic number: ", MagicNumber, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trade comment: ", TradeComment, 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, NL );
   
   
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Chart Rsi: ", RsiVal, ": Previous ", PrevRsiVal, ": Direction is ", RsiDirection, NL);
   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Rsi moving average: ", MaVal, ": Previous ", PrevMaVal, ": Direction is ", MaDirection, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Rsi: ", RsiVal, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Rsi moving average: ", MaVal, NL);
   string info;
   //if (!UseHtfRsi) info = " (for information only - not used in trading decision)"; 
   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trend Rsi: ", TrendRsiVal, ": Trend is ", HtfRsiTrend, info, NL);
   //if (UseChartSma) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Chart Sma: ", ChartSmaVal, NL);
      

   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);

   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----


   //Accommodate different quote sizes
   double multiplier;
   if(Digits == 2 || Digits == 4) multiplier = 1;
   if(Digits == 3 || Digits == 5) multiplier = 10;
   if(Digits == 6) multiplier = 100;   
   TakeProfit*= multiplier;
   StopLoss*= multiplier;
   
   
   if (TradeComment == "") TradeComment = " ";

   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   
   start();
   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
//----
   return(0);
}

bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
{
   
   
   int slippage = 0;
   //if (Digits == 3 || Digits == 5) slippage = 20;
   
   color col = Red;
   if (type == OP_BUY || type == OP_BUYSTOP) col = Green;
   
   int expiry = 0;
   //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);
   
   
      
   
   if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   
   
   //Is a 2 stage criminal
   if (CriminalIsECN)
   {
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col);
	   if (ticket > -1)
      {
         if (stop >0 && take > 0) bool result = OrderModify(OrderTicket(), OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE);
         //Stop loss but no take profit
         if (stop >0 && take == 0) result = OrderModify(OrderTicket(), OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
         //Take profit but no stop loss
         if (stop ==0 && take > 0) result = OrderModify(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE);
         if (!result)
         {
             int err=GetLastError();
             Print(Symbol(), " ", type," SL  order modify failed with error(",err,"): ",ErrorDescription(err));
         }//if (!result)			  
      }//if (ticket > -1)
      
   }//if (CriminalIsECN)
   
   //Error trapping for both
   if (ticket < 0)
   {
      string stype;
      if (type == OP_BUY) stype = "OP_BUY";
      if (type == OP_BUYSTOP) stype = "OP_BUYSTOP";
      if (type == OP_SELL) stype = "OP_SELL";
      if (type == OP_SELLSTOP) stype = "OP_SELLSTOP";
      err=GetLastError();
      //Alert(Symbol(), " ", stype," Nanningbob order send failed with error(",err,"): ",ErrorDescription(err));
      Print(Symbol(), " ", stype," #1 Buy Nanningbob order send failed with error(",err,"): ",ErrorDescription(err));
      return(false);
   }//if (ticket < 0)  
   
   if (ticket > 0) 
   {
      Comment("                 Sleeping after successful trade send");
      Sleep(60000 * 5);//5 mins sleep time to avoid multiple order-sends
   }//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()
{
   
   
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      
      if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
      {
         return(true);         
      }//if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   return(false);

}//End bool DoesTradeExist()

////////////////////////////////////////////////////////////////////////////////////////////////
//Indicator module


double GetRsi(int tf, int period, int ap, int shift)
{
   return(iRSI(NULL, tf, period, ap, shift) );
}//End double GetRsi(int tf, int period, int ap, int shift)

/*
void GetRsiDirection()
{

   if (RsiVal - PrevRsiVal < MinRsiMovement && MinRsiMovement > 0)
   {
      RsiDirection = none;
      return;  
   }//if (RsiVal - PrevRsiVal < MinRsiMovement)
   
   RsiDirection = up;
   double r = 0, pr = 0;//Rsi and prev Rsi 
   
   for (int cc = 0; cc < MaxBarsAgoForCross; cc++)
   {
      r = GetRsi(0, 8, PRICE_CLOSE, cc);
      pr = GetRsi(0, 8, PRICE_CLOSE, cc + 1);
      if (pr >= r) 
      {
         RsiDirection = none;
         return;
      }//if (pr >= r) 
         
   }//for (int cc = 0; cc <= MaxBarsAgoForCross; cc++)
   
 
}//void GetRsiDirection()
*/
double GetMa(int shift)
{
   
   //Returns the sma (3) of the Rsi(8)
   double RsiMa = iRSI(NULL, 0, RsiPeriod, PRICE_CLOSE, shift);
   for (int cc = 1 + shift; cc <= RsiMaPeriod + shift - 1; cc++)
   {
      double rv = iRSI(NULL, 0, RsiPeriod, PRICE_CLOSE, cc);
      RsiMa+= rv;   
   }//for (int cc = 1; cc <= 3; cc++)
   RsiMa/= RsiMaPeriod;
   
   return(RsiMa);

}//End double GetMa(int shift)

/*
void GetMaDirection()
{

   MaDirection = up;
   if (PrevMaVal >= MaVal) MaDirection = none;
   
   if (MaDirection == up) return;
   
   MaDirection = down;
   if (PrevMaVal <= MaVal) MaDirection = none;
   
}//void GetMaDirection()
*/
void GetLongCrossCandlesAgo()
{
   //Called when Rsi > Sma. Calculates how many candls ago the cross occured
   
   
   for (CrossCandlesAgo = 1; CrossCandlesAgo <= Bars; CrossCandlesAgo++)
   {
      double r = GetRsi(0, 8, PRICE_CLOSE, CrossCandlesAgo);
      double s = GetMa(CrossCandlesAgo);
      if (r < s) return;
      if (CrossCandlesAgo > MaxBarsAgoForCross) return;
   }//for (int cc = 0; cc <= Bars; cc++)   
}//void GetLongCrossCandlesAgo()

void GetShortCrossCandlesAgo()
{
   //Called when Rsi < Sma. Calculates how many candls ago the cross occured
   
   
   for (CrossCandlesAgo = 1; CrossCandlesAgo <= Bars; CrossCandlesAgo++)
   {
      double r = GetRsi(0, 8, PRICE_CLOSE, CrossCandlesAgo);
      double s = GetMa(CrossCandlesAgo);
      if (r > s) return;
      if (CrossCandlesAgo > MaxBarsAgoForCross) return;
   }//for (int cc = 0; cc <= Bars; cc++)   
}//void GetCrossCandlesAgo()


void ReadIndicatorValues()
{

   /*
   //Set htf Rsi trend
   TrendRsiVal = GetRsi(RsiTrendDeterminationTf, RsiTrendDeterminationPeriod, PRICE_CLOSE, 0);
   HtfRsiTrend = none;
   if (TrendRsiVal > 55) HtfRsiTrend = up;
   if (TrendRsiVal < 45) HtfRsiTrend = down;
   
   if (UseHtfRsi)
   {
      TradeLong = false;   
      TradeShort = false;
      if (HtfRsiTrend == up) TradeLong = true;
      if (HtfRsiTrend == down) TradeShort = true;
   }//if (UseHtfRsi)
   */
   
   //Rsi curent tf
   RsiVal = GetRsi(0, RsiPeriod, PRICE_CLOSE, 0);
   //PrevRsiVal = GetRsi(0, RsiPeriod, PRICE_CLOSE, MaxBarsAgoForCross);
   //GetRsiDirection();
   
   //Rsi MA
   MaVal = GetMa(0);
   //PrevMaVal = GetMa(MaxBarsAgoForCross);
   //GetMaDirection();
   
   //Chart sma
   //if (UseChartSma) ChartSmaVal = iMA(NULL, 0, ChartSmaPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
   
}//void ReadIndicatorValues()

//End Indicator module
////////////////////////////////////////////////////////////////////////////////////////////////

void LookForTradingOpportunities()
{

   RefreshRates();
      
   //Long
   //string OldTrendRsi = HtfRsiTrend;   
   //if (!UseHtfRsi) HtfRsiTrend = up;
   //if (HtfRsiTrend == up && RsiDirection == up && MaDirection == up && RsiVal >  MaVal && TradeLong)
   if (RsiVal > MaVal && TradeLong && RsiVal > 50 && MaVal > 50)
   { 
      //Daily price movement must be up
      //if (iClose(NULL, PERIOD_D1, 0) < iOpen(NULL, PERIOD_D1, 0) ) return;
      
      //Check the distance ago the cross occured
      GetLongCrossCandlesAgo();
      if (CrossCandlesAgo > MaxBarsAgoForCross) return;
      //if (UseChartSma && Ask < ChartSmaVal) return;
      bool result;
      double stop = 0, take = 0;
      if (StopLoss > 0) stop = NormalizeDouble(Ask - (StopLoss * Point), Digits);
      if (TakeProfit > 0) take = NormalizeDouble(Ask + (TakeProfit * Point), Digits);
      
      result = SendSingleTrade(OP_BUY, TradeComment, Lot, Ask, stop, take);
      
   }//if (RsiVal > MaVal && TradeLong && RsiVal > 50 && MaVal > 50)
   //HtfRsiTrend = OldTrendRsi;   

   //Short
   //OldTrendRsi = HtfRsiTrend;
   //if (!UseHtfRsi) HtfRsiTrend = down;
   //if (HtfRsiTrend == down && RsiDirection == down && MaDirection == down && RsiVal < MaVal && TradeShort)
   if (RsiVal < MaVal && TradeShort && RsiVal < 50 && MaVal < 50)
   { 
      //Check the distance ago the cross occured
      //Daily price movement must be up
      //if (iClose(NULL, PERIOD_D1, 0) > iOpen(NULL, PERIOD_D1, 0) ) return;
      
      GetShortCrossCandlesAgo();
      if (CrossCandlesAgo > MaxBarsAgoForCross) return;
      //if (UseChartSma && Bid > ChartSmaVal) return;
      
      stop = 0;
      take = 0;
      if (StopLoss > 0) stop = NormalizeDouble(Bid + (StopLoss * Point), Digits);
      if (TakeProfit > 0) take = NormalizeDouble(Bid - (TakeProfit * Point), Digits);
      
      result = SendSingleTrade(OP_SELL, TradeComment, Lot, Bid, stop, take);
      
   }//if (D1RsiTrend == down && RsiDirection == down && MaDirection == down && RsiVal < MaVal)
      
   //HtfRsiTrend = OldTrendRsi;
   

}//End void LookForTradingOpportunities()

bool CheckTradingTimes()
{
   int hour = TimeHour(TimeLocal() );
   
   if (end_hourm < start_hourm)
	{
		end_hourm += 24;
	}
	

	if (end_houre < start_houre)
	{
		end_houre += 24;
	}
	
	bool ok2Trade = true;
	
	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))
   {      
      ok2Trade = false;
   }//if (hour >= MathMax(end_hourm, end_houre))

   return(ok2Trade);

}//bool CheckTradingTimes()


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
   
   if (RobotSuspended)
   {
      Comment("......................This robot is suspended.................");
      return;
   }//if (RobotSuspended)
   
   ///////////////////////////////////////////////////////////////////////////////////////////////

   //Trading times
   bool TradeTimeOk = CheckTradingTimes();
   if (!TradeTimeOk)
   {
      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 (DoesTradeExist()) 
   {
      DisplayUserFeedback();
      return;
   }//if (DoesTradeExist()) 

   
   ReadIndicatorValues();   
 
   LookForTradingOpportunities();

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+