//+------------------------------------------------------------------+
//|                                               HMAExpert_v2.1.mq4 |
//|                           Copyright © 2007, TrendLaboratory Ltd. |
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |
//|                                   E-mail: igorad2003@yahoo.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, TrendLaboratory Ltd."
#property link      "http://finance.groups.yahoo.com/group/TrendLaboratory"

#include <stdlib.mqh>

//---- input parameters
extern string     Expert_Name    = "HMAExpert_v2.1";

extern int        Magic          = 20202;    // if Magic=0 then AutoMagic
extern int        Slippage       =     3;

extern string     Main_data      = " Trade Volume & Trade Method";
extern double     Lots           =   0.1;    // Trade Volume 
extern int        MaxOrders      =     1;
extern double     TakeProfit     =     0;    // Take Profit Value in pips 
extern double     StopLoss       =     0;    // Initial Stop Value in pips
extern int        TrailingMode   =     0;    // 0-off,1-standard,2-System  
extern double     TrailingStop   =     0;    // Trailing Stop Value in pips
extern double     StopDeviation  =     0;    // Deviation of Hi/Lo HMA
extern double     BreakEven      =     0;    // Break-Even Value in pips
extern double     ProfitLock     =     0;    // Profit Lock in pips
extern int        ExitMode       =     0;    // System Exit Switch:0-off,1-signal(w/o timefilter),2-signal
extern int        VisualMode     =     0;
extern bool       SignalMail     = False;    // E-mail Alert Switch

extern string     Time_Inputs    = " Timing parameters ";
extern int        StartHour      =     0;    // Start Hour of Trade Session 
extern int        StartMinute    =     0;    // Start Minute of Trade Session 
extern int        EndHour        =    23;    // End Hour of Trade Session
extern int        EndMinute      =     0;    // End Hour of Trade Session
extern int        CloseTimeMode  =     0;    // CloseTime mode: 0-off,1-on
extern int        CloseHour      =    24;    // Trade Close Hour   
extern int        CloseMinute    =     0;    // Trade Close Minute   

extern string     HMA_Inputs     = " HMA parameters";
extern int        TimeFrame      =     0;    // Time Frame in min
extern int        Price          =     0;    // Apply to Price(0-Close;1-Open;2-High;3-Low;4-Median price;5-Typical price;6-Weighted Close) 
extern int        Length         =     9;    // Period of HMA
extern double     PctFilter      =     0;    // Dynamic filter in decimal
extern int        Shift          =     1;    // Shift relative to the current bar
extern int        Mode           =     2;    // TE Mode: 0-off,1-trend(confirmation),2-signal

extern string     ER_Inputs      = " Ergodic parameters ";
extern int        ER_TimeFrame   =     0;    // TimeFrame in min
extern int        ER_PQ          =     1;    // Preliminary Smoothing Period 
extern int        ER_PR          =    10;    // Length (Period)
extern int        ER_PS          =     5;    // Smoothing 
extern int        ER_Signal      =     5;    // Period of Signal MA   
extern int        ER_Mode        =     0;    // Efficiency Mode: 0-off,1-trend,2-signal 

extern string     MM_inputs      = " MoneyManagement parameters";
extern bool       MM             = false;    // ΜΜ Switch
extern double     MaxRisk        =  0.05;    // Risk Factor


int      OrderBar=0;
double   Lotsi;
int      BEvent=0, TriesNum=5;
datetime CurrBar,PrevBar;
double   UpLine, DnLine;
double   trend, ptrend;
double   ER,SigER,pER,pSigER,ppER;
int      aMagic;
bool     dummyResult;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//---- 
   if(Magic==0)
   aMagic = 3000 + func_Symbol2Val(Symbol())*100 + func_TimeFrame_Const2Val(Period()); 
   else
   aMagic = Magic;
    
   CurrBar = iTime(Symbol(),0,0);
   PrevBar = iTime(Symbol(),0,1);
//----
   return(0);
}

// ---- Scan Trades
int ScanTrades()
{   
   int total = OrdersTotal();
   int numords = 0;
      
   for(int cnt=0; cnt<total; cnt++) 
   {        
   dummyResult = OrderSelect(cnt, SELECT_BY_POS);            
   if(OrderSymbol() == Symbol() && OrderType()<=OP_SELLSTOP && OrderMagicNumber() == aMagic) 
   numords++;
   }
   return(numords);
}  

