//+------------------------------------------------------------------+
//|                                     NightExtremum light v1.0.mq4 |
//|          Copyright 2015, Silentspec Megamozg Intergalactic Corp. |
//+------------------------------------------------------------------+

#property copyright "Copyright 2015, Silentspec Megamozg Intergalactic Corp."
#property version   "1.06"

extern string              Settings01 =                  "====Служебные настройки====";
extern string              ExpertName =                  "WT v1.0";
extern int                 Magic =                       0;
extern bool                RealTrade =                   false;
extern string              FiltersString18 =             "+++Сигнал входа+++";
extern int                 MomTrendPer =                 18;
extern int                 TrendMAPer =                  100;
extern double              RSILev =                      30;
extern double              WPRLev =                      10;
extern bool                UseForce =                    true;
extern bool                UseMom =                      true;
extern bool                UseRSI =                      true;
extern bool                UseWPR =                      true;
extern bool                UseDem =                      true;
extern string              Settings43 =                  "====Настройки ММ====";
enum MMVAR
{
MMVAR0=0,                            //  Фиксированный лот
MMVAR1=1,                            //  Фиксированный процент
MMVAR2=2,                            //  Фиксированная пропорция Ральфа Винса
MMVAR3=3,                            //  Фиксированный процент по максимальной просадке
};
input MMVAR                LotVariant =                  3;
extern double              FixLot =                      0.1;                 // Фиксированный лот
extern double              Risk =                        3;                   // Риск в процентах от депозита
extern double              MoneyForMinLot  =             200;                 // Денег депозита на минимальный лот
extern double              MaxDD =                       20;                  // Максимальная просадка
extern double              RiskDD =                      2;                   // Риск в процентах от просадки
extern string              Settings39 =                  "====Настройки SL и TP====";
enum SLVAR
{
SLVAR0=0,                            //  Фиксированный стоп
SLVAR1=1,                            //  Стоп по АТР
};
input SLVAR                SLVariant =                   0;
extern int                 SL =                          60;            // Величина фикс стопа
extern double              SLCoef =                      3.0;           // Коэффициент стопа по АТР
extern double              TPProc =                      100;           // Величина в % от стопа
extern string              SettingsRule =                "====Выход по классике====";
extern bool                UseClassExit =                true;
extern int                 ExitHist =                    20;
extern int                 ExitProfitMinutesClass =      3;
extern string              SettingsADX =                 "====Выход по ADX====";
extern bool                UseADXExit =                  true;
enum ADXVAR
{
ADXVAR0=0,                            //  Выше уровня
ADXVAR1=1,                            //  Пересек уровень
ADXVAR2=2,                            //  Падает 3 свечи подряд и пересек уровень
};
input ADXVAR               EADXVariant =                 0;
extern int                 EADXPer =                     14;
extern double              EADXLevel =                   42;
extern int                 ExitProfitMinutesADX =        3;
extern string              SettingsBB =                  "====Выход по BB====";
extern bool                UseBBExit =                   true;
enum BBVAR
{
BBVAR0=0,                            //  Выше верхнего ББ
BBVAR1=1,                            //  Была выше верхнего ББ, стала ниже
BBVAR2=2,                            //  Ниже нижнего ББ
};
input BBVAR                EBBVariant =                  0;
extern int                 EBBPer =                      14;
extern double              EBBDev =                      2;
extern int                 ExitProfitMinutesBB =        3;
extern string              SettingsDEM =                 "====Выход по DEM====";
extern bool                UseDEMExit =                  true;
enum DEMVAR
{
DEMVAR0=0,                            //  Выше верхнего уровня
DEMVAR1=1,                            //  Была выше верхнего уровня, стала ниже
DEMVAR2=2,                            //  Пересекла ноль
};
input DEMVAR               EDEMVariant =                  0;
extern int                 EDEMPer =                     14;
extern double              EDEMLevel =                   0.3;
extern int                 ExitProfitMinutesDEM =        3;
extern string              SettingsWPR =                 "====Выход по WPR====";
extern bool                UseWPRExit =                  true;
enum WPRVAR
{
WPRVAR0=0,                            //  Выше верхнего уровня
WPRVAR1=1,                            //  Была выше верхнего уровня, стала ниже
WPRVAR2=2,                            //  Пересекла ноль
};
input WPRVAR               EWPRVariant =                 0;
extern int                 EWPRPer =                     14;
extern double              EWPRLevel =                   20;
extern int                 ExitProfitMinutesWPR =        3;
extern string              SettingsSTO =                 "====Выход по Stochastic====";
extern bool                UseSTOExit =                  true;
enum STOVAR
{
STOVAR0=0,                            //  Выше верхнего уровня
STOVAR1=1,                            //  Была выше верхнего уровня, стала ниже
STOVAR2=2,                            //  Пересекла ноль
STOVAR3=3,                            //  Пересекла сигнальную
STOVAR4=4,                            //  Пересекла сигнальную выше нуля
STOVAR5=5,                            //  Пересекла сигнальную выше уровня
};
input STOVAR               ESTOVariant =                 0;
input ENUM_MA_METHOD       ESTOMode =                    MODE_EMA;
extern int                 ESTOKPer =                    14;
extern int                 ESTODPer =                    5;
extern int                 ESTOSPer =                    9;
extern double              ESTOLevel =                   20;
extern int                 ExitProfitMinutesSTO =        3;
extern string              SettingsRVI =                 "====Выход по RVI====";
extern bool                UseRVIExit =                  true;
enum RVIVAR
{
RVIVAR0=0,                            //  Пересекла ноль
RVIVAR1=1,                            //  Пересекла сигнальную
RVIVAR2=2,                            //  Пересекла сигнальную выше нуля
};
input RVIVAR               ERVIVariant =                 0;
extern int                 ERVIPer =                     14;
extern int                 ExitProfitMinutesRVI =        3;
extern string              Settings46 =                  "====Трал====";
extern bool                UseMATral =                   false;                              // Трейлинг по машке
extern bool                UseMATralOnStart =            false;                              // Трейлинг по машке
extern int                 iShift =                      1;
extern int                 iIndent =                     3; 
input ENUM_MA_METHOD       MAMethod =                    MODE_SMA;
extern int                 iMAPeriod =                   24;
extern string              Settings51 =                  "====БУ====";
extern bool                UseBE =                       false;
extern double              BEPerc =                      40;
extern int                 BEPlusPips =                  5;
extern string              FiltersString29 =             "-Фильтр корреляции";
extern bool                BalancePairFilter =           true;
extern bool                OnlyCurrPair =                true;
extern string              FiltersString28 =             "-МаксРиск фильтр";
extern bool                UseMaxRiskFilter =            true;
extern double              MaxRisk =                     15.0;
extern string              Settings53 =                  "====Прочие торговые настройки====";
extern bool                UseComments  =                true;
int                 Slippage =                           1;
int                 RetryAttempts =                      3;                               // Кол-во попыток открыть/закрыть/модифицировать ордер

