//+------------------------------------------------------------------+
//|                                               RichBoy1972mED.mq4 |
//|                                  Copyright © 2009, Massimo Greco |
//|                                       http://www.massimogreco.it |
//|                                                                  |
//+------------------------------------------------------------------+

   /*

   3) For Standard trade: LONG Do you place pending orders as follows:

       * EP1 = 1/2 position at close of 4H Candle (ending at 9.00PM EST) (plus) 2 PIPs + Spread
       * TP1 = EP (plus) 4H ATR on the signal candle
       * SL1 = EP (minus) 4H ATR on the signal candle

       * EP2= 1/2 position at close of 4H Candle (ending at 9.00PM EST) (plus) 2PIPs +Spread
       * TP2 = (Initially) :Open
       * SL2 = (Initially) same as SL1:

   (Once the price moves beyond TP1, move SL2 to EP2 and trail by top of the signal bar)

   4) For Standard trade, SHORT Do you place pending orders as follows:

       * EP1 = 1/2 position at close of 4H Candle (ending at 9.00PM EST) (minus) 2 PIPs (no Spread)
       * TP1 = EP (minus) 4H ATR on the signal candle
       * SL 1= EP (plus) 4H ATR on the signal candle

       * EP2 = 1/2 position at close of 4H Candle (ending at 9.00PM EST) (minus) 2 PIPs (no Spread )
       * TP2 = (Initially) :Open
       * SL2 = (Initially) same as SL1:

   (Once the price moves beyond ATR, move SL2 to EP2 and trail by bottom of the signal bar).

   */



#property copyright "Copyright © 2009, Massimo Greco"
#property link      "http://www.massimogreco.it"

string eaName                       = "RichBoy1972mED 4H ";

bool noLiveTrading                  = true;
datetime ExpirationDate             = D'2009.12.31';

//---- info parameters
extern string   infoVersion         = "-----------  VERSION INFO  -----------";
extern string   VersionNumber       = "0.0.2";
extern datetime VersionDate         = D'2009.07.22';
extern int      MagicNumber         = 91091;

//---- input parameters
extern string  infoMM               = "-----------  MM PARAMETERS -----------";
extern double  RiskPercent          = 3.0; 
extern int     MinAccountEquity     = 0;   
extern bool    UseFixedLotSize      = false;
extern double  FixedLotSizeToUse    = 0.00;
extern double  UserMinLotSize       = 0.01;
extern double  UserMaxLotSize       = 2.00;
extern string  infoBrokerSymbol     = "---------  SYMBOL PARAMETERS ---------";
extern string  SymbolSuffix         = "";
extern string  infoSymbolSuffix     = "If your broker use i.e. EURUSDm you have to set m. Otherwise leave blank";

//---- HEIKEN ASHI and ATR Settings
extern string  HA_ATR_Parameters    = "-----------  HEIKEN ASHI  -----------";
extern int     ATRPeriod            =  20;
extern int     MAMetod              =  2;
extern int     MAPeriod             =  6;
extern int     MAMetod2             =  3;
extern int     MAPeriod2            =  2;

extern string  commentParameter     = "---------- COMMENT PARAMETERS -------";
extern bool    showComment          = true;
extern color   labelCommentColor    = Black;
extern int     labelCorner          = 3;
extern int     labelPosX            = 5;
extern int     labelPosY            = 10;
extern int     labelFontSize        = 8;

string labelComment = "RichBoyComment";

extern string  TimeParameters       = "----------- TIME PARAMETERS ---------";
extern bool    UseTimeControl       =  false;
extern int     StartTradingHour     =  8;
extern int     EndTradingHour       =  23;

//---- Alerts
extern string  AlertsSection        = "-----------     ALERTS     -----------";
extern bool    MailEnabled          =  false;
extern bool    AlertEnabled         =  false;
extern bool    SoundEnabled         =  false;
extern string  AlertSound           = "alert.wav";
extern string  BuyStopSound         = "alert.wav";
extern string  SellStopSound        = "alert.wav";

//---- internal parameters

double moltiplicatore=1.0;

