//+------------------------------------------------------------------+
//|                                              EMATrailingStop mq4 |
//|                              Copyright © 2009, Forex-Station.com |
//|           Original written 2006 by IgorAD,igorad2003@yahoo.co.uk |
//|                                   2009 version written by mladen |
//+------------------------------------------------------------------+
//------------------------------------------------------------------
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#include <stdlib.mqh>

//
//
//
//
//

extern bool   TrailAllSymbols   = true;
extern bool   TrailOnlyInProfit = false;
extern double CloseWhenProfit   = 0.0;
extern bool   showMessages      = true;

//
//
//
//
//

extern int  EMATimeFrame     =   0;
extern int  Price            =   0;
extern int  EMAPeriod        =  13;
extern int  EMAShift         =   2;    
extern int  InitialStop      = 100;
extern int  magicNumberfrom  =   0;
extern int  magicNumberto    =   0;

bool dummyResult;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()   { return(0); }
int deinit()
{
   switch(UninitializeReason())
   {
      case REASON_CHARTCHANGE:
      case REASON_PARAMETERS:  break;
      case REASON_RECOMPILE:
      case REASON_CHARTCLOSE:
      case REASON_REMOVE:
      case REASON_ACCOUNT:     if (showMessages) for(int i=0; i<10; i++)  ObjectDelete("msg.que"+i);
   }
   return(0);
}



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//
      
int start()
{
   if (!CheckTerminalStatus()) return(0); showTwoStateMessage("working","EMA trailing EA working",true);

   //
   //
   //
   //
   //

   datetime startTime   = TimeCurrent();
   double   totalProfit = 0;
   int      err,c;
   
   //
   //
   //
   //
   //

   for (int i=OrdersTotal()-1; i>=0; i--)
   { 
      dummyResult = OrderSelect(i, SELECT_BY_POS,MODE_TRADES);
      if (!TrailAllSymbols)
         if (OrderSymbol()!=Symbol())              continue;
         if (OrderMagicNumber() < magicNumberfrom) continue;
         if (OrderMagicNumber() > magicNumberto)   continue;
      RefreshRates();

      //
      //
      //
      //
      //
         
         int    digits     = MarketInfo(OrderSymbol(),MODE_DIGITS);
         double point      = MarketInfo(OrderSymbol(),MODE_POINT);
         double PointRatio = 1;
               if (digits==3 || digits==5) PointRatio = 10;
      
      //
      //
      //
      //
      //

      if (OrderType()==OP_BUY) 
      {
         totalProfit += OrderProfit();
         double bid        = MarketInfo(OrderSymbol(),MODE_BID);
         double maxBuyStop = NormalizeDouble(bid-MarketInfo(OrderSymbol(),MODE_STOPLEVEL)*point,digits);
            if (OrderStopLoss()==0 && InitialStop > 0)
               {
                  double buyStop        = bid-InitialStop*point*PointRatio;
                  double currentBuyStop = buyStop-point;
               }
            else
               {             
                  buyStop        = stopValue(OrderSymbol());
                  currentBuyStop = OrderStopLoss(); if(currentBuyStop == 0) currentBuyStop = OrderOpenPrice();
                  currentBuyStop = MathMax(currentBuyStop,OrderOpenPrice());
               }                                          
         buyStop        = NormalizeDouble(buyStop       ,digits);
         currentBuyStop = NormalizeDouble(currentBuyStop,digits);
         
         //
         //
         //
         //
         //

         bool doModifyBuy = (buyStop > NormalizeDouble(OrderStopLoss(),digits)); if (TrailOnlyInProfit) doModifyBuy = (buyStop > currentBuyStop);
         if ( doModifyBuy && (buyStop < maxBuyStop))
         for(c=0 ; c<3; c++)
         {
            dummyResult = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(buyStop,Digits),OrderTakeProfit(),0,CLR_NONE);
               err=GetLastError();
               checkError(OrderSymbol()+" buy stop loss set to "+DoubleToStr(buyStop,digits),err);
               if(err==4 || err==136 || err==137 || err==138 || err==146)
               {
                  RefreshRates();
                  continue;
               }
            break; 
         }                     
      }   

      //
      //
      //
      //
      //
      
      if (OrderType()==OP_SELL)
      {
         totalProfit += OrderProfit();
         double ask         = MarketInfo(OrderSymbol(),MODE_ASK);
         double minSellStop = NormalizeDouble(ask+MarketInfo(OrderSymbol(),MODE_STOPLEVEL)*point,digits);
            if (OrderStopLoss()==0 && InitialStop > 0)
               {
                  double sellStop        = ask+InitialStop*point*PointRatio;
                  double currentSellStop = sellStop+point;
               }
            else
               {             
                  sellStop        = stopValue(OrderSymbol());
                  currentSellStop = OrderStopLoss(); if(currentSellStop == 0) currentSellStop = OrderOpenPrice();
                  currentSellStop = MathMin(currentSellStop,OrderOpenPrice());
               }                                          
         sellStop        = NormalizeDouble(sellStop       ,digits);
         currentSellStop = NormalizeDouble(currentSellStop,digits);
         
         //
         //
         //
         //
         //
            
         bool doModifySell = (sellStop < NormalizeDouble(OrderStopLoss(),digits) || OrderStopLoss()==0); if (TrailOnlyInProfit) doModifySell = (sellStop < currentSellStop);
         if ( doModifySell && (sellStop > minSellStop))
         for(c=0 ; c<3; c++)
         {
            dummyResult = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(sellStop,digits),OrderTakeProfit(),0,CLR_NONE);
               err=GetLastError();
               checkError(OrderSymbol()+" sell stop loss set to "+DoubleToStr(sellStop,digits),err);
               if(err==4 || err==136 || err==137 || err==138 || err==146)
               {
                  RefreshRates();
                  continue;
               }
            break; 
         }                     
      }
   }
   
   //
   //
   //
   //
   //
   
   if (CloseWhenProfit>0)
   {
      if ((TimeCurrent()-startTime)>15) totalProfit = colectProfit();
      
      //
      //
      //
      //
      //
      
      if (CloseWhenProfit<totalProfit)
      for (i=OrdersTotal()-1; i>=0; i--)
      { 
         dummyResult = OrderSelect(i, SELECT_BY_POS,MODE_TRADES);
         if (!TrailAllSymbols)
            if (OrderSymbol()!=Symbol())               continue;
            if (OrderMagicNumber() < magicNumberfrom) continue;
            if (OrderMagicNumber() > magicNumberto)   continue;
      
            //
            //
            //
            //
            //
            
            if (OrderType()==OP_BUY || OrderType()==OP_SELL)
            for(c=0 ; c<3; c++)
            {
               dummyResult = OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,CLR_NONE);
                  err=GetLastError();
                  checkError(OrderSymbol()+" order closed",err);
                  if(err==4 || err==136 || err==137 || err==138 || err==146)
                  {
                     RefreshRates();
                     continue;
                  }
                  break; 
            }                     
      }
   }
   return(0);      
}




