//+------------------------------------------------------------------+
//|                                    3MACrossMACDTrendFollower.mq4 |
//|                                   Copyright © 2010, FORTRADER.RU |
//|                                                       10/12.2010 |
//|                                        www: fortrader.ru         |
//|                                   strategy: fortrader.ru         |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, FORTRADER.Ru"
#property link      "http://forexsystems.ru/realizovanye-sovetniki/35402-ts-3-ma-cross-macd-trend-follower.html"
//
extern string rem1                       = "=== Параметры ордеров ===";
extern int    _StopLoss                  =  50; // Стоп-лосс: 0 - не используется
extern int    _TakeProfit                =  30; // Тейк-профит: 0 - не используется
extern int    _BarOrderLive              =  3; // Время жизни ордера в барах: 0 - не используется
extern int    _Indent                    =  10; // Тейк-профит: 0 - не используется



//
extern bool   _IsOrderSend_Rev           =  false; // Включить "переворот" ордеров
extern int    _OrderSend_MaxBuy          =     1; // Количество ордеров открытых в направлении BUY
extern int    _OrderSend_MaxSell         =     1; // Количество ордеров открытых в направлении SELL
extern bool   _IsOrderSend_Loc           = false; // Включить открытие перекрытых ордеров
//
extern string rem2                       = "=== Количество лотов ===";
extern double _Lots0                     =   0.1; // Базовый лот
extern double _LotsMax                   =  10.0; // Максимальный лот
extern int    _Lots0_Mode                =     2; // Режим расчёта лота:
                                                  //    1 - фиксированный;
                                                  //    2 - процент от Баланса
extern double _Lots0_Proc                =     5; // Процент риска
extern double _Lots0_Koef                =   0.1; // Коэффициент риска
//
extern string rem3                       = "=== Параметры безубытка ===";
extern bool   _IsStopLoss_0              = true; // Включение использования уровня безубытка
extern int    _StopLoss_0_Level          =    500; // Уровень безубытка
//
extern string rem4                       = "=== Параметры трейлинг стопа ===";
extern bool   _IsTrailingStop            = false; // Включение трейлинг стопа
extern bool   _IsTrailingStopProfit      =  true; // Включение трейлинг стопа с позиции безубытка
extern int    _TrailingStopLevel         =    500; // Уровень трейлинг стопа
extern int    _TrailingStopStep          =     50; // Шаг перемещения трейлинг стопа
//
extern string rem5                       = "=== Настройки инструмента ===";
extern string symb                    =    ""; // Символьное имя инструмента: "" - текущий символ
extern int    _Timeframe                 =     0; // Период: 0 - период текущего графика
       double pnt;                             // Размер пункта в валюте котировки
extern int    _Slippage                  =     2; // Проскальзывание
extern int    _Magic                     =   108; // Уникальный номер ордеров советника
//
extern string rem6                       = "=== Дополнительные параметры ===";
extern bool   _IsMACDFilter              =  true; // Признак использования фильтра MACD
//
extern string rem7                       = "=== Параметры индикатора MA 1 ===";
extern int    _MA1_Period                =    85; // Период усреднения для вычисления скользящего среднего
extern int    _MA1_Shift                 =     0; // Сдвиг индикатора относительно ценового графика
extern int    _MA1_Method                =     3; // Метод усреднения: 0 - SMA, 1 - EMA, 2 - SMMA, 3 - LWMA
extern int    _MA1_Applied_Price         =     3; // Используемая цена: 0 - close, 3 - low
//
extern string rem8                       = "=== Параметры индикатора MA 2 ===";
extern int    _MA2_Period                =    75; // 
extern int    _MA2_Shift                 =     0; // 
extern int    _MA2_Method                =     3; // 
extern int    _MA2_Applied_Price         =     3; // 
//
extern string rem9                       = "=== Параметры индикатора MA 3 ===";
extern int    _MA3_Period                =     5; // 
extern int    _MA3_Shift                 =     0; // 
extern int    _MA3_Method                =     1; // 
extern int    _MA3_Applied_Price         =     0; // 
//
extern string rem10                      = "=== Параметры индикатора MACD ===";
extern int    _MACD_Fast_Ema_Period      =    15; // 
extern int    _MACD_Slow_Ema_Period      =    26; // 
extern int    _MACD_Signal_Period        =     1; // 
extern int    _MACD_Applied_Price        =     0; // 
extern int    _MACD_Mode                 =     0; // Индекс линии: 0 - main, 1 - signal
//
datetime _TimePrevious;
datetime _TimeCurrent;
//


