//+------------------------------------------------------------------+
//|                                                       cipher.mq4 |
//|                                  Copyright 2015, Khalil Abokwaik |
//|                             http://www.forexfactory.com/abokwaik |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Khalil Abokwaik"
#property link      "http://www.forexfactory.com/abokwaik"
#property version   "1.00"
#property description "Cipher - Grid System"
#property strict
//--- input parameters ----------------------------------------------+
input int      Magic_Number   =4500;   //Magic Number
input double   Lot_Size       =0.1;    //Lot Size
input int      Cipher_level   =1000;   //Cipher Level Pips
input int      SL_pips        =100;//Stop Loss Pips
input int      TP_pips        =100;//Take Profit Pips
input int      trailing_stop  =500;    //Trailing Stop Pips
input int      Order_Type     = 0;//Order Type (0=Stop Orders, 1=Limit Orders)
input bool     multiple_orders=true;//Multiple Orders
input string   trade_comment  ="Cipher";//Trade Comment

//--- global variables ----------------------------------------------+
int NewOrder=0, tries=0,oper_max_tries=10,trail_stop_jump=10;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(Digits==5||Digits==3)
   {
      if (MathMod((double) Cipher_level,500)>0 )
      { 
         Alert("Wrong Cipher Level, must be multiple of 500 Points");
         return(INIT_PARAMETERS_INCORRECT);
      }
      trail_stop_jump=10;
   }
   if(Digits==4||Digits==2)
   {
      if (MathMod((double) Cipher_level,50)>0 )
      { 
         Alert("Wrong Cipher Level, must be multiple of 50 Pips");
         return(INIT_PARAMETERS_INCORRECT);
      }
      trail_stop_jump=1;
   }
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double sell_price=MathFloor((Bid/Point)/Cipher_level)*(Point*Cipher_level);
   double buy_price=sell_price+Cipher_level*Point;
   double trigger_price=sell_price+(Cipher_level*Point/2);
   if(pending_orders()==1 ) delete_pending_orders();
   if(pending_orders()==0 )
   {  if( (total_orders()==0 && !multiple_orders)||multiple_orders)
      {
         if(MathAbs(Bid-trigger_price)<(Cipher_level*0.05*Point)) open_pending_orders(buy_price,sell_price);
      }
   }
   if(total_orders()>0 && trailing_stop>0)
   {
      trail_stop();
   }
  }
//+------------------------------------------------------------------+
int total_orders()
{ int tot_orders=0;
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()==Magic_Number 
         && OrderSymbol()==Symbol()
         && (OrderType()==OP_BUY || OrderType()==OP_SELL)
        ) tot_orders=tot_orders+1;
   }
   return(tot_orders);
}
//+------------------------------------------------------------------+
int order_at_price(double price,int order_type)
{ int tot_orders=0;
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()==Magic_Number 
         && OrderSymbol()==Symbol()
         && OrderType()==order_type
         && OrderOpenPrice()==price
        ) tot_orders=tot_orders+1;
   }
   return(tot_orders);
}

//+------------------------------------------------------------------+
int pending_orders()
{ int tot_orders=0;
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()==Magic_Number 
         && OrderSymbol()==Symbol()
         && (OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP ||OrderType()==OP_SELLLIMIT ||OrderType()==OP_BUYLIMIT)
        ) tot_orders=tot_orders+1;
   }
   return(tot_orders);
}
//+------------------------------------------------------------------+
void delete_pending_orders()
{  bool order_deleted=false;
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()==Magic_Number 
         && OrderSymbol()==Symbol()
         && (OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP ||OrderType()==OP_SELLLIMIT ||OrderType()==OP_BUYLIMIT)
        ) order_deleted=OrderDelete(OrderTicket(),clrWhite);
   }
   
}

