//+------------------------------------------------------------------+
//|                                                   nk3BarHiLo.mq4 |
//|                                Copyright © 2007, Hartono Setiono |
//| Simple EA based on 3 Bar Hi Lo based on Peter Henry idea         |
//| Filter : 240 Minutes 3 Bar high exceeded (3barhilo_240)          |
//| Entry  : 60 Minute 3 Bar high exceed buy 1 pip above for buy entry (3barhilo_60)
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, HS"
#property link      ""
#include <stdlib.mqh>
#include <stderror.mqh> 

//---- input parameters
extern double Lots=0.1;
extern double StopLoss = 100; 
extern double TakeProfit = 500;
extern bool   UseTrailingStop = true;
extern int	  TrailingStopType 	= 2;
extern double TrailingStop	= 100;
extern int  GMTshift = 0;
extern int  HiTFPeriod=6;
extern int  LoTFPeriod=3;
extern int  MagicNumber=234;

int Slippage = 3;
string EAName="nk3BarHiLo";

double OpenBuy=0;
double OpenSell=0;
double OpenBuyLimit=0;
double OpenSellLimit=0;
double OpenBuyStop=0;
double OpenSellStop=0;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//---- TODO: add your code here
   return(0);
  }
  
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//---- TODO: add your code here
   return(0);
  }

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   double open_pos=0;
   double llots=Lots;

   //CalcPivot();
   //CalcADR();
   //CalcMA();
   double Hi3H4=iHigh(NULL,PERIOD_H4,iHighest(NULL,PERIOD_H4,MODE_HIGH,HiTFPeriod,1));
   double Lo3H4=iLow(NULL,PERIOD_H4,iLowest(NULL,PERIOD_H4,MODE_LOW,HiTFPeriod,1));

   double Hi3H1=iHigh(NULL,PERIOD_H1,iHighest(NULL,PERIOD_H1,MODE_HIGH,LoTFPeriod,1));
   double Lo3H1=iLow(NULL,PERIOD_H1,iLowest(NULL,PERIOD_H1,MODE_LOW,LoTFPeriod,1));
   
   if(Bid>Hi3H4+5*Point && Bid>Hi3H1 && OpenBuy==0) 
   {
     CloseShorts(MagicNumber);
     OpenOrder(OP_BUY, llots, Ask, Slippage, StopLoss, TakeProfit, EAName, MagicNumber, 0, Blue); 
   }
   
   if(Bid<Lo3H4-5*Point && Bid<Lo3H1 && OpenSell==0) 
   {
     CloseLongs(MagicNumber);
     OpenOrder(OP_SELL, llots, Bid, Slippage, StopLoss, TakeProfit, EAName, MagicNumber, 0, Red); 
   }

   CheckOpenPositions();
   
   HandleOpenPositions();
   
   return(0);
}
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| Handle Open Positions                                            |
//| Check if any open positions need to be closed or modified        |
//+------------------------------------------------------------------+
int HandleOpenPositions()
{
   int cnt;
   bool YesClose;
   double pt;
   
   for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
   {
      OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol() != Symbol()) continue;
      if ( OrderMagicNumber() != MagicNumber)  continue;
      
      if(UseTrailingStop)	// Handle mods to trailing stop
	      HandleTrailingStop(OrderType(), OrderTicket(), OrderOpenPrice(), OrderStopLoss());
	      
      if(OrderType() == OP_BUY)
      {
      }

      if(OrderType() == OP_SELL)
      {
      }
   }
   return(0);
}


int OpenOrder(int aCmd, double aLots, double aPrice, int aSlipPage, int aStopLoss, int aTakeProfit, string aComment, int aMagic, datetime aExpiration, color aColor) 
{
   int order_ticket = 0;
   int err = 0;
   int l_Try = 0;
   int l_MaxTry = 10;
   double aPrice2=aPrice+Ask-Bid;
   
   switch (aCmd) {
   case OP_BUY:
   case OP_BUYLIMIT:
   case OP_BUYSTOP:
      for (l_Try = 0; l_Try < l_MaxTry; l_Try++) 
      {
         if(aCmd==OP_BUY) { RefreshRates(); aPrice=Ask; aPrice2=Bid; }
         order_ticket = OrderSend(Symbol(), aCmd, aLots, aPrice, aSlipPage, StopLong(aPrice, aStopLoss), TakeLong(aPrice, aTakeProfit), aComment, aMagic, aExpiration, aColor);
         if (order_ticket > 0) break;
         err = GetLastError();
         if (err == 0) break;
         if (err == 4 || err == 137 || err == 146 || err == 136) Sleep(5000);
         else {
            Print("Error Code= ", err);
            break;
         }
      }
      break;
   case OP_SELL:
   case OP_SELLLIMIT:
   case OP_SELLSTOP:
      for (l_Try = 0; l_Try < l_MaxTry; l_Try++) {
         if(aCmd==OP_SELL) { RefreshRates(); aPrice=Bid; aPrice2=Ask; }
         order_ticket = OrderSend(Symbol(), aCmd, aLots, aPrice, aSlipPage, StopShort(aPrice2, aStopLoss), TakeShort(aPrice2, aTakeProfit), aComment, aMagic, aExpiration, aColor);
         if (order_ticket > 0) break;
         err = GetLastError();
         if (err == 0) break;
         if (err == 4 || err == 137 || err == 146 || err == 136) Sleep(5000);
         else {
            Print("Error Code= ", err);
            break;
         }
      }
   }
   return (order_ticket);
}

