//+------------------------------------------------------------------+
//|                                              Ilan1.7Refactor.mq4 |
//|                                                              Leo |
//|                                                                  |
//+------------------------------------------------------------------+
//Добавлены параметры RSI 0.1
//обавлено FirstTP  0.2
#include <stdlib.mqh>

#property copyright "Leo"
//#property strict
//----------------------------------------------------------------------------------

extern double Lots          = 0.05; // начальный размер лота
extern double LotExponent   = 1.2;  // множитель лота для очередного шага сетки
extern int    StepPeriod    = 24;   // период для определения шага сетки
extern int    StepDel       = 2;    // делитель значения шага сетки за период 
extern int    StepMin       = 15;   // минимальное значение шага сетки
extern int    StepPlusOrder = 2;    // номер ордера в сетке, после которого шаг сетки начинает увеличиваться
extern int    StepPlusValue = 10;   // размер прироста шага сетки после ордера StepPlusOrder
extern double Slippage      = 3;    // допустимое проскальзывание при реквотах
extern double TakeProfit    = 5;    // по достижении скольких пунктов прибыли закрывать сетку ордеров
extern bool   FirstTP=false;        // наличие ТП у первого ордера
extern double RsiMinimum    = 30;   // нижний уровень индикатора RSI(14)текущего таймфрейма
extern double RsiMaximum    = 70;   // верхний уровень индикатора RSI(14)текущего таймфрейма
extern int    TfRsi         =5;
extern int    PerRsi        =14;
extern int    MagicBuy      = 111;  // MagicNumber для ордеров BUY
extern int    MagicSell     = 222;  // MagicNumber для ордеров SELL
extern int    MaxTrades     = 15;   // максимально количество ордеров в сетке
extern double StartProfit   = 0.5;  // профит стартового ордера, при достижении которого он закрывается, если еще не открыт парный ордер
//----------------------------------------------------------------------------------

string EAName="I1.7R";

int    timeprev;
string comment;
int    returnvalue;
int    preCountOrders, curCountOrders;
double preRSI,   curRSI;
double preClose, curClose;
int    lotDecimal;

string EAstatus;

string butRemove    = "butRemove";
string butStartStop = "butStartStop";
string butClose     = "butClose";

color colorRemove = clrBlue;
color colorStart  = clrLimeGreen;
color colorStop   = clrRed;
color colorClose  = clrMagenta;

int xLab=7;
int yLab=120;
//----------------------------------------------------------------------------------
int OnInit() 
   {
   EventSetTimer(1);
   
   Init();
    
   return (INIT_SUCCEEDED);
   }
//----------------------------------------------------------------------------
void Init()
   {
   // определить статус советника
   string namestatus= Symbol()+"status";
   if (!GlobalVariableCheck(namestatus)) GlobalVariableSet(namestatus,1);
   double status=GlobalVariableGet(namestatus);
   if (status==1) EAstatus="Active"; else EAstatus="Stop";
   
   CreateButtons();
   
   if (StepPlusOrder<2) StepPlusOrder=2;
   
   // точность расчета значения лота при открытии ордеров
   double lotStep=MarketInfo(Symbol(),MODE_LOTSTEP);
   if (lotStep==0.01) lotDecimal=2; else
   if (lotStep==0.10) lotDecimal=1; else lotDecimal=0;
   
   int countBUY=CountOrders(MagicBuy);
   int countSELL=CountOrders(MagicSell);
   
   // определить размер очередного шага сетки
   int Step=DefineStep(countBUY,countSELL);
   
   double lastprice;
   double distance=0;
   if (countBUY>=countSELL && countBUY>0)
      {
      lastprice=FindLastPrice(OP_BUY, MagicBuy);
      if (Bid<lastprice && Ask<lastprice) distance=NormalizeDouble((lastprice-Ask)/Point,0);
      }
      
   if (countSELL>=countBUY && countSELL>0)
      {
      lastprice=FindLastPrice(OP_SELL, MagicSell);
      if (Ask>lastprice && Bid>lastprice)
         { 
         if (distance>0) distance=0;
         else distance=NormalizeDouble((Bid-lastprice)/Point,0);
         }
      }

   double ATR=NormalizeDouble(iATR(NULL,PERIOD_D1,10,1)/Point,0);
   double ATRtoday=NormalizeDouble((iHigh(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_D1,0))/Point,0);
   
   Comment("Lots=",Lots,"x",LotExponent," MaxTrades=",MaxTrades," Step=",Step,"/",distance,
           " Spread=",MarketInfo(Symbol(),MODE_SPREAD),"\n",
           "ATR=",ATR,"/",ATRtoday," Balance=",AccountBalance(),"/",AccountEquity()," Status=",EAstatus);
   
   double profit=GetProfit();
   string profitstr=DoubleToStr(GetProfit(),2)+" ("+IntegerToString(countBUY)+"/"+IntegerToString(countSELL)+")";
   CreateLabel("profit",profitstr,xLab,yLab,clrDeepSkyBlue,10);
   if (profit>=0) ObjectSet("profit", OBJPROP_COLOR, clrLimeGreen);
   
   curCountOrders=countBUY+countSELL;
   preCountOrders=curCountOrders;
   
   timeprev=Time[0];
   
   preClose = Close[2];
   curClose = Close[1];
         
   preRSI = iRSI(NULL, TfRsi, PerRsi, PRICE_CLOSE, 2);
   curRSI = iRSI(NULL, TfRsi, PerRsi, PRICE_CLOSE, 1);
   }
