//+-------------------------------------------+
//|              Bulldozer_A12_v7.0_Multi.mq4 |
//|                  Copyright © 2010, ir0407 |
//|                    Edited by skumen, 2011 |
//|                    Edited by al22bag 2013 |
//+-------------------------------------------+
#property copyright "Copyright © 2010, ir0407"
#property link      "wlmaster@mail.ru"
#include <stderror.mqh>
#include <stdlib.mqh>
//-------------------------------------
extern string MultiSet           = "Multi Settings";
extern int    MaxSymbolOrders    = 4;    // максимальное количество ордеров в серии в каждую сторону для каждой пары (без суб-ордеров)
extern int    MaxSymbols         = 2;    // максимально разрешенное число символов (пар)
extern int    MaxMultiOrders     = 6;    // максимальное количество ордеров на всех парах терминала (без суб-ордеров)
extern double MaxMultiLots       = 10.0; // максимальная сумма лотов всех ордеров по всем парам терминала (с суб-ордерами)
//-------------------------------------
extern string PrimSigSet         = "Primary Signals"; // ТФ сигналов - это ТФ графика, на котором стоит сова
extern int    PrimPriceDist      = 400;  // какая требуется разница в цене между текущей ценой и наивысшим/наинизшим баром
                                         // из числа анализируемых, первая (основная) серия
extern int    PrimNumOfBars      = 18;   // сколько баров анализировать, первая (основная) серия
//-------------------------------------
extern string OppSigSet          = "Opposite Signals"; // сигналы 2-й (оппозитной) серии
extern int    OppPriceDist       = 400;  // какая требуется разница в цене между текущей ценой и наивысшим/наинизшим баром
                                         // из числа анализируемых, вторая (противоположная = оппозитная) серия
extern int    OppNumOfBars       = 18;   // сколько баров анализировать, вторая (противоположная = оппозитная) серия
//-------------------------------------
extern string SubSigSet          = "Sub Signals"; // сигналы для выставления суб-ордеров (если UseSubSignal = True)
extern bool   UseSubSignal       = True; // использовать ли сигнал рывка для выставления суб-ордера
extern int    SubSigDist         = 400;  // какая требуется разница в цене между текущей ценой и наивысшим/наинизшим баром
                                         // из числа анализируемых для выставления суб-ордера
extern int    SubNumOfBars       = 12;   // сколько баров анализировать для выставления суб-ордера
//-------------------------------------
extern string LotSet             = "Lot Settings"; // настройки основных лотов
extern double InitLot            = 0.01; // размер лота для начала торгов
extern int    LotDecimal         = 2;    // количество десятичных знаков лота
extern int    LotMode            = 0;    // прогрессия роста лота: 0 - геометрическая, 1 - арифметическая
extern double LotExp             = 3.0;  // экспонента лотов - на cколько умножать лот предыдущего ордера, 1 для статических равных лотов
extern double LotInc             = 0.01; // инкремент лотов - cколько добавлять к лоту предыдущего ордера, 0 для статических равных лотов
extern double MaxLot             = 0.3;  // максимальный лот
//-------------------------------------
extern string OppSet             = "Opposite Orders Settings"; // настройки противоположных (= оппозитных, = частично локирующих) ордеров
extern int    StartOppOrders     = 2;    // сколько ордеров надо набрать, чтобы включилась по сигналу противоположная серия, если не нужно, =100
extern int    OppLot_Percent     = 25;   // размер 1-го противоположного ордера в %% от суммы лотов 1-й (первичной) серии в просадке
//-------------------------------------
extern string SubSet             = "Sub-orders Settings"; // настройки вторичных, = суб-ордеров "Матрёшки"
extern int    StartSubOrders     = 2;    // сколько нужно набрать ордеров в серии, чтобы могли выставляться суб-ордера
extern int    SubLot_Percent     = 25;   // размер 1-го ордера дополнительной суб-серии в %% от суммы лотов первичной серии в просадке
extern int    SubLotMode         = 0;    // прогрессия роста суб-лота: 0 - геометрическая, 1 - арифметическая
extern double SubLotExp          = 2.0;  // экспонента суб-лотов - на cколько умножать лот предыдущего ордера, 1 для статических равных лотов
extern double SubLotInc          = 0.01; // инкремент суб-лотов - cколько добавлять (убавлять) к лоту предыдущего ордера, 0 для статических лотов
//-------------------------------------
extern string TPSLSet            = "TP&SL Settings";
extern int    InitTP             = 100;  // начальный ТэйкПрофит
extern int    StartLastTP        = 100;  // сколько ордеров серии надо набрать, чтобы дальнейшие ордера имели свой отдельный ТП, без усреднения
extern bool   UseCloseTP         = False;// использовать ли общий ТП для закрытия всех ордеров
extern double CloseTP            = 20;   // профит В ВАЛЮТЕ ТЕРМИНАЛА, когда закрываются все ордера, 0 для безубытка
extern bool   UseCloseSL         = False;// использовать ли общий СЛ для закрытия всех ордеров
extern double CloseSL            = 100;  // лосс В ВАЛЮТЕ ТЕРМИНАЛА, когда закрываются все ордера
extern bool   CloseAllSymbols    = True; // закрывать ли все пары, или если False, то только пару графика
//-------------------------------------
extern string StepSet            = "PipStep Settings";
extern int    InitPipStep        = 500;  // начальное расстояние (в пунктах) до лимитного ордера
extern int    PipStepMode        = 0;    // 0 - Геометрическая прогрессия, умножение LimitStep на LimitStepExp;
                                         // 1 - Арифметическая прогрессия, добавление к LimitStep LimitStepInc;
