//+------------------------------------------------------------------+
//|                                                      REAV_EA.mq4 |
//|                                  Copyright © 2010, Kenny Hubbard |
//|                                       http://www.compu-forex.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, Kenny Hubbard"
#property link      "http://www.compu-forex.com"
#define        NO_RESULT            -10

extern int     MagicNumber       = 100;
extern double  Eq_StopLoss       = 1000;
extern double  Risk              = 1;
extern double  Trail_From        = 10;
extern double  Trail_Max         = 50.0;
extern double  Trail_Percent     = 25;
extern double  Grid_Size         = 15;

int   
   D_Factor    = 1,
   LotDigits   = 1,
   Slippage    = 3,
   Retries     = 10;
double   
   Anchor,
   Pip,
   Grid_Min = 0,
   Grid_Max = 0,
   Grid_Ord_OpenPrice[][2],
   Auto_Grid;
string
   Order_Cmt = "Bluemele_Grid";
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
   Pip = Point;
//----
   if (Digits == 3|| Digits == 5){D_Factor = 10; Pip *= 10;}
   Grid_Size      *= Pip;
   if (MarketInfo(Symbol(),MODE_LOTSTEP) == 0.01)LotDigits = 2;
   Auto_Grid = Grid_Size;
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
int
   result = NO_RESULT;

//----
   if (!OrdersTotal()){
      Print("Making an initial trade");
      OrderSend(Symbol(), 4, Get_Lots(Risk), NormalizeDouble(Ask+Auto_Grid,Digits), Slippage, 0 ,0 ,Order_Cmt, MagicNumber, 0, Blue);
      OrderSend(Symbol(), 5, Get_Lots(Risk), NormalizeDouble(Bid-Auto_Grid,Digits), Slippage, 0 ,0 ,Order_Cmt, MagicNumber, 0, Blue);
   }
   Update_Grid(Grid_Min, Grid_Max);
   result = Check_For_Trade(Grid_Min, Grid_Max);
   if(result!=NO_RESULT)Do_Trade(result);
   Trail_Stop();
   
 //----
   return(0);
  }