double InitResult=INIT_FAILED;
double StopLevel,MinLot,MaxLot,LotStep=-1,PointValue,BaseLot;
int PriceDigits;

double                     TralStep =                    0.1;
int                        MinTral =                     5;

int OpenPriceDay = 0;

double DayOpenPrice=0, Stoch = 0, StochS = 0;

double MA1, MA2, ATRD;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
   {
   if(RetryAttempts==0) RetryAttempts=10;
   StopLevel   = MarketInfo(Symbol(),MODE_STOPLEVEL);
   MinLot      = MarketInfo(Symbol(),MODE_MINLOT);
   MaxLot      = MarketInfo(Symbol(),MODE_MAXLOT);
   LotStep     = MarketInfo(Symbol(),MODE_LOTSTEP);
   if(LotStep<0) LotStep=0.01;
   PointValue  = SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE);
   PriceDigits = SymbolInfoInteger(Symbol(),SYMBOL_DIGITS);
   if(PriceDigits==5||PriceDigits==3)
      {
      SL*=10;
      Slippage*=10;
      BEPlusPips*=10;
      iIndent*=10;
      }
   EAComment(" Советник "+ExpertName+" начал работу на паре "+_Symbol+" с магиком "+IntegerToString(Magic));
   return(InitResult);
   }
   
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
   {
   switch (_UninitReason)
      {
      case REASON_ACCOUNT:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Смена аккаунта."); 
         break;
      case REASON_CHARTCHANGE:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Смена таймфрейма."); 
         break;
      case REASON_CHARTCLOSE:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Закрытие графика."); 
         break;
      case REASON_PARAMETERS:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Смена параметров."); 
         break;
      case REASON_RECOMPILE:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Советник декомпилирован."); 
         break;
      case REASON_REMOVE:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Советник был удален с графика."); 
         break;
      case REASON_TEMPLATE:
         EAComment(" Советник остановлен. Пара "+_Symbol+". Новый шаблон на графике."); 
         break;
      default:
         EAComment(" Советник остановлен. Пара "+_Symbol); 
      }
   }
   
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   if((RealTrade&&Hour()==0&&Minute()==30)||(!RealTrade&&IsNewBar(1,PERIOD_D1)))
   {
         double Force1 = iForce(_Symbol,PERIOD_D1,2,MODE_EMA,PRICE_CLOSE,1);
         double Force2 = iForce(_Symbol,PERIOD_D1,2,MODE_EMA,PRICE_CLOSE,2);
         double TrendMA = iMA(_Symbol,PERIOD_D1,TrendMAPer,0,MODE_EMA,PRICE_CLOSE,1);
         double Close1 = iClose(_Symbol,PERIOD_D1,1);
         double Mom1 = iMomentum(_Symbol,PERIOD_D1,2,PRICE_CLOSE,1);
         double Mom2 = iMomentum(_Symbol,PERIOD_D1,2,PRICE_CLOSE,2);
         double RSI1 = iRSI(_Symbol,PERIOD_D1,2,PRICE_CLOSE,1);
         double MomTrend = iMomentum(_Symbol,PERIOD_D1,MomTrendPer,PRICE_CLOSE,1);
         double WPR1 = iWPR(_Symbol,PERIOD_D1,2,1);
         double Dem = iDeMarker(_Symbol,PERIOD_D1,2,1);
         
         if(((UseForce&&Force2>0&&Force1<0)||(UseMom&&Mom2>100&&Mom1<100)||(UseRSI&&RSI1<RSILev)||(UseWPR&&WPR1<WPRLev-100)||(UseDem&&Dem==0))&&OrdExist(OP_BUY)==0&&Close1>TrendMA&&MomTrend>100&&ReadyToTrade(OP_BUY))
         {
            OpenOrder(OP_BUY,Ask,1);
            OpenOrder(OP_BUY,Ask,2);
         }
         if(((UseForce&&Force2<0&&Force1>0)||(UseMom&&Mom2<100&&Mom1>100)||(UseRSI&&RSI1>100-RSILev)||(UseWPR&&WPR1>-WPRLev)||(UseDem&&Dem==1))&&OrdExist(OP_SELL)==0&&Close1<TrendMA&&MomTrend<100&&ReadyToTrade(OP_SELL))
         {
            OpenOrder(OP_SELL,Bid,1);
            OpenOrder(OP_SELL,Bid,2);
         }
      if(OrdExist(OP_SELL)>0)
      {
         if(CanExit(OP_SELL))
         {
            CloseOrder(OP_SELL);
            TrailingBE();
         }
         if(CanBE(OP_SELL))
         {
            TrailingBE();
         }
         if(UseMATralOnStart) TrailingByMA();
      }
      if(OrdExist(OP_BUY)>0)
      {
         if(CanExit(OP_BUY))
         {
            CloseOrder(OP_BUY);
            TrailingBE();
         }
         if(CanBE(OP_BUY))
         {
            TrailingBE();
         }
         if(UseMATralOnStart) TrailingByMA();
      }
      if(OrdExist(OP_SELL)==1||OrdExist(OP_BUY)==1)
      {
         TrailingBE();
         TrailingByMA();
      }
   }
   return;
}
//+------------------------------------------------------------------+

