#property show_inputs

extern int Magic  = 64201;

extern int ATRrange=3;
extern double PercentOfADRtp=25;
extern double PercentOfADRsl=75;
extern double PercentOfAccountRisk=1.0;


extern bool useRSItable=true;
extern int LocalGMTOffset=1;
extern int baseRSIrange=2;
extern bool printDebug=false;

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"};


double ADR[];
//string Author  = "Copyright © 2009, Mark Johnson. All rights reserved.";
string Suffix;
int    Step;
int    M01, M05, M15, H01, H04, D01;
 
int init()
{
   Suffix = StringSubstr(Symbol(),6,StringLen(Symbol())-6);
   
   
   ArrayResize(ADR,ArraySize(Pairs));
   for(int a = 0; a < ArraySize(Pairs); a++)
   {
      Pairs[a] = Pairs[a] + Suffix;
      ADR[a] = iATR(Pairs[a],PERIOD_D1,ATRrange,1); //set initial ADR for display so we don't recalculate them at each tick
   }
   

   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...");

    return(0);

}
 

int deinit()
{
   Comment("");
   return(0);
}

int start()
{
   string pScore;
   string PairStat = "\nv23\nRSI  DIR  TRG\n";
   double ticksize; 
   for(int b = 0; b < ArraySize(Pairs); b++)
   {
      ticksize = MarketInfo(Pairs[b],MODE_TICKSIZE);
      
      //if pair does not exist on broker, skip to the next one
      while(ticksize==0.0)
      {
         b++;
         ticksize = MarketInfo(Pairs[b],MODE_TICKSIZE);
      }
      
      
      // set variables
      int Rsi = rsiTable(Pairs[b],LocalGMTOffset);
      double EMA_020 = iMA(Pairs[b],H01,020,0,MODE_EMA,PRICE_CLOSE,0);
      double EMA_200 = iMA(Pairs[b],H04,200,0,MODE_EMA,PRICE_CLOSE,0);
      double RSI_H04 = iRSI(Pairs[b],H04,Rsi,PRICE_CLOSE,0);
      double RSI_H01 = iRSI(Pairs[b],H01,Rsi,PRICE_CLOSE,0);
      double RSI_M15 = iRSI(Pairs[b],M15,Rsi,PRICE_CLOSE,0);
      double RSI_M05 = iRSI(Pairs[b],M05,Rsi,PRICE_CLOSE,0);
      
     // calculate display data
      if(EMA_020 > EMA_200)
      {
         pScore = "B   ";
         if (RSI_M15 < 20) pScore = StringConcatenate(pScore,"L");
         if (RSI_H01 < 20) pScore = StringConcatenate(pScore,"M");
         if (RSI_H04 < 20) pScore = StringConcatenate(pScore,"H");
      }
      if(EMA_020 < EMA_200)
      {
         pScore = "S   ";
         if (RSI_M15 > 80) pScore = StringConcatenate(pScore,"L");
         if (RSI_H01 > 80) pScore = StringConcatenate(pScore,"M");
         if (RSI_H04 > 80) pScore = StringConcatenate(pScore,"H");
      }
      for(int c = 0; c < 11 - StringLen(pScore); c++) pScore = StringConcatenate(pScore," ");    
      PairStat = StringConcatenate(PairStat,"  ", Rsi,"      ",pScore," ", Pairs[b],"  (",DoubleToStr(ADR[b]*MathPow(ticksize,-1),0),")\n");

      //check for trade
      if(TimeDayOfWeek(TimeLocal()) < 5 || (TimeDayOfWeek(TimeLocal()) == 5 && TimeHour(TimeLocal()) < 11) )
      {
         if(EMA_020 > EMA_200 && RSI_M05 > 20 && RSI_M15 < 20 && RSI_H01 < 20 && RSI_H04 < 20)
         {
            if(TradeExist(Pairs[b]) == false && NewsExist(Pairs[b]) == false && IsTradeAllowed() == true) SendOrder(b,OP_BUY, Rsi);
         }

         if(EMA_020 < EMA_200 && RSI_M05 < 80 && RSI_M15 > 80 && RSI_H01 > 80 && RSI_H04 > 80)
         {
            if(TradeExist(Pairs[b]) == false && NewsExist(Pairs[b]) == false && IsTradeAllowed() == true) SendOrder(b,OP_SELL, Rsi);
         }
      }   
   }
   
   if(TimeDayOfWeek(TimeLocal()) == 5 && TimeHour(TimeLocal()) >= 11)
   {
      PairStat = StringConcatenate("\nOutside Trading Hours\n", PairStat);
   }
   Comment(PairStat);

    return(0);
}


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;
         }
      }
   }
   return(Found);
}