bool TimeCondition()
{
   bool result = false;
   
   datetime SessionStart = StrToTime(StartHour+":"+StartMinute);
   datetime SessionEnd   = StrToTime(EndHour+":"+EndMinute);
   
   if (StartHour < EndHour)
   result = TimeCurrent() >= SessionStart && TimeCurrent() < SessionEnd;      
   else
   if (StartHour > EndHour)
   result = (TimeCurrent() > SessionStart && TimeHour(TimeCurrent()) < 24)
          ||(TimeHour(TimeCurrent()) >= 0 && TimeCurrent() < SessionEnd);
   
   return(result);
}   
   
int HMA_Trend(int mode)
{   
   int result = 0; 
   
   trend = iCustom(NULL,TimeFrame,"HMA_v2",Price,Length,PctFilter,1,0,0,0,4,Shift);
   ptrend = iCustom(NULL,TimeFrame,"HMA_v2",Price,Length,PctFilter,1,0,0,0,4,Shift+1);
             
   if (mode == 1)
   {
   if (trend > 0) result =  mode;
   if (trend < 0) result = -mode; 
   }
   else
   if (mode == 2)
   {
   if (trend > 0 && ptrend < 0) result =  mode;  
   if (trend < 0 && ptrend > 0) result = -mode;
   }
   else
   if(mode == 0) result = 0;
   
   return(result); 
}

int ER_Trend(int mode)
{   
   int result = 0; 
   
   string ER_name =  "FX_Snipers_Ergodic_CCI_Trigger";
      
   ER = iCustom(NULL,ER_TimeFrame,ER_name,ER_PQ,ER_PR,ER_PS,ER_Signal,0,1);
   SigER = iCustom(NULL,ER_TimeFrame,ER_name,ER_PQ,ER_PR,ER_PS,ER_Signal,1,1);
   pER = iCustom(NULL,ER_TimeFrame,ER_name,ER_PQ,ER_PR,ER_PS,ER_Signal,0,2);
   pSigER = iCustom(NULL,ER_TimeFrame,ER_name,ER_PQ,ER_PR,ER_PS,ER_Signal,1,2);
   ppER = iCustom(NULL,ER_TimeFrame,ER_name,ER_PQ,ER_PR,ER_PS,ER_Signal,0,3);

   ER = NormalizeDouble(ER,Digits);
   SigER = NormalizeDouble(SigER,Digits);
   pER = NormalizeDouble(pER,Digits);
   pSigER = NormalizeDouble(pSigER,Digits);     
   ppER = NormalizeDouble(ppER,Digits);
   
   if (mode == 1)
   {
   if (ER > SigER ) result =  mode;
   if (ER < SigER ) result = -mode; 
   }
   else
   if (mode == 2)
   {
   if (pER < pSigER && ER > SigER) result =  mode;  
   if (pER > pSigER && ER < SigER) result = -mode;
   }
   else
   if (mode == 3)
   {
   if (ER > SigER && ER-pER > pER-ppER && ER>pER) result =  mode;  
   if (ER < SigER && pER-ER > ppER-pER && ER<pER) result = -mode;
   }
   else
   if (mode == 4)
   {
   if (pER < pSigER && ER > SigER && ER-pER > pER-ppER) result =  mode;  
   if (pER > pSigER && ER < SigER && pER-ER > ppER-pER) result = -mode;
   }
   else
   if (mode == 0) result = 0;
   
   return(result); 
}


int TradeSignal()
{   
   int Signal =0;
   
   if (Mode>0 || ExitMode == 1) int HMA  = HMA_Trend(Mode); else HMA=0; 
   if (ER_Mode>0) int _ER = ER_Trend(ER_Mode); else _ER=0; 
      
   if (TimeCondition())
   {
   if ( HMA == Mode && _ER == ER_Mode) Signal = 1;
   if ( HMA ==-Mode && _ER ==-ER_Mode) Signal =-1;
   }  
 
   return(Signal);
}

