//+-------------------------------------------+
//|             Bulldozer_A12_v4.5_Nonius.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 TradesSet          = "Trades Set";
extern int    MaxBalanceLoss     = 60;    // сколько %% депозита надо потерять, когда сов закроет в убыток 1-й, самый дальний от цены ордер
                                          // ! eсли на счете несколько пар, могут закрыться по 1-му ордеру на разных парах!
extern int    MaxTrades          = 6;     // максимальное количество ордеров в серии в каждую сторону
extern bool   TwoWayTrade        = True;  // Если False, то ордера противоположного открытой серии направления не открываются
//-------------------------------------
extern string LotSet             = "Lot Set";
extern double InitLot            = 0.01;  // размер лота для начала торгов
extern int    LotDecimal         = 2;     // количество десятичных знаков лота
extern double MaxLot             = 0.2;   // максимальный лот
//-------------------------------------
extern string TPSet              = "TakeProfit Set";
extern int    TakeProfit         = 100;   //ТП в пунктах
//-------------------------------------
extern string LimitSet           = "LimitOrders Set";
extern int    LimitLotMode       = 0;     //прогрессия роста лота: 0 - геометрическая, 1 - арифметическая
extern double LimitLotExp        = 1.8;   //экспонента лотов - на cколько умножать лот предыдущего ордера, 1 для статических равных лотов
extern double LimitLotInc        = 0.02;  //инкремент лотов - cколько добавлять к лоту предыдущего ордера, 0 для статических равных лотов
extern int    InitLimitStep      = 300;   //начальное расстояние (в пунктах) до лимитного ордера
extern int    LimitStepMode      = 1;     // 0 - Геометрическая прогрессия, умножение LimitStep на LimitStepExp;
                                          // 1 - Арифметическая прогрессия, добавление к LimitStep LimitStepInc;