//----------------------------------------------------------------------------
void OnDeinit(const int reason) 
   {
   EventKillTimer();
   ObjectDelete(butRemove);
   ObjectDelete(butStartStop);
   ObjectDelete(butClose);
   ObjectDelete("profit");
   ObjectDelete("time");
   }
//----------------------------------------------------------------------------
void OnTimer()
   {
   CreateLabel("time",TimeToStr(TimeCurrent(),TIME_SECONDS),5,25,clrMagenta,10);
   }
//----------------------------------------------------------------------------
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
   {
   if(id==CHARTEVENT_OBJECT_CLICK) // на объекте кликнули мышкой
      {
      string clickedChartObject=sparam;// имя объекта
      
      if(clickedChartObject==butRemove) // щелчок по кнопке Remove
         {
         ExpertRemove();
         Comment("");
         return;
         }
         
      if(clickedChartObject==butStartStop) // щелчок по кнопке StartStop
         { 
         string namestatus=Symbol()+"status";
         if (EAstatus=="Active")
            {
            // остановить советник
            EAstatus="Stop";
            ObjectSetString(0,butStartStop,OBJPROP_TEXT,"EA START"); 
            ObjectSetInteger(0,butStartStop,OBJPROP_COLOR,colorStart);
            GlobalVariableSet(namestatus,0);
            OnTick();
            }
         else // EAstatus=Stop
            {
            // инициировать советник
            EAstatus="Active";
            ObjectSetString(0,butStartStop,OBJPROP_TEXT,"EA STOP"); 
            ObjectSetInteger(0,butStartStop,OBJPROP_COLOR,colorStop);
            GlobalVariableSet(namestatus,1);
            Init();
            }
         return;
         }
         
      if(clickedChartObject==butClose) // щелчок по кнопке Close
         { 
         CloseOrders();
         Init();
         return;
         }
      }
   }
