//+------------------------------------------------------------------+
//|                                               The Holy Grail.mq4 |
//|              Copyright © 2009, Mark Johnson. All rights reserved |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+

#property show_inputs
#include <WinUser32.mqh>
#include <stdlib.mqh>

//+------------------------------------------------------------------+
//| expert External variables                                        |
//+------------------------------------------------------------------+

extern int    Magic  = 3997265;
extern string Key    = "SC";
extern int    Rsi    = 3;
extern bool   CriminalIsECN=false;
extern double LotSize=0;
extern int    take=25;
extern int    stop=100;
extern int    MaxTradesAllowed=5;
extern bool   UseTpAtr=true;
extern double AtrPeriod=14;
extern int    AtrTpMultiplier=1;
extern string hrd="D1=1440: W1=10080: MN=40320";
extern int    AtrTpTf=240;
extern bool   UseSlAtr=true;
extern int    AtrSlMultiplier=1;
extern int    AtrSlTf=1440;
extern bool   EaManagesTrades=true;
extern int    Bep=50;
extern int    GMTShift = -5;

//+------------------------------------------------------------------+
//| expert Internal variables                                        |
//+------------------------------------------------------------------+


string Pairs[] = {"AUDCAD","AUDCHF","AUDJPY","AUDNZD","AUDUSD",
                  "CADCHF","CADJPY","CHFJPY","EURAUD","EURCAD",
                  "EURCHF","EURGBP","EURJPY","EURNZD","EURUSD",
                  "GBPAUD","GBPCAD","GBPCHF","GBPJPY","GBPUSD",
                  "NZDCAD","NZDCHF","NZDJPY","NZDUSD","SGDJPY",
                  "USDCAD","USDCHF","USDDKK","USDHKD","USDNOK",
                  "USDSEK","USDSGD","USDJPY"};


string Author  = "Copyright © 2009, Mark Johnson. All rights reserved.";
string Suffix;
int    Step;
int    M01, M05, M15, H01, H04, D01;
int    OpenTrades, TicketNo;

int OB = 80;
int ML = 50;
int OS = 20;

int Decimals;


//+------------------------------------------------------------------+
//| expert Initialization function                                   |
//+------------------------------------------------------------------+

int init()
  {

    Suffix = StringSubstr(Symbol(),6,StringLen(Symbol())-6);

    for(int a = 0; a < ArraySize(Pairs); a++)
      {
        Pairs[a] = Pairs[a] + Suffix;
      }
      
    if(MarketInfo(Symbol(),MODE_LOTSTEP) == 0.01) Step = 2;
    if(MarketInfo(Symbol(),MODE_LOTSTEP) == 0.10) Step = 1;
    if(MarketInfo(Symbol(),MODE_LOTSTEP) == 1.00) Step = 0;

    M01 = PERIOD_M1;
    M05 = PERIOD_M5;
    M15 = PERIOD_M15;
    H01 = PERIOD_H1;
    H04 = PERIOD_H4;
    D01 = PERIOD_D1;

    Comment("\nWaiting for tick update...");

   double digits = MarketInfo(Symbol(), MODE_DIGITS);
   if (digits == 3 || digits == 5)
   {
      Bep/= 50;
   }//if (digits == 3 || digits == 5)
   

    return(0);
    
  }
  
//+------------------------------------------------------------------+
//| expert Deinitialization function                                 |
//+------------------------------------------------------------------+

int deinit()
  {

    Comment("");
    
    return(0);

  }
  
//+------------------------------------------------------------------+
//| expert Start function                                            |
//+------------------------------------------------------------------+

