//+------------------------------------------------------------------+
//|                                                 SamuraiEA3.1.mq4 |
//|                                                  Богдан Доходный |
//|                                                       fxauto.pro |
//+------------------------------------------------------------------+
#property copyright "Богдан Доходный"
#property link      "fxauto.pro"

string Instrument="EURUSD";   // инструмент
int Timeframe=60;             // таймфрейм
extern double InitialLot=0.01;       // начальный лот
extern double StepLot=0.00;          // шаг лота
extern double Martingale=0.0;        // множитель лота
extern int MagicNumber=26042013;   // магический номер     

extern int TenkanA=1;         // Период расчета Тенкан A по умолчанию
extern int KijunA=1;          // Период расчета Киджун A по умолчанию
extern int TenkanB=36;        // Период расчета Тенкан B по умолчанию
extern int KijunB=13;         // Период расчета Киджун B по умолчанию
extern int Chinkou=794;       // Период расчета Чинкоу по умолчанию

extern int TENKANFLAT=1;      // 1-флэт Тенкан A учитывается как сигнал

// Вес сигналов Ишимоку в индикаторе
extern int a=0;               // Динамика Тенкан A              
extern int b=10;              // Пересечение Тенкан B/Киджун B
extern int c=0;               // Пересечение цены и Киджун A
extern int d=1;               // Пересечение цены и Чинкоу

extern int TP=460;            // Тейк-профит  
extern int SL=495;            // Стоп-лосс   
extern int TS=175;            // Трейлинг-стоп  
extern int SafeLevel=120;     // Перевод стоп-лосс на уровень безубытка
extern int MaxDeviation=3;    // Максимально допустимoe отклонение
extern int SpreadStandard=1;  // Стандартный спред брокера
extern int slippage=5;        // Проскальзывание

datetime LastTime=0;          // Время открытия текущего бара.
bool NoBigError=true;         // Нет критич. ошибок
double LastBid=0;             // Исходная цена для расчета цены сделки
double LastAsk=0;             // Исходная цена для расчета цены сделки
bool Answer;                  // Возвращенный вызванной функцией результат
double Lots;                  // Лот
int Order=0;                  // Тикет текущего открытого ордера

//-------------------------------------------------------------------

int start()
     {
      if(NoBigError==false) // Если есть критич. ошибки, торговать нельзя
         return;
               
      // НА КАЖДОМ ТИКЕ
      
      //Учет ордеров
      Order=OrdersControl();  
     
          
      if(LastTime==iTime(Instrument,Timeframe,0)) // Если еще не открылся новый бар...
         {
         LastBid=MarketInfo(Instrument,MODE_BID); // Последняя цена Bid
         LastAsk=MarketInfo(Instrument,MODE_ASK); // Последняя цена Ask         
                  
         if(Order>0)                              //если есть открытый ордер
            TralingStop();                        // трейлинг-стоп        
         return;                                  // выход из start()
         }
      
      // НА НОВОМ БАРЕ   
         
         LastTime=iTime(Instrument,Timeframe,0);  // ...запоминаем время открытия
         if (LastBid==0)
            return;
         // Подсчет оценки
         int X1=iCustom(Instrument,Timeframe,"SamuraiInd",
         TenkanA,KijunA,TenkanB,KijunB,Chinkou,TENKANFLAT,a,b,c,d,0,1);   
         int X2=iCustom(Instrument,Timeframe,"SamuraiInd",
         TenkanA,KijunA,TenkanB,KijunB,Chinkou,TENKANFLAT,a,b,c,d,0,2);   
         
      
//-----------------------------------------------------------------------         
         
      if(Order>0 && X1==0)         // №1: сигнал "вне рынка" 
          {
           Answer=CloseOrder();          // закрытие текущего ордера
           if(Answer==false)             // крит. ошибка
               NoBigError=false;         // запрет на сделки
           return;                       // выход из start()
          }        
      
      if(Order>0 && X1>0)          // №2: сигнал "закрыть короткие позиции"
         {
          // если наш ордер короткий
          OrderSelect(Order,SELECT_BY_TICKET);
          if(OrderType()==OP_SELL)
            {
            Answer=CloseOrder();        // закрытие текущего ордера       
            if(Answer==false)           // крит. ошибка
                 {
                 NoBigError=false;      // запрет на сделки
                 return;                // выход из start()
                 }
            }
          }      
      
      if(Order>0 && X1<0)          // №3: сигнал "закрыть длинные позиции"
         {
          // если наш ордер длинный
          OrderSelect(Order,SELECT_BY_TICKET);
          if(OrderType()==OP_BUY)
            {
            Answer=CloseOrder();        // закрытие текущего ордера       
            if(Answer==false)           // крит. ошибка
                 {
                 NoBigError=false;      // запрет на сделки
                 return;                // выход из start()
                 }
            }
          }      
          
      if(X1>0 && X2<=0)            // №4: сигнал на покупку
          {
          Answer=OpenBuy();              // покупка         
          if(Answer==false)              // Крит. ошибка
                  {
                  NoBigError=false;      // запрет на сделки
                  }          
          return;                        // выход из start()
          }        
      
      if(X1<0 && X2>=0)            // №5: сигнал на продажу
          {
          Answer=OpenSell();             // продажа
          if(Answer==false)              // крит. ошибка
                  {
                  NoBigError=false;      // запрет на сделки
                  }      
          return;                        // выход из start()          
          }  
       
//-----------------------------------------------------------------------        
      return;                            // выход из start()
     }