double MoneyManagement()
{
   double lot_min =MarketInfo(Symbol(),MODE_MINLOT);
   double lot_max =MarketInfo(Symbol(),MODE_MAXLOT);
   double lot_step=MarketInfo(Symbol(),MODE_LOTSTEP);
   double contract=MarketInfo(Symbol(),MODE_LOTSIZE);
   double vol;
//--- check data
   if(lot_min<0 || lot_max<=0.0 || lot_step<=0.0) 
   {
   Print("CalculateVolume: invalid MarketInfo() results [",lot_min,",",lot_max,",",lot_step,"]");
   return(0);
   }
   if(AccountLeverage()<=0)
   {
   Print("CalculateVolume: invalid AccountLeverage() [",AccountLeverage(),"]");
   return(0);
   }
//--- basic formula
   if ( MM )
   vol=NormalizeDouble(AccountFreeMargin()*MaxRisk*AccountLeverage()/contract,2);
   else
   vol=Lots;
//--- check min, max and step
   vol=NormalizeDouble(vol/lot_step,0)*lot_step;
   if(vol<lot_min) vol=lot_min;
   if(vol>lot_max) vol=lot_max;
//---
   return(vol);
}   


void TrailStop()
{
   int    error;  
   bool   result=false;
   double Gain = 0;
    
   for (int cnt=0;cnt<OrdersTotal();cnt++)
   { 
   dummyResult = OrderSelect(cnt, SELECT_BY_POS);   
   int mode=OrderType();    
      if ( OrderSymbol()==Symbol() && OrderMagicNumber()==aMagic) 
      {
         if (mode==OP_BUY) 
         {
			   if ( BreakEven > 0 && BEvent==0 )
			   {
			   Gain = (MarketInfo(Symbol(),MODE_BID) - OrderOpenPrice())/Point;
			      if( Gain >= BreakEven && OrderStopLoss()<=OrderOpenPrice()+ProfitLock*Point) 
			      {
			      double BuyStop = NormalizeDouble(OrderOpenPrice()+ProfitLock*Point,Digits);
			      BEvent=1;
			      }
			   }
			   else 			   
			   if( TrailingMode==1 && TrailingStop > 0 ) BuyStop = NormalizeDouble(MarketInfo(Symbol(),MODE_BID) - TrailingStop*Point,Digits);
			   else
			   if( TrailingMode==2 && UpLine>0) BuyStop = NormalizeDouble((1.0-0.01*StopDeviation)*UpLine,Digits);
			   
			   if( NormalizeDouble(OrderOpenPrice(),Digits)<= BuyStop) 
            {   
			      if ( BuyStop > NormalizeDouble(OrderStopLoss(),Digits) || OrderStopLoss() == 0) 
			      {
			         for(int k = 0 ; k < TriesNum; k++)
                  {
                  result = OrderModify(OrderTicket(),OrderOpenPrice(),
			                              BuyStop,
			                              OrderTakeProfit(),0,Lime);
                  error=GetLastError();
                     if(error==0) break;
                     else {Sleep(5000); RefreshRates(); continue;}
                  }   		 
               }            
            }
         }   
// - SELL Orders          
         if (mode==OP_SELL)
         {
            if ( BreakEven > 0 && BEvent==0)
			   {
			   Gain = (OrderOpenPrice()-MarketInfo(Symbol(),MODE_ASK))/Point;
			   
			      if( Gain >= BreakEven && (OrderStopLoss()>=OrderOpenPrice()-ProfitLock*Point || OrderStopLoss()== 0)) 
			      {
			      double SellStop = NormalizeDouble(OrderOpenPrice()-ProfitLock*Point,Digits);
			      BEvent=-1;
			      }
			   }
			   else 
			   if (TrailingStop > 0 && TrailingStop > 0) SellStop = NormalizeDouble(MarketInfo(Symbol(),MODE_ASK) + TrailingStop*Point,Digits);   
            else
            if( TrailingMode==2 && DnLine>0) SellStop = NormalizeDouble((1.0+0.01*StopDeviation)*DnLine,Digits);
                        
            if(NormalizeDouble(OrderOpenPrice(),Digits) >= SellStop && SellStop>0) 
            {
               if( SellStop < NormalizeDouble(OrderStopLoss(),Digits) || OrderStopLoss() == 0) 
               {
                  for( k = 0 ; k < TriesNum; k++)
                  {
                  result = OrderModify(OrderTicket(),OrderOpenPrice(),
			                              SellStop,
			                              OrderTakeProfit(),0,Orange);
                  error=GetLastError();
                     if(error==0) break;
                     else {Sleep(5000); RefreshRates(); continue;}
                  }
               }   
   			}	    
         }
      }
   }     
}


