//+------------------------------------------------------------------+
//|                                            NarrowBreakout_GBPM30 |
//|                                   Copyright © 2006, Lingyu Jiang |
//+------------------------------------------------------------------+
extern string    Broker="Alpari";                                  // you can also set "FXDD", "IBFX" here

//---- common parameters
extern bool      UseMM=true;
extern double    LotsIfNoMM=1.0;
extern double    MMRiskFactor=0.2;
extern int       Spread=4;
extern int       Start=9;
extern int       EOD=17;

//---- input parameters for narrow range breakout
extern int       NLookbackBars=4;
extern int       NPips=10;
extern int       NStopLoss=45;
extern int       NBreakEven=15;
extern int       NTakeProfit=0;
extern int       NRangeMax=43; 

//---- global variables
double Lots=1.0;
int    MagicNumber2=2;
double EntryLong2=0,EntryShort2=0;

int init()
{
   if (Broker == "FXDD") {
      Spread=3;
      Start=10;
      EOD=18;
      NLookbackBars=4;
      NPips=10;
      NStopLoss=45;
      NBreakEven=16;
      NTakeProfit=0;
      NRangeMax=42;
   } 
   else if (Broker == "IBFX") {
      Spread=4;
      Start=8;
      EOD=16;
      NLookbackBars=4;
      NPips=10;
      NStopLoss=45;
      NBreakEven=15;
      NTakeProfit=0;
      NRangeMax=43;
   }
   return (0);
}

//--- MM calculation
double CalculateMMLot()
{
   double lot_min =MarketInfo(Symbol(),MODE_MINLOT);
   double lot_max =MarketInfo(Symbol(),MODE_MAXLOT);
   double lot_step=MarketInfo(Symbol(),MODE_LOTSTEP);
   double lot;
   //--- check data
   if(lot_min<0 || lot_max<=0.0 || lot_step<=0.0) {
      Print("CalculateMMLot: invalid MarketInfo() results [",lot_min,",",lot_max,",",lot_step,"]");
      return(0);
   }
   if(AccountLeverage()<=0) {
      Print("CalculateMMLot: invalid AccountLeverage() [",AccountLeverage(),"]");
      return(0);
   }
   //--- basic formula
   lot=NormalizeDouble((AccountBalance())*MMRiskFactor/AccountLeverage()/10.0,2);
   lot=NormalizeDouble(lot/lot_step,0)*lot_step;
   if(lot<lot_min) lot=lot_min;
   if(lot>lot_max) lot=lot_max;
   //---
   return(lot);
  }

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   //---- 
   int i,Ticket,LastOrderTime,StartTime,StartTime1,StartTime2,EODTime;

   if (UseMM) Lots=CalculateMMLot(); else Lots=LotsIfNoMM;

   //Count time
   if(CurTime()>=StrToTime(Start+":00")-60){
      StartTime1=StrToTime(Start+":00");
      if(DayOfWeek()==5)   EODTime=MathMin(StrToTime("22:55"),StrToTime(EOD+":00")-60);
      else if (EOD==24)    EODTime=StrToTime("23:59");
      else                 EODTime=StrToTime(EOD+":00")-60;
   }
   
   // Set narrow range breakout orders
   if(TimeHour(CurTime()) >= Start && TimeHour(CurTime())<EOD) {
      SetNarrowRangeBreakoutOrders(MagicNumber2);
   }
   
   //Manage of open orders
   for (i=0;i<OrdersTotal();i++){
      OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if (OrderMagicNumber()!=MagicNumber2) continue;
      if(CurTime()<=GlobalVariableGet("LastOrderTime")+10) Sleep(10000);
      if(CurTime()>=EODTime){     //close open positions at EOD
         if(OrderSymbol()==Symbol() && OrderType()==OP_BUY)      OrderClose(OrderTicket(),OrderLots(),Bid,3,Red);
         if(OrderSymbol()==Symbol() && OrderType()==OP_SELL)     OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
         if(OrderSymbol()==Symbol() && OrderType()==OP_BUYSTOP)  OrderDelete(OrderTicket());
         if(OrderSymbol()==Symbol() && OrderType()==OP_SELLSTOP) OrderDelete(OrderTicket());
         GlobalVariableSet("LastOrderTime",CurTime());
      }   
      else {
         double OpenPrice = 0;
         // manage narrow range breakout orders
         if (OrderMagicNumber() == MagicNumber2) {
            OpenPrice = 0;
            //move at BE if profit>BE
            if(OrderSymbol()==Symbol() && OrderType()==OP_BUY){
               if (EntryLong2 != 0) {
                  OpenPrice = EntryLong2;
               } else {
                  OpenPrice = OrderOpenPrice();
               }
               if(High[1]-OpenPrice>=NBreakEven*Point && High[0]-OpenPrice>=NBreakEven*Point && OrderStopLoss()<OpenPrice+5*Point){
                  OrderModify(OrderTicket(),OrderOpenPrice(),OpenPrice+5*Point,OrderTakeProfit(),0,Green);
                  GlobalVariableSet("LastOrderTime",CurTime());
               }   
            }   
            if(OrderSymbol()==Symbol() && OrderType()==OP_SELL){
               if (EntryShort2 != 0) {
                  OpenPrice = EntryShort2;
               } else {
                  OpenPrice = OrderOpenPrice();
               }
               if(OpenPrice-Low[1]-Spread*Point>=NBreakEven*Point && OpenPrice-Low[0]-Spread*Point>=NBreakEven*Point && OrderStopLoss()>OpenPrice-5*Point){
                  OrderModify(OrderTicket(),OrderOpenPrice(),OpenPrice-5*Point,OrderTakeProfit(),0,Green);
                  GlobalVariableSet("LastOrderTime",CurTime());
               }
            }
         }   
      }
   }
   
   //Reset global variables at EOD
   if(CurTime()>=EODTime) GlobalVariablesDeleteAll();
   
   return(0);
  }