//=++==============================================================++=
int init()
{
   if(symb == "") symb = Symbol();
   //
   pnt     = MarketInfo(symb, MODE_POINT);
   //
   if(_Timeframe == 0) _Timeframe = Period();
   Print("v108-1 > init() >> _Timeframe=", _Timeframe);
   //
   _TimePrevious=iTime(symb, _Timeframe, 0);
   //
   Print("v108-1 > Завершено: init() >> _TimePrevious=", _TimePrevious, " (", TimeToStr(_TimePrevious,TIME_DATE|TIME_MINUTES), ")");
   return(0);
}


//=++==============================================================++=
bool histsell = false;
bool histbuy  = false;
int start()
{
   double MA1_Cur, MA1_Pre1;
   double MA2_Cur, MA2_Pre1;
   double MA3_Cur, MA3_Pre1;
   double MACD_Cur0;
   bool is_signal_buy, is_signal_sell;
   bool is_signal_buy1, is_signal_sell1;
   bool is_signal_buy2, is_signal_sell2;
   double P1_buy, P2_buy, P3_buy;
   double P1_sell, P2_sell, P3_sell;
   bool b1, b2;
   bool s1, s2;
   bool is_b1 = false, is_s1 = false;
   bool is_b2 = false, is_s2 = false;
   double lots,op,sl,tp;
   int ticket,MG;
   datetime dtexp;
   //
   _TimeCurrent = iTime(symb, _Timeframe, 0);
   if(_TimeCurrent != _TimePrevious)
   {
      MA1_Cur = iMA(symb, _Timeframe, _MA1_Period, _MA1_Shift, _MA1_Method, _MA1_Applied_Price, 1);
      MA1_Pre1 = iMA(symb, _Timeframe, _MA1_Period, _MA1_Shift, _MA1_Method, _MA1_Applied_Price, 2);
      MA2_Cur = iMA(symb, _Timeframe, _MA2_Period, _MA2_Shift, _MA2_Method, _MA2_Applied_Price, 1);
      MA2_Pre1 = iMA(symb, _Timeframe, _MA2_Period, _MA2_Shift, _MA2_Method, _MA2_Applied_Price, 2);
      MA3_Cur = iMA(symb, _Timeframe, _MA3_Period, _MA3_Shift, _MA3_Method, _MA3_Applied_Price, 1);
      MA3_Pre1 = iMA(symb, _Timeframe, _MA3_Period, _MA3_Shift, _MA3_Method, _MA3_Applied_Price, 2);
      MACD_Cur0 = iMACD(symb, _Timeframe, _MACD_Fast_Ema_Period, _MACD_Slow_Ema_Period, _MACD_Signal_Period,
                        _MACD_Applied_Price, _MACD_Mode, 1);
      Print("v108-1 > ", symb, " | ", _Timeframe,
            " -> MA1_Cur=", MA1_Cur, " | MA1_Pre1=", MA1_Pre1,
            " -> MA2_Cur=", MA2_Cur, " | MA2_Pre1=", MA2_Pre1,
            " -> MA3_Cur=", MA3_Cur, " | MA3_Pre1=", MA3_Pre1,
            " -> MACD_Cur0=", MACD_Cur0);
      //
      if(MA3_Cur<= MA1_Cur && MA3_Cur<= MA2_Cur) {histbuy=true;}
      is_signal_buy1 = MA3_Pre1 <= MA1_Pre1 && MA3_Cur >= MA1_Cur && MA3_Cur >= MA2_Cur && histbuy && timecontrol();
      is_signal_buy2 = MA3_Pre1 <= MA2_Pre1 && MA3_Cur >= MA2_Cur && MA3_Cur >= MA1_Cur && histbuy && timecontrol();
      is_signal_buy  = is_signal_buy1 || is_signal_buy2;
      if(_IsMACDFilter)
         is_signal_buy  = is_signal_buy && MACD_Cur0 >= 0;
      //
      if(MA3_Cur>= MA1_Cur && MA3_Cur>= MA2_Cur) {histsell=true;}
      is_signal_sell1 = MA3_Pre1 >= MA1_Pre1 && MA3_Cur <= MA1_Cur && MA3_Cur <= MA2_Cur && histsell && timecontrol();
      is_signal_sell2 = MA3_Pre1 >= MA2_Pre1 && MA3_Cur <= MA2_Cur && MA3_Cur <= MA1_Cur && histsell && timecontrol();
      is_signal_sell  = is_signal_sell1 || is_signal_sell2;
      if(_IsMACDFilter)
         is_signal_sell  = is_signal_sell && MACD_Cur0 <= 0;
      Print("v108-1 > ", symb, " | ", _Timeframe,
            " -> is_signal -> buy=", is_signal_buy, "=", is_signal_buy1, is_signal_buy2,
            " | sell=", is_signal_sell, "=", is_signal_sell1, is_signal_sell2);
      // ========== по рынку
      // ========== открытие ордера BUY
      if( is_signal_buy )
      {histbuy=false;
         Print("v108-1 > ", symb, " | ", _Timeframe,
               " -> сигнал на открытие ордера BUY");
         if( !is_b2 && _IsOrderSend_Rev ) // работа с "перевёртышами"
         {
            OrdersDelete(OP_SELL);
            if(CountOrders(OP_SELL) == 0) is_b2 = true;
         }
         else is_b2 = true;
         //
         if(!is_b1)
         {
            if(CountOrders(OP_BUY) >= _OrderSend_MaxBuy) b1 = false;
            else b1 = true;
            if(!_IsOrderSend_Loc) { if(CountOrders(OP_SELL) > 0) b2 = false; else b2 = true; }
            else b2 = true;
            Print("= buy ===", b1, b2);
            //
            if(b1 && b2)
            {
               P1_buy = MarketInfo(symb, MODE_ASK);
               P2_buy = DoubleTestZero(_TakeProfit, P1_buy + (_TakeProfit) * pnt);
               P3_buy = DoubleTestZero(_StopLoss,   P1_buy - (_StopLoss)   * pnt);
               Print("v108-1 > ", symb, " | ", _Timeframe,
                     " -> BUY -> P1_buy=", P1_buy, " | P2_buy=", P2_buy, " | P3_buy=", P3_buy);
               //
               lots = GetLots(symb);
              // ticket = OrderSend(symb, OP_BUY, lots, P1_buy, _Slippage, P3_buy, P2_buy, NULL, _Magic, 0, CLR_NONE);
               
               op=Bid+_Indent*Point;sl=op-_StopLoss*Point;tp=op+_TakeProfit*Point;
               dtexp=Time[1]+(Period()*60)*_BarOrderLive;
               ticket=OrderSend(Symbol(),OP_BUYSTOP,lots,NormalizeDouble(op,Digits),3,NormalizeDouble(sl,Digits),NormalizeDouble(tp,Digits),"FORTRADER.RU",_Magic,dtexp,Red);
               
               if(ticket == -1)
                  Print("v108-1 > ", symb, " | ", _Timeframe,
                        " -> BUY > Ошибка (открытие) #", GetLastError());
               else is_b1 = true;
            }
            else is_b1 = true;
         }
         else is_b1 = true;
      }
      else { is_b1 = true; is_b2 = true; }
      Print("= buy +++",is_b1,is_b2,"==",is_s1,is_s2);
      // ========== открытие ордера SELL
      if( is_signal_sell )
      {histsell=false;
         Print("v108-1 > ", symb, " | ", _Timeframe,
               " -> сигнал на открытие ордера SELL");
         if( !is_s2 && _IsOrderSend_Rev ) // работа с "перевёртышами"
         {
            OrdersDelete(OP_BUY);
            if(CountOrders(OP_BUY) == 0)
               is_s2 = true;
         }
         else is_s2 = true;
         //
         if(!is_s1)
         {
            if(CountOrders(OP_SELL) >= _OrderSend_MaxSell) s1 = false;
            else s1 = true;
            if(!_IsOrderSend_Loc) { if(CountOrders(OP_BUY) > 0) s2 = false; else s2 = true; }
            else s2 = true;
            Print("= sell ===", s1, s2);
            //
            if(s1 && s2)
            {
               P1_sell = MarketInfo(symb, MODE_BID);
               P2_sell = DoubleTestZero(_TakeProfit, P1_sell - (_TakeProfit) * pnt);
               P3_sell = DoubleTestZero(_StopLoss,   P1_sell + (_StopLoss)   * pnt);
               Print("v108-1 > ", symb, " | ", _Timeframe,
                     " -> SELL -> P1_sell=", P1_sell, " | P2_sell=", P2_sell, " | P3_sell=", P3_sell);
               //
               lots = GetLots(symb);
            //   ticket = OrderSend(symb, OP_SELL, lots, P1_sell, _Slippage, P3_sell, P2_sell,NULL, _Magic, 0, CLR_NONE); // Red);
            
               op=Ask-_Indent*Point;sl=op+_StopLoss*Point;tp=op-_TakeProfit*Point;
               dtexp=Time[1]+(Period()*60)*_BarOrderLive;
               ticket=OrderSend(Symbol(),OP_SELLSTOP,lots,NormalizeDouble(op,Digits),3,NormalizeDouble(sl,Digits),NormalizeDouble(tp,Digits),"FORTRADER.RU",_Magic,dtexp,Red);
                                  
               if(ticket == -1)
                  Print("v108-1 > ", symb, " | ", _Timeframe,
                        " -> SELL > Ошибка (открытие) #", GetLastError());
               else is_s1 = true;
            }
            else is_s1 = true;
         }
         else is_s1 = true;
      }
      else { is_s1 = true; is_s2 = true; }
      Print("= sell +++",is_b1,is_b2,"==",is_s1,is_s2);
      // ==========
      if(is_b1 && is_s1 && is_b2 && is_s2)
         _TimePrevious=_TimeCurrent;
   }
   //
   if(_IsTrailingStop) TrailingStop();
   //
   if(_IsStopLoss_0) StopLoss_0();
   //
   return(0);
}