//----------------------------------------------------------------------------
void OnTick()
   {
   int countBUY=CountOrders(MagicBuy);
   int countSELL=CountOrders(MagicSell);
   
   // определить размер очередного шага сетки
   int Step=DefineStep(countBUY,countSELL);

   int gridDirect=0; // направление сетки: 1-вверх; (-1)-вниз; 0-не определено
   
   double lastbuyprice=0;
   double lastsellprice=0;
   double distance=0;  // расстояние от цены до ближайшего ордера
   
   if (countBUY>=countSELL && countBUY>0)
      {
      lastbuyprice=FindLastPrice(OP_BUY, MagicBuy);
      if (Bid<lastbuyprice && Ask<lastbuyprice) 
         {
         distance=NormalizeDouble((lastbuyprice-Ask)/Point,0);
         gridDirect=-1;
         }
      }
      
   if (countSELL>=countBUY && countSELL>0)
      {
      lastsellprice=FindLastPrice(OP_SELL, MagicSell);
      if (Ask>lastsellprice && Bid>lastsellprice)
         { 
         if (distance>0) 
            { // цена между ордерами
            distance=0;  
            gridDirect=0;
            }
         else 
            {
            distance=NormalizeDouble((Bid-lastsellprice)/Point,0);
            gridDirect=1;
            }
         }
      }
         
   double ATR=NormalizeDouble(iATR(NULL,PERIOD_D1,10,1)/Point,0);
   double ATRtoday=NormalizeDouble((iHigh(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_D1,0))/Point,0);

   Comment("Lots=",Lots,"x",LotExponent," MaxTrades=",MaxTrades," Step=",Step,"/",distance,
           " Spread=",MarketInfo(Symbol(),MODE_SPREAD),"\n",
           "ATR=",ATR,"/",ATRtoday," Balance=",AccountBalance(),"/",AccountEquity(),
           "/",DoubleToStr(AccountFreeMargin(),2)," Status=",EAstatus);
   
   double profit=GetProfit();
   string profitstr=DoubleToStr(profit,2)+" ("+IntegerToString(countBUY)+"/"+IntegerToString(countSELL)+")";
   CreateLabel("profit",profitstr,xLab,yLab,clrDeepSkyBlue,10);
   if (profit>=0) ObjectSet("profit", OBJPROP_COLOR, clrLimeGreen);
   
   if (EAstatus=="Stop") return;
   
   curCountOrders=countBUY+countSELL; // общее количество открытых ордеров
   
   if (profit>=StartProfit && curCountOrders==1)
      { // открыт только инициирующий ордер, который достиг профита InitProfitValue
      CloseOrders();
      Init();
      return;
      }
   
   if (preCountOrders>1 && curCountOrders==1 && profit>0)
      { // сетка закрыта, необходимо закрыть трендовый ордер
      CloseOrders();
      Init();
      return;
      }
   else
      preCountOrders=curCountOrders;
 //******************* ПЕРВЫЙ ОРДЕР ************************     
   if (countBUY==0 && countSELL==0) // нет открытых ордеров
      { // проверить возможность открытия ордера BUY
      if (curClose>preClose && curRSI>preRSI && curRSI>RsiMinimum)
         {// открыть первый ордер BUY с инициирующим лотом
         comment=EAName+"-"+Symbol()+"-1";
         RefreshRates();
         int ticket = OpenOrder(OP_BUY,Lots,comment,MagicBuy,clrLime);
         if(FirstTP)SetTakeProfit(OP_BUY,MagicBuy);// мое
         return;
         }
         
      // проверить возможность открытия ордера SELL
      if (curClose<preClose && curRSI<preRSI && curRSI<RsiMaximum)
         {// открыть первый ордер SELL с инициирующим лотом
         comment=EAName+"-"+Symbol()+"-1";
         RefreshRates();
         ticket = OpenOrder(OP_SELL,Lots,comment,MagicSell,clrHotPink);
         if(FirstTP)SetTakeProfit(OP_SELL,MagicSell);// мое
         return;
         }
      }
 //***************************************************************     
   // анализ на открытие второго  и последующих ордеров выполняется после закрытия очередного бара   
   if (timeprev != Time[0])
      {// новый бар
      timeprev = Time[0];
      
      preClose = Close[2];
      curClose = Close[1];
         
      preRSI = iRSI(NULL, TfRsi, PerRsi, PRICE_CLOSE, 2);
      curRSI = iRSI(NULL, TfRsi, PerRsi, PRICE_CLOSE, 1);
      
      if (countBUY==0 && countSELL==0) return; // нет открытых ордеров
        
      if (countBUY==1 && countSELL==0) // открыт единственный ордер BUY
         { // проверить возможность открытия встречного ордера SELL
         if (curClose<preClose && curRSI<preRSI && curRSI<RsiMaximum)
            {// открыть встречный ордер SELL с инициирующим лотом
            comment=EAName+"-"+Symbol()+"-1-0";
            RefreshRates();
            ticket = OpenOrder(OP_SELL,Lots,comment,MagicSell,clrHotPink);
            }
         return;
         }
         
      if (countBUY==0 && countSELL==1) // открыт единственный ордер SELL
         { // проверить возможность открытия встречного ордера BUY
         if (curClose>preClose && curRSI>preRSI && curRSI>RsiMinimum)
            {// открыть встречный ордер BUY с инициирующим лотом
            comment=EAName+"-"+Symbol()+"-1-0";
            RefreshRates();
            ticket = OpenOrder(OP_BUY,Lots,comment,MagicBuy,clrLime);
            }
         return;
         }
         
      // открыты как минимум два встречных ордера -- построение сетки
      
      if (gridDirect==0) return;  // цена внутри сетки
      
      if (distance >= Step)
         {
         // открыть новый ордер в направлении сетки
         if (gridDirect==1 && countSELL<MaxTrades)
            {
            // открыть новый сеточный ордер SELL
            comment=EAName+"-"+Symbol()+"-"+(countSELL+1)+"-"+Step;
            double nextLots = NormalizeDouble(Lots*MathPow(LotExponent, countSELL), lotDecimal);
            RefreshRates();
            ticket=OpenOrder(OP_SELL,nextLots,comment,MagicSell,clrHotPink);
            if (ticket>0) 
               {
               SetTakeProfit(OP_SELL,MagicSell);
               }
            return;
            }
            
         if (gridDirect==-1 && countBUY<MaxTrades)
            {
            // открыть новый сеточный ордер BUY
            comment=EAName+"-"+Symbol()+"-"+(countBUY+1)+"-"+Step;
            nextLots = NormalizeDouble(Lots*MathPow(LotExponent, countBUY), lotDecimal);
            RefreshRates();
            ticket=OpenOrder(OP_BUY,nextLots,comment,MagicBuy,clrLime);
            if (ticket>0) 
               {
               SetTakeProfit(OP_BUY,MagicBuy);
               }
            return;
            }
         }
      }
   }