extern int    StartDynLimitStep  = 2;     // сколько рыночных ордеров должно быть, чтобы начал увеличиваться шаг LimitStep
extern double LimitStepExp       = 1.3;   // на сколько умножать LimitStep, для статического шага выставить 1
extern int    LimitStepInc       = 200;   // сколько добавлять к LimitStep, для статического шага выставить 0                                          
extern int    LimitTP            = 100;   //TP лимитной отложки, если 0, то TP не выставляется
//-------------------------------------
extern string SigSet             = "Signals Set";
extern bool   InvertSignal       = False; // включение инвертации сигнала на рывок
extern int    PriceDistance      = 500;   // какая требуется разница в цене между текущей ценой и наивысшем/наинизшем баре из числа анализируемых
extern int    NumberOfBars       = 18;    // сколько баров анализировать
//-------------------------------------
extern string GenSet             = "General Set";
extern int    MN_Buy             = 0;
extern int    MN_Sell            = 0;
extern bool   Debug              = True;
//-------------------------------------
string   ExpertName = "Bulldozer_A12_v4.5_Nonius";
double   LastTickTime;
int      Slippage, Error = 0, n, StopLevel;
bool     InitFail = False;
int      LimitExpire = 0; //Срок истечения отложенного ордера в минутах, если 0, то срок не ограничен (1440 = 24 часа)
int      LimitSL = 0;     //SL отложки, если 0, то SL не выставляется
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);
  }
  if(InitFail)
  { 
    if(Debug) Print("!INITIALIZATION FAILED!");
    return(0);
  }
  return(0);
}
// ----- EA deinitialization function -----
int deinit()
{
  return(0);
}
// ----- EA start function -----
int start()
{
  int    Signal, Ticket;
  int    TotalOrders, BuyOrders, SellOrders;
//  int    PipStepBuy, PipStepSell, LimitStep;
  int    LimitStepBuy, LimitStepSell;
  bool   result;
  double TickValue;
  double NewLotBuy, NewLotSell, TotalLots;
  double ProfitPips;
  double LastBuyPrice, LastSellPrice, NewTPPrice;
  double LimitPriceBuy,LimitPriceSell;
  double LastLotBuy, LastLotSell;
  double LimitLotBuy, LimitLotSell;
//------------------------------
  // Здесь часть кода, которая работает при каждом новом тике
  LastTickTime = MarketInfo(Symbol(), MODE_TIME);
  Slippage     = MarketInfo(Symbol(), MODE_SPREAD);
  StopLevel    = MarketInfo(Symbol(), MODE_STOPLEVEL);
  //---------- проверка счета -----------
  if(AccountEquity() <= AccountBalance() * (100 - MaxBalanceLoss) / 100)
  {//если потеряно >= MaxBalanceLoss депозита - закрываем первый, самый дальний от текущей цены ордер
    Ticket = FindFirstOrder();
    //---------------------------------------
    if(OrderSelect(Ticket, SELECT_BY_TICKET))
    {
      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) RecalculateTP(OP_BUY);
      }//exit 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) RecalculateTP(OP_SELL);
      }//exit if(OrderType() == OP_SELL)
    }//exit if(OrderSelect(Ticket, SELECT_BY_TICKET))
  }//exit if(AccountEquity() <= AccountBalance() * (100 - MaxBalanceLoss) / 100)
  //----------------------------
  TotalOrders = CountOfOrders();
  BuyOrders  = CountOfBuy();
  //---удаление осиротевших отложек---
  if((BuyOrders == 0) && (CountOfLimitBuy() > 0))
    DeleteLimitBuy();
  SellOrders = CountOfSell();
  if((SellOrders == 0) && (CountOfLimitSell() > 0))
    DeleteLimitSell();
  //------------------
  if(InvertSignal)  Signal = -GetSignal();
  if(!InvertSignal) Signal =  GetSignal();
  //------------------
  if(TotalOrders == 0) //если нет своих ордеров на рынке
  { 
    switch(Signal)
    { 
      case 1: //если сигнал Бай
        if(Debug) Print("Sending 1st BUY order, InitLot = ",InitLot);
        Ticket = SendMarketOrder(OP_BUY, InitLot, 0, 0, MN_Buy, ExpertName + "-" + (TotalOrders+1) + "-" + 0, Error);
        if(Ticket > 0)
          if(OrderSelect(Ticket, SELECT_BY_TICKET))
          {
            NewTPPrice = OrderOpenPrice() + (TakeProfit * Point);
            ModifyOrder(NewTPPrice);
          }
        break;
      case -1: //если сигнал Селл
        if(Debug) Print("Sending 1st SELL order, InitLot = ",InitLot);
        Ticket = SendMarketOrder(OP_SELL, InitLot, 0, 0, MN_Sell, ExpertName + "-" + (TotalOrders+1) + "-" + 0, Error);
        if(Ticket > 0)
          if(OrderSelect(Ticket, SELECT_BY_TICKET))
          {
            NewTPPrice = OrderOpenPrice() - (TakeProfit * Point);
            ModifyOrder(NewTPPrice);
          }
        break;
      default:
        break;
    }//exit switch(Signal)
    return(0);
  }//exit if(TotalOrders == 0)
  //-----------------
  if(TotalOrders > 0) //если есть хотя бы один свой ордер на рынке
  { 
    //----------------
    if((BuyOrders == 0) && (TwoWayTrade))
    {
      if(Signal == 1)
      {
        NewLotBuy = InitLot;
        if(Debug) Print("Sending 1st BUY order, InitLot = ",NewLotBuy);
        Ticket = SendMarketOrder(OP_BUY, NewLotBuy, 0, 0, MN_Buy, ExpertName + "-" + (BuyOrders+1) + "-" + 0, Error);
        if(Ticket > 0)
        {
          if(OrderSelect(Ticket, SELECT_BY_TICKET))
          {
            NewTPPrice = OrderOpenPrice() + (TakeProfit * Point);
            ModifyOrder(NewTPPrice);
          }
        }//exit if(Ticket > 0)
      }//exit if(Signal == 1)
    }//exit if(BuyOrders == 0)
    //-----------------
    if((SellOrders == 0) && (TwoWayTrade))
    {
      if(Signal == -1)
      {
        NewLotSell = InitLot;
        if(Debug) Print("Sending 1st SELL order, InitLot = ",NewLotSell);
        Ticket = SendMarketOrder(OP_SELL, NewLotSell, 0, 0, MN_Sell, ExpertName + "-" + (SellOrders+1) + "-" + 0, Error);
        if(Ticket > 0)
        {
          if(OrderSelect(Ticket, SELECT_BY_TICKET))
          {
            NewTPPrice = OrderOpenPrice() - (TakeProfit * Point);
            ModifyOrder(NewTPPrice);
          }
        }//exit if(Ticket > 0)
      }//exit if(Signal == -1)
    }//exit if(SellOrders == 0)
    //---------------
    if((BuyOrders > 0) && (BuyOrders < MaxTrades))//если есть хотя бы один свой рыночный ордер BUY
    { 
      RecalculateTP(OP_BUY);     //проверяем не выставлен ли ручной ордер BUY без ТП
      if(CountOfLimitBuy() == 0) //если лимитная отложка BUY не выставлена или стала рыночным ордером
      {
        BuyOrders = CountOfBuy();//пересчитываем BUY ордера, тк отложка могла стать рыночным ордером
        //---цена лимитной отложки BUY---
        if(BuyOrders < StartDynLimitStep)
          LimitStepBuy = InitLimitStep;
        if(BuyOrders >= StartDynLimitStep) //динамический ЛимитСтеп
        {
          if(LimitStepMode == 0) //геометрическая прогрессия степа
            LimitStepBuy = NormalizeDouble(InitLimitStep * MathPow(LimitStepExp, (BuyOrders - StartDynLimitStep + 1)), 0);
          if(LimitStepMode == 1) //арифметическая прогрессия степа
            LimitStepBuy = InitLimitStep + LimitStepInc * (BuyOrders - StartDynLimitStep + 1);
        }//exit if(BuyOrders >= StartDynLimitStep)
        //LimitPriceBuy = NormalizeDouble(Ask - LimitStep * Point, Digits);
        LastBuyPrice = FindLastBuyPrice();
        LimitPriceBuy = NormalizeDouble(LastBuyPrice - LimitStepBuy * Point, Digits);
        if((Ask - LimitPriceBuy) / Point < StopLevel) //если цена отложки слишком близко к текущей цене
        {
          if(Debug) Print("1st Order BuyLimit cannot be closer than ",StopLevel," points");
          return;
        }
        //---лот лимитной отложки BUY---
        if(LimitLotMode == 0) //геометрическая прогрессия лота
          LimitLotBuy = NormalizeDouble(FindLastLotBuy() * LimitLotExp, LotDecimal);
        if(LimitLotMode == 1) //арифметическая прогрессия лота
          LimitLotBuy = NormalizeDouble(FindLastLotBuy() + LimitLotInc, LotDecimal);
        if(LimitLotBuy > MaxLot) LimitLotBuy = MaxLot;
        //---открытие лимитной отложки BUY---
        OpenLimitOrder(OP_BUYLIMIT,LimitPriceBuy,LimitLotBuy);
      }//exit if(CountOfLimitBuy() = 0)
    }//exit if((BuyOrders > 0) && (BuyOrders < MaxTrades))
    //----------------
    if((SellOrders > 0) && (SellOrders < MaxTrades)) //если есть хотя бы один свой рыночный ордер SELL
    { 
      RecalculateTP(OP_SELL);       //проверяем не выставлен ли ручной ордер SELL без ТП
      if(CountOfLimitSell() == 0)   //если лимитная отложка SELL не выставлена или стала рыночным ордером
      {
        SellOrders = CountOfSell(); //пересчитываем SELL ордера, тк отложка могла стать рыночным ордером
        //---цена лимитной отложки SELL---
        if(SellOrders < StartDynLimitStep)
          LimitStepSell = InitLimitStep;
        if(SellOrders >= StartDynLimitStep) //динамический ЛимитСтеп
        {
          if(LimitStepMode == 0) //геометрическая прогрессия степа
            LimitStepSell = NormalizeDouble(InitLimitStep * MathPow(LimitStepExp, (SellOrders - StartDynLimitStep + 1)), 0);
          if(LimitStepMode == 1) //арифметическая прогрессия степа
            LimitStepSell = InitLimitStep + LimitStepInc * (SellOrders - StartDynLimitStep + 1);
        }//exit if(SellOrders >= StartDynLimitStep)
        //LimitPriceSell = NormalizeDouble(Bid + LimitStepSell * Point, Digits);
        LastSellPrice = FindLastSellPrice();
        LimitPriceSell = NormalizeDouble(LastSellPrice + LimitStepSell * Point, Digits);
        if((LimitPriceSell - Bid) / Point < StopLevel)
        {
          if(Debug) Print("1st Order SellLimit cannot be closer than ",StopLevel," points");
          return;
        }
        //---лот лимитной отложки SELL---
        if(LimitLotMode == 0) //геометрическая прогрессия лота
          LimitLotSell = NormalizeDouble(FindLastLotSell() * LimitLotExp, LotDecimal);
        if(LimitLotMode == 1) //арифметическая прогрессия лота
          LimitLotSell = NormalizeDouble(FindLastLotSell() + LimitLotInc, LotDecimal);
        if(LimitLotSell > MaxLot) LimitLotSell = MaxLot;
        //---открытие лимитной отложки SELL---
        OpenLimitOrder(OP_SELLLIMIT,LimitPriceSell,LimitLotSell);
      }//exit if(CountOfLimitSell() = 0)
    }//exit if((SellOrders > 0) && (SellOrders < MaxTrades))
  }//exit if(TotalOrders > 0)
  return(0);
}// exit start function
//--------------
int CountOfOrders()
{
  int count = 0;
  for(int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if((OrderMagicNumber() == MN_Buy) || (OrderMagicNumber() == MN_Sell)) 
          if((OrderType() == OP_BUY) || (OrderType() == OP_SELL)) 
            count++;
  return(count);
}
//--------------
int CountOfBuy()
{
  int count = 0;
  for(int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Buy) 
          if(OrderType() == OP_BUY) 
            count++;
  return(count);
}
//---------------
int CountOfSell()
{
  int count = 0;
  for(int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Sell) 
          if(OrderType() == OP_SELL) 
            count++;
  return(count);
}
//-------------------
int CountOfLimitBuy()
{
  int count = 0;
  for(int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Buy) 
          if(OrderType() == OP_BUYLIMIT) 
            count++;
  return(count);
}
//--------------------
int CountOfLimitSell()
{
  int count = 0;
  for(int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Sell) 
          if(OrderType() == OP_SELLLIMIT) 
            count++;
  return(count);
}
//------------------
int FindFirstOrder()
{
  int ticket = 0;
  for(int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol()) 
        if((OrderMagicNumber() == MN_Buy) || (OrderMagicNumber() == MN_Sell))
          if((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
            if(OrderProfit() < 0)
            {
              if(ticket == 0) 
                ticket = OrderTicket();
              if(OrderTicket() < ticket)
                ticket = OrderTicket();
            }
  return(ticket);
}
//---------------------
double FindLastLotBuy()
{ 
  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() == OP_BUY)
          if(OrderMagicNumber() == MN_Buy) 
            if(OrderTicket() > ticket)
            {
              ticket = OrderTicket();
              lot = OrderLots();
            }
  //if(Debug) Print("LastLotBuy = ", lot);
  return(lot);
}
//----------------------
double FindLastLotSell()
{ 
  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() == OP_SELL)
          if(OrderMagicNumber() == MN_Sell) 
            if(OrderTicket() > ticket)
            {
              ticket = OrderTicket();
              lot = OrderLots();
            }
  //if(Debug) Print("LastLotSell = ", lot);
  return(lot);
}
//-----------------------
double FindLastBuyPrice()
{
  double LastBuyPrice;
  int LastBuyTicket;
  int ticket = 0;
  for (int cnt = OrdersTotal() - 1; cnt >= 0; cnt--)
    if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Buy) 
          if(OrderType() == OP_BUY) 
          {
            LastBuyTicket = OrderTicket();
            if(LastBuyTicket > ticket) 
            {
              LastBuyPrice = OrderOpenPrice();
              ticket = LastBuyTicket;
            }
          }
//  if(Debug) Print("LastBuyPrice = ",LastBuyPrice);
  return(LastBuyPrice);
}
//------------------------
double FindLastSellPrice()
{
  double LastSellPrice;
  int LastSellTicket;
  int ticket = 0;
  for (int cnt = OrdersTotal() - 1; cnt >= 0; cnt--)
    if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Sell) 
          if(OrderType() == OP_SELL) 
          {
            LastSellTicket = OrderTicket();
            if(LastSellTicket > ticket) 
            {
              LastSellPrice = OrderOpenPrice();
              ticket = LastSellTicket;
            }
          }