//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double colectProfit()
{
   double profitSoFar=0;
   
   //
   //
   //
   //
   //
   
   for (int i=OrdersTotal()-1; i>=0; i--)
   { 
      dummyResult = OrderSelect(i, SELECT_BY_POS,MODE_TRADES);
      if (!TrailAllSymbols)
         if (OrderSymbol()!=Symbol())               continue;
         if (OrderMagicNumber() < magicNumberfrom) continue;
         if (OrderMagicNumber() > magicNumberto)   continue;
         if (OrderType()==OP_BUY || OrderType()==OP_SELL)
               profitSoFar += (OrderProfit()+OrderSwap()+OrderCommission());
   }         
   return(profitSoFar);
}

//
//
//
//
//

double stopValue(string symbol)
{
   double ema = iMA(symbol,EMATimeFrame,EMAPeriod,0,MODE_EMA,Price,EMAShift);
   return(ema);
}





//----------------------------------------------------------------------------------------
//       terminal status handling
//----------------------------------------------------------------------------------------
//
//
//
//
//

bool CheckTerminalStatus()
{
   bool status=false;
   
   //
   //
   //
   //
   //
   
   while(true)
   {
         if (!IsConnected())
             { showTwoStateMessage("connected","No connection to server",False); break; }
         else  showTwoStateMessage("connected","Conected to server",true);
         if ( IsStopped())
             { showTwoStateMessage("stopped","EA stopped",False); break; }  
         else  showTwoStateMessage("stopped","EA started",true);
         if (!IsTradeAllowed())
             { showTwoStateMessage("allowed","Trading not allowed",false); break; }
         else  showTwoStateMessage("allowed","Trading allowed",true);
         if (!IsExpertEnabled() && !IsTesting())
            { showTwoStateMessage("disabled","EA''s are disabled",false); break; }
         else showTwoStateMessage("disabled","EA''s are enabled",true);
         if ( IsTradeContextBusy())
            { showTwoStateMessage("busy","Trade contest busy",false); break; }
         else showTwoStateMessage("busy","Trade contest ready",true);
         
      //
      //
      //
      //
      //
      
      status=true;
      break;
   }
   return(status);
}

//----------------------------------------------------------------------------------------
//       messages handling
//----------------------------------------------------------------------------------------
//
//
//
//
//
//

bool   msgerrState[];
string msgerrNames[];
string msgmessageText[10];
color  msgmessageColor[10];
int    msglastMessage=0;

//
//
//
//
//

void checkError(string what,int err)
{
   showMessage(what);
   if(err!=0)
         showMessage("error occured :"+ErrorDescription(err),Red);

}

//
//
//
//
//

void showTwoStateMessage(string name, string message, bool state)
{
   for(int i=ArraySize(msgerrNames)-1; i>-1; i--) if (msgerrNames[i]==name) break;
   if (i==-1)
      {
         int size = ArraySize(msgerrNames)+1;
         i = size-1;
            ArrayResize(msgerrNames,size); msgerrNames[i] = name;
            ArrayResize(msgerrState,size); msgerrState[i] = -1;
      }

   //
   //
   //
   //
   //

   if (msgerrState[i]!= state)
   {   
      msgerrState[i] = state;
      if (state==false)
            showMessage(message,Red);
      else  showMessage(message,Green);
   }      
}

//
//
//
//
//

void showMessage(string text, color theColor=Gray)
{
   if(!showMessages) { Print(text); return; }
   if(msglastMessage>9)
   {
      for(int i=0; i<9; i++)
      {
         msgmessageText[i] =msgmessageText[i+1];
         msgmessageColor[i]=msgmessageColor[i+1];
      }
      msglastMessage = 9;
   }

   //
   //
   //    set message que text and color
   //
   //
   
      msgmessageText[msglastMessage]  = text+" - "+TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS);
      msgmessageColor[msglastMessage] = theColor;
   
   //
   //
   //
   //
   //
      
   for(i=0; i<=msglastMessage; i++)
   {
      string name = "msg.que"+i;
      if (ObjectFind(name) == -1)
      {
         ObjectCreate(name,OBJ_LABEL,0,0,0);
            ObjectSet(name,OBJPROP_CORNER  ,3);
            ObjectSet(name,OBJPROP_XDISTANCE,5);
            ObjectSet(name,OBJPROP_YDISTANCE,5+14*i);
      }
      ObjectSetText(name,msgmessageText[i],9,"Arial",msgmessageColor[i]);
   }
   msglastMessage++;
   WindowRedraw();
}