//----------------------------------------------------------------------------    
int DefineStep(int countBUY, int countSELL)
   {
   int addStep=0;
   if (countBUY>=StepPlusOrder) addStep=(countBUY-StepPlusOrder+1)*StepPlusValue;
   if (countSELL>=StepPlusOrder) addStep=(countSELL-StepPlusOrder+1)*StepPlusValue;
   int Step=StepMin+addStep; // расчетное значение очередного шага сетки
   
   double hi=High[iHighest(NULL,0,MODE_HIGH,StepPeriod,1)]; 
   double lo=Low[iLowest(NULL,0,MODE_LOW,StepPeriod,1)];   
   int calcStep=NormalizeDouble((hi-lo)/StepDel/Point,0); // значение очередного шага сетки за период
   
   if (calcStep>Step) Step=calcStep; 
   return (Step);
   }
//----------------------------------------------------------------------------     
void SetTakeProfit(int orderType, int orderMagic)
   {
   double avgPrice = 0;
   double sumLots  = 0;
   for (int order=OrdersTotal()-1; order >= 0; order--) 
      {
      returnvalue=OrderSelect(order, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol()==Symbol() && OrderMagicNumber()==orderMagic) 
         {
         avgPrice += OrderOpenPrice()*OrderLots();
         sumLots  += OrderLots();
         }
      }
   
   double newTakeProfit=avgPrice/sumLots;
   if (orderType==OP_BUY) 
      newTakeProfit=newTakeProfit+TakeProfit*Point; 
   else 
      newTakeProfit=newTakeProfit-TakeProfit*Point;
   newTakeProfit=NormalizeDouble(newTakeProfit,Digits);
   
   for (order=OrdersTotal()-1; order>=0; order--) 
      {
      returnvalue=OrderSelect(order, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol()==Symbol() && OrderMagicNumber()==orderMagic) 
         {
         returnvalue=OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss(),newTakeProfit,0,clrYellow);
         }
      }
   }      
//----------------------------------------------------------------------------   
int OpenOrder(int orderType, double orderLots, string orderComment, int orderMagic, color orderColor) 
   {
   double orderPrice;
   string orderdirect;
   if (orderType==OP_BUY) 
      {
      orderPrice=Ask; 
      orderdirect="BUY";
      }
   else 
      {
      orderPrice=Bid;
      orderdirect="SELL";
      }
   
   int opencount = 1;
   while (opencount<=10) // 10 попыток открытия
      {
      RefreshRates();
      int ticket=OrderSend(Symbol(),orderType,orderLots,orderPrice,Slippage,0,0,orderComment,orderMagic,0,orderColor);
      if(ticket == -1)
         {
         int error = GetLastError();
         Print(EAName," -- Error opening ",orderdirect," order : ",error," -- ",ErrorDescription(error)); 
         opencount++;
         Sleep(2000);
         }
      else 
         return(ticket);
      }
   // ордер открыть не удалось      
   return (-1);
   }
//----------------------------------------------------------------------------
double FindLastPrice(int orderType, int orderMagic) 
   {
   double lastprice = 0;
   int ticketnumber = 0;
   for (int order=OrdersTotal()-1; order>=0; order--) 
      {
      returnvalue=OrderSelect(order, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol() == Symbol() && OrderType() == orderType && OrderMagicNumber() == orderMagic) 
         {
         if (OrderTicket() > ticketnumber) 
            {
            lastprice = OrderOpenPrice();
            ticketnumber = OrderTicket();
            }
         }
      }
   return (lastprice);
   }
//----------------------------------------------------------------------------
int CountOrders(int orderMagic)
   {
   int count=0;
   for (int order=OrdersTotal()-1; order>=0; order--)
      {
      returnvalue=OrderSelect(order, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol()==Symbol() && OrderMagicNumber()==orderMagic)
         {
         count++;
         }
      }
   return(count);
   }
