//+------------------------------------------------------------------+
//|                                                     Jump kis.mq4 |
//|                                                         AriusKis |
//|                                             https://www.mql5.com |
//| Use on M5 chart                                                  |
//+------------------------------------------------------------------+
#property copyright "AriusKis"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

extern int    MAdensperiod  = 200;                              //Период скользящей средней для плотности цены
extern double Mylevel       = 1.5;                              //Коэф. отношения плотности к среднему значению
extern int    StartHour     = 9;                                //Час начала торговли
extern int    EndHour       = 21;                               //Час окончания торговли
extern int    TralOnMinutes = 30;                               //Минут после сигнала для включения трала
extern int    TralCandle    = 3;                                //Количество свечей для трала
extern double Risk          = 1;                                //% риска на сделку
extern int    Slippage      = 3;
extern int    Magic         = 233;

int CurrentHour=-1;
double Density[];
datetime Newopentime=0; 
int Signalhour=0;
bool check;
int ticket;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   if (Digits()==3 || Digits()==5)
   {
      Slippage *= 10;
   }
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    if (Hour()>=StartHour && Hour()<EndHour)
    {
      if (CurrentHour!=Hour())
      {
         if (CheckSignal())
         {
            PendingsClose();
            int TypeOrder = CheckOpenOrder();
            OrdersOpen(TypeOrder);
            Signalhour=Hour();
         }
      }
      CurrentHour=Hour();
    }
    if (CheckOrders()>0)
    {
       PendingsClose();
       if (Time[0]!=Newopentime && (Hour()>Signalhour || TralOnMinutes<Minute()))
          TralOpenOrders();
       Newopentime=Time[0];
    }

}
//+------------------------------------------------------------------+
//| Функция наличия открытых ордеров                                 |
//+------------------------------------------------------------------+
void TralOpenOrders()
{
   double futurestop;
   int stopindex;
   double spread = MarketInfo(Symbol(), MODE_SPREAD);
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
         {
             if (OrderType()==OP_BUY)
             {
                 stopindex = iLowest(Symbol(), 0, MODE_LOW, TralCandle, 1);
                 futurestop = Low[stopindex];
                 if (futurestop>OrderStopLoss())
                 {
                    if (futurestop+spread*Point()>=Bid)
                       check = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrBlack);
                    else
                       check = OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(futurestop, Digits()), 0, 0, clrGray);
                 }
             }
             if (OrderType()==OP_SELL)
             {
                 stopindex = iHighest(Symbol(), 0, MODE_HIGH, TralCandle, 1);
                 futurestop = High[stopindex];
                 if (futurestop<OrderStopLoss())
                 {
                    if (futurestop-spread*Point()<=Ask)
                       check = OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrBlack);
                    else
                       check = OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(futurestop, Digits()), 0, 0, clrGray);
                 }
             }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Функция наличия открытых ордеров                                 |
//+------------------------------------------------------------------+
int CheckOrders()
{
   int howmanyorders=0;
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
         {
             if (OrderType()==OP_BUY || OrderType()==OP_SELL)
                howmanyorders++;
         }
      }
   }
   return(howmanyorders);
}
//+------------------------------------------------------------------+
//| Функция проверки типа открытого ордера                           |
//+------------------------------------------------------------------+
int CheckOpenOrder()
{
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
         {
            if (OrderType()==OP_SELLSTOP && OrderType()==OP_BUYSTOP)
               return(OrderType());
         }
      }
   }
   return(-1);
}
//+------------------------------------------------------------------+
//| Функция закрытия отложенных ордеров                              |
//+------------------------------------------------------------------+
void PendingsClose()
{
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
         {
            if(OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP)
               check = OrderDelete(OrderTicket(),clrBlack);
         }
      }
   }
}
//+------------------------------------------------------------------+
//| Функция вычисления плотности по часовому графику и проверки сигна|
//+------------------------------------------------------------------+
bool CheckSignal()
{
    ArrayResize(Density, MAdensperiod+1, 0);
    double Sumdensity=0, high, low, averagedensity;
    long volume;
    for (int i=1; i<=MAdensperiod; i++)
    {
       high = iHigh(Symbol(), PERIOD_H1, i);
       low  = iLow(Symbol(), PERIOD_H1, i);
       volume =  iVolume(Symbol(), PERIOD_H1, i);
       if (high==low)
          Density[i]=0;
       else Density[i]=volume/((high-low)/Point());
       Sumdensity += Density[i];
    }
    averagedensity = Sumdensity/MAdensperiod;
    if (averagedensity*Mylevel<=Density[1] && averagedensity<Density[2] && Density[1]>Density[2])
       return(true);
    else return(false);
}
//+------------------------------------------------------------------+
//| Функция открытия отложенных ордеров                              |
//+------------------------------------------------------------------+
void OrdersOpen(int modeopen)
{
    double Levelhigh, Levellow, Lot, Stopvalue, Spread, pricebuy, pricesell;
    Levelhigh = iHigh(Symbol(), PERIOD_H1, 1);
    Levellow  = iLow(Symbol(), PERIOD_H1, 1);
    Stopvalue = NormalizeDouble((Levelhigh-Levellow)/Point(), 0);
    Lot = DealVolume(Risk, Stopvalue);
    Spread = MarketInfo(Symbol(), MODE_SPREAD);
    if (Ask+Spread*Point()>Levelhigh)
       pricebuy=Ask+Spread*Point();
    else pricebuy=Levelhigh+Spread*Point();
    if (Bid-Spread*Point()<Levellow)
       pricesell=Bid-Spread*Point();
    else pricesell=Levellow;
    if (modeopen!=0)
       ticket = OrderSend(Symbol(), OP_BUYSTOP, Lot, NormalizeDouble(pricebuy, Digits()), Slippage, NormalizeDouble(Levellow, Digits()), 0, "Jump AriusKis", Magic, 0, clrBlue);
    if (modeopen!=1)
       ticket = OrderSend(Symbol(), OP_SELLSTOP, Lot, NormalizeDouble(pricesell, Digits()), Slippage, NormalizeDouble(Levelhigh, Digits()), 0, "Jump AriusKis", Magic, 0, clrRed);
}
//+---------------------------------------------------------------------+
//| Функция вычисления объема сделки - здесь от еквити и проверяется шаг|
//+---------------------------------------------------------------------+
double DealVolume(double riskcount,double sl)
  {
   double lot_min  = MarketInfo(Symbol(), MODE_MINLOT);
   double lot_max  = MarketInfo(Symbol(), MODE_MAXLOT);
   double lot_step = MarketInfo(Symbol(), MODE_LOTSTEP);
   double lotcost  = MarketInfo(Symbol(), MODE_TICKVALUE);

   double lot=0;
   double UsdPerPip=0;
   
   lot = MathMin(AccountBalance(), AccountEquity())*riskcount/100;
   
   UsdPerPip=lot/sl;

   lot=UsdPerPip/lotcost;

   lot = MathFloor(lot/lot_step)*lot_step;
   
   if(lot<lot_min) lot = lot_min;
   if(lot>lot_max) lot = lot_max;
   
   return(lot);
  }
//+------------------------------------------------------------------+