//+------------------------------------------------------------------+
int SetNarrowRangeBreakoutOrders(int MN) {
   int i,Ticket,LastOrderTime,Bought=0,Sold=0,ShiftToStart,ShiftToBeginOfRange;
   double SLLong,SLShort,TPLong,TPShort;

   //Check Orders
   for (i=0;i<OrdersTotal();i++){
      OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if(OrderSymbol()==Symbol() && (OrderType()==OP_BUYSTOP || OrderType()==OP_BUY) && OrderMagicNumber()==MN) Bought++;
      if(Bought>1){ //more than 1 buy order
         if(CurTime()<=GlobalVariableGet("LastOrderTime")+10) Sleep(10000);
         if(OrderSymbol()==Symbol() && OrderType()==OP_BUY)      OrderClose(OrderTicket(),OrderLots(),Bid,3,Red);
         if(OrderSymbol()==Symbol() && OrderType()==OP_BUYSTOP)  OrderDelete(OrderTicket());
      }
      if(OrderSymbol()==Symbol() && (OrderType()==OP_SELLSTOP || OrderType()==OP_SELL) && OrderMagicNumber()==MN) Sold++;
      if(Sold>1){ //more than 1 sell order
         if(CurTime()<=GlobalVariableGet("LastOrderTime")+10) Sleep(10000);
         if(OrderSymbol()==Symbol() && OrderType()==OP_SELL)     OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
         if(OrderSymbol()==Symbol() && OrderType()==OP_SELLSTOP) OrderDelete(OrderTicket());
      }
   }
   
   if(Bought==0 && Sold==0){ //no buy order
      // determine range
      EntryLong2   =High[Highest(NULL,PERIOD_M30,MODE_HIGH,NLookbackBars,1)]+(NPips+Spread)*Point;
      EntryShort2  =Low[Lowest (NULL,PERIOD_M30,MODE_LOW, NLookbackBars,1)]-NPips*Point;
      SLLong      =MathMax(EntryLong2-NStopLoss*Point,EntryShort2);
      SLShort     =MathMin(EntryShort2+NStopLoss*Point,EntryLong2);
      if (NTakeProfit!=0) {
         TPLong      =EntryLong2+NTakeProfit*Point;
         TPShort     =EntryShort2-NTakeProfit*Point;
      } else {
         TPLong      =0;
         TPShort     =0;
      }
   
      if (EntryLong2-EntryShort2>=NRangeMax*Point) { //So we can filter out large ranges
         // Ensures that no trades will be opened
         Bought=1;
         Sold=1;
         return (0);
      }

      if(CurTime()<=GlobalVariableGet("LastOrderTime")+10) Sleep(10000);
      Ticket=OrderSend(Symbol(),OP_BUYSTOP,Lots,EntryLong2,3,SLLong,TPLong,NULL,MN,0,Green);
      if(Ticket<0 && GetLastError()==130 && High[0]+Spread*Point>=EntryLong2 && Ask <= EntryLong2+3*Point && Ask>=EntryLong2-3*Point)
         Ticket=OrderSend(Symbol(),OP_BUY,Lots,EntryLong2,3,SLLong,TPLong,NULL,MN,0,Green);
      GlobalVariableSet("LastOrderTime",OrderOpenTime()); 


      if(CurTime()<=GlobalVariableGet("LastOrderTime")+10) Sleep(10000);
      Ticket=OrderSend(Symbol(),OP_SELLSTOP,Lots,EntryShort2,3,SLShort,TPShort,NULL,MN,0,Green);
      if(Ticket<0 && GetLastError()==130 && Low[0]<=EntryShort2 && Bid>=EntryShort2-3*Point && Bid<=EntryShort2+3*Point)
         Ticket=OrderSend(Symbol(),OP_SELL,Lots,EntryShort2,3,SLShort,TPShort,NULL,MN,0,Green);
      GlobalVariableSet("LastOrderTime",OrderOpenTime()); 
   }
}