//+------------------------------------------------------------------+
//|                         enLight_Average_Breakout_Trader_1_04.mq4 |
//|                    Copyright © 2006 enLight ® Trading Solutions™ |
//|                                                          v. 1.04 |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, enLight® Trading Solutions™"
#property link      "http://fxchannel.ru"
//********************************************************************
extern int     MM_Mode = 0;                //метод определения величины лота. 0-фикс. лот, 1-%% от маржи (пер. Risk), 2-метод фиксированной пропорции где дельта это Agressiveness
                                           //3-мартини, 4-анти мартини, больше меньше упомянутого значит метод 0.
extern string  separate1 = "----------------------------------------------------------------------------";
extern double  Lots = 0.1;                 //лот
extern int     Agressiveness = 400;        //дельта для фиксированной пропорции. т.е. на один Lots учавствующий в торгах приходится план
                                           //размером Agressiveness пунктов для повышения лота. Нужна только при MM_Mode = 2
extern string  separate2 = "----------------------------------------------------------------------------";
extern int     TakeProfit = 400;           //тейкпрофит
extern int     TrailStop = 100;            //тралл
extern int     TrailStep = 10;             //шаг трала
extern int     BezubLevel = 150;            //уровень прибыли в пунктах для переноса в безубыток
extern int     BezubSize = 20;              //отклонение нового ордера от безубытка при переносе в безубыток
extern int     StopLossLevel = 5;          //отступ от хая/лоу для постановки ордера
extern int     MaxStopLoss = 200;          //максимально допустимый стоплосс в пунктах, если он больше то он такой

extern string  separate3 = "----------------------------------------------------------------------------";

extern int     Risk = 10;                  //процент для определения величины лота. Нужна только при MM_Mode = 1
extern int     MM4NumOfProfitOrders = 3;   //количество последовательно выигрышных сделок, до которого очередной лот будет увеличиваться в MartingaleMultiplier раз.
                                           //Нужна только при MM_Mode = 4
extern double  MartingaleMultiplier = 2.0; //Коэффициент умножения лота при мартингейле при MM_Mode = 3
extern bool    ReverseClose = TRUE;        //закрытие по противоположному сигналу
extern int     Slippage = 3;
extern int     MAGIC = 9325;
//********************************************************************
int n,x,y,InternalMagic,Signal, Сount;
double StopLevel,Spread,MaxLot,MinLot,LotStep,OrdLots,Price;
datetime OrdCloseTime;
bool HaveOrders;

int init() //=========================================================
{
   InternalMagic = MAGIC + StringGetChar(Symbol(), 0) + StringGetChar(Symbol(), 1) + 100 * StringGetChar(Symbol(), 3) + 100 * StringGetChar(Symbol(), 4);
   StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
   Spread = MarketInfo(Symbol(), MODE_SPREAD); 
   MaxLot = MarketInfo(Symbol(), MODE_MAXLOT); 
   MinLot = MarketInfo(Symbol(), MODE_MINLOT); 
   LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   return (0);
}