int start()
  {
    
    double Lots = NormalizeDouble(AccountBalance()/60000,Decimals);
    double Min  = MarketInfo(Symbol(),MODE_MINLOT);
    double Max  = MarketInfo(Symbol(),MODE_MAXLOT);

    if(Lots < Min) Lots = Min;
    if(Lots > Max) Lots = Max;

    string Status = "Trading enabled...";
    
    int gmtHH = TimeHour(TimeLocal());
    
    if(GMTShift < 0) gmtHH = gmtHH - MathAbs(GMTShift);
    if(GMTShift > 0) gmtHH = gmtHH + MathAbs(GMTShift);
    
    if((TimeDayOfWeek(TimeLocal()) == 5 && TimeHour(TimeLocal()) > 12) || (TimeDayOfWeek(TimeLocal()) == 0 && TimeHour(TimeLocal()) < 23) || TimeDayOfWeek(TimeLocal()) == 6
    || NewsExist() == true)
      {
        Status = "Trading disabled...";
      }
    
    Comment("\n",Author,"\n\n",Status,"\n\n","Lots = ",DoubleToStr(Lots,2));

    if(StringFind(Status,"disabled",0) > 0)
      {
        return(0);
      }

    for(int b = 0; b < ArraySize(Pairs); b++)
      {
        
        bool PairExists = DoesPairExist(Pairs[b] );
        if (!PairExists) continue;
        
        //Open trade management
        if(TradeExist(Pairs[b]) && EaManagesTrades)
        {
            ManageTrade();
        }//if(TradeExist(Pairs[b])
        if(OrdersTotal() == 6)
          {
            break;
          }

        if(MarketInfo(Pairs[b],MODE_BID) > 0 && MarketInfo(Pairs[b],MODE_ASK) > 0)
          {      
            
            int Rsi = 2;

            if((StringSubstr(Pairs[b],0,3) == "AUD" && (gmtHH >= 22 || gmtHH < 06)) || 
               (StringSubstr(Pairs[b],3,3) == "AUD" && (gmtHH >= 22 || gmtHH < 06)) ||
               (StringSubstr(Pairs[b],0,3) == "CAD" && (gmtHH >= 13 && gmtHH < 21)) || 
               (StringSubstr(Pairs[b],3,3) == "CAD" && (gmtHH >= 13 && gmtHH < 21)) ||
               (StringSubstr(Pairs[b],0,3) == "CHF" && (gmtHH >= 07 && gmtHH < 15)) || 
               (StringSubstr(Pairs[b],3,3) == "CHF" && (gmtHH >= 07 && gmtHH < 15)) ||
               (StringSubstr(Pairs[b],0,3) == "EUR" && (gmtHH >= 07 && gmtHH < 15)) || 
               (StringSubstr(Pairs[b],3,3) == "EUR" && (gmtHH >= 07 && gmtHH < 15)) ||
               (StringSubstr(Pairs[b],0,3) == "GBP" && (gmtHH >= 08 && gmtHH < 16)) || 
               (StringSubstr(Pairs[b],3,3) == "GBP" && (gmtHH >= 08 && gmtHH < 16)) ||
               (StringSubstr(Pairs[b],0,3) == "JPY" && (gmtHH >= 24 || gmtHH < 08)) || 
               (StringSubstr(Pairs[b],3,3) == "JPY" && (gmtHH >= 24 || gmtHH < 08)) ||
               (StringSubstr(Pairs[b],0,3) == "NZD" && (gmtHH >= 22 || gmtHH < 06)) || 
               (StringSubstr(Pairs[b],3,3) == "NZD" && (gmtHH >= 22 || gmtHH < 06)) ||
               (StringSubstr(Pairs[b],0,3) == "USD" && (gmtHH >= 13 && gmtHH < 21)) ||
               (StringSubstr(Pairs[b],3,3) == "USD" && (gmtHH >= 13 && gmtHH < 21)))  
              {
                Rsi = 3;
              }            

            double RSI_M05 = iRSI(Pairs[b],M05,Rsi,PRICE_CLOSE,0);
            double RSI_M15 = iRSI(Pairs[b],M15,Rsi,PRICE_CLOSE,0);
            double RSI_H01 = iRSI(Pairs[b],H01,Rsi,PRICE_CLOSE,0);
            double RSI_H04 = iRSI(Pairs[b],H04,Rsi,PRICE_CLOSE,0);

            if(Trend(Pairs[b],M15) == "U" && Trend(Pairs[b],H01) == "U" &&
               Trend(Pairs[b],H04) == "U" && Trend(Pairs[b],D01) == "U")
              {
                if(RSI_M05 > OS && RSI_M15 < OS && RSI_H01 < OS && RSI_H04 < OS)
                  {
                    if(TradeExist(Pairs[b]) == false)
                      {
                        if(IsTradeAllowed() == true) SendOrder(Pairs[b],OP_BUY,Lots);
                      }
                  }
              }
               
            if(Trend(Pairs[b],M15) == "D" && Trend(Pairs[b],H01) == "D" && 
               Trend(Pairs[b],H04) == "D" && Trend(Pairs[b],D01) == "D")
              {
                if(RSI_M05 < OB && RSI_M15 > OB && RSI_H01 > OB && RSI_H04 > OB)
                  {
                    if(TradeExist(Pairs[b]) == false)
                      {
                        if(IsTradeAllowed() == true) SendOrder(Pairs[b],OP_SELL,Lots);
                      }
                  }
              }
              
          }
      
      }
      
    return(0);

  }