//=++==============================================================++=
double DoubleTestZero(double value, double new_value)
{
   if(value==0) return(value);
   else         return(new_value);
}


//=++==============================================================++=
// закрытие ордеров
void OrdersDelete(int cmd)
{
   for(int i = OrdersTotal() - 1; i >= 0 ; i--) 
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if( (OrderSymbol() == symb) && (OrderMagicNumber() == _Magic) && (OrderType() == cmd) )
         {
            if(OrderType() == OP_BUY)
               if(!OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), _Slippage, CLR_NONE))
                  Print("v108-1 > ", symb, " > BUY -> ticket=", OrderTicket(), 
                        " -> Ошибка (закрытие) #", GetLastError());
            if(OrderType() == OP_SELL)
               if(!OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), _Slippage, CLR_NONE))
                  Print("v108-1 > ", symb, " > SELL -> ticket=", OrderTicket(), 
                        " -> Ошибка (закрытие) #", GetLastError());
         }
      }
   }
}


//=++==============================================================++=
// подсчёт количества ордеров по направлению
int CountOrders(int cmd)
{
   int n = 0;
   for(int i = OrdersTotal() - 1; i >= 0 ; i--) 
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if( (OrderSymbol() == symb) && (OrderMagicNumber() == _Magic) && (OrderType() == cmd) ) n++;
      }
   }
   return(n);
}