int start() //=========================================================
{
   double MA, Open_1, Close_1, High_1, Low_1, Close_0;
   bool ProfitSeries = TRUE;
   double NewLots;
   
   Comment("Ордера выставляются c 00:00 до 02:00 серверного времени при наличии необходимых торговых условий.\n В остальное время производится только сопровождение ордеров.");
   
   //--------------------------------------------------расчет лота исходя из выбранного ММ
   Сount = 0;
   OrdCloseTime = 0;
   OrdLots = 0;
   for (n = 0; n < OrdersHistoryTotal(); n++) 
   {
      OrderSelect(n, SELECT_BY_POS, MODE_HISTORY);
      if (OrderMagicNumber() == InternalMagic) 
      {
         if (OrdCloseTime < OrderCloseTime()) 
         {
            OrdCloseTime = OrderCloseTime();
            OrdLots = OrderLots();
            if (OrderProfit() >= 0.0) 
            {
               Сount++;
               ProfitSeries = TRUE;
            } else {
               Сount = 0;
               ProfitSeries = FALSE;
            }
         }
      }
   }
   if (MM_Mode > 4 || MM_Mode < 0) MM_Mode = 0;
   switch (MM_Mode) 
   {
      case 0: //фиксированный лот
         OrdLots = Lots;
         break;
      case 1://фиксированный процент
         OrdLots = AccountFreeMargin() / 1000.0 * (Risk / 100.0);
         break;
      case 2://фиксированная пропорция
         if (Agressiveness <= 0) return(0);
         for (n = 1; AccountFreeMargin() > Agressiveness * n; n++) {}
         NewLots = n / 10.0;
         n = MathCeil(NewLots);
         if (OrdLots <= NewLots || OrdLots >= NewLots + 0.2 * n) OrdLots = NewLots;
         break;
      case 3://мартингейл
         if (ProfitSeries || OrdCloseTime == 0) OrdLots = Lots; else OrdLots *= MartingaleMultiplier;
         break;
      case 4://антимартингейл
         if (!ProfitSeries || OrdCloseTime == 0 || Сount >= MM4NumOfProfitOrders) OrdLots = Lots; else OrdLots *= MartingaleMultiplier;
   }
   //------------------------------------------исключить ошибки с лотами
   if (OrdLots < MinLot) OrdLots = MinLot;
   else {
      if (OrdLots > MaxLot) OrdLots = MaxLot;
      else {
         n = 1000.0 * MinLot;
         x = 1000.0 * LotStep;
         y = 1000.0 * OrdLots;
         while (true) {
            if (n > y) break;
            n += x;
         }
         OrdLots = (n - x) / 1000.0;
      }
   }
   //--------------------------------------------------проверка условий на постановку отложенных ордеров
   MA = iMA(NULL, PERIOD_D1, 3, 3, MODE_EMA, PRICE_CLOSE, 1);
   Open_1 = NormalizeDouble(iOpen(NULL, PERIOD_D1, 1), Digits);
   Close_1 = NormalizeDouble(iClose(NULL, PERIOD_D1, 1), Digits);
   High_1 = NormalizeDouble(iHigh(NULL, PERIOD_D1, 1), Digits);
   Low_1 = NormalizeDouble(iLow(NULL, PERIOD_D1, 1), Digits);
   Close_0 = NormalizeDouble(iClose(NULL, PERIOD_D1, 0), Digits);
   
   Signal = -1;
   
   //if ((Low_1 <= MA && Open_1 >= MA && Close_1 > MA) || (Close_1 > MA && Open_1 <= MA)) Signal = 0;
   //else
   //if ((High_1 >= MA && Open_1 <= MA && Close_1 < MA) || (Open_1 >= MA && Close_1 < MA)) Signal = 1;
   
   if (Low_1 <= MA) Signal = 1;
   else
   if (High_1 >= MA)  Signal = 0;
   
   //-----------------------------------------------------------------дальше если позы не открыты думаем куда что поставить/переставить
   double StopLossForSell = NormalizeDouble(High_1 + StopLossLevel*Point, Digits);
   double PriceForSell = NormalizeDouble(Low_1 - StopLossLevel*Point, Digits);
   double MaxStopLossForSell = NormalizeDouble(PriceForSell + MaxStopLoss*Point, Digits);
   if (StopLossForSell > MaxStopLossForSell) StopLossForSell = MaxStopLossForSell; 
      
   double StopLossForBuy = NormalizeDouble(Low_1 - StopLossLevel*Point, Digits);
   double PriceForBuy = NormalizeDouble(High_1 + StopLossLevel*Point, Digits);
   double MaxStopLossForBuy = NormalizeDouble(PriceForBuy - MaxStopLoss*Point, Digits);
   if (StopLossForBuy < MaxStopLossForBuy) StopLossForBuy = MaxStopLossForBuy; 
   //--------------------------------------------------обработка текущей ситуации с ордерами
   HaveOrders = FALSE;
   for (n = OrdersTotal() - 1; n >= 0; n--) 
   {
      OrderSelect(n, SELECT_BY_POS);
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != InternalMagic) continue;
      //--------------------------------------------------если есть продажа
      if (OrderType() == OP_SELL)
      {
         if (Signal == 0 && ReverseClose == TRUE) 
         {
            OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, CLR_NONE);
            continue;
         }
         HaveOrders = TRUE;
         //------------------------------------------трал продажи
         if (TrailStop > 0) 
         {
            if (OrderOpenPrice()>OrderStopLoss())
            {
               if (OrderOpenPrice() - Ask > TrailStop*Point) 
               {
                  if (OrderStopLoss() > Ask + (TrailStop + TrailStep)*Point) 
                  {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Ask + Point * TrailStop, OrderTakeProfit(), 0, Blue);
                     return (0);
                  }
               }
            }   
         }
         //------------------------------------------перенос в безубыток
         if (BezubLevel <= 0) continue;
         if (OrderStopLoss() <= OrderOpenPrice()) continue;
         if (OrderOpenPrice() - Ask < BezubLevel*Point) continue;
         OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice() - BezubSize*Point, OrderTakeProfit(), 0, Yellow);
         return (0);
      }
      //--------------------------------------------------если есть покупка
      if (OrderType() == OP_BUY) 
      {
         if (Signal == 1 && ReverseClose == TRUE) 
         {
            OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, CLR_NONE);
            continue;
         }
         HaveOrders = TRUE;
         //------------------------------------------трал покупки
         if (TrailStop > 0) {
            if (OrderOpenPrice()<OrderStopLoss())
            {
               if (Bid - OrderOpenPrice() > TrailStop*Point) {
                  if (OrderStopLoss() < Bid - (TrailStop + TrailStep)*Point) 
                  {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Bid - TrailStop*Point, OrderTakeProfit(), 0, Green);
                     return (0);
                  }
               }
            }   
         }
         //------------------------------------------перенос в безубыток
         if (BezubLevel <= 0) continue;
         if (OrderStopLoss() >= OrderOpenPrice()) continue;
         if (Bid - OrderOpenPrice() < BezubLevel*Point) continue;
         OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice() + BezubSize*Point, OrderTakeProfit(), 0, Yellow);
         return (0);
      }
      //---------------------------------------------------обработка отложенной продажи
      if (OrderType() == OP_SELLSTOP && Hour() < 2) 
      {
         if (Signal == 0 ||Low_1  > MA) 
         {
            OrderDelete(OrderTicket());
         } else {  
            HaveOrders = TRUE;
            if (OrderOpenPrice() < NormalizeDouble(Low_1 - StopLossLevel*Point - 1.0*Point, Digits) || OrderStopLoss() > NormalizeDouble(High_1 + StopLossLevel*Point + 1.0*Point, Digits)) 
            {
               if (NormalizeDouble(Close_0 + StopLevel*Point + Spread*Point, Digits) < NormalizeDouble(High_1 + StopLossLevel*Point, Digits) && NormalizeDouble(Close_0 - StopLevel*Point - Spread*Point, Digits) > NormalizeDouble(Low_1 - StopLossLevel*Point, Digits)) 
               {
                  OrderModify(OrderTicket(), PriceForSell, StopLossForSell, NormalizeDouble(Low_1 - StopLossLevel*Point - TakeProfit*Point, Digits), 0, Red);
               } else {
                  Sleep(120000);
               }
            }
         }
      }
      //---------------------------------------------------обработка отложенной покупки
      if (OrderType() == OP_BUYSTOP && Hour() < 2) 
      {
         if (Signal == 1 || High_1 < MA)
         {
            OrderDelete(OrderTicket());
         } else {  
            HaveOrders = TRUE;
            if (OrderOpenPrice() > NormalizeDouble(High_1 + StopLossLevel*Point + 1.0*Point, Digits) || OrderStopLoss() < NormalizeDouble(Low_1 - StopLossLevel*Point - 1.0*Point, Digits)) 
            {
               if (NormalizeDouble(Close_0 + StopLevel*Point + Spread*Point, Digits) < NormalizeDouble(High_1 + StopLossLevel*Point, Digits) && NormalizeDouble(Close_0 - StopLevel*Point - Spread*Point, Digits) > NormalizeDouble(Low_1 - StopLossLevel*Point, Digits)) 
               {
                  OrderModify(OrderTicket(), PriceForBuy, StopLossForBuy, NormalizeDouble(High_1 + StopLossLevel*Point + TakeProfit*Point, Digits), 0, Blue);
               }
            }   
         }
      }
   }
   //--------------------------------------------------установка отложенных ордеров
   if (Signal < 0 || HaveOrders) return (0);
   if (Signal == 0 && Hour() < 2) 
   {
      if (High_1 + StopLossLevel*Point > Close_0 + StopLevel*Point + Spread*Point && Low_1 - StopLossLevel*Point < Close_0 - StopLevel*Point - Spread*Point) 
      {
         if (TakeProfit < StopLevel*Point + Spread*Point || TakeProfit == 0) Price = 0; else Price = NormalizeDouble(High_1 + (StopLossLevel*Point + TakeProfit*Point), Digits);
         OrderSend(Symbol(), OP_BUYSTOP, OrdLots, PriceForBuy, Slippage, StopLossForBuy, Price, "", InternalMagic, 0, Blue);
      }
   }
   if (Signal == 1 && Hour() < 2) 
   {
      if (Low_1 - StopLossLevel*Point < Close_0 - StopLevel*Point - Spread*Point && High_1 + StopLossLevel*Point > Close_0 + StopLevel*Point + Spread*Point) 
      {
         if (TakeProfit < StopLevel*Point + Spread*Point || TakeProfit == 0) Price = 0; else Price = NormalizeDouble(Low_1 - (StopLossLevel*Point + TakeProfit*Point), Digits);
         OrderSend(Symbol(), OP_SELLSTOP, OrdLots, PriceForSell, Slippage, StopLossForSell, Price, "", InternalMagic, 0, Red);
      }
   }   
   return (0);
}