double OnTester()
   {
   double ret=0.0;
   if (TesterStatistics(STAT_BALANCE_DD)>0) ret=TesterStatistics(STAT_TRADES)*TesterStatistics(STAT_PROFIT_FACTOR)*TesterStatistics(STAT_PROFIT)/TesterStatistics(STAT_BALANCE_DD);
   return(ret);
   }

//+------------------------------------------------------------------+
//| Закрывает все ордера                                             |
//+------------------------------------------------------------------+
bool CloseOrder(int dir)   // закрытие всех ордеров
{
   double PriceClose=0;
   int ticket=0,n=0;
   bool rval = false;
   double LastTP = 0;
   int LastTicket = 0;
   color Color;
   for(int i = OrdersTotal()-1; i>=0; i--)
   {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if (OrderSymbol()==_Symbol&&OrderMagicNumber()==Magic)
         {
            if (OrderType() == dir)
            {
               if(OrderProfit()<0)
               {
                  if(dir == OP_BUY) 
                  {
                     PriceClose = Bid;
                     Color = Blue;
                  }
                  if(dir == OP_SELL)
                  {
                     PriceClose = Ask;
                     Color = Red;
                  }
                  for (n = 1; n <= MathMax(1, RetryAttempts); n++)
                  {
                     ticket=OrderClose(OrderTicket(),OrderLots(),PriceClose,Slippage,Color);
                     if(ticket>0)
                     {
                        EAComment ("Успешно закрыли ордер");
                        n=RetryAttempts;
                     }
                     if(ticket==0&&n < MathMax(1, RetryAttempts)) 
                     {
                        EAComment("Не удалось закрыть ордер, пробуем снова!");
                     }
                     if(ticket==0&&n == MathMax(1, RetryAttempts)) 
                     {
                        EAComment("Не удалось закрыть ордер!");
                     }
                  }
                  continue;
               }
            }   
         }
      }
   }  
   return(true);                           
}

//+------------------------------------------------------------------+
//|  New bar function                                                |
//+------------------------------------------------------------------+
bool IsNewBar(int mode=0,int period=0)
   {
   //0 - при первом запуске возвращает true
   //1 - при первом запуске ожидает следующий бар
   static datetime tm[10];
   int t=tfA(period);
   if(tm[t]==0&&mode==1) tm[t]=iTime(_Symbol,period,0);
   if(tm[t]==iTime(_Symbol,period,0)) return (false);
   if(period<=PERIOD_H1&&Minute()%period!=0) return (false);
   tm[t]=iTime(_Symbol,period,0);
   return (true);
   }
 
int tfA(int tf)
   {
   switch (tf)
      {
      case PERIOD_M1: return (0);
      case PERIOD_M5: return (1);
      case PERIOD_M15: return (2);
      case PERIOD_M30: return (3);
      case PERIOD_H1: return (4);
      case PERIOD_H4: return (5);
      case PERIOD_D1: return (6);
      case PERIOD_W1: return (7);
      case PERIOD_MN1: return (8);
      default: return (9);
      }
   }

//+------------------------------------------------------------------+
//|  Comments                                                        |
//+------------------------------------------------------------------+
void EAComment(string st) 
  {
  if (UseComments&&!IsOptimization()) Print(st);
  return;
  }
  
int LastCloseTime()
{
   int LastTime = 0;
   for (int i=0; i<OrdersHistoryTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
      {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == Magic)
         {
            if(OrderCloseTime()>LastTime) LastTime=OrderCloseTime();
         }
      }
   }
   return(LastTime);
}