double internalStopLevel;
int    spread;
double confirmPips = 2;
double internalConfirmPips;
double minLots;
double maxLots;
double lotStep;
double lotSize;

bool buyCondition;
bool sellCondition;
string currentCondition;
 
datetime buysignaltime, sellsignaltime;
datetime candleOpeningTime;

double signalCandlePips;
double signalAtrPips;

//Number of retries for orders send, modify ecc 
int MAX_RETRY = 3;

int currentFixedOrderTicket;
int currentTrailingOrderTicket;
double currentTakeProfitPrice;

#define LONG 1
#define SHORT -1
#define FLAT 0

#define BLUE 1
#define RED -1

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+

int init(){
   
   int expectedDecimal = 4;
   if(StringFind(Symbol(),"JPY",0)>=0){
      //currency with JPY....
      expectedDecimal = 2;
   }
      
   if(Digits > expectedDecimal)
      moltiplicatore = MathPow(10.0,(Digits-expectedDecimal)); //So it will works even with 5 and 6 digits brokers

   //internalBreakEvenPips = BreakEvenPips * moltiplicatore * Point;
   
   internalStopLevel       = MarketInfo ( Symbol() , MODE_STOPLEVEL) * moltiplicatore * Point;   
   internalConfirmPips     = confirmPips * moltiplicatore * Point;
      
   minLots = MarketInfo(Symbol(), MODE_MINLOT);
   maxLots = MarketInfo(Symbol(), MODE_MAXLOT);
   lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   lotSize = MarketInfo(Symbol(), MODE_LOTSIZE);
   spread  = MarketInfo(Symbol(), MODE_SPREAD);      
   
   if(showComment){
      CreateLabel(labelComment, labelCommentColor, labelPosX, labelPosY);
      SetLabel("EA initialized. Spread points: " + spread , labelComment, labelCommentColor);
   }
   
   //Time frame must be set to 4H 
   if(Period()!=PERIOD_H4){
      SetShortLabel("EA developed for H4 TF", labelComment, OrangeRed);
   }

   currentFixedOrderTicket = 0;
   currentTrailingOrderTicket = 0;
   currentTakeProfitPrice = 0;
      
   return(0);
}

  
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit(){
   DeleteLabel(labelComment);   
   return(0);
}

//+------------------------------------------------------------------+
 //| expert start function                                            |
//+------------------------------------------------------------------+
int start(){
   if(IsExpired()){
      SetLabel("EA Expired. Contact the author for a new release.",labelComment, Red);
      return(0);
   }
   
   if(noLiveTrading && !IsDemo()){
      SetLabel("EA UNDER DEVELOPMENT. Only demo account.",labelComment, Red);
      return(0);
   }

   if(Period()!=PERIOD_H4){
      SetLabel("EA Stopped. Switch to H4 time frame.",labelComment, Red);
      return(0);
   }
      
   EvaluateBuyOrSellCondition();
      
   //Security...
   if(sellCondition && buyCondition){
      //System Crash???
      return(0);
   }


   if(buyCondition)
         ActivateAlertsWithSound(Symbol() + currentCondition, BuyStopSound);
   if(sellCondition)
         ActivateAlertsWithSound(Symbol() + currentCondition, SellStopSound);

   MoveTakeProfit();

   ManageNewStopOrder();   

   return(0);
  }
//+------------------------------------------------------------------+

int SignalCandle = 1;
int previousCandleColor = FLAT;

int getHAS()// return 1 is blue ;-1 is red
{
   double hasOpen, hasClose;
   
   hasOpen = iCustom(NULL,0,"Heiken_Ashi_Smoothed",MAMetod,MAPeriod,MAMetod2,MAPeriod2,1,SignalCandle) ;
   hasClose = iCustom(NULL,0,"Heiken_Ashi_Smoothed",MAMetod,MAPeriod,MAMetod2,MAPeriod2,0,SignalCandle) ;
   if (hasOpen < hasClose) return(SHORT); //Red
   if (hasOpen > hasClose) return(LONG);  //Blue
   return(FLAT); 
}