//-----------------------------------------------------------------------
      
int OrdersControl()
      {      
      // ЗАДАЧА: ВЫЯСНИТЬ, ЕСТЬ ЛИ СРЕДИ РЫНОЧНЫХ ОРДЕРОВ ОТКРЫТЫЙ СОВЕТНИКОМ,
      // И ЕСЛИ ЕСТЬ, ТО ВЫЯСНИТЬ ЕГО ТИКЕТ
      
      int Orders=OrdersTotal(); //кол-во рын. и отлож.ордеров
      if(Orders>0) //если есть рын. и отлож. ордера
         {
         int i;
         for(i=0;i<Orders;i++) //перебор по всем рын. и отлож. ордерам
            {
            OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
            // если не наш маг. номер или инструмент, переходим к следующему
            if(OrderMagicNumber()!=MagicNumber || OrderSymbol()!=Instrument)
               continue;
            //если наш маг. номер и инструмент
            //запоминаем его тикет
            Order=OrderTicket();
            return(Order); //ответ в программу
            }    
         }
      return(0);
      }

//-----------------------------------------------------------------------
bool CloseOrder()                                                         
   {    
    OrderSelect(Order,SELECT_BY_TICKET); // находим ордер по тикету
    if(OrderCloseTime()==0)              // если он еще не закрыт
      {
      int Type = OrderType();            // Тип ордера     
      switch(Type)                       //     
           {
            case 0: // Ордер BUY                                                       
                    while (true) // цикл закрытия
                       {
                       double bid=MarketInfo(Instrument,MODE_BID); // Текущий Bid
                       // попытка закрытия
                       bool Answer=OrderClose(Order,OrderLots(),bid,slippage);     
                       if(Answer==false)                  // если не удалось           
                               {
                               int Error=GetLastError();  // Обработка ошибок                             
                               int ErrorAnswer=ERRORS(Error);
                               if(ErrorAnswer==1)         // Преодолимая ошибка
                                    continue;             // Новая попытка
                               if(ErrorAnswer==2)         // Критич. ошибка
                                    return(false);        // Возвращаем ответ в программу
                               }
                       break;  // если удалось, выход из while                            
                       }
                    break;     // выход из switch
            
            case 1: // Ордер SELL                  
                    while (true)                          // цикл закрытия
                       {
                       double ask=MarketInfo(Instrument,MODE_ASK); // Текущий Ask                                                          
                       // попытка закрытия
                       Answer=OrderClose(Order,OrderLots(),ask,slippage);         
                       if(Answer==false)                  // если не удалось
                               {
                               Error=GetLastError();      // Обработка ошибок                             
                               ErrorAnswer=ERRORS(Error);
                               if(ErrorAnswer==1)         // Преодолимая ошибка
                                    continue;             // Новая попытка
                               if(ErrorAnswer==2)         // Критич. ошибка
                                    return(false);        // Возвращаем ответ в программу
                               }
                        break; // если удалось, выход из while 
                       }
           }   
      }      
   return(true); // Ответ в программу
   }


//-----------------------------------------------------------------------