//+------------------------------------------------------------------+
int open_pending_orders(double buy_price,double sell_price)
{  
   if(order_at_price(buy_price,OP_BUY) > 0 ||order_at_price(sell_price,OP_SELL) > 0) return(0); 
   
   bool x=false;
   if(Order_Type==0)
   {
      NewOrder=0;
      tries=0;   
      while(NewOrder<=0 && tries< oper_max_tries)
      {
         NewOrder=OrderSend(Symbol(),OP_BUYSTOP,Lot_Size,buy_price,5,
                            buy_price-(SL_pips*Point),        buy_price+(TP_pips*Point),
                            trade_comment,Magic_Number,0,clrBlue);            
         tries=tries+1;
      }
      NewOrder=0;
      tries=0;   
      while(NewOrder<=0 && tries< oper_max_tries)
      {
         NewOrder=OrderSend(Symbol(),OP_SELLSTOP,Lot_Size,sell_price,5,
                            sell_price+(SL_pips*Point),         sell_price-(TP_pips*Point),
                            trade_comment,Magic_Number,0,clrRed);            
         tries=tries+1;
      }
   }
   else
   {
      NewOrder=0;
      tries=0;   
      while(NewOrder<=0 && tries< oper_max_tries)
      {
         NewOrder=OrderSend(Symbol(),OP_SELLLIMIT,Lot_Size,buy_price,5,
                            buy_price+(SL_pips*Point),        buy_price-(TP_pips*Point),
                            trade_comment,Magic_Number,0,clrBlue);            
         tries=tries+1;
      }
   
      NewOrder=0;
      tries=0;   
      while(NewOrder<=0 && tries< oper_max_tries)
      {
         NewOrder=OrderSend(Symbol(),OP_BUYLIMIT,Lot_Size,sell_price,5,
                            sell_price-(SL_pips*Point),         sell_price+(TP_pips*Point),
                            trade_comment,Magic_Number,0,clrRed);            
         tries=tries+1;
      }
   }
   return(NewOrder);
}
//---------------------------------------------------------------------------------------------------
void trail_stop()
{ double new_sl=0; bool OrderMod=false;
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()==Magic_Number && OrderSymbol()==Symbol())
      {
         if(OrderType()==OP_BUY)
         {  new_sl=0;
            if(MarketInfo(Symbol(),MODE_BID)-OrderOpenPrice()>trailing_stop*Point && OrderOpenPrice()>OrderStopLoss()) new_sl=OrderOpenPrice();
            if (MarketInfo(Symbol(),MODE_BID)-OrderStopLoss()>trailing_stop*Point+trail_stop_jump*Point && OrderStopLoss()>=OrderOpenPrice())
            new_sl = MarketInfo(Symbol(),MODE_BID)-trailing_stop*Point;
            OrderMod=false;
            tries=0;
             
             while(!OrderMod && tries<oper_max_tries && new_sl>0)
            {  
               OrderMod=OrderModify(OrderTicket(),OrderOpenPrice(),new_sl,OrderTakeProfit(),0,NULL);
               tries=tries+1;
            }
            
         }
         if(OrderType()==OP_SELL)
         {   new_sl=0;
             if(OrderOpenPrice()-MarketInfo(Symbol(),MODE_ASK)>trailing_stop*Point && OrderOpenPrice()<OrderStopLoss()) new_sl=OrderOpenPrice();
             if(OrderStopLoss()-MarketInfo(Symbol(),MODE_ASK)>trailing_stop*Point+trail_stop_jump*Point && OrderStopLoss()<=OrderOpenPrice())
             new_sl=MarketInfo(Symbol(),MODE_ASK)+trailing_stop*Point;
             OrderMod=false;
             tries=0;
             
             while(!OrderMod && tries<oper_max_tries && new_sl>0)
            {  
               OrderMod=OrderModify(OrderTicket(),OrderOpenPrice(),new_sl,OrderTakeProfit(),0,NULL);
               tries=tries+1;
            }
         
         }
         
      }
   }
}
//---------------------------------------------------------------------------------------------------