// ---- Open Sell Orders
void SellOrdOpen()
{		     
   double SellPrice = Bid;
   double StopPrice = Bid;
   int    tMode = OP_SELL;
        	  
   if (StopLoss > 0) double SellStop  = StopPrice + StopLoss*Point; 
	else 
	if( TrailingMode==2 && DnLine>0) SellStop = NormalizeDouble((1.0+0.01*StopDeviation)*DnLine,Digits); 
	else SellStop = 0;
   
   if (TakeProfit  > 0) double SellProfit = SellPrice - TakeProfit*Point; else SellProfit=0;
   
	int ticket = OrderSend( Symbol(),tMode,MoneyManagement(),
	                        NormalizeDouble(SellPrice , Digits),
	                        Slippage,
	                        NormalizeDouble(SellStop  , Digits),
	                        NormalizeDouble(SellProfit, Digits),
	                        Expert_Name+" SELL",aMagic,0,Red);
   
   if(ticket > 0) 
   {
      if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) 
      {
		//OrderBar =iBars(OrderSymbol(),BT_TimeFrame);
		Print("SELL order opened : ", OrderOpenPrice());
      BEvent=0;
      if (SignalMail) SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + " Open Sell");
		}
   }
	else 	
   if(GetLastError()>0)
   Print("SELL: OrderSend failed with error #",GetLastError());
   
   return;
}
// ---- Open Buy Orders
void BuyOrdOpen()
{		     
   double BuyPrice  = Ask;
   double StopPrice = Ask;
   int    tMode      = OP_BUY;
      
   if (StopLoss > 0) double BuyStop  = StopPrice - StopLoss*Point; 
	else 
	if ( TrailingMode==2 && UpLine > 0) BuyStop = NormalizeDouble((1.0-0.01*StopDeviation)*UpLine,Digits); 
	else BuyStop = 0;
   
   if (TakeProfit  > 0) double BuyProfit= BuyPrice + TakeProfit*Point; else BuyProfit=0;  
		 
	int ticket = OrderSend(Symbol(),tMode, MoneyManagement(),
	                   NormalizeDouble(BuyPrice , Digits),
	                   Slippage,
	                   NormalizeDouble(BuyStop  , Digits), 
	                   NormalizeDouble(BuyProfit, Digits),
	                   Expert_Name+" BUY",aMagic,0,Blue);
      
   if(ticket > 0) 
   {
      if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) 
      {
		//OrderBar =iBars(OrderSymbol(),BT_TimeFrame); 
		Print("BUY order opened : ", OrderOpenPrice());
      BEvent=0;
      if (SignalMail) SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + " Open Buy");
		}
   }
	else 	
   if(GetLastError()>0)      
   Print("BUY : OrderSend failed with error #",GetLastError());

   return;
} 

void CloseOrder(int mode)  
{
   bool result=false; 
   int  total=OrdersTotal();
   
   for (int i=0; i<=OrdersTotal(); i++)  
   {
   dummyResult = OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if (OrderMagicNumber() == aMagic && OrderSymbol() == Symbol()) 
      {
      if ((mode == 0 || mode ==1) && OrderType()==OP_BUY ) result=CloseAtMarket(OrderTicket(),OrderLots(),Aqua);
      if ((mode == 0 || mode ==2) && OrderType()==OP_SELL) result=CloseAtMarket(OrderTicket(),OrderLots(),Pink);
      }
   }
}


bool CloseAtMarket(int ticket,double lot,color clr) 
{
   bool result = false; 
      
   int tries=0;
   while (!result && tries < TriesNum) 
   {
      //ntr=0; 
      //while (ntr<5 && !IsTradeAllowed()) { ntr++; Sleep(5000); }
      RefreshRates();
      result=OrderClose(ticket,lot,OrderClosePrice(),Slippage,clr);
      tries++;
   }
   if (!result) Print("Error closing order : ",ErrorDescription(GetLastError()));
   return(result);
}

double oProfit(int mode)  
{
   double profit=0;
   int total = OrdersTotal();
      
   for (int i=0; i<total; i++)  
   {
   dummyResult = OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
   if (OrderMagicNumber() != Magic && OrderSymbol() != Symbol()) continue; 
      if (mode==1 && OrderType()==OP_BUY)
      profit = (MarketInfo(Symbol(),MODE_BID) - OrderOpenPrice())/Point;
      else  
      if (mode==2 && OrderType()==OP_SELL) 
      profit = (OrderOpenPrice() - MarketInfo(Symbol(),MODE_ASK))/Point;
   }
   return(profit);
}