//=++==============================================================++=
// отработка уровня безубытка
void StopLoss_0()
{
   double profitpoint, bid, ask;
   bool is;
   //
   for(int i = OrdersTotal() - 1; i >= 0 ; i--) 
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(!( (OrderSymbol() == symb) && (OrderMagicNumber() == _Magic) )) continue;
         //
         if(OrderType() == OP_BUY)
         {
            bid         = MarketInfo(symb, MODE_BID);
            profitpoint = (bid - OrderOpenPrice()) / pnt;
            is = profitpoint >= _StopLoss_0_Level;
            //
            if( is && (OrderStopLoss() == 0 || OrderStopLoss() < OrderOpenPrice()) )
            {
               if(!OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(),
                   OrderTakeProfit(), 0, CLR_NONE))
               {
                  Print("v108-1 б1 > ", symb, " | ", _Timeframe,
                        " -> BUY > ticket=", OrderTicket(), " > Ошибка (безубыток) #", GetLastError());
                  Print("v108-1 б1 >", symb, " | ", _Timeframe,
                        " -> Bid=", MarketInfo(symb, MODE_BID),
                        " | p/o=", OrderOpenPrice(), " | s/l=", OrderStopLoss(),
                        " | d=", _StopLoss_0_Level, " | profitpoint=", profitpoint);
               }
            }
         }
         //
         else if(OrderType() == OP_SELL)
         {
            ask         = MarketInfo(symb, MODE_ASK);
            profitpoint = (OrderOpenPrice() - ask) / pnt;
            is = profitpoint >= _StopLoss_0_Level;
            //
            if( is && (OrderStopLoss() == 0 || OrderStopLoss() > OrderOpenPrice()) )
            {
               if(!OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(),
                   OrderTakeProfit(), 0, CLR_NONE))
               {
                  Print("v108-1 б1 > ", symb, " | ", _Timeframe,
                        " -> SELL -> ticket=", OrderTicket(), " > Ошибка (безубыток) #", GetLastError());
                  Print("v108-1 б1 >", symb, " | ", _Timeframe,
                        " -> Ask =", MarketInfo(symb, MODE_ASK),
                        " | p/o=", OrderOpenPrice(), " | s/l=", OrderStopLoss(),
                        " | d=", _StopLoss_0_Level, " | profitpoint=", profitpoint);
               }
            }
         }
      }
   }
}