int getHA()
{
  
   double haOpen=iCustom(NULL,0,"Heiken_Ashi_Smoothed",MAMetod,MAPeriod,MAMetod2,MAPeriod2,2,SignalCandle);
   double haClose=iCustom(NULL,0,"Heiken_Ashi_Smoothed",MAMetod,MAPeriod,MAMetod2,MAPeriod2,3,SignalCandle);
   if (haOpen < haClose) return (LONG);  //up HA
   if (haOpen > haClose) return (SHORT); //down HA
   return(FLAT); 
}

double getCandlePips(){
   double lowValue = iLow(NULL,0,SignalCandle);
   double highValue= iHigh(NULL,0,SignalCandle);
   
   return (highValue - lowValue);      
}

void EvaluateBuyOrSellCondition(){
   signalCandlePips = 0.0;
   signalAtrPips = 0.0;

   if(candleOpeningTime == Time[0])
      return;
   
   candleOpeningTime = Time[0];
   
   buyCondition = false;
   sellCondition = false;

   int currentCandleColor = FLAT;
      
   if(getHAS()==SHORT && getHA()==SHORT){
      Print("Red candle...");
      currentCandleColor = RED;
   }
   if(getHAS()==LONG && getHA()==LONG){
      Print("Blue candle...");
      currentCandleColor = BLUE;
   }

   if(previousCandleColor == FLAT || currentCandleColor == FLAT){
      previousCandleColor = currentCandleColor;
      return;
   }

   if(previousCandleColor == currentCandleColor)
      return;
   
   //Cambio di trend.... analizzo ATR...
   double candlePips = getCandlePips();
   double atrValue = iATR(NULL,0,ATRPeriod,SignalCandle);

   //Tra il 50% e il 200% buon segnale
   double atr200 = 2.0 * atrValue;
   double atr50  = 0.5 * atrValue;
   
   if(candlePips < atr50) //Invalid signal
      return;
      
   if(candlePips > atr200){
      //TO DO
      //Manage retracement
      
      return;
   }   

   //If here then candlePips in 50%, 200% range --> GOOD SIGNAL
   signalCandlePips = candlePips;
   signalAtrPips = atrValue;
   
   SetLabel("SIGNAL TRIGGERED. Candle: " + NormalizeDouble(candlePips,5) + " ATR: " + NormalizeDouble(atrValue,5) ,labelComment, labelCommentColor);      

   currentCondition = "";
   if(currentCandleColor == BLUE ) 
   {
      buysignaltime = Time[0];
      buyCondition = True; 
      currentCondition = " BUY signal triggered.";
   }
   if(currentCandleColor == RED)
   {
      sellsignaltime = Time[0];
      sellCondition = True; 
      currentCondition = " SELL signal triggered.";
   }

}

void MoveTakeProfit(){
   //currentFixedOrderTicket;
   //currentTrailingOrderTicket;
   //currentTakeProfitPrice;

   double sl;
   
   if(OrderSelect(currentTrailingOrderTicket, SELECT_BY_TICKET)){
      if(OrderCloseTime()!=0) return;
      
      if(OrderType()==OP_SELL){
            if(Ask < currentTakeProfitPrice) {
              if(OrderStopLoss() > iLow(NULL,0,1) ) {
                sl = iLow(NULL,0,1);
                CustomOrderModify(OrderTicket(), OrderOpenPrice(), sl, 0, 0, DarkOrange);
              }
            }
       }         

      if(OrderType()==OP_BUY){
            if(Bid > currentTakeProfitPrice) {
              if(OrderStopLoss() < iHigh(NULL,0,1) ) {
                sl = iHigh(NULL,0,1);
                CustomOrderModify(OrderTicket(), OrderOpenPrice(), sl, 0, 0, DarkOrange);
              }
            }
       }         

   }
     
}

void CloseOrder(int option){
   for(int cnt=0;cnt<OrdersTotal();cnt++){
      if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
            if(OrderType()==option){
               double price = Ask;
               if(option == OP_BUY) price = Bid;
               if(option == OP_BUY || option == OP_SELL)
                  OrderClose(OrderTicket(),OrderLots(),price,3,CLR_NONE) ;
               else
                  OrderDelete(OrderTicket());   
            }   
      }         
   }

}