extern int    StartDynStep       = 2;    // сколько рыночных ордеров должно быть, чтобы начал увеличиваться шаг LimitStep
extern double PipStepExp         = 2.0;  // на сколько умножать LimitStep, для статического шага выставить 1
extern int    PipStepInc         = 200;  // сколько добавлять (или отнимать) к LimitStep, для статического шага выставить 0                                          
extern int    MinPipStep         = 100;  // минимальный ПипСтеп - далее останется таким же, без дальнейшего уменьшения
extern int    MaxPipStep         = 2000; // максимальный ПипСтеп - далее останется таким же, без дальнейшего увеличения
//-------------------------------------
extern string GenSet             = "General Settings";
extern int    MagicMain          = 1;    // МН должны быть разными для разных пар и равными 1, 2, 3, 4, 5, и 6
extern int    MagicSub           = 11;   // МН должны быть разными для разных пар и равными 11, 22, 33, 44, 55, и 66
extern int    MaxBalanceLoss     = 75;   // сколько %% депозита надо потерять, когда сов закроет в убыток 1-й, самый дальний от цены ордер,
                                         // выбранный из всех открытых пар, немного приближая этим общий ТП серии этой пары к цене
extern bool   Debug              = True; // Выдавать ли инфо в печать (False для ускорения тестирования)
extern bool   Sound              = False;// Включить ли звуковое сопровождение
//-------------------------------------
string   ExpertName="Bulldozer_A12_v7.0_Multi";
double   LastTickTime,MINLOT,MAXLOT;
//double  DigsK=1;
int      Slippage,Error=0,n,StopLevel;
bool     InitFail=False;
datetime expiration;
// ----- EA initialization function -----
int init()
{
  if((!IsExpertEnabled()) || (!IsTradeAllowed()))
  {
    Print("!LET ME TRADE!");
    InitFail=True;
    return(0);
  }
  if(!IsLibrariesAllowed())
  {
    Print("!I NEED LIBRARIES!");
    InitFail=True;
    return(0);
  }
  MINLOT = MarketInfo(Symbol(),MODE_MINLOT);
  if(InitLot < MINLOT)
  {
    Print("!Initial Lot cannot be less than ",MINLOT,"!");
    InitFail = True;
    return(0);
  }
  MAXLOT = MarketInfo(Symbol(),MODE_MAXLOT);
  if(MaxLot > MAXLOT)
  {
    Print("!Maximum Lot cannot be more than ",MAXLOT,"!");
    InitFail = True;
    return(0);
  }
  if(InitFail)
  {
    if(Debug) Print("!INITIALIZATION FAILED!");
    return(0);
  }
  /*
  if((Digits == 4) || (Digits == 2))
  {
    DigsK = 0.1;
    InitTP        = NormalizeDouble(InitTP * DigsK,Digits);
    InitSL        = NormalizeDouble(InitSL * DigsK,Digits);
    SubSigDist    = NormalizeDouble(SubSigDist * DigsK,Digits);
    PipStepInc    = NormalizeDouble(PipStepInc * DigsK,Digits);
    MinPipStep    = NormalizeDouble(MinPipStep * DigsK,Digits);
    MaxPipStep    = NormalizeDouble(MaxPipStep * DigsK,Digits);
    InitPipStep   = NormalizeDouble(InitPipStep * DigsK,Digits);
    OppPriceDist  = NormalizeDouble(OppPriceDist * DigsK,Digits);
    PrimPriceDist = NormalizeDouble(PrimPriceDist * DigsK,Digits);
  }
  */
  return(0);
}
// ----- EA deinitialization function -----
int deinit()
{
  return(0);
}
// ----- EA start function -----
int start()
{
  int    PrimSignal=0,Ticket=0;
  int    SymbolOrders,SymbolBuyOrders,SymbolSellOrders;
  int    SymbolSubBuyOrders,SymbolSubSellOrders;
  int    PipStepBuy=0,PipStepSell=0;
  bool   Result;
  double NewLotBuy=0,NewLotSell=0;
  double NewSubLotBuy=0,NewSubLotSell=0;
  double LastBuyPrice=0,LastSellPrice=0,NewTPPrice=0;
  double LastSubBuyPrice=0,LastSubSellPrice=0;
  double CommonProfit=0;
  //--------------------------------------------
  LastTickTime = MarketInfo(Symbol(),MODE_TIME);
  Slippage     = MarketInfo(Symbol(),MODE_SPREAD);
  StopLevel    = MarketInfo(Symbol(),MODE_STOPLEVEL);
  //----- проверка общего профита или лосса -----
  if(UseCloseTP)
  { 
    CommonProfit = CheckCommonProfit();
    if(CommonProfit >= CloseTP)
    {
      if(Debug) Print("CommonProfit = ",CommonProfit,", Closing all orders");
      if(CloseAllSymbols) CloseAllSymbols();
      else CloseAllCurrentSymbol();
    }//if(CommonProfit >= CloseTP)
  }//if(UseCloseTP)
  if(UseCloseSL)
  {
    CommonProfit = CheckCommonProfit();
    if(CommonProfit <= -CloseSL)
    {
      if(Debug) Print("CommonLoss = ",CommonProfit,", Closing all orders");
      if(CloseAllSymbols) CloseAllSymbols();
      else CloseAllCurrentSymbol();
    }//if(CommonProfit <= CloseSL)
  }//if(UseCloseSL)
  //----- проверка эквити и баланса -----
  if(AccountEquity()<=AccountBalance()*(100-MaxBalanceLoss)/100)
  { 
    Ticket = FindFirstMultiOrder();
    if(OrderSelect(Ticket,SELECT_BY_TICKET))
    {
      if((OrderSymbol()==Symbol())&&(OrderMagicNumber()==MagicMain))
      {
        //------------------------
        if(OrderType() == OP_BUY)
        {
          if(Debug) Print("Closing First Order BUY, Ticket ",Ticket);
          Result=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(MarketInfo(Symbol(),MODE_BID),Digits),Slippage,CLR_NONE);
          if(Result != True)
          {
            Error = GetLastError();
            Print("Error Closing BUY Order: LastError = ",Error);
          }
          if(Result == True)
          {
            if(Sound) PlaySound("CloseOrder.wav");
            RecalculateTP(OP_BUY);
          }
        }//if(OrderType() == OP_BUY)
        //------------------------
        if(OrderType() == OP_SELL)
        {
          if(Debug) Print("Closing First Order SELL, Ticket ",Ticket);
          Result=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(MarketInfo(Symbol(),MODE_ASK),Digits),Slippage,CLR_NONE);
          if(Result != True)
          {
            Error = GetLastError();
            Print("Error Closing SELL Order: LastError = ",Error);
          }
          if(Result == True)
          {
            if(Sound) PlaySound("CloseOrder.wav");
            RecalculateTP(OP_SELL);
          }
        }//if((OrderType() == OP_SELL)
      }//if((OrderSymbol()==Symbol())&&(OrderMagicNumber()==MagicMain))
    }//if(OrderSelect(Ticket, SELECT_BY_TICKET))
  }//if(AccountEquity()<=AccountBalance()*(100-MaxBalanceLoss)/100)
  //-----------------------------------
  if((CountOfTotalLots() < MaxMultiLots)&&
     (CountOfMultiOrders() < MaxMultiOrders))
  { 
    SymbolOrders = CountOfSymbolOrders();
    //--------------------------------------------------------
    if((SymbolOrders == 0) && (CountOfSymbols() < MaxSymbols))
    {
      PrimSignal = GetPrimSignal();
      switch(PrimSignal)
      { 
        case 1:
          if(Debug) Print("Sending 1st BUY order, InitLot = ",InitLot);
          Ticket=SendMarketOrder(OP_BUY,InitLot,0,0,MagicMain,ExpertName+"-"+(SymbolOrders+1)+"-"+0,Error);
          if(Ticket > 0)
            if(OrderSelect(Ticket,SELECT_BY_TICKET))
            {
              NewTPPrice=OrderOpenPrice()+(InitTP * Point);
              ModifyOrder(NewTPPrice);
              if(Sound) PlaySound("OpenOrder.wav");
            }
          break;
        case -1:
          if(Debug) Print("Sending 1st SELL order, InitLot = ",InitLot);
          Ticket=SendMarketOrder(OP_SELL,InitLot,0,0,MagicMain,ExpertName+"-"+(SymbolOrders+1)+"-"+0,Error);
          if(Ticket > 0)
            if(OrderSelect(Ticket,SELECT_BY_TICKET))
            {
              NewTPPrice=OrderOpenPrice()-(InitTP * Point);
              ModifyOrder(NewTPPrice);
              if(Sound) PlaySound("OpenOrder.wav");
            }
          break;
        default:
          break;
      }//exit switch(PrimSignal)
      return(0);
    }//if((SymbolOrders==0)&&(CountOfSymbols()<MaxSymbols))
    //--------------------------------------------------
    if(SymbolOrders > 0)
    {
      SymbolBuyOrders = CountSymbolBuy();
      if(SymbolBuyOrders > 0) RecalculateTP(OP_BUY);
      SymbolSellOrders = CountSymbolSell();
      if(SymbolSellOrders > 0) RecalculateTP(OP_SELL);
      //--- включение оппозитных ордеров БАЙ ---
      if((SymbolBuyOrders == 0)&&(SymbolSellOrders >= StartOppOrders))
      {
        if(GetOppSignal() == 1)
        {
          NewLotBuy=NormalizeDouble(CalcSymbolLots(OP_SELL) * OppLot_Percent / 100,LotDecimal);
          if(NewLotBuy < InitLot) NewLotBuy = InitLot;
          if(NewLotBuy > MaxLot) NewLotBuy = MaxLot;
          if(Debug) Print("Sending 1st Opposite BUY order, NewLotBuy = ",NewLotBuy);
          Ticket=SendMarketOrder(OP_BUY,NewLotBuy,0,0,MagicMain,ExpertName+"-"+(SymbolBuyOrders+1)+"-"+0,Error);
          if(Ticket > 0)
            if(OrderSelect(Ticket,SELECT_BY_TICKET))
            {
              NewTPPrice=NormalizeDouble(OrderOpenPrice()+(InitTP * Point),Digits);
              ModifyOrder(NewTPPrice);
              if(Sound) PlaySound("OpenOrder.wav");
            }
        }//if(GetOppSignal() == 1)
      }//if((SymbolBuyOrders == 0) && (SymbolSellOrders >= StartOppOrders))
      //--- включение оппозитных ордеров СЕЛЛ ---
      if((SymbolSellOrders==0)&&(SymbolBuyOrders>=StartOppOrders))
      {
        if(GetOppSignal() == -1)
        {
          NewLotSell=NormalizeDouble(CalcSymbolLots(OP_BUY)*OppLot_Percent/100,LotDecimal);
          if(NewLotSell<InitLot) NewLotSell=InitLot;
          if(NewLotSell>MaxLot) NewLotSell=MaxLot;
          if(Debug) Print("Sending 1st Opposite SELL order, NewLotSell = ",NewLotSell);
          Ticket=SendMarketOrder(OP_SELL,NewLotSell,0,0,MagicMain,ExpertName+"-"+(SymbolSellOrders+1)+"-"+0,Error);
          if(Ticket > 0)
            if(OrderSelect(Ticket,SELECT_BY_TICKET))
            {
              NewTPPrice=NormalizeDouble(OrderOpenPrice()-(InitTP * Point),Digits);
              ModifyOrder(NewTPPrice);
              if(Sound) PlaySound("OpenOrder.wav");
            }
        }//if(GetOppSignal() == -1)
      }//if((SymbolSellOrders == 0) && (SymbolBuyOrders >= StartOppOrders))
      //---------------------------------
      SymbolBuyOrders = CountSymbolBuy();
      if((SymbolBuyOrders > 0) && (SymbolBuyOrders < MaxSymbolOrders))
      { 
        LastBuyPrice = FindLastOpenPrice(OP_BUY,MagicMain);
        //----- расчет динамического ПипСтепа -----
        if(SymbolBuyOrders < StartDynStep) PipStepBuy = InitPipStep;
        if(SymbolBuyOrders >= StartDynStep)
        {
          if(PipStepMode == 0)
            PipStepBuy = NormalizeDouble(InitPipStep*MathPow(PipStepExp,SymbolBuyOrders-StartDynStep+1),0);
          if(PipStepMode == 1)
            PipStepBuy = InitPipStep+(PipStepInc*(SymbolBuyOrders-StartDynStep+1));
          if(PipStepBuy < MinPipStep) PipStepBuy = MinPipStep;
          if(PipStepBuy > MaxPipStep) PipStepBuy = MaxPipStep;
        }//if(BuyOrders >= StartDynStep)
        //--------------------------------------
        if(Ask<=LastBuyPrice-(PipStepBuy*Point))
        { 
          if(LotMode == 0)
            NewLotBuy = NormalizeDouble(FindLastSymbolLot(OP_BUY) * LotExp,LotDecimal);
          if(LotMode == 1)
            NewLotBuy = FindLastSymbolLot(OP_BUY) + LotInc;            
          if(NewLotBuy < InitLot) NewLotBuy = InitLot;
          if(NewLotBuy > MaxLot)  NewLotBuy = MaxLot;
          //----------------------------------
          if(Debug) Print("Sending BUY Order Number ",SymbolBuyOrders+1,", NewLotBuy = ",NewLotBuy);
          Ticket = SendMarketOrder(OP_BUY,NewLotBuy,0,0,MagicMain,ExpertName+"-"+(SymbolBuyOrders+1)+"-"+DoubleToStr((LastBuyPrice-Ask)/Point,0),Error);
          if(Ticket > 0)
          {
            if(OrderSelect(Ticket,SELECT_BY_TICKET))
            {
              NewTPPrice=NormalizeDouble(OrderOpenPrice()+(InitTP*Point),Digits);
              ModifyOrder(NewTPPrice);
            }
            if(CountSymbolBuy()<StartLastTP) RecalculateTP(OP_BUY);
            if(Sound) PlaySound("NewStepOrder.wav");
          }//if(Ticket > 0)
        }//if(Ask <= LastBuyPrice - (PipStepBuy * Point))
        //--- расчет суб-ордера БАЙ ---
        SymbolBuyOrders = CountSymbolBuy();
        if(SymbolBuyOrders >= StartSubOrders)
        {
          SymbolSubBuyOrders = CountSymbolSub(OP_BUY);
          if(SymbolSubBuyOrders == 0)
          {
            LastBuyPrice = FindLastOpenPrice(OP_BUY,MagicMain);
            if((UseSubSignal) && (GetSubSignal() == 1))
            {
              if(Ask<=LastBuyPrice-(SubSigDist*Point))
              {
                NewSubLotBuy=NormalizeDouble(CalcSymbolLots(OP_BUY)*SubLot_Percent/100,LotDecimal);
                if(NewSubLotBuy<InitLot) NewSubLotBuy=InitLot;
                if(NewSubLotBuy>MaxLot)  NewSubLotBuy=MaxLot;
                if(Debug) Print("Sending BUY SubOrder, NewSubLotBuy = ",NewSubLotBuy);
                Ticket=SendMarketOrder(OP_BUY,NewSubLotBuy,0,0,MagicSub,ExpertName+"-"+(SymbolSubBuyOrders+1)+"-"+DoubleToStr((LastBuyPrice-Ask)/Point,0),Error);
                if(Ticket > 0)
                {
                  RecalculateTP(OP_BUY);
                  if(Sound) PlaySound("NewStepOrder.wav");
                }//if(Ticket > 0)
              }//if(Ask <= LastBuyPrice - (SubSigDist * Point))
            }//if((UseSubSignal) && (GetSubSignal() == 1))
          }//if(SymbolSubBuyOrders == 0)
          //----------------------------
          if(SymbolSubBuyOrders > 0)
          {
            LastSubBuyPrice = FindLastOpenPrice(OP_BUY,MagicSub);
            if(Ask <= LastSubBuyPrice - (SubSigDist * Point))
            {//----- расчет следующего cyб-лота -----
              if(SubLotMode == 0)
                NewSubLotBuy = NormalizeDouble(FindLastSubLot(OP_BUY)*SubLotExp,LotDecimal);
              if(SubLotMode == 1)
                NewSubLotBuy = FindLastSubLot(OP_BUY) + SubLotInc;            
              if(NewSubLotBuy < InitLot) NewSubLotBuy = InitLot;
              if(NewSubLotBuy > MaxLot)  NewSubLotBuy = MaxLot;
              if(Debug) Print("Sending BUY SubOrder, NewSubLotBuy = ",NewSubLotBuy);
              Ticket=SendMarketOrder(OP_BUY,NewSubLotBuy,0,0,MagicSub,ExpertName+"-"+(SymbolSubBuyOrders+1)+"-"+DoubleToStr((LastBuyPrice-Ask)/Point,0),Error);
              if(Ticket > 0)
              {
                RecalculateTP(OP_SELL);
                if(Sound) PlaySound("NewStepOrder.wav");
              }//if(Ticket > 0)
            }//if(Ask<=LastSubBuyPrice-(SubSigDist*Point))
          }//if(SymbolSubBuyOrders > 0)
        }//if(SymbolBuyOrders >= StartSubOrders)
      }//if((SymbolBuyOrders > 0) && (SymbolBuyOrders < MaxSymbolOrders))
      //-----------------------------------
      SymbolSellOrders = CountSymbolSell();
      if((SymbolSellOrders > 0)&&(SymbolSellOrders < MaxSymbolOrders))
      { 
        LastSellPrice = FindLastOpenPrice(OP_SELL,MagicMain);
        //----- расчет динамического ПипСтепа -----
        if(SymbolSellOrders < StartDynStep) PipStepSell = InitPipStep;
        if(SymbolSellOrders >= StartDynStep)
        {
          if(PipStepMode == 0)
            PipStepSell = NormalizeDouble(InitPipStep*MathPow(PipStepExp,SymbolSellOrders-StartDynStep+1),0);
          if(PipStepMode == 1)
            PipStepSell = InitPipStep+(PipStepInc*(SymbolSellOrders-StartDynStep+1));
          if(PipStepSell < MinPipStep) PipStepSell = MinPipStep;
          if(PipStepSell > MaxPipStep) PipStepSell = MaxPipStep;
        }//if(SymbolSellOrders >= StartDynStep)
        //----------------------------------------
        if(Bid>=LastSellPrice+(PipStepSell*Point))
        { 
          if(LotMode == 0)
            NewLotSell = NormalizeDouble(FindLastSymbolLot(OP_SELL)*LotExp,LotDecimal);
          if(LotMode == 1)
            NewLotSell = FindLastSymbolLot(OP_SELL) + LotInc;
          if(NewLotSell < InitLot) NewLotSell = InitLot;
          if(NewLotSell > MaxLot)  NewLotSell = MaxLot;
          //----------------------------------
          if(Debug) Print("Sending SELL Order Number ",SymbolSellOrders+1,", NewLotSell = ",NewLotSell);
          Ticket = SendMarketOrder(OP_SELL,NewLotSell,0,0,MagicMain,ExpertName+"-"+(SymbolSellOrders+1)+"-"+DoubleToStr((Bid-LastSellPrice)/Point,0),Error);
          if(Ticket > 0)
          {
            if(OrderSelect(Ticket,SELECT_BY_TICKET))
            {
              NewTPPrice=NormalizeDouble(OrderOpenPrice()-(InitTP*Point),Digits);
              ModifyOrder(NewTPPrice);
            }
            if(CountSymbolSell()<StartLastTP) RecalculateTP(OP_SELL);
            if(Sound) PlaySound("NewStepOrder.wav");
          }//if(Ticket > 0)
        }//if(Bid>=LastSellPrice+(PipStepSell*Point))
        //--- расчет суб-ордера СЕЛЛ ---
        SymbolSellOrders = CountSymbolSell();
        if(SymbolSellOrders >= StartSubOrders)
        {
          SymbolSubSellOrders = CountSymbolSub(OP_SELL);
          if(SymbolSubSellOrders == 0)
          {
            LastSellPrice = FindLastOpenPrice(OP_SELL,MagicMain);
            if((UseSubSignal) && (GetSubSignal() == -1))
            {
              if(Bid>=LastSellPrice+(SubSigDist*Point))
              { 
                NewSubLotSell = NormalizeDouble(CalcSymbolLots(OP_SELL)*SubLot_Percent/100,LotDecimal);
                if(NewSubLotSell<InitLot) NewSubLotSell=InitLot;
                if(NewSubLotSell>MaxLot)  NewSubLotSell=MaxLot;
                if(Debug) Print("Sending SELL SubOrder, NewSubLotSell = ",NewSubLotSell);
                Ticket=SendMarketOrder(OP_SELL,NewSubLotSell,0,0,MagicSub,ExpertName+"-"+(SymbolSubSellOrders+1)+"-"+DoubleToStr((Bid-LastSellPrice)/Point,0),Error);
                if(Ticket > 0)
                {
                  RecalculateTP(OP_SELL);
                  if(Sound) PlaySound("NewStepOrder.wav");
                }//if(Ticket > 0)
              }//if(Bid>=LastSellPrice+(SubSigDist*Point))
            }//if((UseSubSignal) && (GetSubSignal() == -1))
          }//if(SymbolSubSellOrders == 0)
          //-----------------------------------
          if(SymbolSubSellOrders > 0)
          {
            LastSubSellPrice = FindLastOpenPrice(OP_SELL,MagicSub);
            if(Bid>=LastSubSellPrice+(SubSigDist*Point))
            {//----- расчет следующего cyб-лота -----
              if(SubLotMode == 0)
                NewSubLotSell = NormalizeDouble(FindLastSubLot(OP_SELL)*SubLotExp,LotDecimal);
              if(SubLotMode == 1)
                NewSubLotSell = FindLastSubLot(OP_SELL) + SubLotInc;            
              if(NewSubLotSell < InitLot) NewSubLotSell = InitLot;
              if(NewSubLotSell > MaxLot)  NewSubLotSell = MaxLot;
              if(Debug) Print("Sending SELL SubOrder, NewSubLotSell = ",NewSubLotSell);               
              Ticket=SendMarketOrder(OP_SELL,NewSubLotSell,0,0,MagicSub,ExpertName+"-"+(SymbolSubSellOrders+1)+"-"+DoubleToStr((Bid-LastSellPrice)/Point,0),Error);
              if(Ticket > 0)
              {
                RecalculateTP(OP_SELL);
                if(Sound) PlaySound("NewStepOrder.wav");
              }//if(Ticket > 0)
            }//if(Bid>=LastSellPrice+(SubSigDist*Point))
          }//if(SymbolSubSellOrders > 0)
        }//if(SymbolSellOrders >= StartSubOrders)
      }//if((SymbolSellOrders>0)&&(SymbolSellOrders<MaxSymbolOrders))
    }//if((SymbolOrders>0)&&(CountOfSymbols()<=MaxSymbols))
  }//if((CountOfSymbols()<MaxSymbols)&&(CountOfMultiOrders()<MaxMultiOrders)&&(CountOfTotalLots()<MaxMultiLots))
  return(0);
}//exit start function
//------------------
int CountOfSymbols()
{
  int countMN1=0,countMN2=0,countMN3=0,countMN4=0,countMN5=0,countMN6=0;
  int Symbol1=0,Symbol2=0,Symbol3=0,Symbol4=0,Symbol5=0,Symbol6=0,SumSymbols=0;

  for(int a=0;a<OrdersTotal();a++)
    if(OrderSelect(a,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() == 1)
        {
          countMN1++;
          if(countMN1>0) Symbol1=1;
        }
  for(int b=0;b<OrdersTotal();b++)
    if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() == 2)
        {
          countMN2++;
          if(countMN2>0) Symbol2=1;
        }
  for(int c=0;c<OrdersTotal();c++)
    if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() == 3)
        {
          countMN3++;
          if(countMN3>0) Symbol3=1;
        }
  for(int d=0;d<OrdersTotal();d++)
    if(OrderSelect(d,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() == 4)
        {
          countMN4++;
          if(countMN4>0) Symbol4=1;
        }
  for(int e=0;e<OrdersTotal();e++)
    if(OrderSelect(e,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() == 5)
        {
          countMN5++;
          if(countMN5>0) Symbol5=1;
        }
  for(int f=0;f<OrdersTotal();f++)
    if(OrderSelect(f,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() == 6)
        {
          countMN6++;
          if(countMN6>0) Symbol6=1;
        }
  SumSymbols=Symbol1+Symbol2+Symbol3+Symbol4+Symbol5+Symbol6;
  return(SumSymbols);
}
//----------------------
int CountOfMultiOrders() //без суб
{
  int count = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if((OrderMagicNumber()==1)||(OrderMagicNumber()==2)||(OrderMagicNumber()==3)||
           (OrderMagicNumber()==4)||(OrderMagicNumber()==5)||(OrderMagicNumber()==6))
          count++;
  return(count);
}
//-----------------------
int CountOfSymbolOrders() //без суб
{
  int count = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MagicMain)
          if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
            count++;
  return(count);
}
//------------------
int CountSymbolBuy() //без суб
{
  int count = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MagicMain)
          if(OrderType() == OP_BUY)
            count++;
  return(count);
}
//-------------------
int CountSymbolSell() //без суб
{
  int count = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MagicMain)
          if(OrderType() == OP_SELL)
            count++;
  return(count);
}
//--------------------------
int CountSymbolSub(int Type)
{
  int count = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MagicSub)
          if(OrderType() == Type)
            count++;
  return(count);
}
//-----------------------
double CountOfTotalLots() // с суб
{
  double lots = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() > 0)
          lots+=OrderLots();
  return(lots);
}
//-----------------------------
double FindLastSubLot(int Type)
{
  int ticket = 0;
  double lot = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderType()==Type)
        if(OrderMagicNumber()==MagicSub)
        {
          ticket = OrderTicket();
          if(OrderTicket() > ticket)
          {
            ticket = OrderTicket();
            lot = OrderLots();
          }
        }
  return(lot);
}
//------------------------
double CheckCommonProfit() // с суб
{
  double profit=0;
  for(int i=OrdersTotal()-1;i>=0;i--)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
        if(OrderMagicNumber() > 0)
        {
          if(CloseAllSymbols)
            profit+=OrderProfit()+OrderCommission()+OrderSwap();
          else
          {
            if(OrderSymbol()==Symbol())
            profit+=OrderProfit()+OrderCommission()+OrderSwap();
          }
        }
  return(profit);        
}
//--------------------
bool CloseAllSymbols() //all orders of all symbols
{
  for(int cnt=OrdersTotal()-1;cnt>=0;cnt--)
    if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)) 
    {
      if(OrderMagicNumber() > 0)
      {
        if(OrderType()==OP_BUY)
          if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_BID),Slippage,Yellow))
            return(false);
        if(OrderType()==OP_SELL)
          if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_ASK),Slippage,Yellow))
            return(false);
      }
    } 
  return(true);
}
//--------------------------
bool CloseAllCurrentSymbol() //all orders on current chart
{
  for(int cnt=OrdersTotal()-1;cnt>=0;cnt--)
    if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)) 
      if(OrderSymbol()==Symbol())
        if((OrderMagicNumber()==MagicMain)||(OrderMagicNumber()==MagicSub))
        {
          if(OrderType()==OP_BUY)
            if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_BID),Slippage,Yellow))
              return(false);
          if(OrderType()==OP_SELL)
            if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_ASK),Slippage,Yellow))
              return(false);
        }
  return(true);
}
//-----------------------
double CalcSymbolLots(int Type) // без cуб
{
  double lots=0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MagicMain)
          if(OrderType() == Type)
            lots+=OrderLots();
  return(lots);
}
//-----------------------
int FindFirstMultiOrder() //без cуб
{
  int ticket=0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if((OrderType()==OP_BUY)||(OrderType()==OP_SELL))
          if(OrderProfit() < 0)
          {
            if(ticket==0) ticket=OrderTicket();
            if(OrderTicket()<ticket) ticket=OrderTicket();
          }
  return(ticket);
}
//--------------------------------
double FindLastSymbolLot(int Type)
{
  int ticket = 0;
  double lot = 0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderType() == Type)
          if(OrderMagicNumber() == MagicMain)
          {
            if(ticket == 0)
              ticket = OrderTicket();
            if(OrderTicket() > ticket)
              ticket = OrderTicket();
          }
  for(i=0;i<OrdersTotal();i++)
    if(OrderSelect(ticket,SELECT_BY_TICKET))
    {
      lot = OrderLots();
      //if(Debug) Print("LastSymbolLot = ",lot);
    }
  return(lot);
}
//---------------------------------------
double FindLastOpenPrice(int Type,int MN)
{
  double LastOpenPrice = 0;
  int ticket = 0;
  for(int cnt=OrdersTotal()-1;cnt>=0;cnt--)
    if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if((OrderType()==Type)&&(OrderMagicNumber()==MN))
          if(OrderTicket() > ticket)
          {
            ticket = OrderTicket();
            LastOpenPrice = OrderOpenPrice();
          }
  return(LastOpenPrice);
}
//--------------------------
void RecalculateTP(int Type) //вместе с суб
{
  double NewTPPrice;
  if(Type == OP_BUY)
  {
    NewTPPrice=NormalizeDouble(CalculateAveragePrice(OP_BUY)+(InitTP * Point),Digits);
    for(int i=0;i<OrdersTotal();i++)
      if(OrderSelect(i,SELECT_BY_POS))
        if(OrderSymbol() == Symbol())
          if((OrderMagicNumber()==MagicMain)||(OrderMagicNumber()==MagicSub))
            if(OrderType() == OP_BUY)
              if(NormalizeDouble(OrderTakeProfit(),Digits)!=NormalizeDouble(NewTPPrice,Digits))
                ModifyOrder(NewTPPrice);
  }
  if(Type == OP_SELL)
  {
    NewTPPrice=NormalizeDouble(CalculateAveragePrice(OP_SELL)-(InitTP * Point),Digits);
    for(int j=0;j<OrdersTotal();j++)
      if(OrderSelect(j,SELECT_BY_POS))
        if(OrderSymbol() == Symbol())
          if((OrderMagicNumber()==MagicMain)||(OrderMagicNumber()==MagicSub))
            if(OrderType() == OP_SELL)
              if(NormalizeDouble(OrderTakeProfit(),Digits)!=NormalizeDouble(NewTPPrice,Digits))
                ModifyOrder(NewTPPrice);
  }
  return;
}
//------------------------------------
double CalculateAveragePrice(int Type)
{
  double AveragePrice=0;
  double Total=0;
  double OpenLots=0;
  for(int i=0;i<OrdersTotal();i++)
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if((OrderMagicNumber()==MagicMain)||(OrderMagicNumber()==MagicSub))
          if(OrderType() == Type)
          {
            Total+=OrderOpenPrice()*OrderLots();
            OpenLots+=OrderLots();
          }
  if(Total > 0 && OpenLots > 0)
    AveragePrice=NormalizeDouble(Total/OpenLots,Digits);
  return(AveragePrice);
}
//-----------------------------------------------------------------------------------
int SendMarketOrder(int Type,double Lots,int TP,int SL,int MN,string Cmnt,int &error)
{
  double Price,Take,Stop;
  int Ticket = 0,slippage,Color,Err;
  bool Delay=False;
  while(!IsStopped())
  {
    if(!IsExpertEnabled())
    {
      Error=ERR_TRADE_DISABLED;
      Print("!LET ME TRADE!");
      return(-1);
    }
    if(!IsConnected()) Print("!NO CONNECTION!");
    if(IsTradeContextBusy())
    {
      Print("Trade Context Busy!");
      Sleep(3000);
      Delay=True;
      continue;
    }
    if(Delay || (LastTickTime!=MarketInfo(Symbol(),MODE_TIME)))
    {
      RefreshRates();
      LastTickTime=MarketInfo(Symbol(),MODE_TIME);
      Delay=False;
    }
    else
    {
      //if(Debug) Print("Котировки актуальны");
    }
    switch(Type)
    {
      case OP_BUY:
        Price = NormalizeDouble(Ask,Digits);
        Take = IIFd(TP == 0, 0, NormalizeDouble( Price + TP * Point, Digits));
        Stop = IIFd(SL == 0, 0, NormalizeDouble( Price - SL * Point, Digits));
        Color = Blue;
        break;
      case OP_SELL:
        Price= NormalizeDouble(Bid,Digits);
        Take = IIFd(TP == 0, 0, NormalizeDouble( Price - TP * Point, Digits));
        Stop = IIFd(SL == 0, 0, NormalizeDouble( Price + SL * Point, Digits));
        Color = Red;
        break;
      default:
        Print("!INVALID ORDER TYPE!");
        return(-1);
    }
    Slippage=MarketInfo(Symbol(),MODE_SPREAD);
    if(IsTradeAllowed())
    {
      Ticket=OrderSend(Symbol(),Type,Lots,Price,slippage,Stop,Take,Cmnt,MN,0,Color);
      if(Ticket<0)
      {
        Err=GetLastError();
        if(Err == 4   || //SERVER_BUSY
           Err == 129 || //INVALID_PRICE 
           Err == 135 || //PRICE_CHANGED 
           Err == 137 || //BROKER_BUSY 
           Err == 138 || //REQUOTE 
           Err == 146 || //TRADE_CONTEXT_BUSY
           Err == 136 )  //OFF_QUOTES
         {
           Print("!ERROR!(OrderSend - ",Err,"): ",ErrorDescription(Err));
           Print("Waiting 3 sec...");
           Sleep(3000);
           Delay = True;
           continue;
         }
         else
         {
           Print("!CRITICAL ERROR!(OrderSend - ",Err,"): ",ErrorDescription(Err));
           Error=Err;
           break;
         }
       }
       break;
    }
    else
    {
      Print("!LET ME TRADE!");
      break;
    }
  }
  if(!(Ticket > 0))
    Print("!ERROR! ORDER NOT SENT! (ErrorCode = ",Error,": ",ErrorDescription(Error),")");
  return(Ticket);
}
//------------------------------------------------------
double IIFd(bool condition,double ifTrue,double ifFalse)
{
  if(condition) return(ifTrue); else return(ifFalse);
}
//-------------------------
bool ModifyOrder(double TP)
{
  if(NormalizeDouble(OrderTakeProfit(),Digits) == NormalizeDouble(TP,Digits))
    return(true);
  while(!IsStopped())
  {
    if(!IsTesting())
    {
      if(IsTradeContextBusy())
      {
        Print("Trade context busy, waiting 3 sec...");
        Sleep(3000);
        continue;
      }
      if(!IsTradeAllowed())
      {
        Print("!LET ME TRADE!");
        Sleep(3000);
        continue;
      }
    }
    if(!OrderModify(OrderTicket(),OrderOpenPrice(),0,NormalizeDouble(TP,Digits),0,Yellow))
    {
      Print("!ORDER MODIFICATION FAILED! Have fun!");
      int Err = GetLastError();
      Print("Error(",Err,"): ",ErrorDescription(Err));
      break;
    }
    else
    {
      break;
    }
  }
  return(true);
}
//-----------------
int GetPrimSignal()
{
  int sig = 0;
  int num = PrimNumOfBars;
  double dist = PrimPriceDist;
  double NumberOfBars_Highest = NormalizeDouble(High[iHighest(NULL,0,MODE_HIGH,num,1)], Digits);
  double NumberOfBars_Lowest  = NormalizeDouble(Low[iLowest(NULL,0,MODE_LOW,num,1)], Digits);
  if(NormalizeDouble((Bid-NumberOfBars_Lowest) /Point,0)>=dist) sig = -1;
  if(NormalizeDouble((NumberOfBars_Highest-Ask)/Point,0)>=dist) sig = 1;
  return(sig);
}
//----------------
int GetOppSignal()
{
  int sig = 0;
  int num = OppNumOfBars;
  double dist = OppPriceDist;
  double NumberOfBars_Highest = NormalizeDouble(High[iHighest(NULL,0,MODE_HIGH,num,1)], Digits);
  double NumberOfBars_Lowest  = NormalizeDouble(Low[iLowest(NULL,0,MODE_LOW,num,1)], Digits);
  if(NormalizeDouble((Bid - NumberOfBars_Lowest) /Point,0)>= dist) sig = -1;
  if(NormalizeDouble((NumberOfBars_Highest - Ask)/Point,0)>= dist) sig = 1;
  return(sig);
}
//----------------
int GetSubSignal()
{
  int sig=0;
  int num = SubNumOfBars;
  double dist = SubSigDist;
  double NumberOfBars_Highest = NormalizeDouble(High[iHighest(NULL,0,MODE_HIGH,num,1)], Digits);
  double NumberOfBars_Lowest  = NormalizeDouble(Low[iLowest(NULL,0,MODE_LOW,num,1)], Digits);
  if(NormalizeDouble((Bid - NumberOfBars_Lowest)/ Point,0)>=dist) sig =-1;
  if(NormalizeDouble((NumberOfBars_Highest - Ask)/Point,0)>=dist) sig = 1;
  return(sig);
}
//---------------------------