//+----------------------------------------------------------------------+
//|                                        Hans123 Expert Advisor        |
//|                                        Version 8.2 - Feb 13, 2006    |
//|                                                                      |
//|                                        v8.0 Programmed by Fukinagashi|
//|                                        v8.1 Programmed by AymenSaket |
//|                                        v8.2 Programmed by RJ1        |
//| *New features in v8.2*                                               |
//| o Money Management capability (as wished by techie and many others)  |
//|   - Sizing your orders based on risk to your capital                 |
//| o Mini Account consideration                                         |
//| o OffSetToGMT implementation for easier timeframe setting            |
//|   (thanx to Brandon86 for a good discussion on timeframe setting)    |
//| o EquityCutOff implementation                                        |
//|   - EA will stop trading if equity decreases to the specified level  |
//| o Friday trading time correction                                     |
//|   - On Friday, trading will end at 22:55 (thanks to Milan Volf)      |
//|                                                                      |
//| Please read the thread about Hans123 system to understand it. Thank  |
//| you Hans for sharing such a wonderful system.                        |
//| URL: http://www.strategybuilderfx.com/forums/showthread.php?t=15439  |
//+----------------------------------------------------------------------+

#include <stdlib.mqh>

extern int                       BeginSession1=          6; // Recommended not to change this value, unless you know what you are doing
extern int                       LengthSession1=         4;
extern int                       BeginSession2=          10; // Recommended not to change this value, unless you know what you are doing
extern int                       LengthSession2=         4;

extern double                    Lots =                  1.0;

extern int                       OffSetToGMT=            1; // NorthFinance TimeZone GMT+2
                                                            // Change to your server's timezone (in GMT)

extern int                       ClsOnlUnprTX=           1; // 1 = yes / 0 = no
extern int                       ProtectYourInvestments= 1; // 1 = yes / 0 = no
extern int                       Type_TS_Calc=           1; // 1 - classic / 2 - ATR / 3 - HalfVotality
extern double                    FactorTSCalculation =   0.5;

datetime                         bartime =               0;
double                           Slippage=               3; // Possible fix for not getting filled or closed
int                              OrderInterval =         10000;

extern bool                      AccountIsMini = true;      // Change to true if trading mini account.
extern bool                      MoneyManagement = true;    // Change to true to activate money management controls.
                                                             // By enabling this, lot size will be determined by TradeSizePercent.
extern double                    TradeSizePercent = 10;      // Change to whatever percent of equity you wish to risk in trading.
                                                             // MoneyManagement must be set to true to use this. If the percentage  
                                                             // of the equity allows you to trade smaller than 0.1 lot, then the 
                                                             // system will set it as 0.1 lot.
double                           TradeLots;
extern double                    Equitycutoff = 0   ;   // Expert will stop trading if equity level decreases to this level.
                                                        // Leave it as 0 if you want to disable this feature.

//+------------------------------------------------------------------+
//|  Recommended for GBPUSD and EURUSD, H1 timeframe.                |
//+------------------------------------------------------------------+