double LotSelect()
   {   
   // открытых ордеров нет
   Order=0;
   //кол-во закрытых ордеров
   int i;
   int Orders=OrdersHistoryTotal();
   //перебор по всем закрытым ордерам
   for(i=0;i<Orders;i++)
            {
            OrderSelect(i,SELECT_BY_POS,MODE_HISTORY);
            // если не наш маг. номер или инструмент, переходим к следующему
            if(OrderMagicNumber()!=MagicNumber || OrderSymbol()!=Instrument)
                  continue;
            //если наш маг. номер и инструмент
            //если тикет ордера не больше Order, переходим к следующему 
            if(OrderTicket()<=Order)
                  continue;
            // иначе: запоминаем его тикет
            //(т.о. мы нашли самый последний ордер из числа открытых советником)
            Order=OrderTicket();
            }
    //если удалось найти 
    if(Order>0)
            {
            // выясняем его лот
            OrderSelect(Order,SELECT_BY_TICKET);
            Lots=OrderLots();
            if(OrderProfit()>0)
                  Lots=InitialLot;
            // Если сделка была неудачной, увеличиваем лот
            else
                  {
                  // Если активирован множитель лота, умножаем
                  if (Martingale!=0)
                     Lots=NormalizeDouble(Lots*Martingale,2);
                  // Иначе - прибавляем установленную величину
                  else   
                     Lots=Lots+StepLot;
                  }            
            }
   if(Order==0)
            Lots=InitialLot;
   return(Lots);
   }   

//-----------------------------------------------------------------------
                                                        
void TralingStop()                                                        
   {
   OrderSelect(Order, SELECT_BY_TICKET);     // oрдер вкладки "Торговля"    
   // если ордер еще не закрыт
   if (OrderCloseTime()==0)
      {     
      int Type = OrderType();        // Тип ордера      
      switch(Type)
               {
               case 0: // Ордер BUY
                        double bid=MarketInfo(Instrument,MODE_BID);     // Текущий Bid
                        int digits=MarketInfo(Instrument,MODE_DIGITS);  //Формат котировок
                        double point=MarketInfo(Instrument,MODE_POINT); //Размер пункта                 
                        // условие перевода в безубыток
                        if(OrderStopLoss()<OrderOpenPrice() && bid-SafeLevel*point>=OrderOpenPrice())          
                           {
                           OrderModify(OrderTicket(), NormalizeDouble(OrderOpenPrice(),digits),
                           NormalizeDouble(OrderOpenPrice(),digits),
                           NormalizeDouble(OrderTakeProfit(),digits),0); // Модификация
                           }                     
                        // условие трейлинг-стоп
                        if(OrderStopLoss()>=OrderOpenPrice() && bid-TS*point>OrderStopLoss())  
                           {
                           OrderModify(OrderTicket(),NormalizeDouble(OrderOpenPrice(),digits),
                           NormalizeDouble(bid-TS*point,digits),
                           NormalizeDouble(OrderTakeProfit(),digits),0); // Модификация
                           }
                        break; // выход из switch                 
               case 1: // Ордер SELL
                        double ask=MarketInfo(Instrument,MODE_ASK);     // Текущий Ask
                        digits=MarketInfo(Instrument,MODE_DIGITS);      // Формат котировок
                        point=MarketInfo(Instrument,MODE_POINT);        //Размер пункта      
                        // условие перевода в безубыток
                        if(OrderStopLoss()>OrderOpenPrice() && ask+SafeLevel*point<=OrderOpenPrice())
                           {
                           OrderModify(OrderTicket(), NormalizeDouble(OrderOpenPrice(),digits), 
                           NormalizeDouble(OrderOpenPrice(),digits), 
                           NormalizeDouble(OrderTakeProfit(),digits), 0); // Модификация
                           }
                        // условие трейлинг-стоп  
                        if(OrderStopLoss()<=OrderOpenPrice() && ask+TS*point<OrderStopLoss())
                           {             
                           OrderModify(OrderTicket(),NormalizeDouble(OrderOpenPrice(),digits),
                           NormalizeDouble(ask+TS*point,digits),
                           NormalizeDouble(OrderTakeProfit(),digits),0);  // Модификация
                           }
                        break;   
               }
      }
   return;        
   }
//-----------------------------------------------------------------------