void ManageNewStopOrder(){

   if(MinAccountEquity >= AccountEquity() || !IsTimeControlOK())
      return;

   if(buyCondition && !BuyOrderOpened() ){
      CustomSendStopOrder(OP_BUYSTOP);
      if(SellOrderOpened()){
         CloseOrder(OP_SELL);
         CloseOrder(OP_SELLSTOP);
      }
   }
         
   if(sellCondition && !SellOrderOpened() ){
      CustomSendStopOrder(OP_SELLSTOP);
      if(BuyOrderOpened()){
         CloseOrder(OP_BUY);
         CloseOrder(OP_BUYSTOP);
      }
   }
}

bool BuyOrderOpened(){
   for(int cnt=0;cnt<OrdersTotal();cnt++){
      if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
            if(OrderType()==OP_BUY || OrderType()==OP_BUYSTOP)
               return(true);
      }         
   }
   return (false);
}

bool SellOrderOpened(){
   for(int cnt=0;cnt<OrdersTotal();cnt++){
      if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
            if(OrderType()==OP_SELL || OrderType()==OP_SELLSTOP)
               return(true);
      }         
   }
   return (false);
}

bool IsTimeControlOK(){
   if(!UseTimeControl)
      return(true);
   
   if(StartTradingHour <= EndTradingHour){
      if(Hour()>=StartTradingHour && Hour()<=EndTradingHour)
         return(true);
   }else if(StartTradingHour > EndTradingHour){
      if(Hour()>=StartTradingHour || Hour()<=EndTradingHour)
         return(true); 
   }
   
   SetLabel("Time control: OUT OF TRADING HOURS.", labelComment, Red);     
   return(false);        
}

bool IsExpired(){
   if(TimeCurrent() <= ExpirationDate)
      return(false);
      
   return(true);
}

bool CustomSendStopOrder(int option){
   if(option!=OP_BUYSTOP && option!=OP_SELLSTOP)
      return(-1);

   double actualPrice;
   double orderPrice;
   double stopLossPrice;
   
   int maxSlippage = 3 * moltiplicatore;

   color ArrowColor = Green;
   string subject = "OrderType: ";
   
   RefreshRates(); 
   
   if(option==OP_BUYSTOP){
      actualPrice = Ask;
      orderPrice = actualPrice + spread * moltiplicatore * Point + internalConfirmPips;
      stopLossPrice = orderPrice - signalAtrPips;
         
      if((actualPrice-stopLossPrice)<internalStopLevel){
         stopLossPrice = actualPrice - internalStopLevel;
      }
      subject = subject + "BUY";
   }else{
      actualPrice = Bid;
      orderPrice = actualPrice - internalConfirmPips;
      stopLossPrice = orderPrice + signalAtrPips;
         
      if((stopLossPrice-actualPrice)<internalStopLevel){
         stopLossPrice = actualPrice + internalStopLevel;
      }
      subject = subject + "SELL";
      ArrowColor = Red;
   }      

   orderPrice = NormalizeDouble(orderPrice, Digits);
   stopLossPrice = NormalizeDouble(stopLossPrice, Digits);
   
   double stopLossPips = MathAbs( MathFloor( (stopLossPrice-orderPrice)/(moltiplicatore * Point) )  );

   if(option==OP_BUYSTOP){
      currentTakeProfitPrice = orderPrice + signalAtrPips;
   }else{
      currentTakeProfitPrice = orderPrice - signalAtrPips;
   }
   currentTakeProfitPrice = NormalizeDouble(currentTakeProfitPrice, Digits);
   
   double maxLossValue = AccountFreeMargin() * RiskPercent / 100;
   double lostPipsValue = maxLossValue / stopLossPips; // In AccountCurrency ...
   
   double lostPipsValueUSD;
   if(AccountCurrency()=="USD")
      lostPipsValueUSD = lostPipsValue;
   else{
      lostPipsValueUSD = lostPipsValue * MarketInfo(AccountCurrency() + "USD" + SymbolSuffix ,MODE_ASK);
   }
   
   //Standard Lot = 100000 --> 1pip = 10$ --> lots = lotsPipsValueUSD/10$
   double pipValue = (10 * lotSize) / 100000;
   double lots = NormalizeDouble(( lostPipsValueUSD / pipValue ) / 2, 2);
   
   if(UseFixedLotSize && FixedLotSizeToUse>0){
      lots = FixedLotSizeToUse;
   }else{
      if(lots < UserMinLotSize)
         lots = UserMinLotSize;
      if(lots > UserMaxLotSize)
         lots = UserMaxLotSize;
         
      lots = MathMax(lots, minLots);
      lots = MathMin(lots, maxLots);
      lots = (MathCeil(lots / lotStep)) * lotStep;

   }
      
   //First half position
   currentFixedOrderTicket=OrderSend(Symbol(), option, lots, orderPrice , maxSlippage, stopLossPrice, currentTakeProfitPrice, eaName, MagicNumber, 0, ArrowColor);   
   //Second half position
   currentTrailingOrderTicket=OrderSend(Symbol(), option, lots, orderPrice , maxSlippage, stopLossPrice, 0, eaName, MagicNumber, 0, ArrowColor);   
   
   string tradeType = "SELL";
   if(option==OP_BUYSTOP)
      tradeType = "BUY";
   
   if(currentFixedOrderTicket>0 && currentTrailingOrderTicket>0)
      ActivateAlerts(tradeType + " order send. Pair: " + Symbol() + ". Size: " + 2*lots + " lots.");
   else{
      if(currentFixedOrderTicket<0)
         Print("Error sending first " + tradeType + " order for " + lots + " lots. Error = " + GetLastError() );
      if(currentTrailingOrderTicket<0)
         Print("Error sending second " + tradeType + " order for " + lots + " lots. Error = " + GetLastError() );
      return(false);      
   }
   
   return(true);
  }