//  if(Debug) Print("LastSellPrice = ",LastSellPrice);
  return(LastSellPrice);
}
//--------------------------
void RecalculateTP(int Type)
{
  double NewTPPrice;
  if(Type == OP_BUY)
  {
    NewTPPrice = NormalizeDouble(CalculateAveragePriceBuy() + (TakeProfit * Point), Digits);
    for (int i = 0; i < OrdersTotal(); i++) 
    if(OrderSelect(i, SELECT_BY_POS))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Buy) 
          if(OrderType()== OP_BUY)
            //if(OrderTakeProfit() != NewTPPrice)
            if(NormalizeDouble(OrderTakeProfit(),Digits) != NormalizeDouble(NewTPPrice,Digits))
              ModifyOrder(NewTPPrice);
  }
  if(Type == OP_SELL)
  {
    NewTPPrice = NormalizeDouble(CalculateAveragePriceSell() - (TakeProfit * Point), Digits);
    for (int j = 0; j < OrdersTotal(); j++) 
    if(OrderSelect(j, SELECT_BY_POS))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Sell) 
          if(OrderType()== OP_SELL)
            //if(OrderTakeProfit() != NewTPPrice)
            if(NormalizeDouble(OrderTakeProfit(),Digits) != NormalizeDouble(NewTPPrice,Digits))
              ModifyOrder(NewTPPrice);
  }
  return;
}
//-------------------------------
double CalculateAveragePriceBuy()
{
  double Result = 0;
  double AveragePrice = 0;
  double Count = 0;
  for(int i = 0; i < OrdersTotal(); i++)
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Buy)
          if(OrderType() == OP_BUY) 
          {
            AveragePrice += OrderOpenPrice() * OrderLots();
            Count += OrderLots();
          }
  if(AveragePrice > 0 && Count > 0)
    Result = NormalizeDouble(AveragePrice / Count, Digits);
  return(Result);
}
//+------------------------------------------------------------------+
double CalculateAveragePriceSell()
{
  double Result = 0;
  double AveragePrice = 0;
  double Count = 0;
  for (int i = 0; i < OrdersTotal(); i++)
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      if(OrderSymbol() == Symbol())
        if(OrderMagicNumber() == MN_Sell)
          if(OrderType() == OP_SELL) 
          {
            AveragePrice += OrderOpenPrice() * OrderLots();
            Count += OrderLots();
          }
  if(AveragePrice > 0 && Count > 0)
    Result = NormalizeDouble(AveragePrice / Count, Digits);
  return(Result);
}
//+------------------------------------------------------------------+
int SendMarketOrder(int Type, double Lots, int TP, int SL, int Magic, string Cmnt, int& Error)
{
  double Price, Take, Stop;
  int Ticket, Slippage, Color, Err; 
  bool Delay = False;
  //if(Debug) Print("Функция SendMarketOrder");
  while(!IsStopped())
  {
    if(!IsExpertEnabled())
    {
      Error = ERR_TRADE_DISABLED;
      Print("!LET ME TRADE!");
      return(-1);
    }
    //if(Debug) Print("Эксперту разрешено торговать");
    if(!IsConnected())
      Print("!NO CONNECTION!");
    //if(Debug) Print("Связь с сервером установлена");
    if(IsTradeContextBusy())
    {
      Print("Trade Context Busy!");
      Sleep(3000);
      Delay = True;
      continue;
    }
    //if(Debug) Print("Торговый поток свободен");
    if(Delay || (LastTickTime != MarketInfo(Symbol(),MODE_TIME))) 
    {
      //if(Debug) Print("Обновляем котировки");
      RefreshRates();
      LastTickTime = MarketInfo(Symbol(),MODE_TIME);
      Delay = False;
    }
    else
    {
      //if(Debug) Print("Котировки актуальны");
    }
    switch(Type)
    {
      case OP_BUY:
        //if(Debug) Print("Инициализируем параметры для 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:
        //if(Debug) Print("Инициализируем параметры для 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(Debug) Print("Slippage = ",Slippage);
    if(IsTradeAllowed())
    {
      //if(Debug) Print("Торговля разрешена, отправляем ордер...");
      Ticket = OrderSend(Symbol(), Type, Lots, Price, Slippage, Stop, Take, Cmnt, Magic, 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)
    //if(Debug) Print("Order sent OK, Ticket = ",Ticket);
  if(!(Ticket > 0))
    Print("!ERROR! ORDER NOT SENT! (ErrorCode = ", Error, ": ", ErrorDescription(Error), ")");
  return(Ticket);
}
//-------------------------------------------------------
void OpenLimitOrder(int LimitType,double Price,double LOT)
{
  int error,err;
  double SL,TP;
  while(true)
  {  
    error=true;
    if(LimitType==OP_SELLLIMIT) 
    {
      if(LimitTP!=0) TP = NormalizeDouble(Price - LimitTP*Point,Digits); else TP=0;
      if(LimitSL!=0) SL = NormalizeDouble(Price + LimitSL*Point,Digits); else SL=0;          
      error=OrderSend(Symbol(),LimitType, LOT,Price,Slippage,SL,TP,"-",MN_Sell,expiration,CLR_NONE);
    }
    if(LimitType==OP_BUYLIMIT) 
    {
      if(LimitTP!=0) TP = NormalizeDouble(Price + LimitTP*Point,Digits); else TP=0;
      if(LimitSL!=0) SL = NormalizeDouble(Price - LimitSL*Point,Digits); else SL=0;    
      error=OrderSend(Symbol(),LimitType,LOT,Price,Slippage,SL,TP,"-",MN_Buy,expiration,CLR_NONE);
    }
    if(error==-1)
    {  
      Print("\nError ",GetLastError());
      if(LimitType==OP_SELLLIMIT) Print("Opened Order SELL LIMIT, Ask =",DoubleToStr(Ask,Digits),"  Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Price-Ask)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((Price-SL)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((TP-Price)/Point,0),")  StopLevel=",StopLevel);
      if(LimitType==OP_BUYLIMIT)  Print("Opened Order BUY  LIMIT, Bid =",DoubleToStr(Bid,Digits),"  Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Bid-Price)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((SL-Price)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((Price-TP)/Point,0),")  StopLevel=",StopLevel);
      err++;Sleep(1000);RefreshRates();
    }
    else 
    {
      n++;
      return;
    }
  }
  return;
}                  
//-------------------
void DeleteLimitBuy()
{
  int Ticket;
  for(int i = OrdersTotal(); i >=0 ; i--)
  {
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    {
      if(OrderType() == OP_BUYLIMIT && OrderSymbol()==Symbol())
      {
        Ticket = OrderTicket();
        while(true)
        {
          if(OrderDelete(Ticket, CLR_NONE))
          { 
            //Print("OrderDelete ",Ticket);
            break;
          }
          else
          {
            Print("OrderDelete error ",GetLastError()," Ticket ",Ticket);
          }
        }
      }
    }
  }
  return(0);
}
//--------------------
void DeleteLimitSell()
{
  int Ticket;
  for(int i = OrdersTotal(); i >=0 ; i--)
  {
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    {
      if(OrderType() == OP_SELLLIMIT && OrderSymbol()==Symbol())
      {
        Ticket = OrderTicket();
        while(true)
        {
          if(OrderDelete(Ticket, CLR_NONE))
          { 
            //Print("OrderDelete ",Ticket);
            break;
          }
          else
          {
            Print("OrderDelete error ",GetLastError()," Ticket ",Ticket);
          }
        }
      }
    }
  }
  return(0);
}
//--------------------------------------------------------
double IIFd(bool condition, double ifTrue, double ifFalse) 
{
  if (condition) return(ifTrue); else return(ifFalse);
}
//---------------------------------------------------
bool ModifyOrder(double TakeProfit)
{
  int Err;
  int ticket = OrderTicket();
  //if(OrderTakeProfit() == TakeProfit)
  if(NormalizeDouble(OrderTakeProfit(),Digits) == NormalizeDouble(TakeProfit,Digits))
    return(true);
  while(!IsStopped())
  {
    //if(Debug) Print("Function ModifyOrder");
    if(!IsTesting())
    {
      if(IsTradeContextBusy())
      {
        Print("Trade context busy, waiting 3 sec...");
        Sleep(3000);
        continue;
      }
      //if(Debug) Print("Trade context OK");
      if(!IsTradeAllowed())
      {
        Print("!LET ME TRADE!");
        Sleep(3000);
        continue;
      }
      //if(Debug) Print("Modifying Order # ",OrderTicket());
    }
    //-----------------------    
    if(OrderType() == OP_BUY)
    {
      if(!OrderModify(OrderTicket(), OrderOpenPrice(), 0, NormalizeDouble(TakeProfit, Digits), 0, CLR_NONE))
      {
        Print("!BUY ORDER ",ticket," MODIFICATION FAILED!");
        Err = GetLastError();
        Print("Error(",Err,"): ",ErrorDescription(Err));
        break;
      }
      else
      {
        //if(Debug) Print("Order Modification OK");
        break;
      }
    }//exit if(OrderType() == OP_BUY)
    //-----------------------    
    if(OrderType() == OP_SELL)
    {
      if(!OrderModify(OrderTicket(), OrderOpenPrice(), 0, NormalizeDouble(TakeProfit, Digits), 0, CLR_NONE))
      {
        Print("!SELL ORDER ",ticket," MODIFICATION FAILED!");
        Err = GetLastError();
        Print("Error(",Err,"): ",ErrorDescription(Err));
        break;
      }
      else
      {
        //if(Debug) Print("Order Modification OK");
        break;
      }
    }//exit if(OrderType() == OP_SELL)
  }//exit while(!IsStopped())
  return(true);
}
//-----------------
int GetSignal() //every tick
{
  int sig = 0;
  int num = NumberOfBars;
  double dist = PriceDistance;
  
  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);
}
//-----------------