//+------------------------------------------------------------------+
//| Лоты                                                             |
//+------------------------------------------------------------------+
double Lots(double Stop)
   {
   double Lot=0,AccountCurrPrice=1;
   int    orders=OrdersHistoryTotal();
   double TPToSLRatio=0;
   double TPPerc=0;
   // Вычисляем коэффициент поправки расчета лота на валюту депозита
   if (StringSubstr(AccountCurrency(), 0, 3) == "JPY") AccountCurrPrice = MarketInfo("USDJPY" + StringSubstr(Symbol(), 6), MODE_BID);
   if (StringSubstr(AccountCurrency(), 0, 3) == "GBP") AccountCurrPrice = 1/MarketInfo("GBPUSD" + StringSubstr(Symbol(), 6), MODE_BID);
   if (StringSubstr(AccountCurrency(), 0, 3) == "EUR") AccountCurrPrice = 1/MarketInfo("EURUSD" + StringSubstr(Symbol(), 6), MODE_BID);
   if (StringSubstr(AccountCurrency(), 0, 3) == "RUB") AccountCurrPrice = MarketInfo("USDRUB" + StringSubstr(Symbol(), 6), MODE_BID);
   if (StringSubstr(AccountCurrency(), 0, 3) == "AUD") AccountCurrPrice = 1/MarketInfo("AUDUSD" + StringSubstr(Symbol(), 6), MODE_BID);
   // Считаем лот
   switch(LotVariant)
      {
      case 0:  //  Фиксированный лот
         {
         Lot=FixLot*AccountCurrPrice; 
         break;
         }
      case 1:  //  Фиксированный процент
         {
         Lot=(AccountBalance()*(Risk/100)/(Stop))*AccountCurrPrice;
         break;
         }
      case 2:  //  Фиксированная пропорция
         {
         Lot=(AccountBalance()/MoneyForMinLot)*MinLot*AccountCurrPrice;
         break;
         }
      case 3:  //  Фиксированный процент от просадки
         {
         Lot=(RiskDD/100)*(AccountBalance()-(1-MaxDD/100)*MaxDepo())*AccountCurrPrice/Stop;
         break;
         }
      }
   // Возвращаем нормализованное значение лота
   Lot = Lot/2;
   return(MathMin(MathMax(MinLot,MathRound(Lot/LotStep)*LotStep),MaxLot));
   }
   