//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//---- 
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   if( VisualMode ==1)
   {  
   GlobalVariableSet( "vGrafBalance", AccountBalance() );
   GlobalVariableSet( "vGrafEquity", AccountEquity() );
   }
   if( VisualMode ==2)
   {  
   GlobalVariableSet( "vGraf_bProfit", oProfit(1) );
   GlobalVariableSet( "vGraf_sProfit", oProfit(2) );
   }
   
   if (TimeFrame==0) TimeFrame = Period();
       
   if(iBars(Symbol(),TimeFrame) < 100 || IsTradeAllowed()==false) return(0); 
      
   if(AccountFreeMargin()< 1000*MoneyManagement ())
   {
   Print("We have no money. Free Margin = ", AccountFreeMargin());
   return(0);  
   }
   CurrBar = iTime(Symbol(),0,0);
   
   datetime TimeClose = StrToTime(CloseHour+":"+CloseMinute); 
   
   
   
   if (CurrBar != PrevBar)
   {
      if(TrailingMode==2)
      {
      UpLine = iCustom(NULL,TimeFrame,"HMA_v2",Price,Length,0,1,0,0,0,0,Shift);
      DnLine  = iCustom(NULL,TimeFrame,"HMA_v2",Price,Length,0,1,0,0,0,0,Shift);
      }
            
      int Signal = TradeSignal();
      //Print(" Sig=",Signal);      
      if(ScanTrades()>0)
      {
         if(ExitMode == 1)
         {
         if (trend > 0 && ptrend < 0) CloseOrder(2);
         if (trend < 0 && ptrend > 0) CloseOrder(1);
         }
         else
         if(ExitMode == 2)
         {
         if (Signal > 0) CloseOrder(2);
         if (Signal < 0) CloseOrder(1);
         }
         else
         if(ExitMode == 3)
         {
         if (pER < pSigER && ER > SigER) CloseOrder(2);
         if (pER > pSigER && ER < SigER) CloseOrder(1);
         }
         if(ExitMode == 4)
         {
         if ((trend > 0 && ptrend < 0)||(pER < pSigER && ER > SigER)) CloseOrder(2);
         if ((trend < 0 && ptrend > 0)||(pER > pSigER && ER < SigER)) CloseOrder(1);
         }
         
      if (CloseTimeMode > 0 && TimeCurrent() >= TimeClose) CloseOrder(0); 
      }
      
      if(ScanTrades() < MaxOrders)
      {
      if (Signal > 0) BuyOrdOpen() ;
      if (Signal < 0) SellOrdOpen();
      }
   }
   else
   if(ScanTrades()>0)
   {
   if(BreakEven > 0 || TrailingMode>0) TrailStop();
   }
   PrevBar = CurrBar;
   
//----
   return(0);
} //start()
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Time frame interval appropriation  function                      |
//+------------------------------------------------------------------+

int func_TimeFrame_Const2Val(int Constant ) {
   switch(Constant) {
      case 1:  // M1
         return(1);
      case 5:  // M5
         return(2);
      case 15:
         return(3);
      case 30:
         return(4);
      case 60:
         return(5);
      case 240:
         return(6);
      case 1440:
         return(7);
      case 10080:
         return(8);
      case 43200:
         return(9);
   }
   return(0);
}



int func_Symbol2Val(string symbol)
 {
   string mySymbol = StringSubstr(symbol,0,6);
	if(mySymbol=="AUDCAD") return(1);
	if(mySymbol=="AUDJPY") return(2);
	if(mySymbol=="AUDNZD") return(3);
	if(mySymbol=="AUDUSD") return(4);
	if(mySymbol=="CHFJPY") return(5);
	if(mySymbol=="EURAUD") return(6);
	if(mySymbol=="EURCAD") return(7);
	if(mySymbol=="EURCHF") return(8);
	if(mySymbol=="EURGBP") return(9);
	if(mySymbol=="EURJPY") return(10);
	if(mySymbol=="EURUSD") return(11);
	if(mySymbol=="GBPCHF") return(12);
	if(mySymbol=="GBPJPY") return(13);
	if(mySymbol=="GBPUSD") return(14);
	if(mySymbol=="NZDUSD") return(15);
	if(mySymbol=="USDCAD") return(16);
	if(mySymbol=="USDCHF") return(17);
	if(mySymbol=="USDJPY") return(18);
   
   
   Comment("unexpected Symbol");
	return(19);
}