bool OpenBuy()
   {
   // Цена закрытия предыдущего бара без учета спреда
   double BestPrice=(LastBid+LastAsk)/2;                                        
   // Половина стандартного спреда
   double HalfOfSpread=(SpreadStandard*MarketInfo(Instrument,MODE_POINT))/2;    
   // Идеальная цена сделки
   BestPrice=BestPrice+HalfOfSpread;                                            
   // Приемлемая цена сделки
   double GoodPrice=BestPrice+(MaxDeviation*MarketInfo(Instrument,MODE_POINT)); 
   // Пока не удалось открыть позицию или не открылся новый бар
   while (iTime(Instrument,Timeframe,0)==LastTime)         
      {                                                                         
      double ask=MarketInfo(Instrument,MODE_ASK);           // Текущий Ask
      if(ask<=GoodPrice)                                    // Если Ask приемлем 
            {
            double bid=MarketInfo(Instrument,MODE_BID);     // Текущий Bid
            int digits=MarketInfo(Instrument,MODE_DIGITS);  // Формат котировок
            double point=MarketInfo(Instrument,MODE_POINT); // Размер пункта
            // Выбор лота и попытка открытия
            Lots=LotSelect();
            Order=OrderSend(Instrument,OP_BUY,Lots,NormalizeDouble(ask,digits),slippage,
            NormalizeDouble(bid-SL*point,digits),NormalizeDouble(ask+TP*point,digits),NULL,MagicNumber);     
            if (Order<0)
               {
               int Error=GetLastError();             // Обработка ошибок
               int ErrorAnswer=ERRORS(Error);
               if(ErrorAnswer==1)                    // Преодолимая ошибка
                  continue;                          // Новая попытка
               if(ErrorAnswer==2)                    // Критич. ошибка
                  return(false);                     // Выход из функции
               }
            else
               break;   
            }
      else
            break;         
      }
   return(true);
   }  
   
//-----------------------------------------------------------------------

bool OpenSell()
   {
   // Цена закрытия предыдущего бара без учета спреда
   double BestPrice=(LastBid+LastAsk)/2;
   // Половина стандартного спреда
   double HalfOfSpread=(SpreadStandard*MarketInfo(Instrument,MODE_POINT))/2;
   // Идеальная цена сделки
   BestPrice=BestPrice-HalfOfSpread;   
   // Приемлемая цена сделки
   double GoodPrice=BestPrice-(MaxDeviation*MarketInfo(Instrument,MODE_POINT)); 
   // Пока не удалось открыть позицию или не открылся новый бар
   while (iTime(Instrument,Timeframe,0)==LastTime)          
      {
      double bid=MarketInfo(Instrument,MODE_BID);        // Текущий Bid
      if(bid>=GoodPrice)                                 // Если Bid приемлем
         {
         double ask=MarketInfo(Instrument,MODE_ASK);     // Текущий Ask
         int digits=MarketInfo(Instrument,MODE_DIGITS);  // Формат котировок
         double point=MarketInfo(Instrument,MODE_POINT); // Размер пункта
         // Выбор лота и попытка открытия
         Lots=LotSelect();
         Order=OrderSend(Instrument,OP_SELL,Lots,NormalizeDouble(bid,digits),slippage,
         NormalizeDouble(ask+SL*point,digits),NormalizeDouble(ask-TP*point,digits),NULL,MagicNumber);          
         if (Order<0)
            {
            int Error=GetLastError();             // Обработка ошибок
            int ErrorAnswer=ERRORS(Error);
            if(ErrorAnswer==1)                    // Преодолимая ошибка
               continue;                          // Новая попытка
            if(ErrorAnswer==2)                    // Критич. ошибка
               return(false);                     // Выход из функции
            }
         else
            break;   
         }
      else
         break;      
      }
   return(true);   
   }   
   
//-----------------------------------------------------------------------

int ERRORS (int Error)  // Error - номер ошибки  
  {
  if(Error==0)
      return(0);        // Нет ошибки      
  // 4-торговый сервер занят,132-рынок закрыт,137-брокер занят
  if(Error==4||Error==132||Error==137)  
      {
      Sleep(240000);    // Пауза 240 сек.
      return(1);        // Сообщаем о преодол. ошибке
      }
  // 128,142,143 - истек срок ожидания и т.д.
  if(Error==128||Error==142||Error==143) 
      {      
      Sleep(60000);     // Пауза 60 сек.
      return(1);        // Сообщаем о преодол. ошибке 
      }    
  // 135-цена изменилась,138-цена устарела
  if(Error==135||Error==138)               
      {      
      return(1);        // Сообщаем о преодол. ошибке
      }        
  // 6-нет связи,129-неправильные цены,
  // 130-неправильные стопы,136-нет цен
  if(Error==6||Error==129||Error==130||   
  Error==136||Error==137||Error==138)    
      {
      Sleep(5000);      // Пауза 5 сек. 
      return(1);        // Сообщаем о преодол. ошибке
      }
  // 146-подсистема торговли занята
  if(Error==146)               
      {      
      // Пока подсистема занята
      while(IsTradeContextBusy())
         {
         Sleep(10);     // Пауза 0.01 сек.
         }
      return(1);        // Сообщаем о преодол. ошибке
      }         
  // Критическая ошибка
  Alert("Ошибка №",Error,". Дальнейшая работа советника невозможна."); 
  return(2);          // Сообщаем о критич. ошибке
  }
 

