//+------------------------------------------------------------------+
//|                                          The Holy Grail v1.4.mq4 |
//|              Copyright © 2009, Mark Johnson. All rights reserved |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+

#property show_inputs

//+------------------------------------------------------------------+
//| expert External variables                                        |
//+------------------------------------------------------------------+

extern int    Magic = 1801;
extern string Key   = "This is for myfxbook authorization key";

//+------------------------------------------------------------------+
//| expert Internal variables                                        |
//+------------------------------------------------------------------+

string Pairs[] = {"AUDJPY","AUDUSD","CADJPY","CHFJPY","EURAUD",
                  "EURCAD","EURCHF","EURGBP","EURJPY","EURUSD",
                  "GBPJPY","GBPUSD","USDCAD","USDCHF","USDJPY"};

string Author  = "Copyright © 2009, Mark Johnson. All rights reserved.";

int M05 = PERIOD_M5;
int M15 = PERIOD_M15;
int H01 = PERIOD_H1;
int H04 = PERIOD_H4;
int D01 = PERIOD_D1;

int OB = 80;
int ML = 50;
int OS = 20;

int Decimals;

//+------------------------------------------------------------------+
//| expert Initialization function                                   |
//+------------------------------------------------------------------+

int init()
  {

    string Suffix = StringSubstr(Symbol(),6,StringLen(Symbol())-6);

    for(int a = 0; a < ArraySize(Pairs); a++)
      {
        Pairs[a] = Pairs[a] + Suffix;
      }
    
    double Step = MarketInfo(Symbol(),MODE_LOTSTEP);

    if(Step == 0.01) Decimals = 2;
    if(Step == 0.10) Decimals = 1;
    if(Step == 1.00) Decimals = 0;

    if(Magic == 0) Magic = AccountNumber();
    
    Comment("\nWaiting for tick update...");

    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((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++)
      {

        if(OrdersTotal() == 6)
          {
            break;
          }
        
        if(MarketInfo(Pairs[b],MODE_BID) > 0 && MarketInfo(Pairs[b],MODE_ASK) > 0)
          {      
            
            int Rsi = 2;

            if((StringFind(Pairs[b],"AUD",0) > 0 && gmtHH >= 22 || gmtHH < 06) || 
               (StringFind(Pairs[b],"CAD",0) > 0 && gmtHH >= 13 && gmtHH < 21) || 
               (StringFind(Pairs[b],"CHF",0) > 0 && gmtHH >= 07 && gmtHH < 15) || 
               (StringFind(Pairs[b],"EUR",0) > 0 && gmtHH >= 07 && gmtHH < 15) || 
               (StringFind(Pairs[b],"GBP",0) > 0 && gmtHH >= 08 && gmtHH < 16) || 
               (StringFind(Pairs[b],"JPY",0) > 0 && gmtHH >= 24 || gmtHH < 08) || 
               (StringFind(Pairs[b],"NZD",0) > 0 && gmtHH >= 22 || gmtHH < 06) || 
               (StringFind(Pairs[b],"USD",0) > 0 && 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 > ML && 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 < ML && 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;

    for(int c = 0; c <= OrdersTotal(); c++)
      {
        if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES) == true)
          {
            if(OrderSymbol() == symbol && OrderMagicNumber() == Magic)
              {
                Found = true;
                break;
              }
          }
      }
    
    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  = 0;
    int take   = 40;
    int stop   = 100;
        
    if(MarketInfo(symbol,MODE_DIGITS) == 3 || MarketInfo(symbol,MODE_DIGITS) == 5)
      {
        spread *= 10;
        take   *= 10;
        stop   *= 10;
      }
    
    if(dir == OP_BUY && MarketInfo(symbol,MODE_SPREAD) <= spread)
      {
        while(ticket < 0)
          {
            RefreshRates();
            price  = MarketInfo(symbol,MODE_ASK);
            point  = MarketInfo(symbol,MODE_POINT);
            digit  = MarketInfo(symbol,MODE_DIGITS);
            sl     = NormalizeDouble(price-stop*point,digit);
            tp     = NormalizeDouble(price+take*point,digit);
            ticket = OrderSend(symbol,dir,lots,price,3,sl,tp,Key,Magic,0,CLR_NONE);
            Sleep(1000);
          }
      }
      
    if(dir == OP_SELL && MarketInfo(symbol,MODE_SPREAD) <= spread)
      {
        while(ticket < 0)
          {
            RefreshRates();
            price  = MarketInfo(symbol,MODE_BID);
            point  = MarketInfo(symbol,MODE_POINT);
            digit  = MarketInfo(symbol,MODE_DIGITS);
            sl     = NormalizeDouble(price+stop*point,digit);
            tp     = NormalizeDouble(price-take*point,digit);
            ticket = OrderSend(symbol,dir,lots,price,3,sl,tp,Key,Magic,0,CLR_NONE);
            Sleep(1000);
          }
      }
  
  }

//+------------------------------------------------------------------+
//| expert News function                                             |
//+------------------------------------------------------------------+  

bool NewsExist()
  {
  
    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;
          }
      }
      
    return(News);

  }

//+------------------------------------------------------------------+
//| expert Trend function                                            |
//+------------------------------------------------------------------+  

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);
  
  }
       