double StopLong(double ad_0, int ai_8) {
   if (ai_8 == 0) return (0);
   else return (ad_0 - ai_8 * Point);
}

double StopShort(double ad_0, int ai_8) {
   if (ai_8 == 0) return (0);
   else return (ad_0 + ai_8 * Point);
}

double TakeLong(double ad_0, int ai_8) {
   if (ai_8 == 0) return (0);
   else return (ad_0 + ai_8 * Point);
}

double TakeShort(double ad_0, int ai_8) {
   if (ai_8 == 0) return (0);
   else return (ad_0 - ai_8 * Point);
}

double CheckOpenPositions(bool InclOpenOrder=true)
{
   int cnt, total;
   double NumPositions;
   
   NumPositions = 0;
   total=OrdersTotal();
   OpenBuy=0;
   OpenSell=0;
   OpenBuyLimit=0;
   OpenSellLimit=0;
   OpenBuyStop=0;
   OpenSellStop=0;
   for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
     {
      OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol() != Symbol()) continue;
      if ( OrderMagicNumber() != MagicNumber)  continue;
      
      if(OrderType() == OP_BUY ) OpenBuy=OpenBuy+OrderLots();
      if(OrderType() == OP_SELL ) OpenSell=OpenSell+OrderLots();
      if(OrderType() == OP_BUYLIMIT ) OpenBuyLimit=OpenBuyLimit+OrderLots();
      if(OrderType() == OP_SELLLIMIT ) OpenSellLimit=OpenSellLimit+OrderLots();
      if(OrderType() == OP_BUYSTOP ) OpenBuyStop=OpenBuyStop+OrderLots();
      if(OrderType() == OP_SELLSTOP ) OpenSellStop=OpenSellStop+OrderLots();
     }
     NumPositions = OpenBuy-OpenSell;
     if(InclOpenOrder) NumPositions += OpenBuyLimit+OpenBuyStop-OpenSellLimit-OpenSellStop;
     return (NumPositions);
}

int HandleTrailingStop(int type, int ticket, double open_price, double cur_sl)
{
	double pt, TS = 0, myAsk, myBid;


	if (type == OP_BUY)
	{
		myBid = MarketInfo(Symbol(),MODE_BID);
		switch (TrailingStopType)
		{
			case 1: 
				pt = Point * StopLoss;
				if (myBid - cur_sl > pt) 
					ModifyStopLoss(ticket, myBid - pt);
				break;
				
			case 2: 
				pt = Point * TrailingStop;
				if (myBid - open_price > pt && (cur_sl < myBid - pt || cur_sl == 0))
					ModifyStopLoss(ticket, myBid - pt);
				break;

		}
		return(0);
	}


	else if (type ==  OP_SELL)
	{
		myAsk = MarketInfo(Symbol(),MODE_ASK);
		switch (TrailingStopType)
		{
			case 1: 
				pt = Point * StopLoss;
				if (cur_sl - myAsk > pt) 
					ModifyStopLoss(ticket, myAsk+pt);
				break;
				
			case 2: 
				pt = Point * TrailingStop;
				if (open_price - myAsk > pt && (cur_sl > myAsk + pt || cur_sl == 0))
					ModifyStopLoss(ticket, myAsk+pt);
				break;
				
		 }
	 }
	 return(0);
}

int ModifyStopLoss(int ticket, double stoploss)
{
    int Cnt, digits, err;
    string symbol;
    double myStopLoss;
    
    OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
    symbol = OrderSymbol();
    digits = MarketInfo(symbol,MODE_DIGITS);
    if (digits > 0)
    {
			 myStopLoss = NormalizeDouble(stoploss,digits);
    }
    Cnt=0;
    while (Cnt < 3)
    {
       if (OrderModify(ticket,OrderOpenPrice(),myStopLoss,OrderTakeProfit(),0,Aqua))
       {
         Cnt = 3;
       }
       else
       {
          err=GetLastError();
          Print(Cnt," Error modifying order : (", err , ") " + ErrorDescription(err));
         if (err>0) Cnt++;
       }
    }
}

void CloseLongs(int MagicNumber, double clots=0)
{
 int trade, err;
 double llots;
 
 //Print("Close Longs:",MagicNumber,", Lots:",clots);
 for(trade=OrdersTotal()-1;trade>=0;trade--)
 {
  if(!OrderSelect(trade,SELECT_BY_POS,MODE_TRADES)) continue;
  if(OrderSymbol()!=Symbol()) continue;
  if(OrderMagicNumber()!=MagicNumber) continue;
  if(OrderType()!=OP_BUY) continue;
   
  if (clots==0) llots=OrderLots(); else llots=clots;
  //Print("Ticket:",OrderTicket(),", MagicNumber:",OrderMagicNumber(),", Lots:",llots);
  OrderClose(OrderTicket(),llots,Bid,Slippage,Blue);

  err=GetLastError();
  if(err!=0) Print("Error = ", err," - ",ErrorDescription(err));
 }//for
}

void CloseShorts(int MagicNumber, double clots=0)
{
 int trade, err;
 double olots;
 for(trade=OrdersTotal()-1;trade>=0;trade--)
 {
  if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES)==false) continue;
  if(OrderSymbol()!=Symbol()) continue;
  if(OrderMagicNumber()!=MagicNumber) continue;
  if(OrderType()!=OP_SELL) continue;
  
  olots=OrderLots();
  if (clots==0) clots=olots; 
  OrderClose(OrderTicket(),clots,Ask,Slippage,Red);

  err=GetLastError();
  if(err!=0) Print("Error = ", err," - ",ErrorDescription(err));
 }//for
}