//+------------------------------------------------------------------+
//| expert TradeExists function                                      |
//+------------------------------------------------------------------+

bool TradeExist(string symbol)
  {

    bool Found = false;
    OpenTrades=0;

    for(int c = 0; c <= OrdersTotal(); c++)
      {
        if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES) == true)
          {
            if(OrderSymbol() == symbol && OrderMagicNumber() == Magic)
              {
                Found = true;
                TicketNo = OrderTicket();
                break;
              }//if(OrderSymbol() == symbol && OrderMagicNumber() == Magic)
            if (OrderMagicNumber() == Magic) OpenTrades++;
          }
      }

    return(Found);

  }

//+------------------------------------------------------------------+
//| expert SendOrder function                                        |
//+------------------------------------------------------------------+  

void SendOrder(string symbol, int dir, double lots)
  {
    
    double price;
    double point;
    double sl;
    double tp;

    int ticket = -1;
    int spread = 10;
    int digit  = MarketInfo(symbol,MODE_DIGITS);            
    
        
    if(digit == 3 || digit == 5)
      {
        spread *= 10;
        take   *= 10;
        stop   *= 10;
      }
    
    if(dir == OP_BUY && iClose(symbol,0,0) > 0 && MarketInfo(symbol,MODE_SPREAD) <= spread)
      {
        while(ticket < 0)
          {
            RefreshRates();
            price  = MarketInfo(symbol,MODE_ASK);
            point  = MarketInfo(symbol,MODE_POINT);
            sl     = NormalizeDouble(price-stop*point,digit);
            if (UseSlAtr) sl = CalculateStopLoss(symbol, 0, price);            
            tp     = NormalizeDouble(price+take*point,digit);
            if (UseTpAtr) tp = CalculateTakeProfit(symbol, 0, price);            
            if (!CriminalIsECN) ticket = OrderSend(symbol,dir,lots,price,3,sl,tp,Key,Magic,0,CLR_NONE);
            if (CriminalIsECN) ticket = OrderSend(symbol,dir,lots,price,3,0,0,Key,Magic,0,CLR_NONE);
            Sleep(10);
          }
          if (CriminalIsECN)
            {
               OrderSelect(ticket, SELECT_BY_TICKET);
               bool result = OrderModify(ticket, OrderOpenPrice(),	sl, tp, OrderExpiration(), CLR_NONE);
			      if (!result)
			      {
			          int err=GetLastError();
                   Alert(Symbol(), " Buy TP order modify failed with error(",err,"): ",ErrorDescription(err));
			      }//if (!result)
            }
      }
      
    if(dir == OP_SELL && iClose(symbol,0,0) > 0 && MarketInfo(symbol,MODE_SPREAD) <= spread)
      {
        while(ticket < 0)
          {
            RefreshRates();
            price  = MarketInfo(symbol,MODE_BID);
            point  = MarketInfo(symbol,MODE_POINT);
            sl     = NormalizeDouble(price+stop*point,digit);
            if (UseSlAtr) sl = CalculateStopLoss(symbol, 1, price);
            tp     = NormalizeDouble(price-take*point,digit);
            if (UseTpAtr) tp = CalculateTakeProfit(symbol, 1, price);            
            if (!CriminalIsECN) ticket = OrderSend(symbol,dir,lots,price,3,sl,tp,Key,Magic,0,CLR_NONE);
            if (CriminalIsECN) ticket = OrderSend(symbol,dir,lots,price,3,0,0,Key,Magic,0,CLR_NONE);
            Sleep(10);
          }
          
         //Error trapping for both   
         if (ticket < 0)
         {
            err=GetLastError();
            Alert("Scoobs EMA RSI ", symbol, " ", dir," order send failed with error(",err,"): ",ErrorDescription(err) );
            Print("Order send failed with error(",err,"): ",ErrorDescription(err));
            if (err == 146) Sleep(1000);//Trade context busy error, so sleep 1 second to give it a break         
         }//if (ticket < 0)

          
          if (CriminalIsECN)
            {
               OrderSelect(ticket, SELECT_BY_TICKET);
               result = OrderModify(ticket, OrderOpenPrice(),	sl, tp, OrderExpiration(), CLR_NONE);
			      if (!result)
			      {
			          err=GetLastError();
                   Alert(Symbol(), " Sell TP order modify failed with error(",err,"): ",ErrorDescription(err));
			      }//if (!result)
            }
      }
  
  }
  
