#property copyright "master_255"
#define   EAName    "Test-shadow-doll"
#define   VER       "1.1"
#property version   VER
#property strict

#include <Trade\Trade.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\HistoryOrderInfo.mqh>
#include <Trade\DealInfo.mqh>

extern int    MagicNumber = 9999;
extern int    slip = 3;
extern double Lots = 0.1;
extern int    DepoPer001Lot = 0;
extern int    TakeProfit = 100;
extern int    StopLoss = 210;
input  double StopLossLotExponent = 1;
extern int    Distance = 300;
input  int    MaxLevelCount = 4;
sinput string _1 = "Перерыв"; //-
input  int    BreakHourStart = 23;
input  int    BreakHourEnd = 2;
//---------------------------
double minLot, maxLot;
datetime timeprev = 0;
int Min_Dist, Spr;
bool RealTrade=false;
CTrade  trade; 
COrderInfo myorder;
CHistoryOrderInfo myhistory;
CDealInfo mydeal;
MqlTick last_tick;
MqlRates Rates[];
double rl_high=EMPTY_VALUE, rl_low=EMPTY_VALUE, last_level=EMPTY_VALUE;
int Div=3, last_level_cnt=0;

int OnInit() {
   minLot  = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   maxLot  = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   Min_Dist= (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
   Spr     = (int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
   
   if (_Digits == 2 || _Digits == 4){
      Distance /= 10;
      TakeProfit /= 10;
      StopLoss /= 10;
      slip /= 10; if(slip<1) slip=1;
      Print("Correction 4 digits",slip);
      Div=2;
   }

   if(!MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_OPTIMIZATION)) RealTrade=true;
   
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(slip);
   trade.SetTypeFilling(ORDER_FILLING_FOK);

   return (INIT_SUCCEEDED);
}

//нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн
void OnTick(){
   //новый бар
   datetime Time[];
   CopyTime(_Symbol, _Period, 0, 1, Time);
   if (timeprev == Time[0]) return;
   timeprev = Time[0];
   
   if(BreakHourStart!=BreakHourEnd){
      MqlDateTime tm;
      TimeCurrent(tm);
      if(((BreakHourStart>BreakHourEnd) && (tm.hour>=BreakHourStart || tm.hour<BreakHourEnd)) ||
         ((BreakHourStart<BreakHourEnd) && (tm.hour>=BreakHourStart && tm.hour<BreakHourEnd))){
            DeleteAllPending();
            return;
      }
   }
   
   SymbolInfoTick(_Symbol,last_tick);
   CopyRates(_Symbol, _Period, 0, 1, Rates);
   if(RealTrade) Min_Dist= (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);

   //сигнал на вход
   if(rl_high!=EMPTY_VALUE && rl_low!=EMPTY_VALUE){
      if(Rates[0].open<rl_low){
         if(last_level==rl_low) last_level_cnt++; else {last_level_cnt=0; last_level=rl_low;}
         if(last_level_cnt<=MaxLevelCount){
            DinamicLot();
            DeleteAllPending();
            draw_price_arrow("Level_", rl_low);
            
            double boprice = ND(rl_low - Distance*_Point);
            if(boprice > last_tick.bid-Min_Dist*_Point) boprice=last_tick.bid-Min_Dist*_Point;
            
            if(!trade.BuyLimit(CalcLot(),boprice,_Symbol,boprice-StopLoss*_Point,boprice+TakeProfit*_Point,ORDER_TIME_GTC,TimeTradeServer()+PeriodSeconds(PERIOD_D1),EAName))
               Print("Ошибка открытия ордера: ",trade.ResultRetcodeDescription());
         }
      }
   
      if(Rates[0].open>rl_high){
         if(last_level==rl_high) last_level_cnt++; else {last_level_cnt=0; last_level=rl_high;}
         if(last_level_cnt<=MaxLevelCount){
            DinamicLot();
            DeleteAllPending();
            draw_price_arrow("Level_", rl_high);
            
            double soprice = ND(rl_high + Distance*_Point);
            if(soprice < last_tick.ask+Min_Dist*_Point) soprice=last_tick.ask+Min_Dist*_Point;
            
            if(!trade.SellLimit(CalcLot(),soprice,_Symbol,soprice+StopLoss*_Point,soprice-TakeProfit*_Point,ORDER_TIME_GTC,TimeTradeServer()+PeriodSeconds(PERIOD_D1),EAName))
               Print("Ошибка открытия ордера: ",trade.ResultRetcodeDescription());
         }
      }
   }
   if(Rates[0].open>=rl_high || Rates[0].open<=rl_low) recalc_round_level(); 
}

//-------------------------НАЧАЛО ФИЛЬТРА-------------------------------------------------------------//
void recalc_round_level(){
   double rl = round(last_tick.bid*MathPow(10,_Digits)/MathPow(10,Div));
   if(rl/MathPow(10,_Digits-Div) > last_tick.bid){
      rl_high=rl/MathPow(10,_Digits-Div);
      rl_low=(rl-1)/MathPow(10,_Digits-Div);
   }else{
      rl_high=(rl+1)/MathPow(10,_Digits-Div);
      rl_low=rl/MathPow(10,_Digits-Div);
   }
   string n="_RoundPrice "+_Symbol;
   draw_level(n+" high", rl_high);
   draw_level(n+" low",  rl_low);
}

void draw_level(string n, double price){
   if(RealTrade || MQLInfoInteger(MQL_VISUAL_MODE)){
      if(ObjectFind(0,n) != -1) ObjectDelete(0,n);
      
      ObjectCreate(0,n, OBJ_HLINE, 0, TimeCurrent(), price);
      ObjectSetInteger(0,n, OBJPROP_STYLE, STYLE_DOT);
      ObjectSetInteger(0,n, OBJPROP_COLOR, clrLime);
  }
}

void draw_price_arrow(string n, double price){
   if(RealTrade || MQLInfoInteger(MQL_VISUAL_MODE)){
      n+=DoubleToString(price)+" "+IntegerToString(TimeCurrent());
      if(ObjectFind(0,n) != -1) ObjectDelete(0,n);
      
      ObjectCreate(0,n, OBJ_ARROW_LEFT_PRICE, 0, Rates[0].time, price);
      ObjectSetInteger(0,n, OBJPROP_COLOR, clrYellow);
  }
}

void DeleteAllPending(){
   if (HistorySelect(0,TimeCurrent())){    
   int o_total = OrdersTotal();
      for (int j=0; j<o_total; j++){
         if(myorder.Select(OrderGetTicket(j))==false) continue;
         if(myorder.Magic()!=MagicNumber || myorder.Symbol() != _Symbol) continue;
         if(myorder.OrderType() == ORDER_TYPE_BUY_STOP || myorder.OrderType() == ORDER_TYPE_SELL_STOP || myorder.OrderType() == ORDER_TYPE_BUY_LIMIT  || myorder.OrderType() == ORDER_TYPE_SELL_LIMIT){
            trade.OrderDelete(myorder.Ticket());
         }
      }
   }
}

void DinamicLot(){
   if(DepoPer001Lot>0){
      Lots = NormalizeDouble((AccountInfoDouble(ACCOUNT_MARGIN_FREE)/DepoPer001Lot)/100,2);
      if(Lots<minLot) Lots = minLot; 
   }
}


double CalcLot(){
   double iLots=Lots;
   if(StopLossLotExponent>1){
      if (HistorySelect(0,TimeCurrent())){    
         for (int j=HistoryDealsTotal()-1; j>=0; j--){
            mydeal.SelectByIndex(j);
            
            if(mydeal.Magic()!=MagicNumber || mydeal.Symbol()!=_Symbol || mydeal.Profit()==0.0) continue;
            if(mydeal.Profit()<0) iLots=NormalizeDouble(mydeal.Volume()*StopLossLotExponent,2);
            break;
         }
      }
   }
   return iLots;
}

//+------------------------------------------------------------------+
double ND(double ad_0) {
   return (NormalizeDouble(ad_0, _Digits));
}
