//+------------------------------------------------------------------+
//|                            Test3.Советник на индикаторе TMA..mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
/*Создадим советника на базе внешнего индикатора тренда TMA_Fair.Индикатор не 
перерисовывается и расчитывает верхнюю,нижнюю и среднюю границу канала.
От верхней границы канала будем продавать,от нижней границы - покупать.
*/
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//----------------------------------------------------------------------
//Зададим параметры советника
extern double Lots = 0.01;          // Размер лота
extern int    TakeProfit = 300;     // Значение для четырёхзначного брокера
extern int    StopLoss   =  50;     // Значение для четырёхзначного брокера
extern int    Magic      = 111;     // Индентификационный номер
extern int    Slippage   =   3;     // Проскальзывание
//----------------------------------------------------------------------
extern string TMA             = "Параметры индикатора ТМА";//Отделим данной строкой параметры советника от параметров ТМА.
                                                          //Скопируем и перенесём внешние параметры индикатора
extern string TimeFrame       = "current time frame";
extern int    HalfLength      = 56;
extern int    Price           = PRICE_CLOSE;
extern double ATRMultiplier   = 2.0;
extern int    ATRPeriod       = 100;
extern bool   Interpolate     = true;
//------------------------------------------------------------------------
double PriceHigh, PriceLow, SL, TP;      //Объявляем переменные цены High и Low, SL и TP
int ticket;                              //Объявляем целое число открытых ордеров
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
if(Digits == 3 || Digits == 5)                             //Приводим значение пункта для пятизначного брокера
{
  TakeProfit *=10;
  StopLoss   *=10;
  Slippage   *=10;
}
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
              /*Получаем значение индикатора для верхней и нижней границы канала с исползованием функции iCustom , которая вызывает
               значение пользовательского индикатора и имеет ряд характеристик,указанных в скобках .См. справку или урок №3 */
            
  PriceHigh = iCustom(NULL,0,"TMA_Fair", TimeFrame, HalfLength, Price, ATRMultiplier, ATRPeriod, Interpolate, 1,0); //Для верхней границы канала
  PriceLow  = iCustom(NULL,0,"TMA_Fair", TimeFrame, HalfLength, Price, ATRMultiplier, ATRPeriod, Interpolate, 2,0); //Для нижней границы канала
              //Для открытия ордера на продажу проверяем,выполняется ли условие
  if(CountSell() == 0 && Bid >= PriceHigh)                                                        //Если ордеров на продажу нет и цена >= PriceHigh ,то     
  {                                                                  
  
    ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, "TMA robot", Magic, 0, Red); // открываем ордер на продажу с номером ticket(SL и TP принимаем 
                                                                                                  //равными 0. Ниже присвоим ему SL и TP. 
    if(ticket > 0)                                                                                //если ордер открылся(номер>0)
      {                                                                                             //модифицируем ордер:
        SL = NormalizeDouble(Bid + StopLoss*Point, Digits);                                       //расчитываем стоплосс(приводим к нормализованному виду)
        TP = NormalizeDouble(Bid - TakeProfit*Point, Digits);                                     //расчитываем тэйкпрофит(приводим к нормализованному виду)
        
        if(OrderSelect(ticket, SELECT_BY_TICKET))                                                 //проверяем,если номер ордера совпадает (SELECT_BY_TICKET),тогда
           if(!OrderModify(ticket, OrderOpenPrice(), SL, TP, 0)) //назначаем ордеру  SL и TP и если он не модифицируется(!)(OrderModify-булевый тип-возвращает
                                                                 //да или нет
           
             Print("Ошибка модификации ордера на продажу!");     //выводим сообщение об ошибке модификации в журнал                                     
      }   
    else Print("Ошибка открытия ордера на продажу!");        //выводим сообщение об ошибке открытия ордера
  }
                                                                                               