//----------------------------------------------------------------------------------
void CloseOrders()
   {
   for (int order=OrdersTotal()-1; order>=0; order--)
      {
      returnvalue=OrderSelect(order, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol()==Symbol() && (OrderMagicNumber()==MagicSell || OrderMagicNumber()==MagicBuy))
         {
         if (OrderType()==OP_BUY) returnvalue=OrderClose(OrderTicket(),OrderLots(),Bid,100); 
         if (OrderType()==OP_SELL) returnvalue=OrderClose(OrderTicket(),OrderLots(),Ask,100);            
         }
      }
   return;
   }
//----------------------------------------------------------------------------
double GetProfit()
   {
   double profit=0;
   for (int order=OrdersTotal()-1; order>=0; order--)
      {
      returnvalue=OrderSelect(order, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol()==Symbol() && (OrderMagicNumber()==MagicSell || OrderMagicNumber()==MagicBuy))
         {
         profit=profit+OrderProfit()+OrderCommission()+OrderSwap();
         }
      }
   return(profit);
   }
//----------------------------------------------------------------------------
void CreateButtons()
   {
   int Xbut=70;
   int YbutRemove=45;
   int YbutStartStop=YbutRemove+25;
   int YbutClose=YbutStartStop+25;
   
   int butW=65;
   int butH=20;
   
   CreateButton(butRemove,Xbut,YbutRemove,butW,butH,"EA REMOVE","");
   ObjectSetInteger(0,butRemove,OBJPROP_COLOR,colorRemove);
   
   if (EAstatus=="Active") 
      {
      CreateButton(butStartStop,Xbut,YbutStartStop,butW,butH,"EA STOP","");
      ObjectSetInteger(0,butStartStop,OBJPROP_COLOR,colorStop);
      }
   else // EAstatus=Stop
      {
      CreateButton(butStartStop,Xbut,YbutStartStop,butW,butH,"EA START","");
      ObjectSetInteger(0,butStartStop,OBJPROP_COLOR,colorStart);
      }
   
   CreateButton(butClose,Xbut,YbutClose,butW,butH,"CLOSE","");
   ObjectSetInteger(0,butClose,OBJPROP_COLOR,colorClose);
   }
//----------------------------------------------------------------------------
void CreateButton(string buttonName, int Xbutton, int Ybutton, int Xsize, int Ysize, string textButton, string textToolTip)
   {
   if (ObjectFind(0,buttonName) < 0)
      {
      ResetLastError();
      if (!ObjectCreate(0,buttonName,OBJ_BUTTON,0,0,0))
         {
         Print("Ошибка создания объекта ",buttonName," код ошибки - ",GetLastError());
         return;
         }
      }
      
   ObjectSet(buttonName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
   ObjectSetInteger(0,buttonName,OBJPROP_BGCOLOR,White);
   ObjectSetInteger(0,buttonName,OBJPROP_HIDDEN,true);
   ObjectSetInteger(0,buttonName,OBJPROP_XDISTANCE,Xbutton);
   ObjectSetInteger(0,buttonName,OBJPROP_YDISTANCE,Ybutton);
   ObjectSetInteger(0,buttonName,OBJPROP_XSIZE,Xsize);
   ObjectSetInteger(0,buttonName,OBJPROP_YSIZE,Ysize);
   ObjectSetInteger(0,buttonName,OBJPROP_STATE,false);
   ObjectSetString(0,buttonName,OBJPROP_FONT,"Arial");
   ObjectSetString(0,buttonName,OBJPROP_TEXT,textButton);
   ObjectSetInteger(0,buttonName,OBJPROP_FONTSIZE,7);
   ObjectSetInteger(0,buttonName,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,buttonName,OBJPROP_SELECTED,false);
   ObjectSetString(0,buttonName,OBJPROP_TOOLTIP,textToolTip);
   }
//--------------------------------------------------------------------------
void CreateLabel(string objname, string text, int x, int y, color colr, int fontsize) 
   {
   if (ObjectFind(objname) < 0)
      {
      ResetLastError();
      if (!ObjectCreate(objname, OBJ_LABEL, 0, 0, 0))
         {
         Print("Ошибка создания объекта ",objname," код ошибки - ",GetLastError());
         return;
         }
      }
   ObjectSetText(objname, text);
   ObjectSet(objname, OBJPROP_COLOR, colr);
   ObjectSet(objname, OBJPROP_XDISTANCE, x);
   ObjectSet(objname, OBJPROP_YDISTANCE, y);
   ObjectSet(objname, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
   ObjectSetString (0,objname,OBJPROP_FONT,"Calibri");
   ObjectSetInteger(0,objname,OBJPROP_FONTSIZE, fontsize);
   ObjectSetInteger(0,objname,OBJPROP_SELECTABLE,false);
   ObjectSetString (0,objname,OBJPROP_TOOLTIP,"\n");
   }
//--------------------------------------------------------------------------
