//+------------------------------------------------------------------+
//|                                           Kukl Shadow by SVS.mq4 |
//|                                                              SVS |
//|                            https://www.mql5.com/ru/users/svs1996 |
//+------------------------------------------------------------------+
#property copyright "SVS"
#property link      "https://www.mql5.com/ru/users/svs1996"
#property version   "1.02"
double version=1.02;
#property strict

#include <stdlib.mqh>
#include <WinUser32.mqh>
//--- enum parameters
enum AutoMM
  {
   Fixed=0,//Fixed - Автоматика отключена
   Risk_Control=1,//Расчет лота по риску
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum TimeUTC
  {
   GMT=0,
   Curent=1,
  };

//--- input parameters
extern double Lots=0.01;
input AutoMM Type_Calculation=Fixed; //AutoMM - Включать Money Management
input double Risk=5.0;//Risk - Максимальный риск на сделку
extern int TakeProfit=10;//TakeProfit - Профит в пунктах. Если 0, то не устанавливается
extern int StopLoss=21; //StopLoss - Стоп в пунктах. Если 0, то не устанавливается
input int Slippage=50;
input int SpaceRoundLavels=100;//SpaceRoundLavels - в пипсах расстояние между круглыми уровнями
input int Distance_to_Entry=30;//Distance to Entry - расстояние до лимитника от уровня
input    string   SET_Work_Time="==== value format: hh:mm or hh:mm:ss ====";
input TimeUTC UTC=GMT; //UTC - от него зависит в GMT 0 забивать время или по времени текущего сервера.
input string   StartTime1="00:00"; //StartTime1 - формат ввода: чч:мм или чч:мм:сс
input string   EndTime1="07:59"; //EndTime1 - формат ввода: чч:мм или чч:мм:сс
input string   StartTime2= "08:00"; //StartTime2 - формат ввода: чч:мм или чч:мм:сс
input string   EndTime2="19:59:59"; //EndTime2 - формат ввода: чч:мм или чч:мм:сс
input string   StartTime3= "23:00"; //StartTime3 - формат ввода: чч:мм или чч:мм:сс
input string   EndTime3="23:59:59"; //EndTime3 - формат ввода: чч:мм или чч:мм:сс
                                    //input string   TimeClosePendingOrders = "08:00" //TimeClosePendingOrders (GMT)
input bool Use_Comment=true;
input int MagicNumber=333;

//---Global variables
bool Activate,FreeMarginAlert,FatalError;
double Free,Tick,LotVal,Spread,StopLevel,MinLot,MaxLot,LotStep;

//bool FlagTimeClosePendingOrders=False;

double HightRoundLevel=0;
double LowRoundLevel=0;
double LastHightRoundLevel=0;

int BuyTicket=-1;
int SellTicket=-1;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(Use_Comment)
      Comment("Инициализация");
   Activate=False;
// - 1 - == Сбор информации об условиях торговли ========================================   
   MarketAnalysis();
// - 1 - == Окончание блока =============================================================

// - 2 - == Приведение объема сделки к допустимому и проверка корректности объема =======   
   if(!LotCorrection()) return(0);
// - 2 - == Окончание блока =============================================================
//---
   HightRoundLevel=0;
   LowRoundLevel=0;
   Found_RoundLevels();
   LastHightRoundLevel=ND(HightRoundLevel);
//Alert("Верхний круглый уровень=",HightRoundLevel,"\nНижний круглый уровень=",LowRoundLevel);
   CheckPendingOrder();

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MarketAnalysis()
  {
   Free=ND(AccountFreeMargin());
   Tick=MarketInfo(Symbol(),MODE_TICKSIZE);                         // минимальный тик    
   LotVal=MarketInfo(Symbol(),MODE_TICKVALUE);//стоимость 1 пункта 1 лота
   Spread=ND(MarketInfo(Symbol(),MODE_SPREAD)*Point);                  // текщий спрэд
   StopLevel=ND(MarketInfo(Symbol(),MODE_STOPLEVEL)*Point);  // текущий уровень стопов 
   MinLot = MarketInfo(Symbol(),MODE_MINLOT);    // минимальный разрешенный объем сделки
   MaxLot = MarketInfo(Symbol(), MODE_MAXLOT);   // максимальный разрешенный объем сделки
   LotStep=MarketInfo(Symbol(),MODE_LOTSTEP);          // шаг приращения объема сделки
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int LotCorrection()
  {
   Lots=MathRound(Lots/LotStep)*LotStep; // округление объема до ближайшего допустимого
   if(Lots<MinLot || Lots>MaxLot) // объем сделки не меньше MinLot и не больше MaxLot
     {
      Alert("Параметром Lots был задан неправильный объем сделки!");
      return(0);
     }
   else return(1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ND(double A)
  {
   return(NormalizeDouble(A, Digits));
  }
//+-------------------------------------------------------------------------------------+
//| Приведение значений к точности одного тика                                          |
//+-------------------------------------------------------------------------------------+
double NP(double A)
  {
   return(MathFloor(A/Tick)*Tick);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(Scheduler(StartTime1,EndTime1))
     {
      Informer();
      if((Ask+Bid)/2>HightRoundLevel) //Если пробитие снизу вверх
        {
         if(OrderSelect(SellTicket,SELECT_BY_TICKET)==False)
           {
            SellTicket=OpenPendingOrders(OP_SELL);
           }
         else
           {
            if(OrderSelect(SellTicket,SELECT_BY_TICKET))
               if(OrderType()!=OP_SELLLIMIT || OrderCloseTime()!=0)
                 {
                  SellTicket=OpenPendingOrders(OP_SELL);
                 }

           }
         HightRoundLevel+=ND(SpaceRoundLavels*Point);
         HightRoundLevel=ND(HightRoundLevel);
         LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));

        }
      else if((Ask+Bid)/2<LowRoundLevel)
        { //Если пробитие сверху вниз
         if(OrderSelect(BuyTicket,SELECT_BY_TICKET)==False)
           {
            BuyTicket=OpenPendingOrders(OP_BUY);
           }
         else
           {
            if(OrderSelect(BuyTicket,SELECT_BY_TICKET))
               if(OrderType()!=OP_BUYLIMIT || OrderCloseTime()!=0)
                 {
                  BuyTicket=OpenPendingOrders(OP_BUY);
                 }

           }
         HightRoundLevel-=ND(SpaceRoundLavels*Point);
         HightRoundLevel=ND(HightRoundLevel);
         LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));
        }
      if(OrderSelect(BuyTicket,SELECT_BY_TICKET))
        {
         if(OrderType()==OP_BUY)
            ClosePendingOrders(); //Закрываем лимитники если сработала покупка
        }
      if(OrderSelect(SellTicket,SELECT_BY_TICKET))
        {
         if(OrderType()==OP_SELL)
            ClosePendingOrders(); //Закрываем лимитники если сработала продажа
        }
      return;
     }
   else if(StartTime2!=EndTime2)
     {
      if(Scheduler(StartTime2,EndTime2))
        {
           {
            Informer();
            if((Ask+Bid)/2>HightRoundLevel) //Если пробитие снизу вверх
              {
               if(OrderSelect(SellTicket,SELECT_BY_TICKET)==False)
                 {
                  SellTicket=OpenPendingOrders(OP_SELL);
                 }
               else
                 {
                  if(OrderSelect(SellTicket,SELECT_BY_TICKET))
                     if(OrderType()!=OP_SELLLIMIT || OrderCloseTime()!=0)
                       {
                        SellTicket=OpenPendingOrders(OP_SELL);
                       }

                 }
               HightRoundLevel+=ND(SpaceRoundLavels*Point);
               HightRoundLevel=ND(HightRoundLevel);
               LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));

              }
            else if((Ask+Bid)/2<LowRoundLevel)
              { //Если пробитие сверху вниз
               if(OrderSelect(BuyTicket,SELECT_BY_TICKET)==False)
                 {
                  BuyTicket=OpenPendingOrders(OP_BUY);
                 }
               else
                 {
                  if(OrderSelect(BuyTicket,SELECT_BY_TICKET))
                     if(OrderType()!=OP_BUYLIMIT || OrderCloseTime()!=0)
                       {
                        BuyTicket=OpenPendingOrders(OP_BUY);
                       }

                 }
               HightRoundLevel-=ND(SpaceRoundLavels*Point);
               HightRoundLevel=ND(HightRoundLevel);
               LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));
              }
            if(OrderSelect(BuyTicket,SELECT_BY_TICKET))
              {
               if(OrderType()==OP_BUY)
                  ClosePendingOrders(); //Закрываем лимитники если сработала покупка
              }
            if(OrderSelect(SellTicket,SELECT_BY_TICKET))
              {
               if(OrderType()==OP_SELL)
                  ClosePendingOrders(); //Закрываем лимитники если сработала продажа
              }
            return;
           }
        }
     }
   else if(StartTime3!=EndTime3)
     {
      if(Scheduler(StartTime3,EndTime3))
        {
           {
            Informer();
            if((Ask+Bid)/2>HightRoundLevel) //Если пробитие снизу вверх
              {
               if(OrderSelect(SellTicket,SELECT_BY_TICKET)==False)
                 {
                  SellTicket=OpenPendingOrders(OP_SELL);
                 }
               else
                 {
                  if(OrderSelect(SellTicket,SELECT_BY_TICKET))
                     if(OrderType()!=OP_SELLLIMIT || OrderCloseTime()!=0)
                       {
                        SellTicket=OpenPendingOrders(OP_SELL);
                       }

                 }
               HightRoundLevel+=ND(SpaceRoundLavels*Point);
               HightRoundLevel=ND(HightRoundLevel);
               LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));

              }
            else if((Ask+Bid)/2<LowRoundLevel)
              { //Если пробитие сверху вниз
               if(OrderSelect(BuyTicket,SELECT_BY_TICKET)==False)
                 {
                  BuyTicket=OpenPendingOrders(OP_BUY);
                 }
               else
                 {
                  if(OrderSelect(BuyTicket,SELECT_BY_TICKET))
                     if(OrderType()!=OP_BUYLIMIT || OrderCloseTime()!=0)
                       {
                        BuyTicket=OpenPendingOrders(OP_BUY);
                       }

                 }
               HightRoundLevel-=ND(SpaceRoundLavels*Point);
               HightRoundLevel=ND(HightRoundLevel);
               LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));
              }
            if(OrderSelect(BuyTicket,SELECT_BY_TICKET))
              {
               if(OrderType()==OP_BUY)
                  ClosePendingOrders(); //Закрываем лимитники если сработала покупка
              }
            if(OrderSelect(SellTicket,SELECT_BY_TICKET))
              {
               if(OrderType()==OP_SELL)
                  ClosePendingOrders(); //Закрываем лимитники если сработала продажа
              }
            return;
           }
        }
     }
   if(Use_Comment)
      Comment("Kukl Shadow v",version," by SVS\n",
              "Last Tick: ",TimeToStr(CurTime(),TIME_DATE|TIME_SECONDS),"\n",
              "Trading halted on schedule\n",
              "Торговля остановлена по расписанию");
   HightRoundLevel=0;
   LowRoundLevel=0;
   Found_RoundLevels();
   LastHightRoundLevel=ND(HightRoundLevel);
   ClosePendingOrders();
  }