//+------------------------------------------------------------------+

void ActivateAlerts(string message){
   ActivateAlertsWithSound(message, AlertSound);   
}

void ActivateAlertsWithSound(string message, string soundToPlay){
   CustomSendMail(eaName + " INFO", message);
   CustomAlert(message);                  
   CustomSound(soundToPlay);
}

void CustomSendMail(string subject, string message){
   if(!MailEnabled)
      return;
   
   string currentTime = TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS);
   message = eaName + " " 
      + currentTime + "\n" + "+++++++++++++++++++++++++++++++\n\n" 
      + message;
         
   SendMail(subject, message);
        
}

void CustomAlert(string message){
   if(!AlertEnabled)
      return;
   Alert(message);
}


void CustomSound(string filename){
   if(!SoundEnabled)
      return;
   PlaySound(filename);      
}


//-----------------------------------------------------
//          LABEL MANAGEMENT
void CreateLabel(string labelName, color labelColor, double posX, double posY){
   ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0);
   ObjectSetText(labelName, "+ " + eaName + " +" ,labelFontSize, "Tahoma", labelColor);
   ObjectSet(labelName, OBJPROP_CORNER, labelCorner);
   ObjectSet(labelName, OBJPROP_XDISTANCE, posX);
   ObjectSet(labelName, OBJPROP_YDISTANCE, posY);
}

void SetLabel(string message, string labelName, color labelColor){
   if(ObjectFind(labelName)==-1)      
      return;
   string timeString = TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS);
   ObjectSetText(labelName,"+ " + timeString + " " + message + " +",labelFontSize,"Tahoma",labelColor);            
}

void SetShortLabel(string message, string labelName, color labelColor){
   if(ObjectFind(labelName)==-1)      
      return;
   ObjectSetText(labelName,"+ " + message + " +",labelFontSize,"Tahoma",labelColor);            
}

void DeleteLabel(string labelName){
   if(ObjectFind(labelName)==-1)
      return;
   ObjectDelete(labelName);
}
//-----------------------------------------------------


bool CustomOrderModify(int ticket, double openPrice, double slPrice, double takeProfit, datetime expiration, color orderColor){
   bool result;
   for(int retry=0; retry<MAX_RETRY; retry++){
      result = OrderModify(ticket, openPrice, slPrice, takeProfit, expiration, orderColor);
      if(result)
         return(true);
      
      Sleep(5000);    
   }
   return(false); 
}