//+------------------------------------------------------------------+
void Update_Grid(double& Min, double& Max)
{
int
   Order_Cnt=0,
   Grid_Num = 0;
   for(int i=0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderType()>3)Order_Cnt++;
      }
      else Print("Error Selecting Order = " + GetLastError());
   }
   ArrayResize(Grid_Ord_OpenPrice,Order_Cnt);
   ArrayInitialize(Grid_Ord_OpenPrice,0.0);
   for(i=0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderType()>3){
            Grid_Ord_OpenPrice[Grid_Num][0] = OrderOpenPrice();
            Grid_Num++;
         }
      }
      else Print("Error Selecting Order = " + GetLastError());
   }
   ArraySort(Grid_Ord_OpenPrice);
   Min = Grid_Ord_OpenPrice[0][0];
   Max = Grid_Ord_OpenPrice[Order_Cnt-1][0];
}
//+------------------------------------------------------------------+
int Check_For_Trade(double Min, double Max)
{
   if(Ask >= Max + Auto_Grid)return(OP_BUYSTOP);
   if(Bid <= Min - Auto_Grid) return(OP_SELLSTOP);
   return(NO_RESULT);
}
//+------------------------------------------------------------------+
void Do_Trade(int Buy_or_Sell)
{
   switch(Buy_or_Sell){
      case OP_BUYSTOP:  int ticket = OrderSend(Symbol(),OP_BUYSTOP,NormalizeDouble(Get_Lots(Risk),LotDigits),NormalizeDouble(Ask + Auto_Grid,Digits), Slippage,0,0,Order_Cmt,MagicNumber,0,Green);
                        Delete_Opposite_Trade(5);
                        ticket = OrderSend(Symbol(),OP_SELLSTOP,NormalizeDouble(Get_Lots(Risk),LotDigits),NormalizeDouble(Bid - 2 * Auto_Grid,Digits), Slippage,0,0,Order_Cmt,MagicNumber,0,Red);
                        break;
      case OP_SELLSTOP: ticket = OrderSend(Symbol(),OP_SELLSTOP,NormalizeDouble(Get_Lots(Risk),LotDigits),NormalizeDouble(Bid - Auto_Grid,Digits), Slippage,0,0,Order_Cmt,MagicNumber,0,Red);
                        Delete_Opposite_Trade(4);
                        ticket = OrderSend(Symbol(),OP_BUYSTOP,NormalizeDouble(Get_Lots(Risk),LotDigits),NormalizeDouble(Ask + 2 * Auto_Grid,Digits), Slippage,0,0,Order_Cmt,MagicNumber,0,Green);
                        break;
      default        :  Alert("Unknown ordertype returned");
                        break;
   }
   return;
}
//+------------------------------------------------------------------+
void Delete_Opposite_Trade(int Del_B_S)
{
   for(int i=0;i<OrdersTotal();i++){
      OrderSelect(i,SELECT_BY_POS);
      if(OrderMagicNumber() == MagicNumber){
         if(OrderType() == Del_B_S)OrderDelete(OrderTicket());
      }
   }
}
//+------------------------------------------------------------------+
double Get_Lots(double lRisk)
{
double
   Lots = AccountEquity() * lRisk/100/1000;
   if (MarketInfo(Symbol(),MODE_MINLOT) > Lots)Lots = MarketInfo(Symbol(),MODE_MINLOT);
   if (MarketInfo(Symbol(),MODE_MAXLOT) < Lots)Lots = MarketInfo(Symbol(),MODE_MAXLOT);
   return(Lots);
}
//+------------------------------------------------------------------+
bool Trail_Stop()
{
bool
   mod,
   lresult = false;
double
   My_Profit,
   My_Trail,
   My_SL,
   lTrail_Max,
   lTrail_From,
   Stop_Level;
//----
   for (int i = 0; i < OrdersTotal(); i++){
      if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
         if(OrderMagicNumber() == MagicNumber){
            RefreshRates();
            lTrail_Max = Trail_Max * Pip;
            lTrail_From = Trail_From * Pip;
            Stop_Level = MarketInfo(OrderSymbol(),MODE_STOPLEVEL)*Pip;
            switch(OrderType()){
               case OP_BUY :  My_Profit = Bid - OrderOpenPrice();
                              My_Trail = MathMin(My_Profit * Trail_Percent/100,lTrail_Max);
                              My_SL = NormalizeDouble(OrderClosePrice()-My_Trail,Digits);
                              lresult = true;
                              if(My_Profit > lTrail_From){
                                 if(OrderClosePrice() - My_SL > Stop_Level){
                                    if(OrderStopLoss() < My_SL||OrderStopLoss() == 0)mod = OrderModify(OrderTicket(),OrderOpenPrice(),My_SL,OrderTakeProfit(),0, CLR_NONE);
                                 }
                              }
                              break;
                        
               case OP_SELL : My_Profit = OrderOpenPrice() - Ask;
                              My_Trail = MathMin(My_Profit * Trail_Percent/100,lTrail_Max);
                              My_SL = NormalizeDouble(Ask+My_Trail,Digits);
                              lresult = true;
                              if(My_Profit > lTrail_From){
                                 if(My_SL - OrderClosePrice() > Stop_Level){
                                    if(My_SL < OrderStopLoss()||OrderStopLoss() == 0)mod = OrderModify(OrderTicket(),OrderOpenPrice(),My_SL,OrderTakeProfit(),0,CLR_NONE);
                                 }
                              }
                              break;
               }
               if(!mod && GetLastError() > 1)Print("Error entering Trailing Stop - Error " + GetLastError());
            }
      }
      else Print("Error selecting order");
   } 
//----
   return(lresult);
}