void SendOrder(int ind, int dir, int Rsi)
{
   double price;
   double sl, tp, take, stop;
   int ticket = -1;
   int spread = 10;
   int digit  = MarketInfo(Pairs[ind],MODE_DIGITS);   
   double value = MarketInfo(Pairs[ind],MODE_TICKVALUE);       
   double point  = MarketInfo(Pairs[ind],MODE_POINT);
   ADR[ind] = iATR(Pairs[ind],PERIOD_D1,ATRrange,1) ;
   if(digit == 3 || digit == 5) spread *= 10;
   take = ADR[ind]*(PercentOfADRtp/100);
   stop = ADR[ind]*(PercentOfADRsl/100);
   
   if (printDebug) Print (Pairs[ind]," dir: ", dir, " rsi: ", Rsi, " adr: ", DoubleToStr(ADR[ind],5)," take: ", DoubleToStr(take,5)," stop: ", DoubleToStr(stop,5), " point: ", DoubleToStr(point,5), " value: ", DoubleToStr(value,5));
   double lots = NormalizeDouble((AccountBalance()*PercentOfAccountRisk/100)/((stop / point) * value), Step) ;
   if (printDebug) Print (lots);
   
   if(dir == OP_BUY && iClose(Pairs[ind],0,0) > 0 && MarketInfo(Pairs[ind],MODE_SPREAD) <= spread)
   {
      while(ticket < 0)
      {
         RefreshRates();
         price  = MarketInfo(Pairs[ind],MODE_ASK);
         point  = MarketInfo(Pairs[ind],MODE_POINT);
         sl     = NormalizeDouble(price-stop,digit);
         tp     = NormalizeDouble(price+take,digit);
         ticket = OrderSend(Pairs[ind],dir,lots,price,3,sl,tp,StringConcatenate("ZS200-20 R: ", Rsi," A: ", ADR[ind]),Magic,0,CLR_NONE);
         Sleep(10);
      }
   }

   if(dir == OP_SELL && iClose(Pairs[ind],0,0) > 0 && MarketInfo(Pairs[ind],MODE_SPREAD) <= spread)
   {
      while(ticket < 0)
      {
         RefreshRates();
         price  = MarketInfo(Pairs[ind],MODE_BID);
         sl     = NormalizeDouble(price+stop,digit);
         tp     = NormalizeDouble(price-take,digit);
         ticket = OrderSend(Pairs[ind],dir,lots,price,3,sl,tp,StringConcatenate("ZS200-20 R:", Rsi," A:", ADR[ind]),Magic,0,CLR_NONE);
         Sleep(10);
      }
   }
}


bool NewsExist(string symbol)
{
   int    MinutesSincePrevEvent;
   int    MinutesUntilNextEvent;
   bool   News;
   MinutesSincePrevEvent = iCustom(NULL, 0, "Economic News", symbol, true, false, false, true, true, 1, 0);
   MinutesUntilNextEvent = iCustom(NULL, 0, "Economic News", symbol, true, false, false, true, true, 1, 1);
   if((MinutesUntilNextEvent <= 60) || (MinutesSincePrevEvent <= 15)) News = true;
   return(News);
}

int rsiTable(string pr, int GMToffset)
{
   if (!useRSItable) return(baseRSIrange); 
   string curr[2];
   int calcRSI = baseRSIrange;
   curr[0] = StringSubstr(pr,0,3);
   curr[1] = StringSubstr(pr,3,3);
   int gmtHR = TimeHour(TimeLocal()) - GMToffset;
   if (gmtHR > 23) gmtHR = gmtHR - 24;
   if (gmtHR < 0) gmtHR = gmtHR + 24;


   // start hours have been set -1 to market opening hours since the corresponding pairs start being active then
   for(int i=0; i<2;i++)
   {
      if( (curr[i] == "AUD" || curr[i] == "NZD") && (gmtHR >= 21 || gmtHR <=6) ) calcRSI++;
      if( (curr[i] == "JPY") && (gmtHR >= 23 || gmtHR <=8) ) calcRSI++;
      if( (curr[i] == "EUR" || curr[i] == "GBP" || curr[i] == "CHF") && (gmtHR >= 7 && gmtHR <=16) ) calcRSI++;
      if( (curr[i] == "USD" || curr[i] == "CAD") && (gmtHR >= 12 && gmtHR <=20) ) calcRSI++; 
   }
return (calcRSI);
}