//+------------------------------------------------------------------+
bool Scheduler(string StartTime,string EndTime)
  { //Планировщик
   datetime Start=StringToTime(StartTime);
   datetime End=StringToTime(EndTime);
   if(Start==End)
      return (True);
   else
     {
      if(UTC==0)
        {
         if(TimeDay(TimeGMT())<TimeDay(Start))
           {
            Start=Start-86400;
            End=End-86400;
           }
         if((TimeGMT()>=Start) && (TimeGMT()<=End))
            return (True);
         else
            return(False);
        }
      else if(UTC==1)
        {
         if((TimeCurrent()>=Start) && (TimeCurrent()<=End))
            return (True);
         else
            return(False);
        }
     }
   return (False);
  }
//+------------------------------------------------------------------+

void Found_RoundLevels()
  {
   while(HightRoundLevel<(Ask+Bid)/2)
     {
      HightRoundLevel+=ND(SpaceRoundLavels*Point);
      HightRoundLevel=ND(HightRoundLevel);
     }
   LowRoundLevel=ND(HightRoundLevel-ND(SpaceRoundLavels*Point));
  }
//+------------------------------------------------------------------+

void Money_Management()
  {
   switch(Type_Calculation)
     {
      case 0:
         break;
      case 1:
        {
         MarketAnalysis();
         Lots=MathFloor((Free*Risk/100)/((StopLoss+Spread)*LotVal)/LotStep)*LotStep;
         if(Lots<MinLot)  Lots=MinLot;
         if(Lots>MaxLot)  Lots=MaxLot;
         LotCorrection();
         break;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Informer()
  {
   if(Use_Comment)
     {
      Money_Management();
      Comment("Kukl Shadow v",version," by SVS\n",
              "Last Tick: ",TimeToStr(CurTime(),TIME_DATE|TIME_SECONDS),"\n",
              "Рабочий лот=",Lots,"\n",
              "Ближайший верхний уровень=",HightRoundLevel,"\n",
              "Ближайший нижний уровень=",LowRoundLevel,"\n");
     }
  }
//+------------------------------------------------------------------+

int OpenPendingOrders(int Type)
  {
   Money_Management();
   int ErrorCount;
   int Ticket=-1;
   double SL,TP;
   double PriceOpen=0;
   if(Type==OP_BUY)
     {
      PriceOpen=ND(LowRoundLevel-Distance_to_Entry*Point);
      SL=ND(PriceOpen-(StopLoss+Spread)*Point);
      if(StopLoss==0)SL=0;
      TP=ND(PriceOpen+TakeProfit*Point);
      if(TakeProfit==0)TP=0;
      for(ErrorCount=0;ErrorCount<10;ErrorCount++)
        {
         if(Bid>PriceOpen)
           {
            while(!IsTradeAllowed()) Sleep(100);
            Ticket=OrderSend(Symbol(),OP_BUYLIMIT,Lots,PriceOpen,Slippage,SL,TP,NULL,MagicNumber,0,Blue);
            if(Ticket>-1) return (Ticket);
           }
         else
           {
            Ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,0,0,NULL,MagicNumber,0,Blue);
            if(Ticket>-1)
              {
               if(OrderSelect(Ticket,SELECT_BY_TICKET))
                 {
                  if(SL!=0 && SL<=OrderOpenPrice()) SL=ND(OrderOpenPrice()-(StopLoss+Spread)*Point);
                  for(ErrorCount=0;ErrorCount<10;ErrorCount++)
                    {
                     while(!IsTradeAllowed()) Sleep(100);
                     if(OrderModify(OrderTicket(),OrderOpenPrice(),SL,TP,0,Blue)) break;
                     else Print("OpenOrder: TypeOrder=Buy: OrderModify() error - ",ErrorDescription(GetLastError()));
                    }
                 }
               return (Ticket);
              }
           }
        }
     }
   if(Type==OP_SELL)
     {
      PriceOpen=ND(HightRoundLevel+Distance_to_Entry*Point);
      SL=ND(PriceOpen+(StopLoss+Spread)*Point);
      if(StopLoss==0)SL=0;
      TP=ND(PriceOpen-TakeProfit*Point);
      if(TakeProfit==0)TP=0;
      for(ErrorCount=0;ErrorCount<10;ErrorCount++)
        {
         if(Ask<PriceOpen)
           {
            while(!IsTradeAllowed()) Sleep(100);
            Ticket=OrderSend(Symbol(),OP_SELLLIMIT,Lots,PriceOpen,Slippage,SL,TP,NULL,MagicNumber,0,Red);
            if(Ticket>-1) return (Ticket);
           }
         else
           {
            Ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,0,0,NULL,MagicNumber,0,Blue);
            if(Ticket>-1)
              {
               if(OrderSelect(Ticket,SELECT_BY_TICKET))
                 {
                  if(SL!=0 && SL>=OrderOpenPrice()) SL=ND(OrderOpenPrice()+(StopLoss+Spread)*Point);
                  for(ErrorCount=0;ErrorCount<10;ErrorCount++)
                    {
                     while(!IsTradeAllowed()) Sleep(100);
                     if(OrderModify(OrderTicket(),OrderOpenPrice(),SL,TP,0,Blue)) break;
                     else Print("OpenOrder: TypeOrder=Sell: OrderModify() error - ",ErrorDescription(GetLastError()));
                    }
                 }
               return (Ticket);
              }
           }
        }
     }
   return (Ticket);
  }
//+------------------------------------------------------------------+
int ClosePendingOrders()
  {
   int err=1;
   for(int j=OrdersTotal(); j>=0; j--)
     {
      // Print("Запуск скрипта удаляющего все отложенные ордера ",TimeToStr(TimeCurrent(),TIME_MINUTES)," попытка ",err);
      if(OrderSelect(j,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderType()>1 && OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
           {
            while(true)
              {
               if(OrderDelete(OrderTicket())) break;
               else
                 {
                  err++;
                  if(err>10) break;
                  Sleep(1000);
                  RefreshRates();
                 }
              }
           }
        }
      else Print("Error when order select ",GetLastError());
     }
   return(0);
  }
//+------------------------------------------------------------------+

void CheckPendingOrder()
  {
   for(int j=OrdersTotal(); j>=0; j--)
     {
      if(OrderSelect(j,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderType()==OP_BUYLIMIT && OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
           {
            BuyTicket=OrderTicket();
            return;
           }
         if(OrderType()==OP_SELLLIMIT && OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
           {
            SellTicket=OrderTicket();
            return;
           }
        }
     }
   return;
  }

//+------------------------------------------------------------------+