//Аналогично, для открытия ордера на покупку, проверяем,выполняется ли условие
  if(CountBuy() == 0 && Ask <= PriceLow)                                                           //Если ордеров на покупку нет и цена <= PriceLow ,то 
  {
    ticket = OrderSend(Symbol(), OP_BUY,Lots, Ask, Slippage, 0, 0, "TMA robot", Magic, 0, Blue);   // открываем ордер на покупку с номером ticket(SL и TP принимаем 
                                                                                                   //равными 0. Ниже присвоим ему SL и TP. 
    if(ticket > 0)                                                                                 //проверяем соблюдаются ли условия для открытия ордера(номер>0)
     {
        SL = NormalizeDouble(Ask - StopLoss*Point, Digits);                                        //расчитываем стоплосс(приводим к нормализованному виду)
        TP = NormalizeDouble(Ask + TakeProfit*Point, Digits);                                      //расчитываем тэйкпрофит (приводим к нормализованному виду)
        
        if(OrderSelect(ticket, SELECT_BY_TICKET))                                                  //проверяем,если номер ордера совпадает (SELECT_BY_TICKET),тогда
           if(!OrderModify(ticket, OrderOpenPrice(), SL, TP, 0)) //модифицируем ордер с назначением ему  SL и TP и если он не открыт(OrderModify-булевый тип-возвращает
                                                                 //да или нет
               Print("Ошибка модификации ордера на покупку!");   //выводим сообщение в журнал
     }    else Print("Ошибка открытия ордера на покупку!");      //выводим сообщение об ошибке открытия ордера   
   }
                        /*Пропишем условия,чтобы ордер закрывался не только по ТП,но и при возникновении условия,когда цена дошла до нижней границы
                          канала индикатора  TMA_Fair при открытом ордере на продажу и до его верхней границы при ордере на покупку.
                                        */
                                        //Для открытого ордера на продажу:
                                        
     if(Ask <= PriceLow && CountSell() > 0)                                     //если текущая цена продажи меньше или равна PriceLow канала TMA_Fair  и кол-во ордеров 
   {                                                                            // на продажу CountSell() > 0,т.е. есть открытый ордер(ордера),
     for(int i = OrdersTotal() -1; i >=0; i--)                                  //тогда перебираем открытые ордера с конца к началу и проверяем соблюдение условия:
      {               
        if(OrderSelect(i,SELECT_BY_POS, MODE_TRADES))                           //если ордер соответствует выбранному (i),соответствует номеру по открытой позиции и 
         {                                                                      //является рыночным,
           if(OrderMagicNumber() == Magic && OrderType() == OP_SELL)            //так же если совпадает его Magic и тип ордера "На продажу"
              if(!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Black)) //Закрыть ордер(в скобках-его характеристики),а если условия не совпадают(!),то
                Print("Ошибка закрытия ордера на продажу!");                    //напечатать в журнале "Ошибка закрытия ордера на продажу!"
         } 
      }
   }
                                        //Для открытого ордера на покупку:
   if(Bid >= PriceHigh && CountBuy() > 0)                                       //если текущая цена покупки > или равна PriceLow каналаTMA_Fair  и кол-во ордеров 
   {                                                                            // на покупку CountBuy() > 0,т.е. есть открытый ордер(ордера),
     for(int i = OrdersTotal() -1; i >=0; i--)                                  //тогда перебираем открытые ордера с конца к началу и проверяем соблюдение условия:
      {
        if(OrderSelect(i,SELECT_BY_POS, MODE_TRADES))                           //если ордер соответствует выбранному (i),соответствует номеру по открытой позиции и 
         {                                                                      //является рыночным,
           if(OrderMagicNumber() == Magic && OrderType() == OP_BUY)             //так же если совпадает его Magic и тип ордера "На покупку"
              if(!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, Black)) //Закрыть ордер(в скобках-его характеристики),а если условия не совпадают(!),то
              Print("Ошибка закрытия ордера на покупку!");                      //напечатать в журнале "Ошибка закрытия ордера на покупку!"
         } 
      }
   }
 }                                                                                              

//+------------------------------------------------------------------+

// Проверяем кол-во открытых ордеров на продажу для дальнейшей передачи в строку 64
int CountSell()                                                                             //количество открытых ордеров на продажу
{
  int count = 0;                                                                            //изначально примем число ордеров = 0
  for(int trade = OrdersTotal();trade>=0;trade--)                                           //в цикле переберём ордера от конца к началу
  {
    if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES))                                        // OrderSelect - это булевый тип данных.Поэтому проверяем его условием if. 
    {
       if(OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == OP_SELL)   // также проверяем валютную пару и Magic ордера
       count++;                                                                             //если условия совпадают,то плюсуем  count.Теперь он равен 1.
    }
  }
  return(count);                                                                            //возвращаем значение count = 1 значению CountSell(в стр.135)
}


// Проверяем кол-во открытых ордеров на покупку для дальнейшей передачи в строку 85
int CountBuy()                                                                             //количество открытых ордеров на покупку
{
  int count = 0;                                                                            //изначально примем число ордеров = 0
  for(int trade = OrdersTotal();trade>=0;trade--)                                           //в цикле переберём ордера от конца к началу
  {
    if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES))                                        // OrderSelect - это булевый тип данных.Поэтому проверяем его условием if. 
    {
       if(OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == OP_BUY)// также проверяем условия
       count++;                                                                             //если условия совпадают,то плюсуем  count.Теперь он равен 1.
    }
  }
  return(count);                                                                            //возвращаем значение count = 1 значению CountBuy (в стр.149)
  }                                                                            