//=++==============================================================++=
// отработка трейлинг стопа
void TrailingStop()
{
   double profitpoint, bid, ask;
   double fromprice;
   //
   for(int i = OrdersTotal() - 1; i >= 0 ; i--) 
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(!( (OrderSymbol() == symb) && (OrderMagicNumber() == _Magic) )) continue;
         //
         if(OrderType() == OP_BUY)
         {
            if(_IsTrailingStopProfit) fromprice = OrderOpenPrice();
            else                      fromprice = OrderStopLoss();
            //
            bid         = MarketInfo(symb, MODE_BID);
            profitpoint = (bid - fromprice) / pnt;
            //
            if( profitpoint >= _TrailingStopLevel &&
                bid > (OrderStopLoss() + (_TrailingStopLevel + _TrailingStopStep) * pnt) )
            {
               if(!OrderModify(OrderTicket(), OrderOpenPrice(), (bid - (_TrailingStopLevel) * pnt),
                   OrderTakeProfit(), 0, CLR_NONE))
               {
                  Print("v108-1 т1 >", symb, " | ", _Timeframe,
                        " -> Bid=", MarketInfo(symb, MODE_BID),
                        " | p/o=", OrderOpenPrice(), " | s/l=", OrderStopLoss(),
                        " | d=", _TrailingStopLevel, " | profitpoint=", profitpoint,
                        " -> BUY > ticket=", OrderTicket(), " > Ошибка (трейлинг стоп) #", GetLastError());
               }
            }
         }
         //
         else if(OrderType() == OP_SELL)
         {
            if(_IsTrailingStopProfit) fromprice = OrderOpenPrice();
            else                      fromprice = OrderStopLoss();
            //
            ask         = MarketInfo(symb, MODE_ASK);
            profitpoint = (fromprice - ask) / pnt;  
            //
            if( profitpoint >= _TrailingStopLevel &&
                ask < (OrderStopLoss() - (_TrailingStopLevel + _TrailingStopStep) * pnt) )
            {
               if(!OrderModify(OrderTicket(), OrderOpenPrice(), (ask + (_TrailingStopLevel) * pnt),
                   OrderTakeProfit(), 0, CLR_NONE))
               {
                  Print("v108-1 т1 >", symb, " | ", _Timeframe,
                        " -> Ask=", MarketInfo(symb, MODE_ASK),
                        " | p/o=", OrderOpenPrice(), " | s/l=", OrderStopLoss(),
                        " | d=", _TrailingStopLevel, " | profitpoint=", profitpoint,
                        " -> SELL > ticket=", OrderTicket(), " > Ошибка (трейлинг стоп) #", GetLastError());
               }
            }
         }
      }
   }
}


//=++==============================================================++=
// расчёт потребного количества лотов
double GetLots(string symbol)
{
   double lots = 0;
   double sl;
   //
   switch(_Lots0_Mode)
   {
      case 1: // фиксированный
         lots = _Lots0;
         break;
      case 2: // процент от Баланса
         if(_StopLoss == 0)
            lots = _Lots0;
         else
         {
            lots = (AccountBalance() + AccountCredit()) * (_Lots0_Proc / 100) * _Lots0_Koef / _StopLoss;
            lots = NormalizeDouble(lots / MarketInfo(symb, MODE_LOTSTEP), 0);
            lots = lots * MarketInfo(symb, MODE_LOTSTEP);
            lots = MathMin(lots, _LotsMax);
            lots = MathMin(lots, MarketInfo(symb, MODE_MAXLOT));
            lots = MathMax(lots, MarketInfo(symb, MODE_MINLOT));
         }
         break;
   }
   Print("v108-1 лб2а > ", symb, " | ", _Timeframe,
         " -> lots=", lots);
   //
   return(lots);
}


extern int time=1; //1 - включено, 0 - выключено.
extern int starttime = 4; 
extern int stoptime = 9; 

//Ограничение по времени
int timecontrol()
{// Подробное описание http://fxnow.ru/blog.php?user=Yuriy&blogentry_id=1
   if ( ( (Hour()>=0 && Hour()<=stoptime-1) ||  (Hour()>=starttime && Hour()<=23)) && starttime>stoptime)
      {
      return(1);
      }  
      if ( (Hour()>=starttime && Hour()<=stoptime-1) && starttime<stoptime)
      {
      return(1);
      }  
      
   if(time==0){ return(1);}
     
return(0);
}