//+------------------------------------------------------------------+
//| expert News function                                             |
//+------------------------------------------------------------------+  

/*
bool NewsExist(string symbol)
  {
  
    string NewsPairs[5];
    int    MinutesSincePrevEvent;
    int    MinutesUntilNextEvent;
    bool   News;

    NewsPairs[0] = "EURUSD" + Suffix;
    NewsPairs[1] = "USDJPY" + Suffix;
    NewsPairs[2] = "GBPUSD" + Suffix;
    NewsPairs[3] = "USDCHF" + Suffix;
    NewsPairs[4] = symbol;
    
    for(int d = 0; d < ArraySize(NewsPairs); d++)
      {
        MinutesSincePrevEvent =
          iCustom(NULL, 0, "Economic News", NewsPairs[d], true, false, false, true, true, 1, 0);

        MinutesUntilNextEvent =
          iCustom(NULL, 0, "Economic News", NewsPairs[d], true, false, false, true, true, 1, 1);

        if((MinutesUntilNextEvent <= 60) || 
           (MinutesSincePrevEvent <= 15))
          {
            News = true;
          }
      }
      
    return(News);

  }
 */
//+------------------------------------------------------------------+
//| expert News function |
//+------------------------------------------------------------------+ 

bool NewsExist()
{

string xmlFileName = Month()+"-"+Day()+"-"+Year()+"-"+Symbol()+Period()+"-"+"FFCal.xml";
bool News;

for(int d = 0; d < ArraySize(Pairs); d++)
{
int MinutesSincePrevEvent =
iCustom(NULL,0,"Economic News",Pairs[d],true,false,false,true,true,1,0);

int MinutesUntilNextEvent =
iCustom(NULL,0,"Economic News",Pairs[d],true,false,false,true,true,1,1);

if(MinutesUntilNextEvent < 60 ||
MinutesSincePrevEvent < 15)
{
News = true;
}
}

int handle = FileOpen(xmlFileName,FILE_BIN|FILE_READ|FILE_WRITE);

if(handle < 0)
{
News = true;
}

FileClose(handle);

return(News);

}

   
bool DoesPairExist(string symbol)
{
   if (MarketInfo(symbol, MODE_SPREAD) == 0 && MarketInfo(symbol, MODE_ASK) == 0 && MarketInfo(symbol, MODE_BID) == 0) return(false);
   return(true);

}


