//+------------------------------------------------------------------+
//|                                                   nkHedgeLot.mq4 |
//|                                Copyright © 2007, Hartono Setiono |
//| Simple EA based on Hedging Lot Strategy                          |
//+------------------------------------------------------------------+
#property copyright "©2007, HS"
#property link      ""
#include <stdlib.mqh>
#include <stderror.mqh> 

//---- input parameters
extern double Lots=1;

extern double StopDistance = 30;
extern double TakeProfit = 30;
extern double StopLoss=60;
extern bool FirstOrderIsLong = true;
extern int  MagicNumber=999;

extern bool UseHourTrade  = false;  
extern int  FromHourTrade  = 9; // broker's server time
extern int  ToHourTrade  = 20;// broker's server time

int Slippage = 3;

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

double LastBuyStopPrice=0;
double LastSellStopPrice=0;
double BuyStopPrice=0;
double SellStopPrice=0;
double aLots[]={1,3,6,12,24,48,96,192,384,768};
double MaxLots=0;

//Trade Signal
#define _NONE 0
#define _BUY   1
#define _SELL  2
#define _CLOSEBUY 4
#define _CLOSESELL 8
#define _OPENBUYSTOP 16
#define _OPENSELLSTOP 32
#define _DELETEBUYSTOP 64
#define _DELETESELLSTOP 128

int cur_signal=_NONE;

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

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   double llots;
   double lSL;
   bool OpenNewTradesOK;
   
   OpenNewTradesOK = true;
   if (UseHourTrade)
    {
      if (!(Hour()>=FromHourTrade && Hour()<=ToHourTrade)) 
      {
         Comment("Time for trade has not come yet!");
         OpenNewTradesOK = false;
      } 
   }   

   if(MaxLots==0) llots=Lots; else
   if(MaxLots==Lots) llots=3*Lots; else
     llots=MaxLots*2;
     
   lSL=StopLoss;
   
   CheckSignal();
   
   if(cur_signal & _BUY !=0)
     if (OpenNewTradesOK) OpenOrder(OP_BUY, llots, Ask, Slippage, lSL, TakeProfit, WindowExpertName(), MagicNumber, 0, Blue); 

   if(cur_signal & _SELL !=0)
     if (OpenNewTradesOK) OpenOrder(OP_SELL, llots, Bid, Slippage, lSL, TakeProfit, WindowExpertName(), MagicNumber, 0, Red); 

   if(cur_signal & _CLOSEBUY !=0)
   {
     CloseLongs(MagicNumber);
   }

   if(cur_signal & _CLOSESELL !=0)
   {
     CloseShorts(MagicNumber);
   }
   
   if(cur_signal & _DELETEBUYSTOP !=0)
     DeleteOpenOrder(OP_BUYSTOP);

   if(cur_signal & _DELETESELLSTOP !=0)
     DeleteOpenOrder(OP_SELLSTOP);

   if(cur_signal & _OPENBUYSTOP !=0)
   {
    if (OpenNewTradesOK)
    {
     DeleteOpenOrder(OP_BUYSTOP);
     if(FirstOrderIsLong) BuyStopPrice=EntryPrice; else BuyStopPrice=EntryPrice+StopDistance*Point;
     OpenOrder(OP_BUYSTOP, llots, BuyStopPrice, Slippage, lSL, TakeProfit, WindowExpertName(), MagicNumber, 0, Blue); 
    }
   }

   if(cur_signal & _OPENSELLSTOP !=0)
   {
    if (OpenNewTradesOK)
    {
     DeleteOpenOrder(OP_SELLSTOP);
     if(FirstOrderIsLong) SellStopPrice=EntryPrice-StopDistance*Point; else SellStopPrice=EntryPrice;
     OpenOrder(OP_SELLSTOP, llots, SellStopPrice, Slippage, lSL, TakeProfit, WindowExpertName(), MagicNumber, 0, Red); 
    }
   }

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


void CheckSignal()
{
  cur_signal=_NONE;
  
  if(OpenBuy==0 && OpenSell==0)
  {
    if(OpenBuyStop>0) cur_signal |= _DELETEBUYSTOP;
    if(OpenSellStop>0) cur_signal |= _DELETESELLSTOP;
    
    if(cur_signal==_NONE)
    {
      if(FirstOrderIsLong) cur_signal |= _BUY; else cur_signal |= _SELL;
      EntryPrice=0;
    }
  }
  
  if(OpenBuy!=0 || OpenSell!=0)
  {
    if(OpenBuy>OpenSell && OpenSellStop==0)
    {
      cur_signal |= _OPENSELLSTOP;
    }
    if(OpenBuy<OpenSell && OpenBuyStop==0)
    {
      cur_signal |= _OPENBUYSTOP;
    }
  }
}


//+------------------------------------------------------------------+
//| 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(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 aPrice, int aPips) {
   if (aPips == 0) return (0);
   else return (aPrice - aPips * Point);
}

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

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

double TakeShort(double aPrice, int aPips) {
   if (aPips == 0) return (0);
   else return (aPrice - aPips * 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;
   MaxLots=0;

   for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
     {
      OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol() != Symbol()) continue;
      
      if ( OrderMagicNumber() != MagicNumber)  continue;
      
      if(MaxLots<OrderLots()) MaxLots=OrderLots();
      
      if(OrderType() == OP_BUY ) 
      {
        OpenBuy=OpenBuy+OrderLots();
        if(EntryPrice==0) EntryPrice=OrderOpenPrice();
      }
      if(OrderType() == OP_SELL ) 
      {  
        OpenSell=OpenSell+OrderLots();
        if(EntryPrice==0) EntryPrice=OrderOpenPrice();
      }
      
      if(OrderType() == OP_BUYLIMIT ) OpenBuyLimit=OpenBuyLimit+OrderLots();
      if(OrderType() == OP_SELLLIMIT ) OpenSellLimit=OpenSellLimit+OrderLots();
      if(OrderType() == OP_BUYSTOP ) {OpenBuyStop=OpenBuyStop+OrderLots(); LastBuyStopPrice=OrderOpenPrice();}
      if(OrderType() == OP_SELLSTOP ) {OpenSellStop=OpenSellStop+OrderLots(); LastSellStopPrice=OrderOpenPrice();}
     }
     NumPositions = OpenBuy-OpenSell;
     if(InclOpenOrder) NumPositions += OpenBuyLimit+OpenBuyStop-OpenSellLimit-OpenSellStop;
     return (NumPositions);
}


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
}


int DeleteOpenOrder(int aOrderType=-1)
{
   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(aOrderType==OrderType()) OrderDelete(OrderTicket());
      else if(aOrderType==-1)
      switch(OrderType())
      {
        case OP_BUYLIMIT: 
        case OP_SELLLIMIT: 
        case OP_BUYSTOP: 
        case OP_SELLSTOP: OrderDelete(OrderTicket()); break;
      }
   }
   return(0);
}