double MaxDepo()
{
   double MaxBal = 0;
   double Bal = 0;
   if (OrdersHistoryTotal()==0) return(AccountBalance());
   for(int i=OrdersHistoryTotal()-1; i>=0; i--)
   {
      if (!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      Bal = Bal + OrderProfit();
      if(Bal>MaxBal) MaxBal = Bal;
   }
   return(MaxBal);
}
   
//+------------------------------------------------------------------+
//| Стопы                                                            |
//+------------------------------------------------------------------+
double StopLoss(int dir,double OpenPrice)
   {
   double Stop=0;
   double ATR = iATR(_Symbol,PERIOD_D1,20,1);
   switch(SLVariant)
   {
      case 0:
      {
         if(dir==OP_BUY||dir==OP_BUYSTOP||dir==OP_BUYLIMIT) Stop=OpenPrice-SL*_Point;
         if(dir==OP_SELL||dir==OP_SELLSTOP||dir==OP_SELLLIMIT) Stop=OpenPrice+SL*_Point;
      }
      case 1:
      {
         if(dir==OP_BUY||dir==OP_BUYSTOP||dir==OP_BUYLIMIT) Stop=OpenPrice-ATR*SLCoef;
         if(dir==OP_SELL||dir==OP_SELLSTOP||dir==OP_SELLLIMIT) Stop=OpenPrice+ATR*SLCoef;
      }
   }
   return(NormalizeDouble(Stop,_Digits));
   }
   
double TakeProfit(int dir,double OpenPrice)
   {
   double Take=0;
   if(dir==OP_BUY||dir==OP_BUYSTOP||dir==OP_BUYLIMIT) Take=OpenPrice+(OpenPrice-StopLoss(OP_BUY,OpenPrice))*(TPProc/100);
   if(dir==OP_SELL||dir==OP_SELLSTOP||dir==OP_SELLLIMIT) Take=OpenPrice-(StopLoss(OP_SELL,OpenPrice)-OpenPrice)*(TPProc/100);
   return(NormalizeDouble(Take,_Digits));
   }

//+------------------------------------------------------------------+
//| Return existing orders counted                                   |
//+------------------------------------------------------------------+
int OrdExist(int direction)
{
int OrdCount=0;
if (OrdersTotal()>0)
   {
   for(int i=OrdersTotal(); i>=0; i--)
      {
      if (!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
      if (OrderMagicNumber()!=Magic||OrderSymbol()!=_Symbol) continue;
      if (OrderType()==direction) OrdCount++;
      }
   }
return (OrdCount);
}

//+------------------------------------------------------------------+
//| Открытие ордера                                                  |
//+------------------------------------------------------------------+
void OpenOrder (int direction, double OpenPrice, int OrdNum)
{
   double Lot=0,Stop=0,Take=0;
   color Color;
   int ticket=0,ticket1=0,n=0,i=0;
   Stop=StopLoss(direction,OpenPrice);
   if(OrdNum == 1) Take = TakeProfit(direction,OpenPrice);
   if(OrdNum < 1) Take = 0;
   if(direction==OP_BUY) 
   {
      Lot=Lots((OpenPrice-Stop)/_Point);
      Color = Blue;
   }
   if(direction==OP_SELL) 
   {
      Lot=Lots((Stop-OpenPrice)/_Point);
      Color = Red;
   }
   for (i = 1; i <= MathMax(1, RetryAttempts); i++)
      {
      RefreshRates();
      ticket=OrderSend(_Symbol,direction,Lot,OpenPrice,Slippage,0,0,ExpertName+" "+IntegerToString(Magic)+" Спред:"+(Ask-Bid)/_Point,Magic,0,Color);
      if(ticket>0)
         {
            for (n = 1; n <= MathMax(1, RetryAttempts); n++)
               {
               RefreshRates();
               ticket1=OrderModify(ticket,OrderOpenPrice(),Stop,Take,0,Green);
               if(ticket1>0) 
                  {
                  EAComment("Успешно выставили ТП и СЛ для ордера!");
                  return;
                  }
               if(ticket1==0&&n < MathMax(1, RetryAttempts)) 
                  {
                  EAComment("ТП и СЛ для ордера не выставлен, пробуем снова!");
                  }
               if(ticket1==0&&n == MathMax(1, RetryAttempts)) 
                  {
                  EAComment("ТП и СЛ для ордера не выставлены!");
                  return;
                  }
               }
         return;
         }
      if(ticket==0&&i < MathMax(1, RetryAttempts)) 
         {
         EAComment("Ордер не выставлен, пробуем снова!");
         Sleep(3000);
         continue;
         }
      if(ticket==0&&i == MathMax(1, RetryAttempts)) 
         {
         EAComment("Ордер не выставлен!");
         return;
         }
      }
return;
}

//+------------------------------------------------------------------+
//| Закрывает все ордера                                             |
//+------------------------------------------------------------------+
bool CloseAllOrders(int dir)   // закрытие всех ордеров
   {
   double PriceClose=0;
   int ticket=0,n=0;
   bool rval = false;
   for(int i = OrdersTotal()-1; i>=0; i--)
      {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
         if (OrderSymbol()==_Symbol&&OrderMagicNumber()==Magic)
            {
            if (OrderType() == dir)
               {
               if (OrderType() == OP_BUY) PriceClose = Bid;
               if (OrderType() == OP_SELL) PriceClose = Ask;
               for (n = 1; n <= MathMax(1, RetryAttempts); n++)
                  {
                  ticket=OrderClose(OrderTicket(),OrderLots(),PriceClose,Slippage,CLR_NONE);
                  if(ticket>0)
                     {
                     EAComment ("Успешно закрыли ордер");
   					   continue;
                     }
                  if(ticket==0&&n < MathMax(1, RetryAttempts)) 
                     {
                     EAComment("Не удалось закрыть ордер, пробуем снова!");
                     }
                  if(ticket==0&&n == MathMax(1, RetryAttempts)) 
                     {
                     EAComment("Не удалось закрыть ордер!");
                     continue;
                     }
                  }
               }   
            }
         }
      }  
   return(true);                           
   }
//+---------------------------------------------------------------------------------------------------+

bool ReadyToTrade(int dir)
   {
   if(!IsTesting()&&!BalancedPair(dir)) return(false);
   if(!IsTesting()&&!MaxRiskAll()) return(false);
   return(true);
   }

//+------------------------------------------------------------------+
//| Фильтр коррелированных сделок                                    |
//+------------------------------------------------------------------+
bool BalancedPair(int type)
   {
   if(!BalancePairFilter) return(true);
   int i=0;
   if(OnlyCurrPair)
      {
      for (i=OrdersTotal();i>=0;i--)
         {
         if (!OrderSelect(i,SELECT_BY_POS)) continue;
         if ((OrderType()==OP_BUY||OrderType()==OP_BUYSTOP||OrderType()==OP_BUYLIMIT)&&(type==OP_BUY||type==OP_BUYSTOP||type==OP_BUYLIMIT)&&OrderSymbol()==Symbol()) 
            {
            EAComment("BalancedPair: торговля запрещена, по данной паре уже открыта сделка");
            return(false);
            }
         if ((OrderType()==OP_SELL||OrderType()==OP_SELLSTOP||OrderType()==OP_SELLLIMIT)&&(type==OP_SELL||type==OP_SELLSTOP||type==OP_SELLLIMIT)&&OrderSymbol()==Symbol()) 
            {
            EAComment("BalancedPair: торговля запрещена, по данной паре уже открыта сделка");
            return(false);
            }
         }
      return(true);
      }
   string BuyCcy1, SellCcy1, BuyCcy2, SellCcy2;
   if (type==OP_BUY||type==OP_BUYSTOP||type==OP_BUYLIMIT)
      {
      BuyCcy1 = StringSubstr(Symbol(),0,3);
      SellCcy1 = StringSubstr(Symbol(),3,3);
      }
   if (type==OP_SELL||type==OP_SELLSTOP||type==OP_SELLLIMIT)
      {
      BuyCcy1 = StringSubstr(Symbol(),3,3);
      SellCcy1 = StringSubstr(Symbol(),0,3);
      }
   for (i=OrdersTotal()-1;i>=0;i--)
      {
      if (!OrderSelect(i,SELECT_BY_POS)) continue;
      if (OrderMagicNumber()==Magic) continue;
      if (OrderType()==OP_BUY||OrderType()==OP_BUYSTOP||OrderType()==OP_BUYLIMIT)
         {
         BuyCcy2=StringSubstr(OrderSymbol(),0,3);
         SellCcy2=StringSubstr(OrderSymbol(),3,3);
         }
      if (OrderType()==OP_SELL||OrderType()==OP_SELLSTOP||OrderType()==OP_SELLLIMIT)
         {
         BuyCcy2=StringSubstr(OrderSymbol(),3,3);
         SellCcy2=StringSubstr(OrderSymbol(),0,3);
         }
      if (BuyCcy1==BuyCcy2||SellCcy1==SellCcy2) 
         {
         EAComment("BalancedPair: торговля запрещена, по коррелирующей паре уже открыта сделка");
         return(false);
         }
      }
   return(true);
   }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Расчет макс риска                                                |
//+------------------------------------------------------------------+
//Возвращает true в случае удачного прохода фильтра
bool MaxRiskAll()
   {
   if(!UseMaxRiskFilter) return(true);
   double TekRisk=0;
   if(OrdersTotal()>0)
      {
      for(int i=OrdersTotal();i>=0;i--)
         {
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
         if(OrderMagicNumber()!=Magic||OrderSymbol()!=Symbol())
            {
            if(OrderType()==OP_SELL&&OrderOpenPrice()<OrderStopLoss())
               {
               TekRisk=TekRisk+((OrderStopLoss()-OrderOpenPrice())*OrderLots()/AccountBalance())*100;
               }
            if(OrderType()==OP_BUY&&OrderOpenPrice()>OrderStopLoss())
               {
               TekRisk=TekRisk+((OrderOpenPrice()-OrderStopLoss())*OrderLots()/AccountBalance())*100;
               }
            }
         }
      }
   if(TekRisk>MaxRisk) 
      {
      EAComment ("Достигнут максимальный уровень риска, вход в позицию пока запрещен.");
      return(false);
      }
   return(true);
   }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| ТРЕЙЛИНГ ПО СКОЛЬЗЯЩЕМУ СРЕДНЕМУ                                 |
//| Функции передаётся тикет позиции и параметры средней (таймфрейм, | 
//| период, тип, сдвиг относительно графика, метод сглаживания,      |
//| составляющая OHCL для построения, № бара, на котором берется     |
//| значение средней.                                                | 
//+------------------------------------------------------------------+  
void TrailingByMA()
{
   if(!UseMATral) return;
   int n=0,ticket=0,i=0;
   HideTestIndicators(true);
   double dMA = iMA(Symbol(),PERIOD_D1,iMAPeriod,0,MAMethod,PRICE_CLOSE,iShift);  
   if (OrdersTotal()>0)
   {
      for(i=OrdersTotal()-1; i>=0; i--)
      {
         if (!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
         if (OrderMagicNumber()!=Magic||OrderSymbol()!=_Symbol) continue;
         if (OrderType()==OP_BUY)
         {
            if (dMA-iIndent*Point-10*_Point>OrderOpenPrice()&&(OrderStopLoss()<dMA-iIndent*Point-10*_Point) && (dMA-iIndent*Point<Bid-MarketInfo(Symbol(),MODE_STOPLEVEL)*Point))
            {
               if (!OrderModify(OrderTicket(),OrderOpenPrice(),dMA-iIndent*Point,OrderTakeProfit(),OrderExpiration()))
               Print("Не удалось модифицировать стоплосс ордера №",OrderTicket(),". Ошибка: ",GetLastError());
            }
         }
         if (OrderType()==OP_SELL)
         {
            if (dMA+(MarketInfo(Symbol(),MODE_SPREAD)+iIndent)*Point+10*_Point<OrderOpenPrice()&&((OrderStopLoss()==0) || (OrderStopLoss()>dMA+(MarketInfo(Symbol(),MODE_SPREAD)+iIndent)*Point+10*_Point)) && (dMA+(MarketInfo(Symbol(),MODE_SPREAD)+iIndent)*Point>Ask+MarketInfo(Symbol(),MODE_STOPLEVEL)*Point))
            {
               if (!OrderModify(OrderTicket(),OrderOpenPrice(),dMA+(MarketInfo(Symbol(),MODE_SPREAD)+iIndent)*Point,OrderTakeProfit(),OrderExpiration()))
               Print("Не удалось модифицировать стоплосс ордера №",OrderTicket(),". Ошибка: ",GetLastError());
            }
         }
      }
   }
   HideTestIndicators(false);
   return;
}

void TrailingBE()
   {
   if(!UseBE) return;
   int n=0,ticket=0;
   double NewStopBuy=0,NewStopSell=0;
   if (OrdersTotal()>0)
      {
      for(int i=OrdersTotal()-1; i>=0; i--)
         {
         if (!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
         if (OrderMagicNumber()!=Magic||OrderSymbol()!=_Symbol) continue;
         if (OrderType()==OP_BUY)
            {
            if(OrderStopLoss()<OrderOpenPrice()&&Bid>OrderOpenPrice()+BEPlusPips*_Point+MarketInfo(Symbol(),MODE_STOPLEVEL)*Point)       
               {
               for (n = 1; n <= MathMax(1, RetryAttempts); n++)
                  {
                  ticket=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+BEPlusPips*_Point,OrderTakeProfit(),0,Green);
                  if(ticket>0)
                     {
                     EAComment ("Сработал стандартный безубыток");
                     n = RetryAttempts + 1;
                     }
                  if(ticket==0&&n < MathMax(1, RetryAttempts)) 
                     {
                     EAComment("Ошибка стандартного безубытка, пробуем снова!");
                     }
                  if(ticket==0&&n == MathMax(1, RetryAttempts)) 
                     {
                     EAComment("Ошибка стандартного безубытка!");
                     continue;
                     }
                  }
               }
            }
         if (OrderType()==OP_SELL)
            {
            if(OrderStopLoss()>OrderOpenPrice()&&Ask<OrderOpenPrice()-BEPlusPips*_Point-MarketInfo(Symbol(),MODE_STOPLEVEL)*Point)
               {
               for (n = 1; n <= MathMax(1, RetryAttempts); n++)
                  {
                  ticket=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-BEPlusPips*_Point,OrderTakeProfit(),0,Green);
                  if(ticket>0)
                     {
                     EAComment ("Сработал стандартный безубыток");
                     n = RetryAttempts + 1;
                     }
                  if(ticket==0&&n < MathMax(1, RetryAttempts)) 
                     {
                     EAComment("Ошибка стандартного безубытка, пробуем снова!");
                     }
                  if(ticket==0&&n == MathMax(1, RetryAttempts)) 
                     {
                     EAComment("Ошибка стандартного безубытка!");
                     continue;
                     }
                  }
               }
            }
         }
      }
   return;
   }
   
bool CanExit(int dir)
{
   if(ADXExit(dir)||BBExit(dir)||
      DEMExit(dir)||STOExit(dir)||
      WPRExit(dir)||RVIExit(dir)||ClassicExit(dir))
      return (true);
return (false);
}
   
// ADX
// АДХ выше уровня
// АДХ пересекла уровень сверху вниз
bool ADXExit(int dir)
{
   double EADX1 = iADX(_Symbol,PERIOD_D1,EADXPer,PRICE_CLOSE,MODE_MAIN,1);
   double EADX2 = iADX(_Symbol,PERIOD_D1,EADXPer,PRICE_CLOSE,MODE_MAIN,2);
   double EADX3 = iADX(_Symbol,PERIOD_D1,EADXPer,PRICE_CLOSE,MODE_MAIN,3);
   if(!ExitTimeProfit(dir,ExitProfitMinutesADX)||!UseADXExit) return (false);
   switch(EADXVariant)
   {
      case 0:
      {
         if(EADX1>EADXLevel) 
         return (true);
      }
      case 1:
      {
         if(EADX2>EADXLevel&&EADX1<EADXLevel) 
         return (true);
      }
      case 2:
      {
         if(EADX3>EADX2&&EADX2>EADXLevel&&EADX1<EADXLevel) 
         return (true);
      }
   }
   
   return (false);
}

// ББ
bool BBExit(int dir)
{
   double EBBUp1 = iBands(_Symbol,PERIOD_D1,EBBPer,EBBDev,0,PRICE_CLOSE,MODE_UPPER,1);
   double EBBDn1 = iBands(_Symbol,PERIOD_D1,EBBPer,EBBDev,0,PRICE_CLOSE,MODE_LOWER,1);
   double EBBCn1 = iBands(_Symbol,PERIOD_D1,EBBPer,EBBDev,0,PRICE_CLOSE,MODE_MAIN,1);
   double EClose1 = iClose(_Symbol,PERIOD_D1,1);
   double EBBUp2 = iBands(_Symbol,PERIOD_D1,EBBPer,EBBDev,0,PRICE_CLOSE,MODE_UPPER,2);
   double EBBDn2 = iBands(_Symbol,PERIOD_D1,EBBPer,EBBDev,0,PRICE_CLOSE,MODE_LOWER,2);
   double EClose2 = iClose(_Symbol,PERIOD_D1,2);
   if(!ExitTimeProfit(dir,ExitProfitMinutesBB)||!UseBBExit) return (false);
   
   switch(EBBVariant)
   {
      case 0:
      {
         if((dir == OP_BUY && EClose1>EBBUp1)||(dir == OP_SELL && EClose1<EBBDn1))
         return (true);
      }
      case 1:
      {
         if((dir == OP_BUY && EClose2>EBBUp2 && EClose1<EBBUp1)||(dir == OP_SELL && EClose2<EBBDn2 && EClose1>EBBDn1))
         return (true);
      }
      case 2:
      {
         if((dir == OP_BUY && EClose1<EBBDn1)||(dir == OP_SELL && EClose1>EBBUp1))
         return (true);
      }
   }
   return (false);
}

bool ClassicExit(int dir)
{
   double EHigh1 = iHigh(_Symbol,PERIOD_D1,iHighest(_Symbol,PERIOD_D1,MODE_HIGH,ExitHist,2));
   double ELow1 = iLow(_Symbol,PERIOD_D1,iLowest(_Symbol,PERIOD_D1,MODE_LOW,ExitHist,2));
   double EClose1 = iClose(_Symbol,PERIOD_D1,1);
   if(!ExitTimeProfit(dir,ExitProfitMinutesClass)||!UseClassExit) return (false);
   if((dir == OP_BUY && EClose1<ELow1)||(dir == OP_SELL && EClose1>EHigh1))
      return (true);
   return (false);
}

bool DEMExit(int dir)
{
   double EDEM1 = iDeMarker(_Symbol,PERIOD_D1,EDEMPer,1);
   double EDEM2 = iDeMarker(_Symbol,PERIOD_D1,EDEMPer,2);
   if(!ExitTimeProfit(dir,ExitProfitMinutesDEM)||!UseDEMExit) return (false);
   switch(EDEMVariant)
   {
      case 0:
      {
         if((dir == OP_BUY && EDEM1>1-EDEMLevel)||(dir == OP_SELL && EDEM1<EDEMLevel))
         return (true);
      }
      case 1:
      {
         if((dir == OP_BUY && EDEM1<1-EDEMLevel && EDEM2>1-EDEMLevel)||(dir == OP_SELL && EDEM1>EDEMLevel && EDEM2<EDEMLevel))
         return (true);
      }
      case 2:
      {
         if((dir == OP_BUY && EDEM1<0.5 && EDEM2>0.5)||(dir == OP_SELL && EDEM1>0.5 && EDEM2<0.5))
         return (true);
      }
   }
   return (false);
}

bool WPRExit(int dir)
{
   double EWPR1 = iWPR(_Symbol,PERIOD_D1,EWPRPer,1);
   double EWPR2 = iWPR(_Symbol,PERIOD_D1,EWPRPer,2);
   if(!ExitTimeProfit(dir,ExitProfitMinutesWPR)||!UseWPRExit) return (false);
   switch(EWPRVariant)
   {
      case 0:
      {
         if((dir == OP_BUY && EWPR1>-EWPRLevel)||(dir == OP_SELL && EWPR1<EWPRLevel-100))
         return (true);
      }
      case 1:
      {
         if((dir == OP_BUY && EWPR1<-EWPRLevel && EWPR2>-EWPRLevel)||(dir == OP_SELL && EWPR1>EWPRLevel-100 && EWPR2<EWPRLevel-100))
         return (true);
      }
      case 2:
      {
         if((dir == OP_BUY && EWPR1<-50 && EWPR2>-50)||(dir == OP_SELL && EWPR1>-50 && EWPR2<-50))
         return (true);
      }
   }
   return (false);
}

bool STOExit(int dir)
{
   double ESTO1 = iStochastic(_Symbol,PERIOD_D1,ESTOKPer,ESTODPer,ESTOSPer,ESTOMode,1,MODE_MAIN,1);
   double ESTO2 = iStochastic(_Symbol,PERIOD_D1,ESTOKPer,ESTODPer,ESTOSPer,ESTOMode,1,MODE_MAIN,2);
   double ESTOS1 = iStochastic(_Symbol,PERIOD_D1,ESTOKPer,ESTODPer,ESTOSPer,ESTOMode,1,MODE_SIGNAL,1);
   double ESTOS2 = iStochastic(_Symbol,PERIOD_D1,ESTOKPer,ESTODPer,ESTOSPer,ESTOMode,1,MODE_SIGNAL,2);
   if(!ExitTimeProfit(dir,ExitProfitMinutesSTO)||!UseSTOExit) return (false);
   switch(ESTOVariant)
   {
      case 0:
      {
         if((dir == OP_BUY && ESTO1>100-ESTOLevel)||(dir == OP_SELL && ESTO1<ESTOLevel))
         return (true);
      }
      case 1:
      {
         if((dir == OP_BUY && ESTO1<100-ESTOLevel && ESTO2>100-ESTOLevel)||(dir == OP_SELL && ESTO1>ESTOLevel && ESTO2<ESTOLevel))
         return (true);
      }
      case 2:
      {
         if((dir == OP_BUY && ESTO1<50 && ESTO2>50)||(dir == OP_SELL && ESTO1>50 && ESTO2<50))
         return (true);
      }
      case 3:
      {
         if((dir == OP_BUY && ESTO1<ESTOS1 && ESTO2>ESTOS2)||(dir == OP_SELL && ESTO1>ESTOS1 && ESTO2<ESTOS2))
         return (true);
      }
      case 4:
      {
         if((dir == OP_BUY && ESTO1<ESTOS1 && ESTO2>ESTOS2 && ESTO1>50)||(dir == OP_SELL && ESTO1>ESTOS1 && ESTO2<ESTOS2 && ESTO1<50))
         return (true);
      }
      case 5:
      {
         if((dir == OP_BUY && ESTO1<ESTOS1 && ESTO2>ESTOS2 && ESTO1>100-ESTOLevel)||(dir == OP_SELL && ESTO1>ESTOS1 && ESTO2<ESTOS2 && ESTO1<ESTOLevel))
         return (true);
      }
   }
   return (false);
}

bool RVIExit(int dir)
{
   double ERVI1 = iRVI(_Symbol,PERIOD_D1,ERVIPer,MODE_MAIN,1);
   double ERVI2 = iRVI(_Symbol,PERIOD_D1,ERVIPer,MODE_MAIN,2);
   double ERVIS1 = iRVI(_Symbol,PERIOD_D1,ERVIPer,MODE_SIGNAL,1);
   double ERVIS2 = iRVI(_Symbol,PERIOD_D1,ERVIPer,MODE_SIGNAL,2);
   if(!ExitTimeProfit(dir,ExitProfitMinutesRVI)||!UseRVIExit) return (false);
   switch(ERVIVariant)
   {
      case 0:
      {
         if((dir == OP_BUY && ERVI1<0 && ERVI2>0)||(dir == OP_SELL && ERVI1>0 && ERVI2<0))
         return (true);
      }
      case 1:
      {
         if((dir == OP_BUY && ERVI1<ERVIS1 && ERVI2>ERVIS2)||(dir == OP_SELL && ERVI1>ERVIS1 && ERVI2<ERVIS2))
         return (true);
      }
      case 2:
      {
         if((dir == OP_BUY && ERVI1<ERVIS1 && ERVI2>ERVIS2 && ERVI1>0)||(dir == OP_SELL && ERVI1>ERVIS1 && ERVI2<ERVIS2 && ERVI1<0))
         return (true);
      }
   }
   return (false);
}


// Время и прибыль
bool ExitTimeProfit(int dir, int ExitProfitMinutes)
   {
   for(int i=OrdersTotal(); i>=0; i--)
      {
      if (!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
      if (OrderSymbol()!=Symbol()||OrderMagicNumber()!=Magic) continue;
      if (TimeCurrent()-OrderOpenTime()>60*ExitProfitMinutes*PERIOD_D1) return(true);
      }
   return(false);
   }
   

bool CanBE(int dir)
   {
   for(int i=OrdersTotal(); i>=0; i--)
      {
      if (!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
      if (OrderSymbol()!=Symbol()||OrderMagicNumber()!=Magic) continue;
      if(dir == OP_BUY && OrderType() == OP_BUY && Ask - OrderOpenPrice()>(OrderOpenPrice()-OrderStopLoss())*BEPerc/100)
         return(true);
      if(dir == OP_SELL && OrderType() == OP_SELL && OrderOpenPrice() - Bid >(OrderStopLoss()-OrderOpenPrice())*BEPerc/100)
         return(true);
      }
   return(false);
   }