double CalculateTakeProfit(string symbol, int type, double price)
{
   
   // Calculate tp by getting ATR and using ADX to set the multiplier
   double AtrValue=iATR(symbol,AtrTpTf,AtrPeriod,0) * AtrTpMultiplier;
   
   double digits = MarketInfo(symbol, MODE_DIGITS);
   
   //Long trade
   if (type == 0)
   {
      return(NormalizeDouble(price + AtrValue, digits));
   }
   
   // Short 
   if (type == 1)
   {
      return(NormalizeDouble(price - AtrValue, digits));
   }

}

double CalculateStopLoss(string symbol, int type, double price)
{
   
   // Calculate tp by getting ATR and using ADX to set the multiplier
   double AtrValue=iATR(symbol,AtrSlTf,AtrPeriod,0) * AtrSlMultiplier;
   
   double digits = MarketInfo(symbol, MODE_DIGITS);
   
   //Long trade
   if (type == 0)
   {
      return(NormalizeDouble(price - AtrValue, digits));
   }
   
   // Short 
   if (type == 1)
   {
      return(NormalizeDouble(price + AtrValue, digits));
   }

}

void ManageTrade()
{
   OrderSelect(TicketNo, SELECT_BY_TICKET);
   if (OrderCloseTime() > 0) return;
   if (OrderProfit() <= 0) return;
   
   double digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
   double ask = MarketInfo(OrderSymbol(), MODE_ASK);
   double bid = MarketInfo(OrderSymbol(), MODE_BID);
   double point = MarketInfo(OrderSymbol(), MODE_POINT);
   
   double AtrValue = iATR(OrderSymbol(),0,AtrPeriod,0) * (AtrTpMultiplier / 2);
   double BuyTarget = NormalizeDouble(OrderOpenPrice() + AtrValue, digits);
   double SellTarget = NormalizeDouble(OrderOpenPrice() - AtrValue, digits);
   
   
   if (OrderType() == 0 && ask >= BuyTarget && OrderStopLoss() < OrderOpenPrice() )
   {
      double stop = NormalizeDouble(OrderOpenPrice() + (Bep * point), digits);
      if (stop - OrderOpenPrice() < MarketInfo(OrderSymbol(), MODE_STOPLEVEL) ) stop = OrderOpenPrice();
      bool result = OrderModify(TicketNo, OrderOpenPrice(),	stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
      if (!result)
      {
          int err=GetLastError();
          Alert(OrderSymbol(), " Scoobs 20 EMA Buy SL order modify failed with error(",err,"): ",ErrorDescription(err));
      }//if (!result)
   
   }//if (OrderType() == 0)
   
   if (OrderType() == 1 && bid <= SellTarget && OrderStopLoss() > OrderOpenPrice() )
   {
      stop = NormalizeDouble(OrderOpenPrice() - (Bep * point), digits);
      if (OrderOpenPrice() - stop < MarketInfo(OrderSymbol(), MODE_STOPLEVEL) ) stop = OrderOpenPrice();
      result = OrderModify(TicketNo, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
      if (!result)
      {
          err=GetLastError();
          Alert(OrderSymbol(), " Scoobs 20 EMA Sell SL order modify failed with error(",err,"): ",ErrorDescription(err));
      }//if (!result)
   
   }//if (OrderType() == 1 && bid <= BuyTarget && OrderStopLoss() > OrderOpenPrice() )
   

}//void ManageTrade()


string Trend(string symbol, int tf)
  {
  
    string Pair_Trend = "F"; // Flat
    
    double EMA_020 = iMA(symbol,tf,020,0,MODE_EMA,PRICE_CLOSE,0);
    double EMA_200 = iMA(symbol,tf,200,0,MODE_EMA,PRICE_CLOSE,0);
    
    if(EMA_020 < EMA_200)
      {
        Pair_Trend = "D"; // Down
      }

    if(EMA_020 > EMA_200)
      {
        Pair_Trend = "U"; // Up
      }
       
    return(Pair_Trend);
  
  }