int start()
   {
   int                           cnt, ticket, err, i, j;
   int                           MagicNumber;
   double                        ts, tp, sl, LowestPrice, HighestPrice, Price; 
   bool                          Order[5];
   string                        setup;
   datetime                      Validity=0;
   double                        TrailingStop;
   double                        TakeProfit;
   double                        InitialStopLoss;
   int                           PipsForEntry;
   int                           TimeZoneDiff= OffSetToGMT - 1;   

	MagicNumber = func_Symbol2Val(Symbol()); 

   setup="H123_v8.2_" + Symbol();

   if (Symbol()=="GBPUSD") 
   {
      PipsForEntry= 13;
      TrailingStop = 40;
      TakeProfit = 80;
      InitialStopLoss=70;
   } 
    
    else    if (Symbol()=="EURUSD") 
    {
      PipsForEntry= 13;
      TrailingStop = 30;
      TakeProfit = 80;
      InitialStopLoss=60;
    } 
    
    else    if (Symbol()=="USDCHF") 
    {
      PipsForEntry= 13;
      TrailingStop = 30;
      TakeProfit = 100;
      InitialStopLoss=50;
    } 
    
    else 
    {      
      PipsForEntry= 10;
      TrailingStop = 40;
      TakeProfit = 60;
      InitialStopLoss=50;
    } 

   if (bartime == Time[0]) 
   {
      return(0);
   } 
   
   else 
   {
      bartime = Time[0]; 
   }


//+------------------------------------------------------------------+
//|  Open orders modification.                                       |
//+------------------------------------------------------------------+

   for(cnt=OrdersTotal();cnt>=0;cnt--)
   {
      if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES)) {
      err = GetLastError();
  		if (err>1) { Print("Error selecting order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); }
      
      if(OrderType()==OP_BUY && OrderSymbol()==Symbol() && (OrderMagicNumber()==(MagicNumber+1) || OrderMagicNumber()==(MagicNumber+3))) {
      	if(TimeDay(OrderOpenTime())!=TimeDay(Time[0])) {
            if (ClsOnlUnprTX==1) {
               if(Bid-OrderOpenPrice()<Point*TrailingStop) {
                  OrderClose(OrderTicket(), OrderLots(), Bid, 3, Red);
               }  
            } else {
         		 OrderClose(OrderTicket(), OrderLots(), Bid, 3, Red);
         	}
            err = GetLastError();
      		if (err>1) { Print("Error closing buy order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); }
			} else if (TrailingStop>0) {
			   if (ProtectYourInvestments==1 && Bid-OrderOpenPrice()>Point*TrailingStop) {
			      ts = OrderOpenPrice();
			   } else {
			      if (Type_TS_Calc==1) {
                  ts = Bid-(Point*TrailingStop);
               } else if (Type_TS_Calc==2) {
                  ts = Low[0] - FactorTSCalculation * iATR(NULL,0,14,0);
               } else if (Type_TS_Calc==3) {
                  ts = Low[0] - (FactorTSCalculation *(High[0]-Low[0]));
               }
				}
				if (OrderStopLoss()<ts && Bid-OrderOpenPrice()>Point*TrailingStop) OrderModify(OrderTicket(),OrderOpenPrice(),ts,OrderTakeProfit(),0,White);
            err = GetLastError();
      		if (err>1) { Print("Error modifying buy order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); }
			}
      } else if(OrderType()==OP_SELL && OrderSymbol()==Symbol() && (OrderMagicNumber()==(MagicNumber+2) || OrderMagicNumber()==(MagicNumber+4))) {
      	if(TimeDay(OrderOpenTime())!=TimeDay(Time[0])) {
            if (ClsOnlUnprTX==1) {
               if((OrderOpenPrice()-Ask)<(Point*TrailingStop)) {
                  OrderClose(OrderTicket(), OrderLots(), Ask, 3, Red);
               }
            } else {
         		 OrderClose(OrderTicket(), OrderLots(), Ask, 3, Red);
         	}
            err = GetLastError();
      		if (err>1) { Print("Error closing Sell order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); }
			} else if (TrailingStop>0) {	
			   if (ProtectYourInvestments==1 && (OrderOpenPrice()-Ask)>(Point*TrailingStop)) {
			      ts = OrderOpenPrice();
			   } else {
			      if (Type_TS_Calc==1) {
                  ts = Ask+(Point*TrailingStop);
               } else if (Type_TS_Calc==2) {
                  ts = High[0] + FactorTSCalculation * iATR(NULL,0,14,0);
               } else if (Type_TS_Calc==3) {
                  ts = High[0] + (FactorTSCalculation *(High[0]-Low[0]));
               }
				}

				if (OrderStopLoss()>ts && (OrderOpenPrice()-Ask)>(Point*TrailingStop)) OrderModify(OrderTicket(),OrderOpenPrice(),ts,OrderTakeProfit(),0,White);
            err = GetLastError();
      		if (err>1) { Print("Error modifying Sell order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); }
			}
		}
		}
	}
			

//+------------------------------------------------------------------+
//|  Preparing new orders                                            |
//+------------------------------------------------------------------+
   
   if(AccountFreeMargin()<(1000*Lots) || AccountFreeMargin() < Equitycutoff) return(0);  
   
   if(DayOfWeek()==5)   Validity=StrToTime(TimeYear(Time[0]) + "." + TimeMonth(Time[0]) + "." + TimeDay(Time[0]) + " 22:55")+(TimeZoneDiff*3600);
   else                 Validity=StrToTime(TimeYear(Time[0]) + "." + TimeMonth(Time[0]) + "." + TimeDay(Time[0]) + " 23:59")+(TimeZoneDiff*3600);
   
	if(MoneyManagement)
   {
     TradeLots = NormalizeDouble(MathFloor(AccountBalance()*TradeSizePercent/10000)/10,1);
     if(AccountIsMini)
     {
       TradeLots = MathFloor(TradeLots)/10;
    
        if(TradeLots<0.1) TradeLots=0.1;
        }
     }
   else {
   
     TradeLots = Lots;
     
     if(AccountIsMini)
     {
       if (TradeLots >= 1.0) TradeLots = TradeLots/10;
       if (TradeLots < 0.1) TradeLots = 0.1;
     }
   }
	
	for(i=1;i<5;i++) { Order[i]=false; } 
   for(cnt=OrdersTotal();cnt>=0;cnt--)
   {
      OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
		err = GetLastError();
      
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==(MagicNumber+1)) 
      {
      	Order[1]=true;
      } 
      else if (OrderSymbol()==Symbol() && OrderMagicNumber()==(MagicNumber+2)) 
      {
      	Order[2]=true;
      } 
      else if (OrderSymbol()==Symbol() && OrderMagicNumber()==(MagicNumber+3)) 
      {
      	Order[3]=true;
      } 
      else if (OrderSymbol()==Symbol() && OrderMagicNumber()==(MagicNumber+4)) 
      {
      	Order[4]=true;
      }
	}      	
	
	if (TimeHour(Time[0])==BeginSession1+LengthSession1+TimeZoneDiff && TimeMinute(Time[0])==0) 
	{
	   LowestPrice=Low[Lowest(NULL, 0, MODE_LOW, LengthSession1*60/Period(), 0)];
		HighestPrice=High[Highest(NULL, 0, MODE_HIGH, LengthSession1*60/Period(), 0)];
		
		Print("Determine Low: " + LowestPrice + " and High: " + HighestPrice + " for timephase " + TimeToStr(Time[240/Period()]) + " - " + TimeToStr(Time[0]));
		
		Price = HighestPrice+PipsForEntry*Point;

   	if (TakeProfit>0) 
   	{  
      	tp=Price+TakeProfit*Point;
		} 
		else 
		{
		   tp=0; 
		}
	
		if (InitialStopLoss>0) 
		{ 	
         if((Price-InitialStopLoss*Point)<LowestPrice-PipsForEntry*Point) 
         { 
            sl = LowestPrice-PipsForEntry*Point;
         } 
         else 
         {                                        
            sl = Price-InitialStopLoss*Point;
         }
		} 
		else 
		{
		      sl=0; 
		}

      if (!Order[1]) ticket=OrderSendExtended(Symbol(),OP_BUYSTOP,TradeLots,Price,Slippage,sl,tp,setup,(MagicNumber+1),Validity,Green);
      	   
  		Price = LowestPrice-PipsForEntry*Point;

   	if (TakeProfit>0) 
   	{
   	   tp=Price-TakeProfit*Point;
		} 
		else 
		{
		   tp=0; 
		}
		
		if (InitialStopLoss>0)
		{ 	
         if((Price+InitialStopLoss*Point)>HighestPrice+PipsForEntry*Point) 
         { 
            sl = HighestPrice+PipsForEntry*Point;
         } 
         else 
         {                                         
            sl = Price+InitialStopLoss*Point;
         }
		} 
		else 
		{
		   sl=0;
		}

      Sleep(OrderInterval);

		if (!Order[2]) ticket=OrderSendExtended(Symbol(),OP_SELLSTOP,TradeLots,Price,Slippage,sl,tp,setup,(MagicNumber+2),Validity,Green); 
		
	}
	
	if (TimeHour(Time[0])==BeginSession2+LengthSession2+TimeZoneDiff && TimeMinute(Time[0])==0) 
	{
		LowestPrice=Low[Lowest(NULL, 0, MODE_LOW, LengthSession2*60/Period(), 0)];
		HighestPrice=High[Highest(NULL, 0, MODE_HIGH, LengthSession2*60/Period(), 0)];
		
		Print("Determine Low: " + LowestPrice + " and High: " + HighestPrice + " for timephase " + TimeToStr(Time[240/Period()]) + " - " + TimeToStr(Time[0]));

		Price = HighestPrice+PipsForEntry*Point;
		
   	if (TakeProfit>0) 
   	{  
   	tp=Price+TakeProfit*Point;
		} 
		else 
		{
		tp=0; 
		}
	
		if (InitialStopLoss>0) 
		{ 	
         if((Price-InitialStopLoss*Point)<LowestPrice-PipsForEntry*Point) 
         { 
            sl = LowestPrice-PipsForEntry*Point;
         } 
         else 
         {                                        
            sl = Price-InitialStopLoss*Point;
         }
		} 
		else 
		{
		sl=0; 
		}

		if (!Order[3]) ticket=OrderSendExtended(Symbol(),OP_BUYSTOP,TradeLots,Price,Slippage,sl,tp,setup,(MagicNumber+3),Validity,Green); 

		Price = LowestPrice-PipsForEntry*Point;

   	if (TakeProfit>0) 
   	{  
   	tp=Price-TakeProfit*Point;
		} 
		else 
		{
		tp=0; 
		}
		
		if (InitialStopLoss>0) 
		{ 	
         if((Price+InitialStopLoss*Point)>HighestPrice+PipsForEntry*Point) 
         { 
            sl = HighestPrice+PipsForEntry*Point;
         } 
         else 
         {                                         
            sl = Price+InitialStopLoss*Point;
         }
		} 
		else 
		{
		sl=0; 
		}

      Sleep(OrderInterval);
      
		if (!Order[4]) ticket=OrderSendExtended(Symbol(),OP_SELLSTOP,TradeLots,Price,Slippage,sl,tp,setup,(MagicNumber+2),Validity,Green); 

	}
}

//+------------------------------------------------------------------+
//| Functions beyond this point shouldn't need any modification      |
//+------------------------------------------------------------------+

int func_Symbol2Val(string symbol) {
	if(symbol=="AUDUSD") {	return(01);

	} else if(symbol=="CHFJPY") {	return(02);

	} else if(symbol=="EURAUD") {	return(10);
	} else if(symbol=="EURCAD") {	return(11);
	} else if(symbol=="EURCHF") {	return(12);
	} else if(symbol=="EURGBP") {	return(13);
	} else if(symbol=="EURJPY") {	return(14);
	} else if(symbol=="EURUSD") {	return(15);
	} else if(symbol=="GBPCHF") {	return(20);
	} else if(symbol=="GBPJPY") {	return(21);
	} else if(symbol=="GBPUSD") { return(22);
	} else if(symbol=="USDCAD") {	return(40);
	} else if(symbol=="USDCHF") {	return(41);
	} else if(symbol=="USDJPY") {	return(42);
	} else if(symbol=="GOLD") {	return(90);
	} else return(0);	
}

int OrderSendExtended(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic, datetime expiration=0, color arrow_color=CLR_NONE) {
   
   datetime    OldCurTime;
   int         timeout=5;
   int         ticket=0;
   int         err1;
   
   if (!IsTesting()) 
   {
         MathSrand(LocalTime());
         Sleep(MathRand()/6);
   }

   OldCurTime=CurTime();
   
   while (GlobalVariableCheck("InTrade") && !IsTradeAllowed()) 
   {
      
         if(OldCurTime+timeout<=CurTime()) 
         {
         Print("Error in OrderSendExtended(): Timeout encountered");
         return(0); 
         }
      
         Sleep(OrderInterval/10);
   }
     
   ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
   Sleep (OrderInterval+5000);
      
   err1 = GetLastError();
   		
	if (err1==130)
	{
         ticket=OrderSend(symbol, cmd, volume, Ask, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
         Sleep (OrderInterval+5000);
   } 
     
   while (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) 
   {
         ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
         Sleep (OrderInterval+5000);
         
         err1 = GetLastError();

         if (err1==130)
	      {
         ticket=OrderSend(symbol, cmd, volume, Ask, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
         Sleep (OrderInterval+5000);
         } 
  
         if (err1 > 0)
         {
         Print("error(",err1,"): ",ErrorDescription(err1));
         }
   }
   
   return(ticket);
}