← К каталогу
Исходный код · ID 2788

Blessing 3

blessing_3_v3.9.6.23.mq4

Похожие материалы по тегам

blessing_3_v3_9_6.mq4MQL4 / MetaTrader 4 · 4 общих теговblessing_3_v3.9.6.15.mq4MQL4 / MetaTrader 4 · 4 общих теговblessing 3 v4.mq4MQL4 / MetaTrader 4 · 4 общих теговblessing_3_v3.9.6.21.mq4MQL4 / MetaTrader 4 · 4 общих теговblessing_3_v3.9.6.18.mq4MQL4 / MetaTrader 4 · 4 общих теговblessinglite-gamma.mq4MQL4 / MetaTrader 4 · 4 общих тегов
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

Blessing 3 v3.9.6.23 — торговый советник для MetaTrader 4, работающий на языке MQL4. Советник обрабатывает рыночные и торговые события, анализирует ценовые данные и технические показатели, использует торговые операции MetaTrader и отправляет уведомления о событиях и условиях. В исходном коде присутствуют обработчики событий, функции работы с ордерами и позициями, а также вспомогательные функции для отображения информации на графике. Советник поддерживает настройку торговых параметров, управление рисками, хеджирование и отправку email-уведомлений. Все настройки задаются через входные параметры, которые можно изменять в окне свойств советника. Код содержит большое количество пользовательских настроек, сгруппированных по категориям: торговые параметры, настройки сетки, хеджирование, управление капиталом, отображение и оптимизация. Советник не является библиотекой или индикатором, а представляет собой полноценный торговый робот для автоматической торговли на платформе MetaTrader 4.

Настройки программы

НастройкаОписание
Version_3_9_6_23 Отображает версию советника.
TradeComment Комментарий, добавляемый к торговым операциям советника.
Notes Произвольные заметки пользователя, не влияющие на работу советника.
EA Magic Number (EANumber) Уникальный номер советника (Magic Number), используемый для идентификации ордеров, открытых этим советником.
CLOSE ALL NOW *** (EmergencyCloseAll) Экстренно закрывает все открытые позиции и удаляет отложенные ордера.
. (s1) Разделитель в списке параметров.
NO NEW TRADES *** (ShutDown) Запрещает открытие новых сделок, но не закрывает существующие позиции.
. (s2) Разделитель в списке параметров.
== ACCOUNT SETTINGS == (LabelAcc) Заголовок раздела настроек аккаунта.
. (s3) Разделитель в списке параметров.
Opt. with 'Open prices only' -- (eopb) Вспомогательный параметр для режима 'Open prices only'.
EnableOncePerBar Включает режим, при котором торговые сигналы проверяются только один раз на бар, что ускоряет оптимизацию.
UseMinMarginPercent Включает контроль минимального процента свободной маржи.
MinMarginPercent Минимальный процент свободной маржи, при котором разрешена торговля.
. (eopb1) Вспомогательный параметр для режима 'Open prices only'.
CUSTOM TESTER SETTINGS ------ (LabelTST) Заголовок раздела пользовательских настроек тестера.
. (LabelTST2) Разделитель для пользовательских настроек тестера.
LOT SIZE ----------- (LabelLS) Заголовок раздела размера лота.
GRID SETTINGS ------ (LabelGS) Заголовок раздела настроек сетки.
===== TRADING ===== (LabelTS) Заголовок раздела торговых настроек.
EXITS ----------- (LabelES) Заголовок раздела выходов.
EARLY EXITS --------- (LabelEE) Заголовок раздела ранних выходов.
. (LabelAdv) Разделитель для дополнительных настроек.
GRID SIZE --------- (LabelGrid) Заголовок раздела размера сетки.
. (LabelEST0) Разделитель для параметров входа.
== ENTRY PARAMETERS == (LabelEST) Заголовок раздела параметров входа.
MA ------------- (LabelMA) Заголовок раздела настроек скользящей средней.
CCI ------------- (LabelCCI) Заголовок раздела настроек CCI.
BOLLINGER BANDS ----- (LabelBBS) Заголовок раздела настроек Bollinger Bands.
ICHIMOKU CLOUD ----- (LabelIchi) Заголовок раздела настроек Ichimoku Cloud.
Ichimoku Entry (IchimokuEntry) Выбор режима входа по индикатору Ichimoku.
TF setting, but only current will work (ICHI_TF) Таймфрейм для индикатора Ichimoku (работает только текущий).
Tenkan (Tenkan_Sen) Период линии Tenkan в индикаторе Ichimoku.
Kijun (Kijun_Sen) Период линии Kijun в индикаторе Ichimoku.
Senkou (Senkou_Span) Период линии Senkou в индикаторе Ichimoku.
Trade if price breaks cloud / Kumo (useCloudBreakOut) Включает торговлю при пробое облака (Kumo).
Trade if Tenken crosses Kijun (useTenken_Kijun_cross) Выбор режима торговли при пересечении Tenkan и Kijun.
Trade if Price crosses Tenken (usePriceCrossTenken) Включает торговлю при пересечении ценой линии Tenkan.
Trade if price crosses Kijun (usePriceCrossKijun) Включает торговлю при пересечении ценой линии Kijun.
Trade if chiku crosses Price (useChikuspan) Включает торговлю при пересечении линии Chikou Span с ценой.
Close all orders if price dives into the cloud/kumo (useCloudSL) Закрывает все ордера, если цена входит в облако (Kumo).
STOCHASTIC -------- (LabelSto) Заголовок раздела настроек стохастика.
MACD ------------ (LabelMACD) Заголовок раздела настроек MACD.
SMART GRID --------- (LabelSG) Заголовок раздела умной сетки.
. (LabelHS0) Разделитель для настроек хеджирования.
HEDGE SETTINGS ----- (LabelHS) Заголовок раздела настроек хеджирования.
. (LabelOS0) Разделитель для прочих настроек.
OTHER ----------- (LabelOS) Заголовок раздела прочих настроек.
EMAIL ------------ (LabelUE) Заголовок раздела настроек email.
UseEmail Включает отправку email-уведомлений о событиях советника.
. (LabelEDD) Разделитель для настроек email-просадки.
EmailDD1 Первый порог просадки для отправки email-уведомления.
EmailDD2 Второй порог просадки для отправки email-уведомления.
EmailDD3 Третий порог просадки для отправки email-уведомления.
. (LabelEH) Разделитель для настроек email-часов.
Minimum number of hours between emails (EmailHours) Минимальное количество часов между отправкой email-уведомлений.
DISPLAY ----------- (LabelDisplay) Заголовок раздела настроек отображения.
Debug Включает или выключает вывод отладочных сообщений в журнал.
GRID OPTIMIZATION ---- (LabelGridOpt) Заголовок раздела оптимизации сетки.
. (LabelOpt) Разделитель для настроек оптимизации.
SetArray1 Первый параметр для оптимизации настроек.
SetArray2 Второй параметр для оптимизации настроек.
SetArray3 Третий параметр для оптимизации настроек.
SetArray4 Четвёртый параметр для оптимизации настроек.
GridArray1 Первый параметр сетки для оптимизации.
GridArray2 Второй параметр сетки для оптимизации.
GridArray3 Третий параметр сетки для оптимизации.
GridArray4 Четвёртый параметр сетки для оптимизации.
GridArray5 Пятый параметр сетки для оптимизации.
TPArray1 Первый параметр тейк-профита для оптимизации.
TPArray2 Второй параметр тейк-профита для оптимизации.
TPArray3 Третий параметр тейк-профита для оптимизации.
TPArray4 Четвёртый параметр тейк-профита для оптимизации.
TPArray5 Пятый параметр тейк-профита для оптимизации.
Получить полный код

Поиск по коду файла

#property version   "396.23"
#property strict

#ifdef __MQL5__

#define MT4_TICKET_TYPE

#ifndef __MT4ORDERS__

#ifdef MT4ORDERS_BENCHMARK_MINTIME
  #include <fxsaber\Benchmark.mqh> // 

  #define _B2(A) _B(A, MT4ORDERS_BENCHMARK_MINTIME)
  #define _B3(A) _B(A, 1)
  #define _BV2(A) _BV(A, MT4ORDERS_BENCHMARK_MINTIME)
#else // MT4ORDERS_BENCHMARK_MINTIME
  #define _B2(A) (A)
  #define _B3(A) (A)
  #define _BV2(A) { A; }
#endif // MT4ORDERS_BENCHMARK_MINTIME

#define __MT4ORDERS__ "2020.09.30"
#define MT4ORDERS_SLTP_OLD // Enabling the old mechanism for determining SL / TP closed positions via OrderClose

#ifdef MT4_TICKET_TYPE
  #define TICKET_TYPE int
  #define MAGIC_TYPE  int

  #undef MT4_TICKET_TYPE
#else // MT4_TICKET_TYPE
  #define TICKET_TYPE long // Negative values are also required for OrderSelectByTicket.
  #define MAGIC_TYPE  long
#endif // MT4_TICKET_TYPE

struct MT4_ORDER
{
  long Ticket;
  int Type;

  long TicketOpen;
  long TicketID;

  double Lots;

  string Symbol;
  string Comment;

  double OpenPriceRequest;
  double OpenPrice;

  long OpenTimeMsc;
  datetime OpenTime;

  ENUM_DEAL_REASON OpenReason;

  double StopLoss;
  double TakeProfit;

  double ClosePriceRequest;
  double ClosePrice;

  long CloseTimeMsc;
  datetime CloseTime;

  ENUM_DEAL_REASON CloseReason;

  ENUM_ORDER_STATE State;

  datetime Expiration;

  long MagicNumber;

  double Profit;

  double Commission;
  double Swap;

#define POSITION_SELECT (-1)
#define ORDER_SELECT (-2)

  static int GetDigits( double Price )
  {
    int Res = 0;

    while ((bool)(Price = ::NormalizeDouble(Price - (int)Price, 8)))
    {
      Price *= 10;

      Res++;
    }

    return(Res);
  }

  static string DoubleToString( const double Num, const int digits )
  {
    return(::DoubleToString(Num, ::MathMax(digits, MT4_ORDER::GetDigits(Num))));
  }

  static string TimeToString( const long time )
  {
    return((string)(datetime)(time / 1000) + "." + ::IntegerToString(time % 1000, 3, '0'));
  }

  static const MT4_ORDER GetPositionData( void )
  {
    MT4_ORDER Res = {0};

    Res.Ticket = ::PositionGetInteger(POSITION_TICKET);
    Res.Type = (int)::PositionGetInteger(POSITION_TYPE);

    Res.Lots = ::PositionGetDouble(POSITION_VOLUME);

    Res.Symbol = ::PositionGetString(POSITION_SYMBOL);

    Res.OpenPrice = ::PositionGetDouble(POSITION_PRICE_OPEN);
    Res.OpenTimeMsc = (datetime)::PositionGetInteger(POSITION_TIME_MSC);

    Res.StopLoss = ::PositionGetDouble(POSITION_SL);
    Res.TakeProfit = ::PositionGetDouble(POSITION_TP);

    Res.ClosePrice = ::PositionGetDouble(POSITION_PRICE_CURRENT);
    Res.CloseTimeMsc = 0;

    Res.Expiration = 0;

    Res.MagicNumber = ::PositionGetInteger(POSITION_MAGIC);

    Res.Profit = ::PositionGetDouble(POSITION_PROFIT);

    Res.Swap = ::PositionGetDouble(POSITION_SWAP);

    return(Res);
  }

  static const MT4_ORDER GetOrderData( void )
  {
    MT4_ORDER Res = {0};

    Res.Ticket = ::OrderGetInteger(ORDER_TICKET);
    Res.Type = (int)::OrderGetInteger(ORDER_TYPE);

    Res.Lots = ::OrderGetDouble(ORDER_VOLUME_CURRENT);

    Res.Symbol = ::OrderGetString(ORDER_SYMBOL);
    Res.Comment = ::OrderGetString(ORDER_COMMENT);

    Res.OpenPrice = ::OrderGetDouble(ORDER_PRICE_OPEN);
    Res.OpenTimeMsc = (datetime)::OrderGetInteger(ORDER_TIME_SETUP_MSC);

    Res.StopLoss = ::OrderGetDouble(ORDER_SL);
    Res.TakeProfit = ::OrderGetDouble(ORDER_TP);

    Res.ClosePrice = ::OrderGetDouble(ORDER_PRICE_CURRENT);
    Res.CloseTimeMsc = 0; // (datetime)::OrderGetInteger(ORDER_TIME_DONE)

    Res.Expiration = (datetime)::OrderGetInteger(ORDER_TIME_EXPIRATION);

    Res.MagicNumber = ::OrderGetInteger(ORDER_MAGIC);

    Res.Profit = 0;

    Res.Commission = 0;
    Res.Swap = 0;

    if (!Res.OpenPrice)
      Res.OpenPrice = Res.ClosePrice;

    return(Res);
  }

  string ToString( void ) const
  {
    static const string Types[] = {"buy", "sell", "buy limit", "sell limit", "buy stop", "sell stop", "balance"};
    const int digits = (int)::SymbolInfoInteger(this.Symbol, SYMBOL_DIGITS);

    MT4_ORDER TmpOrder = {0};

    if (this.Ticket == POSITION_SELECT)
    {
      TmpOrder = MT4_ORDER::GetPositionData();

      TmpOrder.Comment = this.Comment;
      TmpOrder.Commission = this.Commission;
    }
    else if (this.Ticket == ORDER_SELECT)
      TmpOrder = MT4_ORDER::GetOrderData();

    return(((this.Ticket == POSITION_SELECT) || (this.Ticket == ORDER_SELECT)) ? TmpOrder.ToString() :
           ("#" + (string)this.Ticket + " " +
            MT4_ORDER::TimeToString(this.OpenTimeMsc) + " " +
            ((this.Type < ::ArraySize(Types)) ? Types[this.Type] : "unknown") + " " +
            MT4_ORDER::DoubleToString(this.Lots, 2) + " " +
            (::StringLen(this.Symbol) ? this.Symbol + " " : NULL) +
            MT4_ORDER::DoubleToString(this.OpenPrice, digits) + " " +
            MT4_ORDER::DoubleToString(this.StopLoss, digits) + " " +
            MT4_ORDER::DoubleToString(this.TakeProfit, digits) + " " +
            ((this.CloseTimeMsc > 0) ? (MT4_ORDER::TimeToString(this.CloseTimeMsc) + " ") : "") +
            MT4_ORDER::DoubleToString(this.ClosePrice, digits) + " " +
            MT4_ORDER::DoubleToString(::NormalizeDouble(this.Commission, 3), 2) + " " + // Don't print more than three digits after the decimal point
            MT4_ORDER::DoubleToString(this.Swap, 2) + " " +
            MT4_ORDER::DoubleToString(this.Profit, 2) + " " +
            ((this.Comment == "") ? "" : (this.Comment + " ")) +
            (string)this.MagicNumber +
            (((this.Expiration > 0) ? (" expiration " + (string)this.Expiration): ""))));
  }
};

#define RESERVE_SIZE 1000
#define DAY (24 * 3600)
#define HISTORY_PAUSE (MT4HISTORY::IsTester ? 0 : 5)
#define END_TIME D'31.12.3000 23:59:59'
#define THOUSAND 1000
#define LASTTIME(A)                                          \
  if (Time##A >= LastTimeMsc)                                \
  {                                                          \
    const datetime TmpTime = (datetime)(Time##A / THOUSAND); \
                                                             \
    if (TmpTime > this.LastTime)                             \
    {                                                        \
      this.LastTotalOrders = 0;                              \
      this.LastTotalDeals = 0;                               \
                                                             \
      this.LastTime = TmpTime;                               \
      LastTimeMsc = this.LastTime * THOUSAND;                \
    }                                                        \
                                                             \
    this.LastTotal##A##s++;                                  \
  }

#ifndef MT4ORDERS_FASTHISTORY_OFF
  #include <Generic\HashMap.mqh>
#endif // MT4ORDERS_FASTHISTORY_OFF

class MT4HISTORY
{
private:
  static const bool MT4HISTORY::IsTester;

#ifndef MT4ORDERS_FASTHISTORY_OFF
  CHashMap<ulong, ulong> DealsIn;  // By positionID returns DealIn
  CHashMap<ulong, ulong> DealsOut; // By positionID returns DealOut
#endif // MT4ORDERS_FASTHISTORY_OFF

  long Tickets[];
  uint Amount;

  int LastTotalDeals;
  int LastTotalOrders;

#ifdef MT4ORDERS_HISTORY_OLD

  datetime LastTime;
  datetime LastInitTime;

  int PrevDealsTotal;
  int PrevOrdersTotal;

  bool IsChangeHistory( void )
  {
    bool Res = !_B2(::HistorySelect(0, INT_MAX));

    if (!Res)
    {
      const int iDealsTotal = ::HistoryDealsTotal();
      const int iOrdersTotal = ::HistoryOrdersTotal();

      if (Res = (iDealsTotal != this.PrevDealsTotal) || (iOrdersTotal != this.PrevOrdersTotal))
      {
        this.PrevDealsTotal = iDealsTotal;
        this.PrevOrdersTotal = iOrdersTotal;
      }
    }

    return(Res);
  }

  bool RefreshHistory( void )
  {
    bool Res = !MT4HISTORY::IsChangeHistory();

    if (!Res)
    {
      const datetime LastTimeCurrent = ::TimeCurrent();

      if (!MT4HISTORY::IsTester && ((LastTimeCurrent >= this.LastInitTime + DAY)))
      {
        this.LastTime = 0;

        this.LastTotalOrders = 0;
        this.LastTotalDeals = 0;

        this.Amount = 0;

        ::ArrayResize(this.Tickets, this.Amount, RESERVE_SIZE);

        this.LastInitTime = LastTimeCurrent;

      #ifndef MT4ORDERS_FASTHISTORY_OFF
        this.DealsIn.Clear();
        this.DealsOut.Clear();
      #endif // MT4ORDERS_FASTHISTORY_OFF
      }

      const datetime LastTimeCurrentLeft = LastTimeCurrent - HISTORY_PAUSE;

      if (!this.LastTime || _B2(::HistorySelect(this.LastTime, END_TIME))) // 
      {
        const int TotalOrders = ::HistoryOrdersTotal();
        const int TotalDeals = ::HistoryDealsTotal();

        Res = ((TotalOrders > this.LastTotalOrders) || (TotalDeals > this.LastTotalDeals));

        if (Res)
        {
          int iOrder = this.LastTotalOrders;
          int iDeal = this.LastTotalDeals;

          ulong TicketOrder = 0;
          ulong TicketDeal = 0;

          long TimeOrder = (iOrder < TotalOrders) ? ::HistoryOrderGetInteger((TicketOrder = ::HistoryOrderGetTicket(iOrder)), ORDER_TIME_DONE_MSC) : LONG_MAX;
          long TimeDeal = (iDeal < TotalDeals) ? ::HistoryDealGetInteger((TicketDeal = ::HistoryDealGetTicket(iDeal)), DEAL_TIME_MSC) : LONG_MAX;

          if (this.LastTime < LastTimeCurrentLeft)
          {
            this.LastTotalOrders = 0;
            this.LastTotalDeals = 0;

            this.LastTime = LastTimeCurrentLeft;
          }

          long LastTimeMsc = this.LastTime * THOUSAND;

          while ((iDeal < TotalDeals) || (iOrder < TotalOrders))
            if (TimeOrder < TimeDeal)
            {
              LASTTIME(Order)

              if (MT4HISTORY::IsMT4Order(TicketOrder))
              {
                this.Amount = ::ArrayResize(this.Tickets, this.Amount + 1, RESERVE_SIZE);

                this.Tickets[this.Amount - 1] = -(long)TicketOrder;
              }

              iOrder++;

              TimeOrder = (iOrder < TotalOrders) ? ::HistoryOrderGetInteger((TicketOrder = ::HistoryOrderGetTicket(iOrder)), ORDER_TIME_DONE_MSC) : LONG_MAX;
            }
            else
            {
              LASTTIME(Deal)

              if (MT4HISTORY::IsMT4Deal(TicketDeal))
              {
                this.Amount = ::ArrayResize(this.Tickets, this.Amount + 1, RESERVE_SIZE);

                this.Tickets[this.Amount - 1] = (long)TicketDeal;

              #ifndef MT4ORDERS_FASTHISTORY_OFF
                _B2(this.DealsOut.Add(::HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID), TicketDeal));
              #endif // MT4ORDERS_FASTHISTORY_OFF
              }
            #ifndef MT4ORDERS_FASTHISTORY_OFF
              else if ((ENUM_DEAL_ENTRY)::HistoryDealGetInteger(TicketDeal, DEAL_ENTRY) == DEAL_ENTRY_IN)
                _B2(this.DealsIn.Add(::HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID), TicketDeal));
            #endif // MT4ORDERS_FASTHISTORY_OFF

              iDeal++;

              TimeDeal = (iDeal < TotalDeals) ? ::HistoryDealGetInteger((TicketDeal = ::HistoryDealGetTicket(iDeal)), DEAL_TIME_MSC) : LONG_MAX;
            }
        }
        else if (LastTimeCurrentLeft > this.LastTime)
        {
          this.LastTime = LastTimeCurrentLeft;

          this.LastTotalOrders = 0;
          this.LastTotalDeals = 0;
        }
      }
    }

    return(Res);
  }

#else // #ifdef MT4ORDERS_HISTORY_OLD
  bool RefreshHistory( void )
  {
    if (_B2(::HistorySelect(0, INT_MAX)))
    {
      const int TotalOrders = ::HistoryOrdersTotal();
      const int TotalDeals = ::HistoryDealsTotal();

      if ((TotalOrders > this.LastTotalOrders) || (TotalDeals > this.LastTotalDeals))
      {
        ulong TicketOrder = 0;
        ulong TicketDeal = 0;

        long TimeOrder = (this.LastTotalOrders < TotalOrders) ?
                           ::HistoryOrderGetInteger((TicketOrder = ::HistoryOrderGetTicket(this.LastTotalOrders)), ORDER_TIME_DONE_MSC) : LONG_MAX;
        long TimeDeal = (this.LastTotalDeals < TotalDeals) ?
                          ::HistoryDealGetInteger((TicketDeal = ::HistoryDealGetTicket(this.LastTotalDeals)), DEAL_TIME_MSC) : LONG_MAX;

        while ((this.LastTotalDeals < TotalDeals) || (this.LastTotalOrders < TotalOrders))
          if (TimeOrder < TimeDeal)
          {
            if (MT4HISTORY::IsMT4Order(TicketOrder))
            {
              this.Amount = ::ArrayResize(this.Tickets, this.Amount + 1, RESERVE_SIZE);

              this.Tickets[this.Amount - 1] = -(long)TicketOrder;
            }

            this.LastTotalOrders++;

            TimeOrder = (this.LastTotalOrders < TotalOrders) ?
                          ::HistoryOrderGetInteger((TicketOrder = ::HistoryOrderGetTicket(this.LastTotalOrders)), ORDER_TIME_DONE_MSC) : LONG_MAX;
          }
          else
          {
            if (MT4HISTORY::IsMT4Deal(TicketDeal))
            {
              this.Amount = ::ArrayResize(this.Tickets, this.Amount + 1, RESERVE_SIZE);

              this.Tickets[this.Amount - 1] = (long)TicketDeal;

              _B2(this.DealsOut.Add(::HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID), TicketDeal));
            }
            else if ((ENUM_DEAL_ENTRY)::HistoryDealGetInteger(TicketDeal, DEAL_ENTRY) == DEAL_ENTRY_IN)
              _B2(this.DealsIn.Add(::HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID), TicketDeal));

            this.LastTotalDeals++;

            TimeDeal = (this.LastTotalDeals < TotalDeals) ?
                         ::HistoryDealGetInteger((TicketDeal = ::HistoryDealGetTicket(this.LastTotalDeals)), DEAL_TIME_MSC) : LONG_MAX;
          }
      }
    }

    return(true);
  }
#endif // #ifdef MT4ORDERS_HISTORY_OLD #else
public:
  static bool IsMT4Deal( const ulong &Ticket )
  {
    const ENUM_DEAL_TYPE DealType = (ENUM_DEAL_TYPE)::HistoryDealGetInteger(Ticket, DEAL_TYPE);
    const ENUM_DEAL_ENTRY DealEntry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(Ticket, DEAL_ENTRY);

    return(((DealType != DEAL_TYPE_BUY) && (DealType != DEAL_TYPE_SELL)) ||      // not a bargain
           ((DealEntry == DEAL_ENTRY_OUT) || (DealEntry == DEAL_ENTRY_OUT_BY))); // commercial
  }

  static bool IsMT4Order( const ulong &Ticket )
  {

    return(!::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID) || (::HistoryOrderGetDouble(Ticket, ORDER_VOLUME_CURRENT) &&
                                                                    ::HistoryOrderGetInteger(Ticket, ORDER_TYPE) > ORDER_TYPE_SELL));
  }

  MT4HISTORY( void ) : Amount(::ArrayResize(this.Tickets, 0, RESERVE_SIZE)),
                       LastTotalDeals(0), LastTotalOrders(0)
                     #ifdef MT4ORDERS_HISTORY_OLD
                       , LastTime(0), LastInitTime(0), PrevDealsTotal(0), PrevOrdersTotal(0)
                     #endif // #ifdef MT4ORDERS_HISTORY_OLD
  {
  }

  ulong GetPositionDealIn( const ulong PositionIdentifier = -1 ) // 0 - it is impossible, because the balance sheet of the tester has zero
  {
    ulong Ticket = 0;

    if (PositionIdentifier == -1)
    {
      const ulong MyPositionIdentifier = ::PositionGetInteger(POSITION_IDENTIFIER);

    #ifndef MT4ORDERS_FASTHISTORY_OFF
      if (!_B2(this.DealsIn.TryGetValue(MyPositionIdentifier, Ticket))
          #ifndef MT4ORDERS_HISTORY_OLD
          && !_B2(this.RefreshHistory() && this.DealsIn.TryGetValue(MyPositionIdentifier, Ticket))
          #endif // #ifndef MT4ORDERS_HISTORY_OLD
          )
    #endif // MT4ORDERS_FASTHISTORY_OFF
      {
        const datetime PosTime = (datetime)::PositionGetInteger(POSITION_TIME);

        if (_B3(::HistorySelect(PosTime, PosTime)))
        {
          const int Total = ::HistoryDealsTotal();

          for (int i = 0; i < Total; i++)
          {
            const ulong TicketDeal = ::HistoryDealGetTicket(i);

            if ((::HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID) == MyPositionIdentifier)) // The first mention and so will be DEAL_ENTRY_IN
            {
              Ticket = TicketDeal;

            #ifndef MT4ORDERS_FASTHISTORY_OFF
              _B2(this.DealsIn.Add(MyPositionIdentifier, Ticket));
            #endif // MT4ORDERS_FASTHISTORY_OFF

              break;
            }
          }
        }
      }
    }
    else if (PositionIdentifier && // PositionIdentifier of balance transactions is zero
           #ifndef MT4ORDERS_FASTHISTORY_OFF
             !_B2(this.DealsIn.TryGetValue(PositionIdentifier, Ticket)) &&
             #ifndef MT4ORDERS_HISTORY_OLD
               !_B2(this.RefreshHistory() && this.DealsIn.TryGetValue(PositionIdentifier, Ticket)) &&
             #endif // #ifndef MT4ORDERS_HISTORY_OLD
           #endif // MT4ORDERS_FASTHISTORY_OFF
             _B3(::HistorySelectByPosition(PositionIdentifier)) && (::HistoryDealsTotal() > 1)) // Почему > 1, а не > 0 ?!
    {
      Ticket = _B2(::HistoryDealGetTicket(0)); // The first mention and so will be DEAL_ENTRY_IN

    #ifndef MT4ORDERS_FASTHISTORY_OFF
      _B2(this.DealsIn.Add(PositionIdentifier, Ticket));
    #endif // MT4ORDERS_FASTHISTORY_OFF
    }

    return(Ticket);
  }

  ulong GetPositionDealOut( const ulong PositionIdentifier )
  {
    ulong Ticket = 0;

  #ifndef MT4ORDERS_FASTHISTORY_OFF
    if (!_B2(this.DealsOut.TryGetValue(PositionIdentifier, Ticket)) && _B2(this.RefreshHistory()))
      _B2(this.DealsOut.TryGetValue(PositionIdentifier, Ticket));
    #endif // MT4ORDERS_FASTHISTORY_OFF

    return(Ticket);
  }

  int GetAmount( void )
  {
    _B2(this.RefreshHistory());

    return((int)this.Amount);
  }

  long operator []( const uint &Pos )
  {
    long Res = 0;

    if ((Pos >= this.Amount))
    {
      _B2(this.RefreshHistory());

      if (Pos < this.Amount)
        Res = this.Tickets[Pos];
    }
    else
      Res = this.Tickets[Pos];

    return(Res);
  }
};

static const bool MT4HISTORY::IsTester = ::MQLInfoInteger(MQL_TESTER);

#undef LASTTIME
#undef THOUSAND
#undef END_TIME
#undef HISTORY_PAUSE
#undef DAY
#undef RESERVE_SIZE

#define OP_BUY ORDER_TYPE_BUY
#define OP_SELL ORDER_TYPE_SELL
#define OP_BUYLIMIT ORDER_TYPE_BUY_LIMIT
#define OP_SELLLIMIT ORDER_TYPE_SELL_LIMIT
#define OP_BUYSTOP ORDER_TYPE_BUY_STOP
#define OP_SELLSTOP ORDER_TYPE_SELL_STOP
#define OP_BALANCE 6

#define SELECT_BY_POS 0
#define SELECT_BY_TICKET 1

#define MODE_TRADES 0
#define MODE_HISTORY 1

class MT4ORDERS
{
private:
  static MT4_ORDER Order;
  static MT4HISTORY History;

  static const bool MT4ORDERS::IsTester;
  static const bool MT4ORDERS::IsHedging;

  static int OrderSendBug;

  static bool HistorySelectOrder( const ulong Ticket )
  {
    return(Ticket && ((::HistoryOrderGetInteger(Ticket, ORDER_TICKET) == Ticket) ||
                      (_B2(::HistorySelect(0, INT_MAX)) && (::HistoryOrderGetInteger(Ticket, ORDER_TICKET) == Ticket))));
  }

  static bool HistorySelectDeal( const ulong &Ticket )
  {
    return(Ticket && ((::HistoryDealGetInteger(Ticket, DEAL_TICKET) == Ticket) ||
                      (_B2(::HistorySelect(0, INT_MAX)) && (::HistoryDealGetInteger(Ticket, DEAL_TICKET) == Ticket))));
  }

#define UNKNOWN_COMMISSION DBL_MIN
#define UNKNOWN_REQUEST_PRICE DBL_MIN
#define UNKNOWN_TICKET 0

  static bool CheckNewTicket( void )
  {
    return(false); // This functionality is useless - there is INT_MIN / INT_MAX with SELECT_BY_POS + MODE_TRADES

    static long PrevPosTimeUpdate = 0;
    static long PrevPosTicket = 0;

    const long PosTimeUpdate = ::PositionGetInteger(POSITION_TIME_UPDATE_MSC);
    const long PosTicket = ::PositionGetInteger(POSITION_TICKET);

    const bool Res = ((PosTimeUpdate != PrevPosTimeUpdate) || (PosTicket != PrevPosTicket));

    if (Res)
    {
      MT4ORDERS::GetPositionData();

      PrevPosTimeUpdate = PosTimeUpdate;
      PrevPosTicket = PosTicket;
    }

    return(Res);
  }

  static bool CheckPositionTicketOpen( void )
  {
    if ((MT4ORDERS::Order.TicketOpen == UNKNOWN_TICKET) || MT4ORDERS::CheckNewTicket())
      MT4ORDERS::Order.TicketOpen = (long)_B2(MT4ORDERS::History.GetPositionDealIn()); // All because of this very expensive function

    return(true);
  }

  static bool CheckPositionCommissionComment( void )
  {
    if ((MT4ORDERS::Order.Commission == UNKNOWN_COMMISSION) || MT4ORDERS::CheckNewTicket())
    {
      MT4ORDERS::Order.Commission = 0; // Always zero
      MT4ORDERS::Order.Comment = ::PositionGetString(POSITION_COMMENT);

      if (!MT4ORDERS::Order.Commission || (MT4ORDERS::Order.Comment == ""))
      {
        MT4ORDERS::CheckPositionTicketOpen();

        const ulong Ticket = MT4ORDERS::Order.TicketOpen;

        if ((Ticket > 0) && _B2(MT4ORDERS::HistorySelectDeal(Ticket)))
        {
          if (!MT4ORDERS::Order.Commission)
          {
            const double LotsIn = ::HistoryDealGetDouble(Ticket, DEAL_VOLUME);

            if (LotsIn > 0)
              MT4ORDERS::Order.Commission = ::HistoryDealGetDouble(Ticket, DEAL_COMMISSION) * ::PositionGetDouble(POSITION_VOLUME) / LotsIn;
          }

          if (MT4ORDERS::Order.Comment == "")
            MT4ORDERS::Order.Comment = ::HistoryDealGetString(Ticket, DEAL_COMMENT);
        }
      }
    }

    return(true);
  }

  static bool CheckPositionOpenPriceRequest( void )
  {
    const long PosTicket = ::PositionGetInteger(POSITION_TICKET);

    if (((MT4ORDERS::Order.OpenPriceRequest == UNKNOWN_REQUEST_PRICE) || MT4ORDERS::CheckNewTicket()) &&
        !(MT4ORDERS::Order.OpenPriceRequest = (_B2(MT4ORDERS::HistorySelectOrder(PosTicket)) &&
                                              (MT4ORDERS::IsTester || (::PositionGetInteger(POSITION_TIME_MSC) ==
                                              ::HistoryOrderGetInteger(PosTicket, ORDER_TIME_DONE_MSC)))) // Is this check necessary?
                                            ? ::HistoryOrderGetDouble(PosTicket, ORDER_PRICE_OPEN)
                                            : ::PositionGetDouble(POSITION_PRICE_OPEN)))
      MT4ORDERS::Order.OpenPriceRequest = ::PositionGetDouble(POSITION_PRICE_OPEN); // In case the order price is zero

    return(true);
  }

  static void GetPositionData( void )
  {
    MT4ORDERS::Order.Ticket = POSITION_SELECT;

    MT4ORDERS::Order.Commission = UNKNOWN_COMMISSION;
    MT4ORDERS::Order.OpenPriceRequest = UNKNOWN_REQUEST_PRICE;
    MT4ORDERS::Order.TicketOpen = UNKNOWN_TICKET;

    return;
  }

#undef UNKNOWN_TICKET
#undef UNKNOWN_REQUEST_PRICE
#undef UNKNOWN_COMMISSION

  static void GetOrderData( void )
  {
    MT4ORDERS::Order.Ticket = ORDER_SELECT;

    return;
  }

  static void GetHistoryOrderData( const ulong Ticket )
  {
    MT4ORDERS::Order.Ticket = ::HistoryOrderGetInteger(Ticket, ORDER_TICKET);
    MT4ORDERS::Order.Type = (int)::HistoryOrderGetInteger(Ticket, ORDER_TYPE);

    MT4ORDERS::Order.TicketOpen = MT4ORDERS::Order.Ticket;
    MT4ORDERS::Order.TicketID = MT4ORDERS::Order.Ticket;

    MT4ORDERS::Order.Lots = ::HistoryOrderGetDouble(Ticket, ORDER_VOLUME_CURRENT);

    if (!MT4ORDERS::Order.Lots)
      MT4ORDERS::Order.Lots = ::HistoryOrderGetDouble(Ticket, ORDER_VOLUME_INITIAL);

    MT4ORDERS::Order.Symbol = ::HistoryOrderGetString(Ticket, ORDER_SYMBOL);
    MT4ORDERS::Order.Comment = ::HistoryOrderGetString(Ticket, ORDER_COMMENT);

    MT4ORDERS::Order.OpenTimeMsc = ::HistoryOrderGetInteger(Ticket, ORDER_TIME_SETUP_MSC);
    MT4ORDERS::Order.OpenTime = (datetime)(MT4ORDERS::Order.OpenTimeMsc / 1000);

    MT4ORDERS::Order.OpenPrice = ::HistoryOrderGetDouble(Ticket, ORDER_PRICE_OPEN);
    MT4ORDERS::Order.OpenPriceRequest = MT4ORDERS::Order.OpenPrice;

    MT4ORDERS::Order.OpenReason = (ENUM_DEAL_REASON)::HistoryOrderGetInteger(Ticket, ORDER_REASON);

    MT4ORDERS::Order.StopLoss = ::HistoryOrderGetDouble(Ticket, ORDER_SL);
    MT4ORDERS::Order.TakeProfit = ::HistoryOrderGetDouble(Ticket, ORDER_TP);

    MT4ORDERS::Order.CloseTimeMsc = ::HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE_MSC);
    MT4ORDERS::Order.CloseTime = (datetime)(MT4ORDERS::Order.CloseTimeMsc / 1000);

    MT4ORDERS::Order.ClosePrice = ::HistoryOrderGetDouble(Ticket, ORDER_PRICE_CURRENT);
    MT4ORDERS::Order.ClosePriceRequest = MT4ORDERS::Order.ClosePrice;

    MT4ORDERS::Order.CloseReason = MT4ORDERS::Order.OpenReason;

    MT4ORDERS::Order.State = (ENUM_ORDER_STATE)::HistoryOrderGetInteger(Ticket, ORDER_STATE);

    MT4ORDERS::Order.Expiration = (datetime)::HistoryOrderGetInteger(Ticket, ORDER_TIME_EXPIRATION);

    MT4ORDERS::Order.MagicNumber = ::HistoryOrderGetInteger(Ticket, ORDER_MAGIC);

    MT4ORDERS::Order.Profit = 0;

    MT4ORDERS::Order.Commission = 0;
    MT4ORDERS::Order.Swap = 0;

    return;
  }

  static string GetTickFlag( uint tickflag )
  {
    string flag = " " + (string)tickflag;

  #define TICKFLAG_MACRO(A) flag += ((bool)(tickflag & TICK_FLAG_##A)) ? " TICK_FLAG_" + #A : ""; \
                            tickflag -= tickflag & TICK_FLAG_##A;
    TICKFLAG_MACRO(BID)
    TICKFLAG_MACRO(ASK)
    TICKFLAG_MACRO(LAST)
    TICKFLAG_MACRO(VOLUME)
    TICKFLAG_MACRO(BUY)
    TICKFLAG_MACRO(SELL)
  #undef TICKFLAG_MACRO

    if (tickflag)
      flag += " FLAG_UNKNOWN (" + (string)tickflag + ")";

    return(flag);
  }

#define TOSTR(A) " " + #A + " = " + (string)Tick.A
#define TOSTR2(A) " " + #A + " = " + ::DoubleToString(Tick.A, digits)
#define TOSTR3(A) " " + #A + " = " + (string)(A)

  static string TickToString( const string &Symb, const MqlTick &Tick )
  {
    const int digits = (int)::SymbolInfoInteger(Symb, SYMBOL_DIGITS);

    return(TOSTR3(Symb) + TOSTR(time) + "." + ::IntegerToString(Tick.time_msc % 1000, 3, '0') +
           TOSTR2(bid) + TOSTR2(ask) + TOSTR2(last)+ TOSTR(volume) + MT4ORDERS::GetTickFlag(Tick.flags));
  }

  static string TickToString( const string &Symb )
  {
    MqlTick Tick = {0};

    return(TOSTR3(::SymbolInfoTick(Symb, Tick)) + MT4ORDERS::TickToString(Symb, Tick));
  }

#undef TOSTR3
#undef TOSTR2
#undef TOSTR

  static void AlertLog( void )
  {
    ::Alert("Please send the logs to the coauthor - ");

    string Str = ::TimeToString(::TimeLocal(), TIME_DATE);
    ::StringReplace(Str, ".", NULL);

    ::Alert(::TerminalInfoString(TERMINAL_PATH) + "\\MQL5\\Logs\\" + Str + ".log");

    return;
  }

  static long GetTimeCurrent( void )
  {
    long Res = 0;
    MqlTick Tick = {0};

    for (int i = ::SymbolsTotal(true) - 1; i >= 0; i--)
    {
      const string SymbName = ::SymbolName(i, true);

      if (!::SymbolInfoInteger(SymbName, SYMBOL_CUSTOM) && ::SymbolInfoTick(SymbName, Tick) && (Tick.time_msc > Res))
        Res = Tick.time_msc;
    }

    return(Res);
  }

  static string TimeToString( const long time )
  {
    return((string)(datetime)(time / 1000) + "." + ::IntegerToString(time % 1000, 3, '0'));
  }

#define WHILE(A) while ((!(Res = (A))) && MT4ORDERS::Waiting())

#define TOSTR(A)  #A + " = " + (string)(A) + "\n"
#define TOSTR2(A) #A + " = " + ::EnumToString(A) + " (" + (string)(A) + ")\n"

  static void GetHistoryPositionData( const ulong Ticket )
  {
    MT4ORDERS::Order.Ticket = (long)Ticket;
    MT4ORDERS::Order.TicketID = ::HistoryDealGetInteger(MT4ORDERS::Order.Ticket, DEAL_POSITION_ID);
    MT4ORDERS::Order.Type = (int)::HistoryDealGetInteger(Ticket, DEAL_TYPE);

    if ((MT4ORDERS::Order.Type > OP_SELL))
      MT4ORDERS::Order.Type += (OP_BALANCE - OP_SELL - 1);
    else
      MT4ORDERS::Order.Type = 1 - MT4ORDERS::Order.Type;

    MT4ORDERS::Order.Lots = ::HistoryDealGetDouble(Ticket, DEAL_VOLUME);

    MT4ORDERS::Order.Symbol = ::HistoryDealGetString(Ticket, DEAL_SYMBOL);
    MT4ORDERS::Order.Comment = ::HistoryDealGetString(Ticket, DEAL_COMMENT);

    MT4ORDERS::Order.CloseTimeMsc = ::HistoryDealGetInteger(Ticket, DEAL_TIME_MSC);
    MT4ORDERS::Order.CloseTime = (datetime)(MT4ORDERS::Order.CloseTimeMsc / 1000);

    MT4ORDERS::Order.ClosePrice = ::HistoryDealGetDouble(Ticket, DEAL_PRICE);

    MT4ORDERS::Order.CloseReason = (ENUM_DEAL_REASON)::HistoryDealGetInteger(Ticket, DEAL_REASON);;

    MT4ORDERS::Order.Expiration = 0;

    MT4ORDERS::Order.MagicNumber = ::HistoryDealGetInteger(Ticket, DEAL_MAGIC);

    MT4ORDERS::Order.Profit = ::HistoryDealGetDouble(Ticket, DEAL_PROFIT);

    MT4ORDERS::Order.Commission = ::HistoryDealGetDouble(Ticket, DEAL_COMMISSION);
    MT4ORDERS::Order.Swap = ::HistoryDealGetDouble(Ticket, DEAL_SWAP);

#ifndef MT4ORDERS_SLTP_OLD
    MT4ORDERS::Order.StopLoss = ::HistoryDealGetDouble(Ticket, DEAL_SL);
    MT4ORDERS::Order.TakeProfit = ::HistoryDealGetDouble(Ticket, DEAL_TP);
#else // MT4ORDERS_SLTP_OLD
    MT4ORDERS::Order.StopLoss = 0;
    MT4ORDERS::Order.TakeProfit = 0;
#endif // MT4ORDERS_SLTP_OLD

    const ulong OrderTicket = (MT4ORDERS::Order.Type < OP_BALANCE) ? ::HistoryDealGetInteger(Ticket, DEAL_ORDER) : 0;
    const ulong PosTicket = MT4ORDERS::Order.TicketID;
    const ulong OpenTicket = (OrderTicket > 0) ? _B2(MT4ORDERS::History.GetPositionDealIn(PosTicket)) : 0;

    if (OpenTicket > 0)
    {
      const ENUM_DEAL_REASON Reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(Ticket, DEAL_REASON);
      const ENUM_DEAL_ENTRY DealEntry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(Ticket, DEAL_ENTRY);

    #ifdef MT4ORDERS_FASTHISTORY_OFF
      const bool Res = true;
    #else // MT4ORDERS_FASTHISTORY_OFF

      bool Res = MT4ORDERS::IsTester ? MT4ORDERS::HistorySelectOrder(OrderTicket) : MT4ORDERS::Waiting(true);

      if (!Res)
        WHILE(_B2(MT4ORDERS::HistorySelectOrder(OrderTicket))) // 
          ;

      if (_B2(MT4ORDERS::HistorySelectDeal(OpenTicket))) // Sure to work, because OpenTicket guaranteed in history
    #endif // MT4ORDERS_FASTHISTORY_OFF
      {
        MT4ORDERS::Order.TicketOpen = (long)OpenTicket;

        MT4ORDERS::Order.OpenReason = Reason;

        MT4ORDERS::Order.OpenPrice = ::HistoryDealGetDouble(OpenTicket, DEAL_PRICE);

        MT4ORDERS::Order.OpenTimeMsc = ::HistoryDealGetInteger(OpenTicket, DEAL_TIME_MSC);
        MT4ORDERS::Order.OpenTime = (datetime)(MT4ORDERS::Order.OpenTimeMsc / 1000);

        const double OpenLots = ::HistoryDealGetDouble(OpenTicket, DEAL_VOLUME);

        if (OpenLots > 0)
          MT4ORDERS::Order.Commission += ::HistoryDealGetDouble(OpenTicket, DEAL_COMMISSION) * MT4ORDERS::Order.Lots / OpenLots;

          const long __Magic = ::HistoryDealGetInteger(OpenTicket, DEAL_MAGIC);

          if (__Magic)
            MT4ORDERS::Order.MagicNumber = __Magic;

          const string StrComment = ::HistoryDealGetString(OpenTicket, DEAL_COMMENT);

        if (Res) // OrderTicket may not be in history, but may be among the living. Perhaps it is reasonable to get the necessary info from there.
        {
          double OrderPriceOpen = ::HistoryOrderGetDouble(OrderTicket, ORDER_PRICE_OPEN);

      #ifdef MT4ORDERS_SLTP_OLD
          if (Reason == DEAL_REASON_SL)
          {
            if (!OrderPriceOpen)

              OrderPriceOpen = (double)::StringSubstr(MT4ORDERS::Order.Comment, MT4ORDERS::IsTester ? 3 : (::StringFind(MT4ORDERS::Order.Comment, "sl ") + 3));

            MT4ORDERS::Order.StopLoss = OrderPriceOpen;
            MT4ORDERS::Order.TakeProfit = ::HistoryOrderGetDouble(OrderTicket, ORDER_SL);
          }
          else if (Reason == DEAL_REASON_TP)
          {
            if (!OrderPriceOpen)

              OrderPriceOpen = (double)::StringSubstr(MT4ORDERS::Order.Comment, MT4ORDERS::IsTester ? 3 : (::StringFind(MT4ORDERS::Order.Comment, "tp ") + 3));

            MT4ORDERS::Order.TakeProfit = OrderPriceOpen;
            MT4ORDERS::Order.StopLoss = ::HistoryOrderGetDouble(OrderTicket, ORDER_TP);
          }
          else
          {

            MT4ORDERS::Order.StopLoss = ::HistoryOrderGetDouble(OrderTicket, ORDER_TP);
            MT4ORDERS::Order.TakeProfit = ::HistoryOrderGetDouble(OrderTicket, ORDER_SL);
          }
      #endif // MT4ORDERS_SLTP_OLD

          MT4ORDERS::Order.State = (ENUM_ORDER_STATE)::HistoryOrderGetInteger(OrderTicket, ORDER_STATE);

          if (!(MT4ORDERS::Order.ClosePriceRequest = (DealEntry == DEAL_ENTRY_OUT_BY) ? MT4ORDERS::Order.ClosePrice : OrderPriceOpen))
            MT4ORDERS::Order.ClosePriceRequest = MT4ORDERS::Order.ClosePrice;

          if (!(MT4ORDERS::Order.OpenPriceRequest = _B2(MT4ORDERS::HistorySelectOrder(PosTicket) &&

                                                    (MT4ORDERS::IsTester || (::HistoryDealGetInteger(OpenTicket, DEAL_TIME_MSC) == ::HistoryOrderGetInteger(PosTicket, ORDER_TIME_DONE_MSC)))) ?
                                                   ::HistoryOrderGetDouble(PosTicket, ORDER_PRICE_OPEN) : MT4ORDERS::Order.OpenPrice))
            MT4ORDERS::Order.OpenPriceRequest = MT4ORDERS::Order.OpenPrice;
        }
        else
        {
          MT4ORDERS::Order.State = ORDER_STATE_FILLED;

          MT4ORDERS::Order.ClosePriceRequest = MT4ORDERS::Order.ClosePrice;
          MT4ORDERS::Order.OpenPriceRequest = MT4ORDERS::Order.OpenPrice;
        }

        if (StrComment != "")
          MT4ORDERS::Order.Comment = StrComment;
      }

      if (!Res)
      {
        ::Alert("HistoryOrderSelect(" + (string)OrderTicket + ") - BUG! MT4ORDERS - not Sync with History!");
        MT4ORDERS::AlertLog();

        ::Print(__FILE__ + "\nVersion = " + __MT4ORDERS__ + "\nCompiler = " + (string)__MQLBUILD__ + "\n" + TOSTR(__DATE__) +
                TOSTR(::AccountInfoString(ACCOUNT_SERVER)) + TOSTR2((ENUM_ACCOUNT_TRADE_MODE)::AccountInfoInteger(ACCOUNT_TRADE_MODE)) +
                TOSTR((bool)::TerminalInfoInteger(TERMINAL_CONNECTED)) +
                TOSTR(::TerminalInfoInteger(TERMINAL_PING_LAST)) + TOSTR(::TerminalInfoDouble(TERMINAL_RETRANSMISSION)) +
                TOSTR(::TerminalInfoInteger(TERMINAL_BUILD)) + TOSTR((bool)::TerminalInfoInteger(TERMINAL_X64)) +
                TOSTR((bool)::TerminalInfoInteger(TERMINAL_VPS)) + TOSTR2((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)) +
                TOSTR(::TimeCurrent()) + TOSTR(::TimeTradeServer()) + TOSTR(MT4ORDERS::TimeToString(MT4ORDERS::GetTimeCurrent())) +
                TOSTR(::SymbolInfoString(MT4ORDERS::Order.Symbol, SYMBOL_PATH)) + TOSTR(::SymbolInfoString(MT4ORDERS::Order.Symbol, SYMBOL_DESCRIPTION)) +
                "CurrentTick =" + MT4ORDERS::TickToString(MT4ORDERS::Order.Symbol) + "\n" +
                TOSTR(::PositionsTotal()) + TOSTR(::OrdersTotal()) +
                TOSTR(::HistorySelect(0, INT_MAX)) + TOSTR(::HistoryDealsTotal()) + TOSTR(::HistoryOrdersTotal()) +
                TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE)) + TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL)) +
                TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)) + TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_USED)) +
                TOSTR(::MQLInfoInteger(MQL_MEMORY_LIMIT)) + TOSTR(::MQLInfoInteger(MQL_MEMORY_USED)) +
                TOSTR(Ticket) + TOSTR(OrderTicket) + TOSTR(OpenTicket) + TOSTR(PosTicket) +
                TOSTR(MT4ORDERS::TimeToString(MT4ORDERS::Order.CloseTimeMsc)) +
                TOSTR(MT4ORDERS::HistorySelectOrder(OrderTicket)) + TOSTR(::OrderSelect(OrderTicket)) +
                (::OrderSelect(OrderTicket) ? TOSTR2((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE)) : NULL) +
                (::HistoryDealsTotal() ? TOSTR(::HistoryDealGetTicket(::HistoryDealsTotal() - 1)) +
                   "DEAL_TIME_MSC = " + MT4ORDERS::TimeToString(::HistoryDealGetInteger(::HistoryDealGetTicket(::HistoryDealsTotal() - 1), DEAL_TIME_MSC)) + "\n"
                                       : NULL) +
                (::HistoryOrdersTotal() ? TOSTR(::HistoryOrderGetTicket(::HistoryOrdersTotal() - 1)) +
                   "ORDER_TIME_DONE_MSC = " + MT4ORDERS::TimeToString(::HistoryOrderGetInteger(::HistoryOrderGetTicket(::HistoryOrdersTotal() - 1), ORDER_TIME_DONE_MSC)) + "\n"
                                        : NULL));
      }
    }
    else
    {
      MT4ORDERS::Order.TicketOpen = MT4ORDERS::Order.Ticket;

      if (!MT4ORDERS::Order.TicketID && (MT4ORDERS::Order.Type <= OP_SELL)) // The balance sheet ID must remain zero
        MT4ORDERS::Order.TicketID = MT4ORDERS::Order.Ticket;

      MT4ORDERS::Order.OpenPrice = MT4ORDERS::Order.ClosePrice;

      MT4ORDERS::Order.OpenTimeMsc = MT4ORDERS::Order.CloseTimeMsc;
      MT4ORDERS::Order.OpenTime = MT4ORDERS::Order.CloseTime;

      MT4ORDERS::Order.OpenReason = MT4ORDERS::Order.CloseReason;

      MT4ORDERS::Order.State = ORDER_STATE_FILLED;

      MT4ORDERS::Order.ClosePriceRequest = MT4ORDERS::Order.ClosePrice;
      MT4ORDERS::Order.OpenPriceRequest = MT4ORDERS::Order.OpenPrice;
    }

    if (OrderTicket)
    {
      bool Res = MT4ORDERS::IsTester ? MT4ORDERS::HistorySelectOrder(OrderTicket) : MT4ORDERS::Waiting(true);

      if (!Res)
        WHILE(_B2(MT4ORDERS::HistorySelectOrder(OrderTicket))) // 
          ;

      if ((ENUM_ORDER_TYPE)::HistoryOrderGetInteger(OrderTicket, ORDER_TYPE) == ORDER_TYPE_CLOSE_BY)
      {
        const ulong PosTicketBy = ::HistoryOrderGetInteger(OrderTicket, ORDER_POSITION_BY_ID);

        if (PosTicketBy == PosTicket) // CloseBy-Slave should not affect trade.
        {
          MT4ORDERS::Order.Lots = 0;
          MT4ORDERS::Order.Commission = 0;

          MT4ORDERS::Order.ClosePrice = MT4ORDERS::Order.OpenPrice;
          MT4ORDERS::Order.ClosePriceRequest = MT4ORDERS::Order.ClosePrice;
        }
        else // CloseBy-Master must receive a commission from CloseBy-Slave
        {
          const ulong OpenTicketBy = (OrderTicket > 0) ? _B2(MT4ORDERS::History.GetPositionDealIn(PosTicketBy)) : 0;

          if ((OpenTicketBy > 0) && _B2(MT4ORDERS::HistorySelectDeal(OpenTicketBy)))
          {
            const double OpenLots = ::HistoryDealGetDouble(OpenTicketBy, DEAL_VOLUME);

            if (OpenLots > 0)
              MT4ORDERS::Order.Commission += ::HistoryDealGetDouble(OpenTicketBy, DEAL_COMMISSION) * MT4ORDERS::Order.Lots / OpenLots;
          }
        }
      }
    }

    return;
  }

  static bool Waiting( const bool FlagInit = false )
  {
    static ulong StartTime = 0;

    const bool Res = FlagInit ? false : (::GetMicrosecondCount() - StartTime < MT4ORDERS::OrderSend_MaxPause);

    if (FlagInit)
    {
      StartTime = ::GetMicrosecondCount();

      MT4ORDERS::OrderSendBug = 0;
    }
    else if (Res)
    {
      MT4ORDERS::OrderSendBug++;
    }

    return(Res);
  }

  static bool EqualPrices( const double Price1, const double &Price2, const int &digits)
  {
    return(!::NormalizeDouble(Price1 - Price2, digits));
  }

  static bool HistoryDealSelect2( MqlTradeResult &Result ) // At the end of the name is a number for greater compatibility with macros
  {
  #ifdef MT4ORDERS_HISTORY_OLD

    if (!Result.deal && Result.order && _B3(::HistorySelectByPosition(::HistoryOrderGetInteger(Result.order, ORDER_POSITION_ID))))
    {
  #else // #ifdef MT4ORDERS_HISTORY_OLD
    if (!Result.deal && Result.order && _B2(MT4ORDERS::HistorySelectOrder(Result.order)))
    {
      const long OrderTimeFill = ::HistoryOrderGetInteger(Result.order, ORDER_TIME_DONE_MSC);
  #endif // #ifdef MT4ORDERS_HISTORY_OLD #else
      for (int i = ::HistoryDealsTotal() - 1; i >= 0; i--)
      {
        const ulong DealTicket = ::HistoryDealGetTicket(i);

        if (Result.order == ::HistoryDealGetInteger(DealTicket, DEAL_ORDER))
        {
          Result.deal = DealTicket;
          Result.price = ::HistoryDealGetDouble(DealTicket, DEAL_PRICE);

          break;
        }
      #ifndef MT4ORDERS_HISTORY_OLD
        else if (::HistoryDealGetInteger(DealTicket, DEAL_TIME_MSC) < OrderTimeFill)
          break;
      #endif // #ifndef MT4ORDERS_HISTORY_OLD
      }
    }

    return(_B2(MT4ORDERS::HistorySelectDeal(Result.deal)));
  }

#define TMP_MT4ORDERS_BENCHMARK(A) \
  static ulong Max##A = 0;         \
                                   \
  if (Interval##A > Max##A)        \
  {                                \
    MT4ORDERS_BENCHMARK            \
                                   \
    Max##A = Interval##A;          \
  }

  static void OrderSend_Benchmark( const ulong &Interval1, const ulong &Interval2 )
  {
    #ifdef MT4ORDERS_BENCHMARK
      TMP_MT4ORDERS_BENCHMARK(1)
      TMP_MT4ORDERS_BENCHMARK(2)
    #endif // MT4ORDERS_BENCHMARK

    return;
  }

#undef TMP_MT4ORDERS_BENCHMARK

  static string ToString( const MqlTradeRequest &Request )
  {
    return(TOSTR2(Request.action) + TOSTR(Request.magic) + TOSTR(Request.order) +
           TOSTR(Request.symbol) + TOSTR(Request.volume) + TOSTR(Request.price) +
           TOSTR(Request.stoplimit) + TOSTR(Request.sl) +  TOSTR(Request.tp) +
           TOSTR(Request.deviation) + TOSTR2(Request.type) + TOSTR2(Request.type_filling) +
           TOSTR2(Request.type_time) + TOSTR(Request.expiration) + TOSTR(Request.comment) +
           TOSTR(Request.position) + TOSTR(Request.position_by));
  }

  static string ToString( const MqlTradeResult &Result )
  {
    return(TOSTR(Result.retcode) + TOSTR(Result.deal) + TOSTR(Result.order) +
           TOSTR(Result.volume) + TOSTR(Result.price) + TOSTR(Result.bid) +
           TOSTR(Result.ask) + TOSTR(Result.comment) + TOSTR(Result.request_id) +
           TOSTR(Result.retcode_external));
  }

  static bool OrderSend( const MqlTradeRequest &Request, MqlTradeResult &Result )
  {
    MqlTick PrevTick = {0};

    if (!MT4ORDERS::IsTester)
      ::SymbolInfoTick(Request.symbol, PrevTick); // Может тормозить.

    const long PrevTimeCurrent = MT4ORDERS::IsTester ? 0 : MT4ORDERS::GetTimeCurrent();
    const ulong StartTime1 = MT4ORDERS::IsTester ? 0 : ::GetMicrosecondCount();

    bool Res = ::OrderSend(Request, Result);

    const ulong Interval1 = MT4ORDERS::IsTester ? 0 : (::GetMicrosecondCount() - StartTime1);

    const ulong StartTime2 = MT4ORDERS::IsTester ? 0 : ::GetMicrosecondCount();

    if (!MT4ORDERS::IsTester && Res && (Result.retcode < TRADE_RETCODE_ERROR) && (MT4ORDERS::OrderSend_MaxPause > 0))
    {
      Res = (Result.retcode == TRADE_RETCODE_DONE);
      MT4ORDERS::Waiting(true);

      if (Request.action == TRADE_ACTION_DEAL)
      {
        if (!Result.deal)
        {
          WHILE(_B2(::OrderSelect(Result.order)) || _B2(MT4ORDERS::HistorySelectOrder(Result.order)))
            ;

          if (!Res)
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(::OrderSelect(Result.order)) + TOSTR(MT4ORDERS::HistorySelectOrder(Result.order)));
          else if (::OrderSelect(Result.order) && !(Res = ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) == ORDER_STATE_PLACED) ||
                                                          ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) == ORDER_STATE_PARTIAL)))
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(::OrderSelect(Result.order)) + TOSTR2((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE)));
        }

        if (Res)
        {
          const bool ResultDeal = (!Result.deal) && (!MT4ORDERS::OrderSendBug);

          if (MT4ORDERS::OrderSendBug && (!Result.deal))
            ::Print("Line = " + (string)__LINE__ + "\n" + "Before ::HistoryOrderSelect(Result.order):\n" + TOSTR(MT4ORDERS::OrderSendBug) + TOSTR(Result.deal));

          WHILE(_B2(MT4ORDERS::HistorySelectOrder(Result.order)))
            ;

          if (ResultDeal)
            MT4ORDERS::OrderSendBug = 0;

          if (!Res)
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(MT4ORDERS::HistorySelectOrder(Result.order)) + TOSTR(MT4ORDERS::HistorySelectDeal(Result.deal)) + TOSTR(::OrderSelect(Result.order)));

          else if (!(Res = ((ENUM_ORDER_STATE)::HistoryOrderGetInteger(Result.order, ORDER_STATE) == ORDER_STATE_FILLED) ||
                           ((ENUM_ORDER_STATE)::HistoryOrderGetInteger(Result.order, ORDER_STATE) == ORDER_STATE_PARTIAL)))
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR2((ENUM_ORDER_STATE)::HistoryOrderGetInteger(Result.order, ORDER_STATE)));
        }

        if (Res)
        {
          const bool ResultDeal = (!Result.deal) && (!MT4ORDERS::OrderSendBug);

          if (MT4ORDERS::OrderSendBug && (!Result.deal))
            ::Print("Line = " + (string)__LINE__ + "\n" + "Before MT4ORDERS::HistoryDealSelect(Result):\n" + TOSTR(MT4ORDERS::OrderSendBug) + TOSTR(Result.deal));

          WHILE(MT4ORDERS::HistoryDealSelect2(Result))
            ;

          if (ResultDeal)
            MT4ORDERS::OrderSendBug = 0;

          if (!Res)
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(MT4ORDERS::HistoryDealSelect2(Result)));
        }
      }
      else if (Request.action == TRADE_ACTION_PENDING)
      {
        if (Res)
        {
          WHILE(_B2(::OrderSelect(Result.order)))
            ;

          if (!Res)
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(::OrderSelect(Result.order)));
          else if (!(Res = ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) == ORDER_STATE_PLACED) ||
                           ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) == ORDER_STATE_PARTIAL)))
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR2((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE)));
        }
        else
        {
          WHILE(_B2(MT4ORDERS::HistorySelectOrder(Result.order)))
            ;

          ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(MT4ORDERS::HistorySelectOrder(Result.order)));

          Res = false;
        }
      }
      else if (Request.action == TRADE_ACTION_SLTP)
      {
        if (Res)
        {
          const int digits = (int)::SymbolInfoInteger(Request.symbol, SYMBOL_DIGITS);

          bool EqualSL = false;
          bool EqualTP = false;

          do
            if (Request.position ? _B2(::PositionSelectByTicket(Request.position)) : _B2(::PositionSelect(Request.symbol)))
            {
              EqualSL = MT4ORDERS::EqualPrices(::PositionGetDouble(POSITION_SL), Request.sl, digits);
              EqualTP = MT4ORDERS::EqualPrices(::PositionGetDouble(POSITION_TP), Request.tp, digits);
            }
          WHILE(EqualSL && EqualTP);

          if (!Res)
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(::PositionGetDouble(POSITION_SL)) + TOSTR(::PositionGetDouble(POSITION_TP)) +
                    TOSTR(EqualSL) + TOSTR(EqualTP) +
                    TOSTR(Request.position ? ::PositionSelectByTicket(Request.position) : ::PositionSelect(Request.symbol)));
        }
      }
      else if (Request.action == TRADE_ACTION_MODIFY)
      {
        if (Res)
        {
          const int digits = (int)::SymbolInfoInteger(Request.symbol, SYMBOL_DIGITS);

          bool EqualSL = false;
          bool EqualTP = false;
          bool EqualPrice = false;

          do

            if (_B2(::OrderSelect(Result.order)) && ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) != ORDER_STATE_REQUEST_MODIFY))
            {
              EqualSL = MT4ORDERS::EqualPrices(::OrderGetDouble(ORDER_SL), Request.sl, digits);
              EqualTP = MT4ORDERS::EqualPrices(::OrderGetDouble(ORDER_TP), Request.tp, digits);
              EqualPrice = MT4ORDERS::EqualPrices(::OrderGetDouble(ORDER_PRICE_OPEN), Request.price, digits);
            }
          WHILE((EqualSL && EqualTP && EqualPrice));

          if (!Res)
            ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(::OrderGetDouble(ORDER_SL)) + TOSTR(Request.sl)+
                    TOSTR(::OrderGetDouble(ORDER_TP)) + TOSTR(Request.tp) +
                    TOSTR(::OrderGetDouble(ORDER_PRICE_OPEN)) + TOSTR(Request.price) +
                    TOSTR(EqualSL) + TOSTR(EqualTP) + TOSTR(EqualPrice) +
                    TOSTR(::OrderSelect(Result.order)) +
                    TOSTR2((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE)));
        }
      }
      else if (Request.action == TRADE_ACTION_REMOVE)
      {
        if (Res)
          WHILE(_B2(MT4ORDERS::HistorySelectOrder(Result.order)))
            ;

        if (!Res)
          ::Print("Line = " + (string)__LINE__ + "\n" + TOSTR(MT4ORDERS::HistorySelectOrder(Result.order)));
      }

      const ulong Interval2 = ::GetMicrosecondCount() - StartTime2;

      Result.comment += " " + ::DoubleToString(Interval1 / 1000.0, 3) + " + " +
                              ::DoubleToString(Interval2 / 1000.0, 3) + " (" + (string)MT4ORDERS::OrderSendBug + ") ms.";

      if (!Res || MT4ORDERS::OrderSendBug)
      {
        ::Alert(Res ? "OrderSend(" + (string)Result.order + ") - BUG!" : "MT4ORDERS - not Sync with History!");
        MT4ORDERS::AlertLog();

        ::Print(__FILE__ + "\nVersion = " + __MT4ORDERS__ + "\nCompiler = " + (string)__MQLBUILD__ + "\n" + TOSTR(__DATE__) +
                TOSTR(::AccountInfoString(ACCOUNT_SERVER)) + TOSTR2((ENUM_ACCOUNT_TRADE_MODE)::AccountInfoInteger(ACCOUNT_TRADE_MODE)) +
                TOSTR((bool)::TerminalInfoInteger(TERMINAL_CONNECTED)) +
                TOSTR(::TerminalInfoInteger(TERMINAL_PING_LAST)) + TOSTR(::TerminalInfoDouble(TERMINAL_RETRANSMISSION)) +
                TOSTR(::TerminalInfoInteger(TERMINAL_BUILD)) + TOSTR((bool)::TerminalInfoInteger(TERMINAL_X64)) +
                TOSTR((bool)::TerminalInfoInteger(TERMINAL_VPS)) + TOSTR2((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)) +
                TOSTR(::TimeCurrent()) + TOSTR(::TimeTradeServer()) +
                TOSTR(MT4ORDERS::TimeToString(MT4ORDERS::GetTimeCurrent())) + TOSTR(MT4ORDERS::TimeToString(PrevTimeCurrent)) +
                "PrevTick =" + MT4ORDERS::TickToString(Request.symbol, PrevTick) + "\n" +
                "CurrentTick =" + MT4ORDERS::TickToString(Request.symbol) + "\n" +
                TOSTR(::SymbolInfoString(Request.symbol, SYMBOL_PATH)) + TOSTR(::SymbolInfoString(Request.symbol, SYMBOL_DESCRIPTION)) +
                TOSTR(::PositionsTotal()) + TOSTR(::OrdersTotal()) +
                TOSTR(::HistorySelect(0, INT_MAX)) + TOSTR(::HistoryDealsTotal()) + TOSTR(::HistoryOrdersTotal()) +
                (::HistoryDealsTotal() ? TOSTR(::HistoryDealGetTicket(::HistoryDealsTotal() - 1)) +
                   "DEAL_TIME_MSC = " + MT4ORDERS::TimeToString(::HistoryDealGetInteger(::HistoryDealGetTicket(::HistoryDealsTotal() - 1), DEAL_TIME_MSC)) + "\n"
                                       : NULL) +
                (::HistoryOrdersTotal() ? TOSTR(::HistoryOrderGetTicket(::HistoryOrdersTotal() - 1)) +
                   "ORDER_TIME_DONE_MSC = " + MT4ORDERS::TimeToString(::HistoryOrderGetInteger(::HistoryOrderGetTicket(::HistoryOrdersTotal() - 1), ORDER_TIME_DONE_MSC)) + "\n"
                                        : NULL) +
                TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE)) + TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL)) +
                TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)) + TOSTR(::TerminalInfoInteger(TERMINAL_MEMORY_USED)) +
                TOSTR(::MQLInfoInteger(MQL_MEMORY_LIMIT)) + TOSTR(::MQLInfoInteger(MQL_MEMORY_USED)) +
                TOSTR(MT4ORDERS::IsHedging) + TOSTR(Res) + TOSTR(MT4ORDERS::OrderSendBug) +
                MT4ORDERS::ToString(Request) + MT4ORDERS::ToString(Result));
      }
      else
        MT4ORDERS::OrderSend_Benchmark(Interval1, Interval2);
    }
    else if (!MT4ORDERS::IsTester && MT4ORDERS::OrderSend_MaxPause)
    {
      Result.comment += " " + ::DoubleToString(Interval1 / 1000.0, 3) + " ms";

      ::Print(TOSTR(::TimeCurrent()) + TOSTR(::TimeTradeServer()) + TOSTR(MT4ORDERS::TimeToString(PrevTimeCurrent)) +
              MT4ORDERS::TickToString(Request.symbol, PrevTick) + "\n" + MT4ORDERS::TickToString(Request.symbol) + "\n" +
              MT4ORDERS::ToString(Request) + MT4ORDERS::ToString(Result));
    }

    return(Res);
  }

#undef TOSTR2
#undef TOSTR
#undef WHILE

  static ENUM_DAY_OF_WEEK GetDayOfWeek( const datetime &time )
  {
    MqlDateTime sTime = {0};

    ::TimeToStruct(time, sTime);

    return((ENUM_DAY_OF_WEEK)sTime.day_of_week);
  }

  static bool SessionTrade( const string &Symb )
  {
    datetime TimeNow = ::TimeCurrent();

    const ENUM_DAY_OF_WEEK DayOfWeek = MT4ORDERS::GetDayOfWeek(TimeNow);

    TimeNow %= 24 * 60 * 60;

    bool Res = false;
    datetime From, To;

    for (int i = 0; (!Res) && ::SymbolInfoSessionTrade(Symb, DayOfWeek, i, From, To); i++)
      Res = ((From <= TimeNow) && (TimeNow < To));

    return(Res);
  }

  static bool SymbolTrade( const string &Symb )
  {
    MqlTick Tick;

    return(::SymbolInfoTick(Symb, Tick) ? (Tick.bid && Tick.ask && MT4ORDERS::SessionTrade(Symb)) : false);
  }

  static bool CorrectResult( void )
  {
    ::ZeroMemory(MT4ORDERS::LastTradeResult);

    MT4ORDERS::LastTradeResult.retcode = MT4ORDERS::LastTradeCheckResult.retcode;
    MT4ORDERS::LastTradeResult.comment = MT4ORDERS::LastTradeCheckResult.comment;

    return(false);
  }

  static bool NewOrderCheck( void )
  {
    return((::OrderCheck(MT4ORDERS::LastTradeRequest, MT4ORDERS::LastTradeCheckResult) &&
           (MT4ORDERS::IsTester || MT4ORDERS::SymbolTrade(MT4ORDERS::LastTradeRequest.symbol))) ||
           (!MT4ORDERS::IsTester && MT4ORDERS::CorrectResult()));
  }

  static bool NewOrderSend( const int &Check )
  {
    return((Check == INT_MAX) ? MT4ORDERS::NewOrderCheck() :
           (((Check != INT_MIN) || MT4ORDERS::NewOrderCheck()) && MT4ORDERS::OrderSend(MT4ORDERS::LastTradeRequest, MT4ORDERS::LastTradeResult) ? MT4ORDERS::LastTradeResult.retcode < TRADE_RETCODE_ERROR : false));
  }

  static bool ModifyPosition( const long &Ticket, MqlTradeRequest &Request )
  {
    const bool Res = _B2(::PositionSelectByTicket(Ticket));

    if (Res)
    {
      Request.action = TRADE_ACTION_SLTP;

      Request.position = Ticket;
      Request.symbol = ::PositionGetString(POSITION_SYMBOL); // One ticket is not enough!
    }

    return(Res);
  }

  static ENUM_ORDER_TYPE_FILLING GetFilling( const string &Symb, const uint Type = ORDER_FILLING_FOK )
  {
    static ENUM_ORDER_TYPE_FILLING Res = ORDER_FILLING_FOK;
    static string LastSymb = NULL;
    static uint LastType = ORDER_FILLING_FOK;

    const bool SymbFlag = (LastSymb != Symb);

    if (SymbFlag || (LastType != Type)) // You can speed up a little by changing the order of checking the conditions
    {
      LastType = Type;

      if (SymbFlag)
        LastSymb = Symb;

      const ENUM_SYMBOL_TRADE_EXECUTION ExeMode = (ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(Symb, SYMBOL_TRADE_EXEMODE);
      const int FillingMode = (int)::SymbolInfoInteger(Symb, SYMBOL_FILLING_MODE);

      Res = (!FillingMode || (Type >= ORDER_FILLING_RETURN) || ((FillingMode & (Type + 1)) != Type + 1)) ?
            (((ExeMode == SYMBOL_TRADE_EXECUTION_EXCHANGE) || (ExeMode == SYMBOL_TRADE_EXECUTION_INSTANT)) ?
             ORDER_FILLING_RETURN : ((FillingMode == SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) :
            (ENUM_ORDER_TYPE_FILLING)Type;
    }

    return(Res);
  }

  static ENUM_ORDER_TYPE_TIME GetExpirationType( const string &Symb, uint Expiration = ORDER_TIME_GTC )
  {
    static ENUM_ORDER_TYPE_TIME Res = ORDER_TIME_GTC;
    static string LastSymb = NULL;
    static uint LastExpiration = ORDER_TIME_GTC;

    const bool SymbFlag = (LastSymb != Symb);

    if ((LastExpiration != Expiration) || SymbFlag)
    {
      LastExpiration = Expiration;

      if (SymbFlag)
        LastSymb = Symb;

      const int ExpirationMode = (int)::SymbolInfoInteger(Symb, SYMBOL_EXPIRATION_MODE);

      if ((Expiration > ORDER_TIME_SPECIFIED_DAY) || (!((ExpirationMode >> Expiration) & 1)))
      {
        if ((Expiration < ORDER_TIME_SPECIFIED) || (ExpirationMode < SYMBOL_EXPIRATION_SPECIFIED))
          Expiration = ORDER_TIME_GTC;
        else if (Expiration > ORDER_TIME_DAY)
          Expiration = ORDER_TIME_SPECIFIED;

        uint i = 1 << Expiration;

        while ((Expiration <= ORDER_TIME_SPECIFIED_DAY) && ((ExpirationMode & i) != i))
        {
          i <<= 1;
          Expiration++;
        }
      }

      Res = (ENUM_ORDER_TYPE_TIME)Expiration;
    }

    return(Res);
  }

  static bool ModifyOrder( const long Ticket, const double &Price, const datetime &Expiration, MqlTradeRequest &Request )
  {
    const bool Res = _B2(::OrderSelect(Ticket));

    if (Res)
    {
      Request.action = TRADE_ACTION_MODIFY;
      Request.order = Ticket;

      Request.price = Price;

      Request.symbol = ::OrderGetString(ORDER_SYMBOL);

      Request.type_filling = _B2(MT4ORDERS::GetFilling(Request.symbol));
      Request.type_time = _B2(MT4ORDERS::GetExpirationType(Request.symbol, (uint)Expiration));

      if (Expiration > ORDER_TIME_DAY)
        Request.expiration = Expiration;
    }

    return(Res);
  }

  static bool SelectByPosHistory( const int Index )
  {
    const long Ticket = MT4ORDERS::History[Index];
    const bool Res = (Ticket > 0) ? _B2(MT4ORDERS::HistorySelectDeal(Ticket)) : ((Ticket < 0) && _B2(MT4ORDERS::HistorySelectOrder(-Ticket)));

    if (Res)
    {
      if (Ticket > 0)
        _BV2(MT4ORDERS::GetHistoryPositionData(Ticket))
      else
        _BV2(MT4ORDERS::GetHistoryOrderData(-Ticket))
    }

    return(Res);
  }

  static bool OrderVisible( void )
  {
    bool Market = false;
    bool Res = !(::OrderGetInteger(ORDER_POSITION_ID) &&
                 (Market = (::OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL))); // Partial-delayer has non-zero PositionID

    if (Res && Market)
    {
      const long Ticket = ::PositionGetInteger(POSITION_TICKET);

      if (_B2(::PositionSelectByTicket(::OrderGetInteger(ORDER_TICKET)))) // The order and its position can be simultaneous - this condition will help only on Hedge accounts
      {
        if (Ticket && (::PositionGetInteger(POSITION_TICKET) != Ticket))
          _B2(::PositionSelectByTicket(Ticket));

        Res = false;
      }
    }
    return(Res);
  }

  static ulong OrderGetTicket( const int Index )
  {
    ulong Res;
    int PrevTotal;
    const long PrevTicket = ::OrderGetInteger(ORDER_TICKET);

    do
    {
      Res = 0;
      PrevTotal = ::OrdersTotal();

      if ((Index >= 0) && (Index < PrevTotal))
      {
        int Count = 0;

        for (int i = 0; i < PrevTotal; i++)
        {
          const int Total = ::OrdersTotal();

          if (Total != PrevTotal)
          {
            PrevTotal = Total;

            Count = 0;
            i = -1;
          }
          else
          {
            const ulong Ticket = ::OrderGetTicket(i);

            if (Ticket && MT4ORDERS::OrderVisible())
            {
              if (Count == Index)
              {
                Res = Ticket;

                break;
              }

              Count++;
            }
          }
        }

        if (!Res && PrevTicket && (::OrderGetInteger(ORDER_TICKET) != PrevTicket))
          const bool AntiWarning = _B2(::OrderSelect(PrevTicket));
      }
    } while (PrevTotal != ::OrdersTotal()); // The number of orders may change during the search

    return(Res);
  }

  static bool SelectByPos( const int Index )
  {
    bool Flag = (Index == INT_MAX);
    bool Res = Flag || (Index == INT_MIN);

    if (!Res)
    {
      const int Total = ::PositionsTotal();

      Flag = (Index < Total);
      Res = (Flag) ? _B2(::PositionGetTicket(Index)) :
                                                     #ifdef MT4ORDERS_SELECTFILTER_OFF
                                                       ::OrderGetTicket(Index - Total);
                                                     #else // MT4ORDERS_SELECTFILTER_OFF
                                                       (MT4ORDERS::IsTester ? ::OrderGetTicket(Index - Total) : _B2(MT4ORDERS::OrderGetTicket(Index - Total)));
                                                     #endif //MT4ORDERS_SELECTFILTER_OFF
    }

    if (Res)
    {
      if (Flag)
        MT4ORDERS::GetPositionData(); // (Index == INT_MAX) - switch to MT5 position without checking for existence and updating
      else
        MT4ORDERS::GetOrderData();    // (Index == INT_MIN) - switch to a live MT5 order without checking for existence and updating
    }

    return(Res);
  }

  static bool SelectByHistoryTicket( const long &Ticket )
  {
    bool Res = false;

    if (!Ticket) // Selection by OrderTicketID (zero value - balance operations)
    {
      const ulong TicketDealOut = MT4ORDERS::History.GetPositionDealOut(Ticket);

      if (Res = _B2(MT4ORDERS::HistorySelectDeal(TicketDealOut)))
        _BV2(MT4ORDERS::GetHistoryPositionData(TicketDealOut));
    }
    else if (_B2(MT4ORDERS::HistorySelectDeal(Ticket)))
    {
      if (Res = MT4HISTORY::IsMT4Deal(Ticket))
        _BV2(MT4ORDERS::GetHistoryPositionData(Ticket))
      else
      {
        const ulong TicketDealOut = MT4ORDERS::History.GetPositionDealOut(HistoryDealGetInteger(Ticket, DEAL_POSITION_ID)); // DealIn selection

        if (Res = _B2(MT4ORDERS::HistorySelectDeal(TicketDealOut)))
          _BV2(MT4ORDERS::GetHistoryPositionData(TicketDealOut))
      }
    }
    else if (_B2(MT4ORDERS::HistorySelectOrder(Ticket)))
    {
      if (Res = MT4HISTORY::IsMT4Order(Ticket))
        _BV2(MT4ORDERS::GetHistoryOrderData(Ticket))
      else
      {

        const ulong TicketDealOut = MT4ORDERS::History.GetPositionDealOut(HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID));

        if (Res = _B2(MT4ORDERS::HistorySelectDeal(TicketDealOut)))
          _BV2(MT4ORDERS::GetHistoryPositionData(TicketDealOut));
      }
    }
    else
    {

      const ulong TicketDealOut = MT4ORDERS::History.GetPositionDealOut(Ticket);

      if (Res = _B2(MT4ORDERS::HistorySelectDeal(TicketDealOut)))
        _BV2(MT4ORDERS::GetHistoryPositionData(TicketDealOut));
    }

    return(Res);
  }

  static bool SelectByExistingTicket( const long &Ticket )
  {
    bool Res = true;

    if (Ticket < 0)
    {
      if (_B2(::OrderSelect(-Ticket)))
        MT4ORDERS::GetOrderData();
      else if (_B2(::PositionSelectByTicket(-Ticket)))
        MT4ORDERS::GetPositionData();
      else
        Res = false;
    }
    else if (_B2(::PositionSelectByTicket(Ticket)))
      MT4ORDERS::GetPositionData();
    else if (_B2(::OrderSelect(Ticket)))
      MT4ORDERS::GetOrderData();
    else if (_B2(MT4ORDERS::HistorySelectDeal(Ticket)))
    {
      if (MT4HISTORY::IsMT4Deal(Ticket)) // If a choice is made by DealOut
        _BV2(MT4ORDERS::GetHistoryPositionData(Ticket))
      else if (_B2(::PositionSelectByTicket(::HistoryDealGetInteger(Ticket, DEAL_POSITION_ID)))) // DealIn selection
        MT4ORDERS::GetPositionData();
      else
        Res = false;
    }
    else if (_B2(MT4ORDERS::HistorySelectOrder(Ticket)) && _B2(::PositionSelectByTicket(::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID)))) // Выбор по тикету MT5-ордера
      MT4ORDERS::GetPositionData();
    else
      Res = false;

    return(Res);
  }

  static bool SelectByTicket( const long &Ticket, const int &Pool )
  {
    return((Pool == MODE_TRADES) || (Ticket < 0) ?
           (_B2(MT4ORDERS::SelectByExistingTicket(Ticket)) || ((Ticket > 0) && _B2(MT4ORDERS::SelectByHistoryTicket(Ticket)))) :
           (_B2(MT4ORDERS::SelectByHistoryTicket(Ticket)) || _B2(MT4ORDERS::SelectByExistingTicket(Ticket))));
  }

#ifdef MT4ORDERS_SLTP_OLD
  static void CheckPrices( double &MinPrice, double &MaxPrice, const double Min, const double Max )
  {
    if (MinPrice && (MinPrice >= Min))
      MinPrice = 0;

    if (MaxPrice && (MaxPrice <= Max))
      MaxPrice = 0;

    return;
  }
#endif // MT4ORDERS_SLTP_OLD

  static int OrdersTotal( void )
  {
    int Res = 0;
    const long PrevTicket = ::OrderGetInteger(ORDER_TICKET);
    int PrevTotal;

    do
    {
      PrevTotal = ::OrdersTotal();

      for (int i = PrevTotal - 1; i >= 0; i--)
      {
        const int Total = ::OrdersTotal();

        if (Total != PrevTotal)
        {
          PrevTotal = Total;

          Res = 0;
          i = PrevTotal;
        }
        else if (::OrderGetTicket(i) && MT4ORDERS::OrderVisible())
          Res++;
      }
    } while (PrevTotal != ::OrdersTotal()); // The number of orders may change during the search

    if (PrevTicket && (::OrderGetInteger(ORDER_TICKET) != PrevTicket))
      const bool AntiWarning = _B2(::OrderSelect(PrevTicket));

    return(Res);
  }

public:
  static uint OrderSend_MaxPause; // Maximum time for synchronization in microseconds

  static MqlTradeResult LastTradeResult;
  static MqlTradeRequest LastTradeRequest;
  static MqlTradeCheckResult LastTradeCheckResult;

  static bool MT4OrderSelect( const long &Index, const int &Select, const int &Pool )
  {
    return((Select == SELECT_BY_POS) ?
           ((Pool == MODE_TRADES) ? _B2(MT4ORDERS::SelectByPos((int)Index)) : _B2(MT4ORDERS::SelectByPosHistory((int)Index))) :
           _B2(MT4ORDERS::SelectByTicket(Index, Pool)));
  }

  static int MT4OrdersTotal( void )
  {
  #ifdef MT4ORDERS_SELECTFILTER_OFF
    return(::OrdersTotal() + ::PositionsTotal());
  #else // MT4ORDERS_SELECTFILTER_OFF
    int Res;

    if (MT4ORDERS::IsTester)
      return(::OrdersTotal() + ::PositionsTotal());
    else
    {
      int PrevTotal;

      do
      {
        PrevTotal = ::PositionsTotal();

        Res = _B2(MT4ORDERS::OrdersTotal()) + PrevTotal;

      } while (PrevTotal != ::PositionsTotal()); // We only track changes in positions, because orders are tracked in MT4ORDERS :: OrdersTotal ()
    }

    return(Res); // 
  #endif //MT4ORDERS_SELECTFILTER_OFF
  }

  static int MT4OrdersTotal( const bool )
  {
    return(::OrdersTotal());
  }

  static int MT4OrdersHistoryTotal( void )
  {
    return(MT4ORDERS::History.GetAmount());
  }

  static long MT4OrderSend( const string &Symb, const int &Type, const double &dVolume, const double &Price, const int &SlipPage, const double &SL, const double &TP,
                            const string &comment, const MAGIC_TYPE &magic, const datetime &dExpiration, const color &arrow_color )

  {
    ::ZeroMemory(MT4ORDERS::LastTradeRequest);

    MT4ORDERS::LastTradeRequest.action = (((Type == OP_BUY) || (Type == OP_SELL)) ? TRADE_ACTION_DEAL : TRADE_ACTION_PENDING);
    MT4ORDERS::LastTradeRequest.magic = magic;

    MT4ORDERS::LastTradeRequest.symbol = ((Symb == NULL) ? ::Symbol() : Symb);
    MT4ORDERS::LastTradeRequest.volume = dVolume;
    MT4ORDERS::LastTradeRequest.price = Price;

    MT4ORDERS::LastTradeRequest.tp = TP;
    MT4ORDERS::LastTradeRequest.sl = SL;
    MT4ORDERS::LastTradeRequest.deviation = SlipPage;
    MT4ORDERS::LastTradeRequest.type = (ENUM_ORDER_TYPE)Type;

    MT4ORDERS::LastTradeRequest.type_filling = _B2(MT4ORDERS::GetFilling(MT4ORDERS::LastTradeRequest.symbol, (uint)MT4ORDERS::LastTradeRequest.deviation));

    if (MT4ORDERS::LastTradeRequest.action == TRADE_ACTION_PENDING)
    {
      MT4ORDERS::LastTradeRequest.type_time = _B2(MT4ORDERS::GetExpirationType(MT4ORDERS::LastTradeRequest.symbol, (uint)dExpiration));

      if (dExpiration > ORDER_TIME_DAY)
        MT4ORDERS::LastTradeRequest.expiration = dExpiration;
    }

    if (comment != NULL)
      MT4ORDERS::LastTradeRequest.comment = comment;

    return((arrow_color == INT_MAX) ? (MT4ORDERS::NewOrderCheck() ? 0 : -1) :
           ((((int)arrow_color != INT_MIN) || MT4ORDERS::NewOrderCheck()) &&
            MT4ORDERS::OrderSend(MT4ORDERS::LastTradeRequest, MT4ORDERS::LastTradeResult) ?
            (MT4ORDERS::IsHedging ? (long)MT4ORDERS::LastTradeResult.order : // PositionID == Result.order - особенность MT5-Hedge
             ((MT4ORDERS::LastTradeRequest.action == TRADE_ACTION_DEAL) ?
              (MT4ORDERS::IsTester ? (_B2(::PositionSelect(MT4ORDERS::LastTradeRequest.symbol)) ? PositionGetInteger(POSITION_TICKET) : 0) :
                                      ::HistoryDealGetInteger(MT4ORDERS::LastTradeResult.deal, DEAL_POSITION_ID)) :
              (long)MT4ORDERS::LastTradeResult.order)) : -1));
  }

  static bool MT4OrderModify( const long &Ticket, const double &Price, const double &SL, const double &TP, const datetime &Expiration, const color &Arrow_Color )
  {
    ::ZeroMemory(MT4ORDERS::LastTradeRequest);

    bool Res = (Ticket < 0) ? MT4ORDERS::ModifyOrder(-Ticket, Price, Expiration, MT4ORDERS::LastTradeRequest) :
               ((MT4ORDERS::Order.Ticket != ORDER_SELECT) ?
                (MT4ORDERS::ModifyPosition(Ticket, MT4ORDERS::LastTradeRequest) || MT4ORDERS::ModifyOrder(Ticket, Price, Expiration, MT4ORDERS::LastTradeRequest)) :
                (MT4ORDERS::ModifyOrder(Ticket, Price, Expiration, MT4ORDERS::LastTradeRequest) || MT4ORDERS::ModifyPosition(Ticket, MT4ORDERS::LastTradeRequest)));

    {
      MT4ORDERS::LastTradeRequest.tp = TP;
      MT4ORDERS::LastTradeRequest.sl = SL;

      Res = MT4ORDERS::NewOrderSend(Arrow_Color);
    }

    return(Res);
  }

  static bool MT4OrderClose( const long &Ticket, const double &dLots, const double &Price, const int &SlipPage, const color &Arrow_Color, const string &comment )
  {

    _B2(::PositionSelectByTicket(Ticket));

    ::ZeroMemory(MT4ORDERS::LastTradeRequest);

    MT4ORDERS::LastTradeRequest.action = TRADE_ACTION_DEAL;
    MT4ORDERS::LastTradeRequest.position = Ticket;

    MT4ORDERS::LastTradeRequest.symbol = ::PositionGetString(POSITION_SYMBOL);

    MT4ORDERS::LastTradeRequest.comment = (comment == NULL) ? ::PositionGetString(POSITION_COMMENT) : comment;

    MT4ORDERS::LastTradeRequest.volume = dLots;
    MT4ORDERS::LastTradeRequest.price = Price;

  #ifdef MT4ORDERS_SLTP_OLD

    MT4ORDERS::LastTradeRequest.tp = ::PositionGetDouble(POSITION_SL);
    MT4ORDERS::LastTradeRequest.sl = ::PositionGetDouble(POSITION_TP);

    if (MT4ORDERS::LastTradeRequest.tp || MT4ORDERS::LastTradeRequest.sl)
    {
      const double __StopLevel = ::SymbolInfoInteger(MT4ORDERS::LastTradeRequest.symbol, SYMBOL_TRADE_STOPS_LEVEL) *
                                 ::SymbolInfoDouble(MT4ORDERS::LastTradeRequest.symbol, SYMBOL_POINT);

      const bool FlagBuy = (::PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
      const double CurrentPrice = SymbolInfoDouble(MT4ORDERS::LastTradeRequest.symbol, FlagBuy ? SYMBOL_ASK : SYMBOL_BID);

      if (CurrentPrice)
      {
        if (FlagBuy)
          MT4ORDERS::CheckPrices(MT4ORDERS::LastTradeRequest.tp, MT4ORDERS::LastTradeRequest.sl, CurrentPrice - __StopLevel, CurrentPrice + __StopLevel);
        else
          MT4ORDERS::CheckPrices(MT4ORDERS::LastTradeRequest.sl, MT4ORDERS::LastTradeRequest.tp, CurrentPrice - __StopLevel, CurrentPrice + __StopLevel);
      }
      else
      {
        MT4ORDERS::LastTradeRequest.tp = 0;
        MT4ORDERS::LastTradeRequest.sl = 0;
      }
    }
  #endif // MT4ORDERS_SLTP_OLD

    MT4ORDERS::LastTradeRequest.deviation = SlipPage;

    MT4ORDERS::LastTradeRequest.type = (ENUM_ORDER_TYPE)(1 - ::PositionGetInteger(POSITION_TYPE));

    MT4ORDERS::LastTradeRequest.type_filling = _B2(MT4ORDERS::GetFilling(MT4ORDERS::LastTradeRequest.symbol, (uint)MT4ORDERS::LastTradeRequest.deviation));

    return(MT4ORDERS::NewOrderSend(Arrow_Color));
  }

  static bool MT4OrderCloseBy( const long &Ticket, const long &Opposite, const color &Arrow_Color )
  {
    ::ZeroMemory(MT4ORDERS::LastTradeRequest);

    MT4ORDERS::LastTradeRequest.action = TRADE_ACTION_CLOSE_BY;
    MT4ORDERS::LastTradeRequest.position = Ticket;
    MT4ORDERS::LastTradeRequest.position_by = Opposite;

    if ((!MT4ORDERS::IsTester) && _B2(::PositionSelectByTicket(Ticket))) // Need for MT4ORDERS::SymbolTrade ()
      MT4ORDERS::LastTradeRequest.symbol = ::PositionGetString(POSITION_SYMBOL);

    return(MT4ORDERS::NewOrderSend(Arrow_Color));
  }

  static bool MT4OrderDelete( const long &Ticket, const color &Arrow_Color )
  {
    ::ZeroMemory(MT4ORDERS::LastTradeRequest);

    MT4ORDERS::LastTradeRequest.action = TRADE_ACTION_REMOVE;
    MT4ORDERS::LastTradeRequest.order = Ticket;

    if ((!MT4ORDERS::IsTester) && _B2(::OrderSelect(Ticket))) // Need for MT4ORDERS::SymbolTrade ()
      MT4ORDERS::LastTradeRequest.symbol = ::OrderGetString(ORDER_SYMBOL);

    return(MT4ORDERS::NewOrderSend(Arrow_Color));
  }

#define MT4_ORDERFUNCTION(NAME,T,A,B,C)                               \
  static T MT4Order##NAME( void )                                     \
  {                                                                   \
    return(POSITION_ORDER((T)(A), (T)(B), MT4ORDERS::Order.NAME, C)); \
  }

#define POSITION_ORDER(A,B,C,D) (((MT4ORDERS::Order.Ticket == POSITION_SELECT) && (D)) ? (A) : ((MT4ORDERS::Order.Ticket == ORDER_SELECT) ? (B) : (C)))

  MT4_ORDERFUNCTION(Ticket, long, ::PositionGetInteger(POSITION_TICKET), ::OrderGetInteger(ORDER_TICKET), true)
  MT4_ORDERFUNCTION(Type, int, ::PositionGetInteger(POSITION_TYPE), ::OrderGetInteger(ORDER_TYPE), true)
  MT4_ORDERFUNCTION(Lots, double, ::PositionGetDouble(POSITION_VOLUME), ::OrderGetDouble(ORDER_VOLUME_CURRENT), true)
  MT4_ORDERFUNCTION(OpenPrice, double, ::PositionGetDouble(POSITION_PRICE_OPEN), (::OrderGetDouble(ORDER_PRICE_OPEN) ? ::OrderGetDouble(ORDER_PRICE_OPEN) : ::OrderGetDouble(ORDER_PRICE_CURRENT)), true)
  MT4_ORDERFUNCTION(OpenTimeMsc, long, ::PositionGetInteger(POSITION_TIME_MSC), ::OrderGetInteger(ORDER_TIME_SETUP_MSC), true)
  MT4_ORDERFUNCTION(OpenTime, datetime, ::PositionGetInteger(POSITION_TIME), ::OrderGetInteger(ORDER_TIME_SETUP), true)
  MT4_ORDERFUNCTION(StopLoss, double, ::PositionGetDouble(POSITION_SL), ::OrderGetDouble(ORDER_SL), true)
  MT4_ORDERFUNCTION(TakeProfit, double, ::PositionGetDouble(POSITION_TP), ::OrderGetDouble(ORDER_TP), true)
  MT4_ORDERFUNCTION(ClosePrice, double, ::PositionGetDouble(POSITION_PRICE_CURRENT), ::OrderGetDouble(ORDER_PRICE_CURRENT), true)
  MT4_ORDERFUNCTION(CloseTimeMsc, long, 0, 0, true)
  MT4_ORDERFUNCTION(CloseTime, datetime, 0, 0, true)
  MT4_ORDERFUNCTION(Expiration, datetime, 0, ::OrderGetInteger(ORDER_TIME_EXPIRATION), true)
  MT4_ORDERFUNCTION(MagicNumber, long, ::PositionGetInteger(POSITION_MAGIC), ::OrderGetInteger(ORDER_MAGIC), true)
  MT4_ORDERFUNCTION(Profit, double, ::PositionGetDouble(POSITION_PROFIT), 0, true)
  MT4_ORDERFUNCTION(Swap, double, ::PositionGetDouble(POSITION_SWAP), 0, true)
  MT4_ORDERFUNCTION(Symbol, string, ::PositionGetString(POSITION_SYMBOL), ::OrderGetString(ORDER_SYMBOL), true)
  MT4_ORDERFUNCTION(Comment, string, MT4ORDERS::Order.Comment, ::OrderGetString(ORDER_COMMENT), MT4ORDERS::CheckPositionCommissionComment())
  MT4_ORDERFUNCTION(Commission, double, MT4ORDERS::Order.Commission, 0, MT4ORDERS::CheckPositionCommissionComment())

  MT4_ORDERFUNCTION(OpenPriceRequest, double, MT4ORDERS::Order.OpenPriceRequest, ::OrderGetDouble(ORDER_PRICE_OPEN), MT4ORDERS::CheckPositionOpenPriceRequest())
  MT4_ORDERFUNCTION(ClosePriceRequest, double, ::PositionGetDouble(POSITION_PRICE_CURRENT), ::OrderGetDouble(ORDER_PRICE_CURRENT), true)

  MT4_ORDERFUNCTION(TicketOpen, long, MT4ORDERS::Order.TicketOpen, ::OrderGetInteger(ORDER_TICKET), MT4ORDERS::CheckPositionTicketOpen())
  MT4_ORDERFUNCTION(OpenReason, ENUM_DEAL_REASON, ::PositionGetInteger(POSITION_REASON), ::OrderGetInteger(ORDER_REASON), true)
  MT4_ORDERFUNCTION(CloseReason, ENUM_DEAL_REASON, 0, ::OrderGetInteger(ORDER_REASON), true)
  MT4_ORDERFUNCTION(TicketID, long, ::PositionGetInteger(POSITION_IDENTIFIER), ::OrderGetInteger(ORDER_TICKET), true)

#undef POSITION_ORDER
#undef MT4_ORDERFUNCTION

  static void MT4OrderPrint( void )
  {
    if (MT4ORDERS::Order.Ticket == POSITION_SELECT)
      MT4ORDERS::CheckPositionCommissionComment();

    ::Print(MT4ORDERS::Order.ToString());

    return;
  }

#undef ORDER_SELECT
#undef POSITION_SELECT
};

static MT4_ORDER MT4ORDERS::Order = {0};

static MT4HISTORY MT4ORDERS::History;

static const bool MT4ORDERS::IsTester = ::MQLInfoInteger(MQL_TESTER);

static const bool MT4ORDERS::IsHedging = ((ENUM_ACCOUNT_MARGIN_MODE)::AccountInfoInteger(ACCOUNT_MARGIN_MODE) ==
                                          ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);

static int MT4ORDERS::OrderSendBug = 0;

static uint MT4ORDERS::OrderSend_MaxPause = 1000000; // Maximum time for synchronization in microseconds

static MqlTradeResult MT4ORDERS::LastTradeResult = {0};
static MqlTradeRequest MT4ORDERS::LastTradeRequest;// = {0};
static MqlTradeCheckResult MT4ORDERS::LastTradeCheckResult = {0};

bool OrderClose( const long Ticket, const double dLots, const double Price, const int SlipPage, const color Arrow_Color = clrNONE, const string comment = NULL )
{
  return(MT4ORDERS::MT4OrderClose(Ticket, dLots, Price, SlipPage, Arrow_Color, comment));
}

bool OrderModify( const long Ticket, const double Price, const double SL, const double TP, const datetime Expiration, const color Arrow_Color = clrNONE )
{
  return(MT4ORDERS::MT4OrderModify(Ticket, Price, SL, TP, Expiration, Arrow_Color));
}

bool OrderCloseBy( const long Ticket, const long Opposite, const color Arrow_Color = clrNONE )
{
  return(MT4ORDERS::MT4OrderCloseBy(Ticket, Opposite, Arrow_Color));
}

bool OrderDelete( const long Ticket, const color Arrow_Color = clrNONE )
{
  return(MT4ORDERS::MT4OrderDelete(Ticket, Arrow_Color));
}

void OrderPrint( void )
{
  MT4ORDERS::MT4OrderPrint();

  return;
}

#define MT4_ORDERGLOBALFUNCTION(NAME,T)     \
  T Order##NAME( void )                     \
  {                                         \
    return((T)MT4ORDERS::MT4Order##NAME()); \
  }

MT4_ORDERGLOBALFUNCTION(sHistoryTotal, int)
MT4_ORDERGLOBALFUNCTION(Ticket, TICKET_TYPE)
MT4_ORDERGLOBALFUNCTION(Type, int)
MT4_ORDERGLOBALFUNCTION(Lots, double)
MT4_ORDERGLOBALFUNCTION(OpenPrice, double)
MT4_ORDERGLOBALFUNCTION(OpenTimeMsc, long)
MT4_ORDERGLOBALFUNCTION(OpenTime, datetime)
MT4_ORDERGLOBALFUNCTION(StopLoss, double)
MT4_ORDERGLOBALFUNCTION(TakeProfit, double)
MT4_ORDERGLOBALFUNCTION(ClosePrice, double)
MT4_ORDERGLOBALFUNCTION(CloseTimeMsc, long)
MT4_ORDERGLOBALFUNCTION(CloseTime, datetime)
MT4_ORDERGLOBALFUNCTION(Expiration, datetime)
MT4_ORDERGLOBALFUNCTION(MagicNumber, MAGIC_TYPE)
MT4_ORDERGLOBALFUNCTION(Profit, double)
MT4_ORDERGLOBALFUNCTION(Commission, double)
MT4_ORDERGLOBALFUNCTION(Swap, double)
MT4_ORDERGLOBALFUNCTION(Symbol, string)
MT4_ORDERGLOBALFUNCTION(Comment, string)

MT4_ORDERGLOBALFUNCTION(OpenPriceRequest, double)
MT4_ORDERGLOBALFUNCTION(ClosePriceRequest, double)

MT4_ORDERGLOBALFUNCTION(TicketOpen, long)
MT4_ORDERGLOBALFUNCTION(OpenReason, ENUM_DEAL_REASON)
MT4_ORDERGLOBALFUNCTION(CloseReason, ENUM_DEAL_REASON)
MT4_ORDERGLOBALFUNCTION(TicketID, long)

#undef MT4_ORDERGLOBALFUNCTION

#define OrdersTotal MT4ORDERS::MT4OrdersTotal // AFTER Expert / Expert.mqh - there is a call to MT5-OrdersTotal ()

bool OrderSelect( const long Index, const int Select, const int Pool = MODE_TRADES )
{
  return(_B2(MT4ORDERS::MT4OrderSelect(Index, Select, Pool)));
}

TICKET_TYPE OrderSend( const string Symb, const int Type, const double dVolume, const double Price, const int SlipPage, const double SL, const double TP,
                       const string comment = NULL, const MAGIC_TYPE magic = 0, const datetime dExpiration = 0, color arrow_color = clrNONE )
{
  return((TICKET_TYPE)MT4ORDERS::MT4OrderSend(Symb, Type, dVolume, Price, SlipPage, SL, TP, comment, magic, dExpiration, arrow_color));
}

#define RETURN_ASYNC(A) return((A) && ::OrderSendAsync(MT4ORDERS::LastTradeRequest, MT4ORDERS::LastTradeResult) &&                        \
                               (MT4ORDERS::LastTradeResult.retcode == TRADE_RETCODE_PLACED) ? MT4ORDERS::LastTradeResult.request_id : 0);

uint OrderCloseAsync( const long Ticket, const double dLots, const double Price, const int SlipPage, const color Arrow_Color = clrNONE )
{
  RETURN_ASYNC(OrderClose(Ticket, dLots, Price, SlipPage, INT_MAX))
}

uint OrderModifyAsync( const long Ticket, const double Price, const double SL, const double TP, const datetime Expiration, const color Arrow_Color = clrNONE )
{
  RETURN_ASYNC(OrderModify(Ticket, Price, SL, TP, Expiration, INT_MAX))
}

uint OrderDeleteAsync( const long Ticket, const color Arrow_Color = clrNONE )
{
  RETURN_ASYNC(OrderDelete(Ticket, INT_MAX))
}

uint OrderSendAsync( const string Symb, const int Type, const double dVolume, const double Price, const int SlipPage, const double SL, const double TP,
                    const string comment = NULL, const MAGIC_TYPE magic = 0, const datetime dExpiration = 0, color arrow_color = clrNONE )
{
  RETURN_ASYNC(!OrderSend(Symb, Type, dVolume, Price, SlipPage, SL, TP, comment, magic, dExpiration, INT_MAX))
}

#undef RETURN_ASYNC

#undef MT4ORDERS_SLTP_OLD

#undef _BV2
#undef _B3
#undef _B2

#ifdef MT4ORDERS_BENCHMARK_MINTIME
  #undef MT4ORDERS_BENCHMARK_MINTIME
#endif // MT4ORDERS_BENCHMARK_MINTIME

#endif // __MT4ORDERS__
#else  // __MQL5__
  #define TICKET_TYPE int
  #define MAGIC_TYPE  int
#endif // __MQL5__

#ifdef __MQL5__

#include <StdLibErr.mqh>

ENUM_TIMEFRAMES TFMigrate(int __timeframe)
{
   switch (__timeframe)
   {
      case 0:
         return (PERIOD_CURRENT);
      case 1:
         return (PERIOD_M1);
      case 5:
         return (PERIOD_M5);
      case 15:
         return (PERIOD_M15);
      case 30:
         return (PERIOD_M30);
      case 60:
         return (PERIOD_H1);
      case 240:
         return (PERIOD_H4);
      case 1440:
         return (PERIOD_D1);
      case 10080:
         return (PERIOD_W1);
      case 43200:
         return (PERIOD_MN1);

      case 2:
         return (PERIOD_M2);
      case 3:
         return (PERIOD_M3);
      case 4:
         return (PERIOD_M4);
      case 6:
         return (PERIOD_M6);
      case 10:
         return (PERIOD_M10);
      case 12:
         return (PERIOD_M12);
      case 16385:
         return (PERIOD_H1);
      case 16386:
         return (PERIOD_H2);
      case 16387:
         return (PERIOD_H3);
      case 16388:
         return (PERIOD_H4);
      case 16390:
         return (PERIOD_H6);
      case 16392:
         return (PERIOD_H8);
      case 16396:
         return (PERIOD_H12);
      case 16408:
         return (PERIOD_D1);
      case 32769:
         return (PERIOD_W1);
      case 49153:
         return (PERIOD_MN1);
      default:
         return (PERIOD_CURRENT);
   }
}

ENUM_APPLIED_PRICE PriceMigrate(int __price)
{
   switch (__price)
   {
      case 1:
         return (PRICE_CLOSE);
      case 2:
         return (PRICE_OPEN);
      case 3:
         return (PRICE_HIGH);
      case 4:
         return (PRICE_LOW);
      case 5:
         return (PRICE_MEDIAN);
      case 6:
         return (PRICE_TYPICAL);
      case 7:
         return (PRICE_WEIGHTED);
      default:
         return (PRICE_CLOSE);
   }
}

ENUM_MA_METHOD MethodMigrate(int __method)
{
   switch (__method)
   {
      case 0:
         return (MODE_SMA);
      case 1:
         return (MODE_EMA);
      case 2:
         return (MODE_SMMA);
      case 3:
         return (MODE_LWMA);
      default:
         return (MODE_SMA);
   }
}

ENUM_STO_PRICE StoFieldMigrate(int __field)
{
   switch (__field)
   {
      case 0:
         return (STO_LOWHIGH);
      case 1:
         return (STO_CLOSECLOSE);
      default:
         return (STO_LOWHIGH);
   }
}

#define Point                               _Point
#define Digits                              _Digits
#define Bid                                 (::SymbolInfoDouble(_Symbol, ::SYMBOL_BID))
#define Ask                                 (::SymbolInfoDouble(_Symbol, ::SYMBOL_ASK))

#define DoubleToStr                         DoubleToString
#define StringGetChar                       StringGetCharacter
#define StrToInteger                        (int)StringToInteger
#define StrToTime                           StringToTime
#define TimeToStr                           TimeToString

#define EMPTY                              -1

#define ERR_NO_ERROR                        0
#define ERR_NO_RESULT                       1
#define ERR_SERVER_BUSY                     4
#define ERR_NO_CONNECTION                   6
#define ERR_TRADE_TIMEOUT                 128
#define ERR_INVALID_PRICE                 129
#define ERR_NOT_ENOUGH_MONEY              134
#define ERR_PRICE_CHANGED                 135
#define ERR_OFF_QUOTES                    136
#define ERR_BROKER_BUSY                   137
#define ERR_REQUOTE                       138
#define ERR_TRADE_MODIFY_DENIED           145
#define ERR_TRADE_CONTEXT_BUSY            146

#define MODE_TIME                           5
#define MODE_BID                            9
#define MODE_ASK                           10
#define MODE_POINT                         11
#define MODE_DIGITS                        12
#define MODE_SPREAD                        13
#define MODE_STOPLEVEL                     14
#define MODE_LOTSIZE                       15
#define MODE_TICKVALUE                     16
#define MODE_TICKSIZE                      17
#define MODE_SWAPLONG                      18
#define MODE_SWAPSHORT                     19
#define MODE_STARTING                      20
#define MODE_EXPIRATION                    21
#define MODE_TRADEALLOWED                  22
#define MODE_MINLOT                        23
#define MODE_LOTSTEP                       24
#define MODE_MAXLOT                        25
#define MODE_SWAPTYPE                      26
#define MODE_PROFITCALCMODE                27
#define MODE_MARGINCALCMODE                28
#define MODE_MARGININIT                    29
#define MODE_MARGINMAINTENANCE             30
#define MODE_MARGINHEDGED                  31
#define MODE_MARGINREQUIRED                32
#define MODE_FREEZELEVEL                   33

#define LONG_VALUE                          INT_VALUE

#define OBJPROP_TIME1                       OBJPROP_TIME
#define OBJPROP_PRICE1                      OBJPROP_PRICE

#define MODE_ASCEND                         0
#define MODE_DESCEND                        1

#define MODE_TENKANSEN                      1
#define MODE_KIJUNSEN                       2
#define MODE_SENKOUSPANA                    3
#define MODE_SENKOUSPANB                    4 
#define MODE_CHIKOUSPAN                     5

void HideTestIndicators(bool __status = true)
{
   TesterHideIndicators(__status);
}

bool IsTradeContextBusy(void)
{
   return (false);
}

bool RefreshRates(void)
{
   return (true);
}

double AccountFreeMarginCheck(const string __symbol, const int __cmd, const double __volume)
{
   double __Margin = 0;

   return (::AccountInfoDouble(::ACCOUNT_MARGIN_FREE) -
           (::OrderCalcMargin((ENUM_ORDER_TYPE)__cmd, __symbol, __volume, ::SymbolInfoDouble(__symbol, (__cmd == ::ORDER_TYPE_BUY) ? ::SYMBOL_ASK : ::SYMBOL_BID), __Margin) ? __Margin : 0));
}

bool ObjectCreate(string __name, ENUM_OBJECT __type, int __window, datetime __time1, double __price1, datetime __time2 = 0, double __price2 = 0, datetime __time3 = 0, double __price3 = 0)
{
   return (ObjectCreate(0, __name, __type, __window, __time1, __price1, __time2, __price2, __time3, __price3));
}

bool ObjectDelete(string __name)
{
   return (ObjectDelete(0, __name));
}

int ObjectFind(string __name)
{
   return (ObjectFind(0, __name));
}

bool ObjectMove(string __name, int __point, datetime __time1, double __price1)
{
   return (ObjectMove(0, __name, __point, __time1, __price1));
}

string ObjectName(int __index)
{
   return (ObjectName(0, __index));
}

bool ObjectSet(string __name, ENUM_OBJECT_PROPERTY_INTEGER __index, long __value)
{
   return ((bool)ObjectSetInteger(0, __name, __index, __value));
}

bool ObjectSet(string __name, ENUM_OBJECT_PROPERTY_DOUBLE __index, double __value)
{
   return ((bool)ObjectSetDouble(0, __name, __index, __value));
}

bool ObjectSetText(string __name, string __text, int __font_size, string __font = "", color __text_color = CLR_NONE)
{
   int __ObjType = ObjectType(__name);

   if (__ObjType != OBJ_LABEL && __ObjType != OBJ_TEXT)
      return (false);

   if (StringLen(__text) > 0 && __font_size > 0)
   {
      if (ObjectSetString(0, __name, OBJPROP_TEXT, __text) == true && ObjectSetInteger(0, __name, OBJPROP_FONTSIZE, __font_size) == true)
      {
         if (StringLen(__font) > 0 && ObjectSetString(0, __name, OBJPROP_FONT, __font) == false)
            return (false);

         if (ObjectSetInteger(0, __name, OBJPROP_COLOR, __text_color) == false)
            return (false);

         return (true);
      }

      return (false);
   }

   return (false);
}

bool ObjectSetText(string __name, string __text)
{
   int __ObjType = ObjectType(__name);

   if (__ObjType != OBJ_LABEL && __ObjType != OBJ_TEXT)
      return (false);

   if (StringLen(__text) > 0)
   {
      if (ObjectSetString(0, __name, OBJPROP_TEXT, __text) == true)
         return (true);

      return (false);
   }

   return (false);
}

int ObjectType(string __name)
{
   return ((int)ObjectGetInteger(0, __name, OBJPROP_TYPE));
}

int ObjectsTotal(int __type = EMPTY, int __window = -1)
{
   return (ObjectsTotal(0, __window, __type));
}

void WindowRedraw()
{
   ChartRedraw(0);
}

int Year(void)
{
   MqlDateTime __Time;

   ::TimeToStruct(TimeCurrent(), __Time);

   return (__Time.year);
}

int DayOfWeek(void)
{
   MqlDateTime __Time;

   ::TimeToStruct(TimeCurrent(), __Time);

   return (__Time.day_of_week);
}

int TimeDayOfWeek(const datetime __date)
{
   MqlDateTime __Time;

   ::TimeToStruct(__date, __Time);

   return (__Time.day_of_week);
}

double GetMarginRequired(const string __symbol)
{
  MqlTick __Tick;
  double __MarginInit, __MarginMain;

  return (SymbolInfoTick(__symbol, __Tick) && SymbolInfoMarginRate(__symbol, ORDER_TYPE_BUY, __MarginInit, __MarginMain)
          ? __MarginInit * __Tick.ask * SymbolInfoDouble(__symbol, SYMBOL_TRADE_TICK_VALUE) / (SymbolInfoDouble(__symbol, SYMBOL_TRADE_TICK_SIZE) * AccountInfoInteger(ACCOUNT_LEVERAGE))
          : 0);
}

double MarketInfo(const string __symbol, const int __type)
{
   switch(__type)
   {
      case MODE_BID:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_BID));
      case MODE_ASK:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_ASK));
      case MODE_POINT:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_POINT));
      case MODE_DIGITS:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_DIGITS));
      case MODE_SPREAD:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_SPREAD));
      case MODE_LOW:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_LASTLOW));
      case MODE_HIGH:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_LASTHIGH));
      case MODE_TIME:
         return double(::SymbolInfoInteger(__symbol, ::SYMBOL_TIME));
      case MODE_STOPLEVEL:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_TRADE_STOPS_LEVEL));
      case MODE_LOTSIZE:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_TRADE_CONTRACT_SIZE));
      case MODE_MINLOT:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_VOLUME_MIN));
      case MODE_LOTSTEP:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_VOLUME_STEP));
      case MODE_MAXLOT:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_VOLUME_MAX));
      case MODE_TICKSIZE:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_TRADE_TICK_SIZE));
      case MODE_TICKVALUE:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_TRADE_TICK_VALUE));
      case MODE_SWAPTYPE:
         return double(::SymbolInfoInteger(__symbol, ::SYMBOL_SWAP_MODE));
      case MODE_SWAPLONG:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_SWAP_LONG));
      case MODE_SWAPSHORT:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_SWAP_SHORT));
      case MODE_STARTING:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_START_TIME));
      case MODE_EXPIRATION:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_EXPIRATION_TIME));
      case MODE_TRADEALLOWED:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED);
      case MODE_PROFITCALCMODE:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_TRADE_CALC_MODE));
      case MODE_MARGINCALCMODE:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_TRADE_CALC_MODE));
      case MODE_MARGININIT:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_MARGIN_INITIAL));
      case MODE_MARGINMAINTENANCE:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_MARGIN_MAINTENANCE));
      case MODE_MARGINHEDGED:
         return (::SymbolInfoDouble(__symbol, ::SYMBOL_MARGIN_HEDGED));
      case MODE_MARGINREQUIRED:
         return (GetMarginRequired(__symbol));
      case MODE_FREEZELEVEL:
         return ((double)::SymbolInfoInteger(__symbol, ::SYMBOL_TRADE_FREEZE_LEVEL));
   }

   return (-1);
}

string ErrorDescription(int __error)
{
   switch (__error)
   {
      case ERR_SUCCESS:
         return ("The operation completed successfully");
      case ERR_INTERNAL_ERROR:
         return ("Unexpected internal Error ");
      case ERR_WRONG_INTERNAL_PARAMETER:
         return ("Wrong parameter in the inner call of the client terminal function");
      case ERR_INVALID_PARAMETER:
         return ("Wrong parameter when calling the system function");
      case ERR_NOT_ENOUGH_MEMORY:
         return ("Not enough memory to perform the system function");
      case ERR_STRUCT_WITHOBJECTS_ORCLASS:
         return ("The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes");
      case ERR_INVALID_ARRAY:
         return ("Array of a wrong type, wrong size, or a damaged object of a dynamic array");
      case ERR_ARRAY_RESIZE_ERROR:
         return ("Not enough memory for the relocation of an array, or an attempt to change the size of a static array");
      case ERR_STRING_RESIZE_ERROR:
         return ("Not enough memory for the relocation of string");
      case ERR_NOTINITIALIZED_STRING:
         return ("Not initialized string");
      case ERR_INVALID_DATETIME:
         return ("Invalid date and/or time");
      case ERR_ARRAY_BAD_SIZE:
         return ("Requested array size exceeds 2GB");
      case ERR_INVALID_POINTER:
         return ("Wrong pointer");
      case ERR_INVALID_POINTER_TYPE:
         return ("Wrong type of pointer");
      case ERR_FUNCTION_NOT_ALLOWED:
         return ("Function is not allowed for call");
      case ERR_RESOURCE_NAME_DUPLICATED:
         return ("The names of the dynamic and the static resource match");
      case ERR_RESOURCE_NOT_FOUND:
         return ("Resource with this name has not been found in EX5");
      case ERR_RESOURCE_UNSUPPOTED_TYPE:
         return ("Unsupported resource type or its size exceeds 16MB");
      case ERR_RESOURCE_NAME_IS_TOO_LONG:
         return ("The resource name exceeds 63 characters");
      case ERR_CHART_WRONG_ID:
         return ("Wrong chart ID");
      case ERR_CHART_NO_REPLY:
         return ("Chart does not respond");
      case ERR_CHART_NOT_FOUND:
         return ("Chart not found");
      case ERR_CHART_NO_EXPERT:
         return ("No Expert Advisor in the chart that could handle the event");
      case ERR_CHART_CANNOT_OPEN:
         return ("Chart opening Error ");
      case ERR_CHART_CANNOT_CHANGE:
         return ("Failed to change chart symbol and period");
      case ERR_CHART_WRONG_PARAMETER:
         return ("Error value of the parameter for the function of working with charts");
      case ERR_CHART_CANNOT_CREATE_TIMER:
         return ("Failed to create timer");
      case ERR_CHART_WRONG_PROPERTY:
         return ("Wrong chart property ID");
      case ERR_CHART_SCREENSHOT_FAILED:
         return ("Error creating screenshots");
      case ERR_CHART_NAVIGATE_FAILED:
         return ("Error navigating through chart");
      case ERR_CHART_TEMPLATE_FAILED:
         return ("Error applying template");
      case ERR_CHART_WINDOW_NOT_FOUND:
         return ("Subwindow containing the indicator was not found");
      case ERR_CHART_INDICATOR_CANNOT_ADD:
         return ("Error adding an indicator to chart");
      case ERR_CHART_INDICATOR_CANNOT_DEL:
         return ("Error deleting an indicator from the chart");
      case ERR_CHART_INDICATOR_NOT_FOUND:
         return ("Indicator not found on the specified chart");
      case ERR_OBJECT_ERROR:
         return ("Error working with a graphical object");
      case ERR_OBJECT_NOT_FOUND:
         return ("Graphical object was not found");
      case ERR_OBJECT_WRONG_PROPERTY:
         return ("Wrong ID of a graphical object property");
      case ERR_OBJECT_GETDATE_FAILED:
         return ("Unable to get date corresponding to the value");
      case ERR_OBJECT_GETVALUE_FAILED:
         return ("Unable to get value corresponding to the date");
      case ERR_MARKET_UNKNOWN_SYMBOL:
         return ("Unknown symbol");
      case ERR_MARKET_NOT_SELECTED:
         return ("Symbol is not selected in MarketWatch");
      case ERR_MARKET_WRONG_PROPERTY:
         return ("Wrong identifier of a symbol property");
      case ERR_MARKET_LASTTIME_UNKNOWN:
         return ("Time of the last tick is not known (no ticks)");
      case ERR_MARKET_SELECT_ERROR:
         return ("Error adding or deleting a symbol in MarketWatch");
      case ERR_HISTORY_NOT_FOUND:
         return ("Requested history not found");
      case ERR_HISTORY_WRONG_PROPERTY:
         return ("Wrong ID of the history property");
      case ERR_HISTORY_TIMEOUT:
         return ("Exceeded history request timeout");
      case ERR_HISTORY_BARS_LIMIT:
         return ("Number of requested bars limited by terminal settings");
      case ERR_HISTORY_LOAD_ERRORS:
         return ("Multiple errors when loading history");
      case ERR_HISTORY_SMALL_BUFFER:
         return ("Receiving array is too small to store all requested data");
      case ERR_GLOBALVARIABLE_NOT_FOUND:
         return ("Global variable of the client terminal is not found");
      case ERR_GLOBALVARIABLE_EXISTS:
         return ("Global variable of the client terminal with the same name already exists");
      case ERR_MAIL_SEND_FAILED:
         return ("Email sending failed");
      case ERR_PLAY_SOUND_FAILED:
         return ("Sound playing failed");
      case ERR_MQL5_WRONG_PROPERTY:
         return ("Wrong identifier of the program property");
      case ERR_TERMINAL_WRONG_PROPERTY:
         return ("Wrong identifier of the terminal property");
      case ERR_FTP_SEND_FAILED:
         return ("File sending via ftp failed");
      case ERR_NOTIFICATION_SEND_FAILED:
         return ("Failed to send a notification");
      case ERR_NOTIFICATION_WRONG_PARAMETER:
         return ("Invalid parameter for sending a notification – an empty string or NULL has been passed to the SendNotification() function");
      case ERR_NOTIFICATION_WRONG_SETTINGS:
         return ("Wrong settings of notifications in the terminal (ID is not specified or permission is not set)");
      case ERR_NOTIFICATION_TOO_FREQUENT:
         return ("Too frequent sending of notifications");
      case ERR_FTP_NOSERVER:
         return ("FTP server is not specified");
      case ERR_FTP_NOLOGIN:
         return ("FTP login is not specified");
      case ERR_FTP_FILE_ERROR:
         return ("File not found in the MQL5\\Files directory to send on FTP server");
      case ERR_FTP_CONNECT_FAILED:
         return ("FTP connection failed");
      case ERR_FTP_CHANGEDIR:
         return ("FTP path not found on server");
      case ERR_BUFFERS_NO_MEMORY:
         return ("Not enough memory for the distribution of indicator buffers");
      case ERR_BUFFERS_WRONG_INDEX:
         return ("Wrong indicator buffer index");
      case ERR_CUSTOM_WRONG_PROPERTY:
         return ("Wrong ID of the custom indicator property");
      case ERR_ACCOUNT_WRONG_PROPERTY:
         return ("Wrong account property ID");
      case ERR_TRADE_WRONG_PROPERTY:
         return ("Wrong trade property ID");
      case ERR_TRADE_DISABLED:
         return ("Trading by Expert Advisors prohibited");
      case ERR_TRADE_POSITION_NOT_FOUND:
         return ("Position not found");
      case ERR_TRADE_ORDER_NOT_FOUND:
         return ("Order not found");
      case ERR_TRADE_DEAL_NOT_FOUND:
         return ("Deal not found");
      case ERR_TRADE_SEND_FAILED:
         return ("Trade request sending failed");
      case ERR_INDICATOR_UNKNOWN_SYMBOL:
         return ("Unknown symbol");
      case ERR_INDICATOR_CANNOT_CREATE:
         return ("Indicator cannot be created");
      case ERR_INDICATOR_NO_MEMORY:
         return ("Not enough memory to add the indicator");
      case ERR_INDICATOR_CANNOT_APPLY:
         return ("The indicator cannot be applied to another indicator");
      case ERR_INDICATOR_CANNOT_ADD:
         return ("Error applying an indicator to chart");
      case ERR_INDICATOR_DATA_NOT_FOUND:
         return ("Requested data not found");
      case ERR_INDICATOR_WRONG_HANDLE:
         return ("Wrong indicator handle");
      case ERR_INDICATOR_WRONG_PARAMETERS:
         return ("Wrong number of parameters when creating an indicator");
      case ERR_INDICATOR_PARAMETERS_MISSING:
         return ("No parameters when creating an indicator");
      case ERR_INDICATOR_CUSTOM_NAME:
         return ("The first parameter in the array must be the name of the custom indicator");
      case ERR_INDICATOR_PARAMETER_TYPE:
         return ("Invalid parameter type in the array when creating an indicator");
      case ERR_INDICATOR_WRONG_INDEX:
         return ("Wrong index of the requested indicator buffer");
      case ERR_BOOKS_CANNOT_ADD:
         return ("Depth Of Market can not be added");
      case ERR_BOOKS_CANNOT_DELETE:
         return ("Depth Of Market can not be removed");
      case ERR_BOOKS_CANNOT_GET:
         return ("The data from Depth Of Market can not be obtained");
      case ERR_BOOKS_CANNOT_SUBSCRIBE:
         return ("Error in subscribing to receive new data from Depth Of Market");
      case ERR_TOO_MANY_FILES:
         return ("More than 64 files cannot be opened at the same time");
      case ERR_WRONG_FILENAME:
         return ("Invalid file name");
      case ERR_TOO_LONG_FILENAME:
         return ("Too long file name");
      case ERR_CANNOT_OPEN_FILE:
         return ("File opening Error ");
      case ERR_FILE_CACHEBUFFER_ERROR:
         return ("Not enough memory for cache to read");
      case ERR_CANNOT_DELETE_FILE:
         return ("File deleting Error ");
      case ERR_INVALID_FILEHANDLE:
         return ("A file with this handle was closed, or was not opening at all");
      case ERR_WRONG_FILEHANDLE:
         return ("Wrong file handle");
      case ERR_FILE_NOTTOWRITE:
         return ("The file must be opened for writing");
      case ERR_FILE_NOTTOREAD:
         return ("The file must be opened for reading");
      case ERR_FILE_NOTBIN:
         return ("The file must be opened as a binary one");
      case ERR_FILE_NOTTXT:
         return ("The file must be opened as a text");
      case ERR_FILE_NOTTXTORCSV:
         return ("The file must be opened as a text or CSV");
      case ERR_FILE_NOTCSV:
         return ("The file must be opened as CSV");
      case ERR_FILE_READERROR:
         return ("File reading Error ");
      case ERR_FILE_BINSTRINGSIZE:
         return ("String size must be specified, because the file is opened as binary");
      case ERR_INCOMPATIBLE_FILE:
         return ("A text file must be for string arrays, for other arrays - binary");
      case ERR_FILE_IS_DIRECTORY:
         return ("This is not a file, this is a directory");
      case ERR_FILE_NOT_EXIST:
         return ("File does not exist");
      case ERR_FILE_CANNOT_REWRITE:
         return ("File can not be rewritten");

      case ERR_DIRECTORY_NOT_EXIST:
         return ("Directory does not exist");
      case ERR_FILE_ISNOT_DIRECTORY:
         return ("This is a file, not a directory");
      case ERR_CANNOT_DELETE_DIRECTORY:
         return ("The directory cannot be removed");
      case ERR_CANNOT_CLEAN_DIRECTORY:
         return ("Failed to clear the directory (probably one or more files are blocked and removal operation failed)");
      case ERR_FILE_WRITEERROR:
         return ("Failed to write a resource to a file");
      case ERR_FILE_ENDOFFILE:
         return ("Unable to read the next piece of data from a CSV file (FileReadString, FileReadNumber, FileReadDatetime, FileReadBool), since the end of file is reached");
      case ERR_NO_STRING_DATE:
         return ("No date in the string");
      case ERR_WRONG_STRING_DATE:
         return ("Wrong date in the string");
      case ERR_WRONG_STRING_TIME:
         return ("Wrong time in the string");
      case ERR_STRING_TIME_ERROR:
         return ("Error converting string to date");
      case ERR_STRING_OUT_OF_MEMORY:
         return ("Not enough memory for the string");
      case ERR_STRING_SMALL_LEN:
         return ("The string length is less than expected");
      case ERR_STRING_TOO_BIGNUMBER:
         return ("Too large number, more than ULONG_MAX");
      case ERR_WRONG_FORMATSTRING:
         return ("Invalid format string");
      case ERR_TOO_MANY_FORMATTERS:
         return ("Amount of format specifiers more than the parameters");
      case ERR_TOO_MANY_PARAMETERS:
         return ("Amount of parameters more than the format specifiers");
      case ERR_WRONG_STRING_PARAMETER:
         return ("Damaged parameter of string type");
      case ERR_STRINGPOS_OUTOFRANGE:
         return ("Position outside the string");
      case ERR_STRING_ZEROADDED:
         return ("0 added to the string end, a useless operation");
      case ERR_STRING_UNKNOWNTYPE:
         return ("Unknown data type when converting to a string");
      case ERR_WRONG_STRING_OBJECT:
         return ("Damaged string object");
      case ERR_INCOMPATIBLE_ARRAYS:
         return ("Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only");
      case ERR_SMALL_ASSERIES_ARRAY:
         return ("The receiving array is declared as AS_SERIES, and it is of insufficient size");
      case ERR_SMALL_ARRAY:
         return ("Too small array, the starting position is outside the array");
      case ERR_ZEROSIZE_ARRAY:
         return ("An array of zero length");
      case ERR_NUMBER_ARRAYS_ONLY:
         return ("Must be a numeric array");
      case ERR_ONEDIM_ARRAYS_ONLY:
         return ("Must be a one-dimensional array");
      case ERR_SERIES_ARRAY:
         return ("Timeseries cannot be used");
      case ERR_DOUBLE_ARRAY_ONLY:
         return ("Must be an array of type double");
      case ERR_FLOAT_ARRAY_ONLY:
         return ("Must be an array of type float");
      case ERR_LONG_ARRAY_ONLY:
         return ("Must be an array of type long");
      case ERR_INT_ARRAY_ONLY:
         return ("Must be an array of type int");
      case ERR_SHORT_ARRAY_ONLY:
         return ("Must be an array of type short");
      case ERR_CHAR_ARRAY_ONLY:
         return ("Must be an array of type char");
      case ERR_OPENCL_NOT_SUPPORTED:
         return ("OpenCL functions are not supported on this computer");
      case ERR_OPENCL_INTERNAL:
         return ("Internal error occurred when running OpenCL");
      case ERR_OPENCL_INVALID_HANDLE:
         return ("Invalid OpenCL handle");
      case ERR_OPENCL_CONTEXT_CREATE:
         return ("Error creating the OpenCL context");
      case ERR_OPENCL_QUEUE_CREATE:
         return ("Failed to create a run queue in OpenCL");
      case ERR_OPENCL_PROGRAM_CREATE:
         return ("Error occurred when compiling an OpenCL program");
      case ERR_OPENCL_TOO_LONG_KERNEL_NAME:
         return ("Too long kernel name (OpenCL kernel)");
      case ERR_OPENCL_KERNEL_CREATE:
         return ("Error creating an OpenCL kernel");
      case ERR_OPENCL_SET_KERNEL_PARAMETER:
         return ("Error occurred when setting parameters for the OpenCL kernel");
      case ERR_OPENCL_EXECUTE:
         return ("OpenCL program runtime Error ");
      case ERR_OPENCL_WRONG_BUFFER_SIZE:
         return ("Invalid size of the OpenCL buffer");
      case ERR_OPENCL_WRONG_BUFFER_OFFSET:
         return ("Invalid offset in the OpenCL buffer");
      case ERR_OPENCL_BUFFER_CREATE:
         return ("Failed to create an OpenCL buffer");
      case ERR_WEBREQUEST_INVALID_ADDRESS:
         return ("Invalid URL");
      case ERR_WEBREQUEST_CONNECT_FAILED:
         return ("Failed to connect to specified URL");
      case ERR_WEBREQUEST_TIMEOUT:
         return ("Timeout exceeded");
      case ERR_WEBREQUEST_REQUEST_FAILED:
         return ("HTTP request failed");
      case ERR_USER_ERROR_FIRST:
         return ("User defined errors start with this code");
      default:
         return ("");
   }
}

double CopyBufferMQL4(int __handle, int __index, int __shift)
{
   double __Buffer[];

   switch (__index)
   {
      case 0:
         if (CopyBuffer(__handle, 0, __shift, 1, __Buffer) > 0)
            return (__Buffer[0]);

         break;
      case 1:
         if (CopyBuffer(__handle, 1, __shift, 1, __Buffer) > 0)
            return (__Buffer[0]);

         break;
      case 2:
         if (CopyBuffer(__handle, 2, __shift, 1, __Buffer) > 0)
            return (__Buffer[0]);

         break;
      case 3:
         if (CopyBuffer(__handle, 3, __shift, 1, __Buffer) > 0)
            return (__Buffer[0]);

         break;
      case 4:
         if (CopyBuffer(__handle, 4, __shift, 1, __Buffer) > 0)
            return (__Buffer[0]);

         break;
      default:
         break;
   }

   return (EMPTY_VALUE);
}

double iATRMQL4(string __symbol, int __timeframe, int __period, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);

   int __Handle = iATR(__symbol, __TimeFrame, __period);

   if (__Handle < 0)
   {
      Print("The iATR object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, 0, __shift));
}

#define iATR iATRMQL4

double iCloseMQL4(string __symbol, int __tf, int __index)
{
   if (__index < 0)
      return (-1);

   double __Array[];
   ENUM_TIMEFRAMES __Timeframe = TFMigrate(__tf);

   if (CopyClose(__symbol, __Timeframe, __index, 1, __Array) > 0)
      return (__Array[0]);

   return (-1);
}

#define iClose iCloseMQL4

double iCCIMQL4(string __symbol, int __timeframe, int __period, int __price, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);
   ENUM_APPLIED_PRICE __AppliedPrice = PriceMigrate(__price);

   int __Handle = iCCI(__symbol, __TimeFrame, __period, __AppliedPrice);

   if (__Handle < 0)
   {
      Print("The iCCI object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, 0, __shift));
}

#define iCCI iCCIMQL4

double iIchimokuMQL4(string __symbol, int __timeframe, int __tenkan_sen, int __kijun_sen, int __senkou_span_b, int __mode, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);

   int __Handle = iIchimoku(__symbol, __TimeFrame, __tenkan_sen, __kijun_sen, __senkou_span_b);

   if (__Handle < 0)
   {
      Print("The iIchimoku object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, __mode - 1, __shift));
}

#define iIchimoku iIchimokuMQL4

double iMAMQL4(string __symbol, int __timeframe, int __period, int __ma_shift, int __method, int __price, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);
   ENUM_MA_METHOD __Method = MethodMigrate(__method);
   ENUM_APPLIED_PRICE __AppliedPrice = PriceMigrate(__price);

   int __Handle = iMA(__symbol, __TimeFrame, __period, __ma_shift, __Method, __AppliedPrice);

   if (__Handle < 0)
   {
      Print("The iMA object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, 0, __shift));
}

#define iMA iMAMQL4

double iMAOnArrayMQL4(double &__array[], int __total, int __period, int __ma_shift, int __ma_method, int __shift)
{
   double __Buffer[], __Array[];

   if (__total == 0)
      __total = ArraySize(__Array);

   if (__total > 0 && __total <= __period)
      return (0);

   if (__shift > __total - __period - __ma_shift)
      return (0);

   switch (__ma_method)
   {
      case MODE_SMA :
      {
         __total = ArrayCopy(__Array, __array, 0, __shift + __ma_shift, __period);

         if (ArrayResize(__Buffer, __total) < 0)
            return (0);

         double __Sum = 0;
         int __Position = __total - 1;

         for (int __Index = 1; __Index < __period; __Index++, __Position--)
            __Sum += __Array[__Position];

         while (__Position >= 0)
         {
            __Sum += __Array[__Position];
            __Buffer[__Position] = __Sum / __period;
            __Sum -= __Array[__Position + __period - 1];
            __Position--;
         }

         return (__Buffer[0]);
      }
      case MODE_EMA :
      {
         if (ArrayResize(__Buffer, __total) < 0)
            return (0);

         double __pr = 2.0 / (__period + 1);
         int __Position = __total - 2;

         while (__Position >= 0)
         {
            if (__Position == __total - 2)
               __Buffer[__Position + 1] = __array[__Position + 1];

            __Buffer[__Position] = __array[__Position] * __pr + __Buffer[__Position + 1] * (1 - __pr);
            __Position--;
         }

         return (__Buffer[__shift + __ma_shift]);
      }
      case MODE_SMMA :
      {
         if (ArrayResize(__Buffer, __total) < 0)
            return (0);

         double __Sum = 0;
         int __Position = __total - __period;

         while (__Position >= 0)
         {
            if (__Position == __total - __period)
            {
               for (int __Index = 0, __Element = __Position; __Index < __period; __Index++, __Element++)
               {
                  __Sum += __array[__Element];
                  __Buffer[__Element] = 0;
               }
            }
            else
               __Sum = __Buffer[__Position + 1] * (__period - 1) + __array[__Position];

            __Buffer[__Position] = __Sum / __period;
            __Position--;
         }

         return (__Buffer[__shift + __ma_shift]);
      }
      case MODE_LWMA :
      {
         if (ArrayResize(__Buffer, __total) < 0)
            return (0);

         double __Sum = 0.0, __LinearSum = 0.0;
         double __Price;

         int __Index, __Weight = 0, __Position = __total - 1;

         for(__Index = 1; __Index <= __period; __Index++, __Position--)
         {
            __Price = __array[__Position];
            __Sum += __Price * __Index;
            __LinearSum += __Price;
            __Weight += __Index;
         }

         __Position++;
         __Index = __Position + __period;

         while (__Position >= 0)
         {
            __Buffer[__Position] = __Sum / __Weight;

            if (__Position == 0)
               break;

            __Position--;
            __Index--;
            __Price = __array[__Position];
            __Sum = __Sum - __LinearSum + __Price * __period;
            __LinearSum -= __array[__Index];
            __LinearSum += __Price;
         }

         return (__Buffer[__shift + __ma_shift]);
      }

      default:
         return (0);
   }

   return (0);
}

#define iMAOnArray iMAOnArrayMQL4

double iMACDMQL4(string __symbol, int __timeframe, int __fast_ema_period, int __slow_ema_period, int __signal_period, int __price, int __mode, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);
   ENUM_APPLIED_PRICE __AppliedPrice = PriceMigrate(__price);

   int __Handle = iMACD(__symbol, __TimeFrame, __fast_ema_period, __slow_ema_period, __signal_period, __AppliedPrice);

   if (__Handle < 0)
   {
      Print("The iMACD object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, __mode, __shift));
}

#define iMACD iMACDMQL4

double iRSIMQL4(string __symbol, int __timeframe, int __period, int __price, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);
   ENUM_APPLIED_PRICE __AppliedPrice = PriceMigrate(__price);

   int __Handle = iRSI(__symbol, __TimeFrame, __period, __AppliedPrice);

   if (__Handle < 0)
   {
      Print("The iRSI object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, 0, __shift));
}

#define iRSI iRSIMQL4

double iStdDevMQL4(string __symbol, int __timeframe, int __ma_period, int __ma_shift, int __method, int __price, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);
   ENUM_MA_METHOD __Method = MethodMigrate(__method);
   ENUM_APPLIED_PRICE __AppliedPrice = PriceMigrate(__price);

   int __Handle = iStdDev(__symbol, __TimeFrame, __ma_period, __ma_shift, __Method, __AppliedPrice);

   if (__Handle < 0)
   {
      Print("The iStdDev object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, 0, __shift));
}

#define iStdDev iStdDevMQL4

double iStochasticMQL4(string __symbol, int __timeframe, int __Kperiod, int __Dperiod, int __slowing, int __method, int __price, int __mode, int __shift)
{
   ENUM_TIMEFRAMES __TimeFrame = TFMigrate(__timeframe);
   ENUM_MA_METHOD __Method = MethodMigrate(__method);
   ENUM_STO_PRICE __Price = StoFieldMigrate(__price);

   int __Handle = iStochastic(__symbol, __TimeFrame, __Kperiod, __Dperiod, __slowing, __Method, __Price);

   if (__Handle < 0)
   {
      Print("The iStochastic object was not created: Error ", GetLastError());

      return (-1);
   }
   else
      return (CopyBufferMQL4(__Handle, __mode, __shift));
}

#define iStochastic iStochasticMQL4

template <typename T>

void SwitchRow(T &__array[], const int __upper, const int __lower)
{
   const T __Saved = __array[__upper];

   __array[__upper] = __array[__lower];
   __array[__lower] = __Saved;
}

template <typename T>

bool ArraySortMQL4(T &__array[], int __count = WHOLE_ARRAY, int __start = 0, int __sort_dir = MODE_DESCEND)
{
   const bool __Result = ArraySort(__array);

   if (__Result && (__sort_dir == MODE_DESCEND))
   {
      const int __Size = ArraySize(__array);

      for (int __Index = (__Size >> 1) - 1; __Index >= 0; __Index--)
         SwitchRow(__array, __Index, __Size - 1 - __Index);
   }

   return (__Result);
}

template <typename T>

void SwitchRow(T &__array[][2], const int __upper, const int __lower)
{
   T __Saved[99];
   const int __Cells = ArrayRange(__array, 1);

   for (int __Cell = 0; __Cell < __Cells; __Cell++)
   {
      __Saved[__Cell] = __array[__upper][__Cell];
      __array[__upper][__Cell] = __array[__lower][__Cell];
      __array[__lower][__Cell] = __Saved[__Cell];
   }
}

template <typename T>

bool ArraySortMQL4(T &__array[][2], int __count = WHOLE_ARRAY, int __start = 0, int __sort_dir = MODE_DESCEND)
{
   const bool __Result = ArraySort(__array);

   if (__Result && (__sort_dir == MODE_DESCEND))
   {
      const int __Size = ArrayRange(__array, 0);

      for (int __Index = (__Size >> 1) - 1; __Index >= 0; __Index--)
         SwitchRow(__array, __Index, __Size - 1 - __Index);
   }

   return (__Result);
}

#define ArraySort ArraySortMQL4
#endif // __MQL5__

#ifndef __MQL5__
#include <StdLib.mqh>
#include <StdError.mqh>
#include <WinUser32.mqh>
#endif // __MQL5__

#define A    1                  //All (Basket + Hedge)
#define B    2                  //Basket
#define H    3                  //Hedge
#define T    4                  //Ticket
#define P    5                  //Pending

enum portChgs
{
   no_change = 0,              // No changes
   increase  = 1,              // Increase only
   any       = -1              // Increase / decrease
};

enum mktCond
{
   uptrend   = 0,              // Long only
   downtrend = 1,              // Short only
   range     = 2,              // Long & short
   automatic = 3               // Automatic
};

enum entType
{
   disable = 0,                // Disabled
   enable  = 1,                // Enabled
   reverse = 2                 // Reverse
};

enum crossType
{
   ic_disable = 0,             // Disabled
   ic_enabled = 1,             // Cross
   ic_cloud   = 2              // Cross Cloud Direction 
};

enum tFrame
{
   current = 0,                // Current
   m1      = 1,                // M1
   m5      = 2,                // M5
   m15     = 3,                // M15
   m30     = 4,                // M30
   h1      = 5,                // H1
   h4      = 6,                // H4
   d1      = 7,                // Daily
   w1      = 8,                // Weekly
   mn1     = 9                 // Monthly
};

input string             Version_3_9_6_23      = "EA Settings:";
input string             TradeComment          = "b3_v396.23";
input string             Notes                 = "";
input int                EANumber              = 1;                                                                         // EA Magic Number
input bool               EmergencyCloseAll     = false;                                                                     // *** CLOSE ALL NOW ***

input string             s1                    = "";                                                                        //.
input bool               ShutDown              = false;                                                                     // *** NO NEW TRADES ***
input string             s2                    = "";                                                                        //.

input string             LabelAcc              = "";                                                                        // ==   ACCOUNT SETTINGS   ==
input double             StopTradePercent      = 10;;                                                                       // Percentage of balance lost before trading stops

input bool               NanoAccount           = false;;                                                                    // Small Lot Account (0.01)
input string             s3                    = "... PortionPC > 100 forces effective balance to that amount (e.g. 1000)"; //.
input double             PortionPC             = 100;;                                                                      // Percentage of account you want to trade on this pair
input portChgs           PortionChange         = increase;;                                                                 // Permitted Portion change with open basket

input double             MaxDDPercent          = 50;;                                                                       // Percent of portion for max drawdown level.
input double             MaxSpread             = 5;;                                                                        // Maximum allowed spread while placing trades
input bool               UseHolidayShutdown    = true;;                                                                     // Enable holiday shut-downs
input string             Holidays              = "18/12-01/01";;                                                            // Comma-separated holiday list (format: [day]/[mth]-[day]/[mth])
input bool               PlaySounds            = false;;                                                                    // Audible alerts
input string             AlertSound            = "Alert.wav";;                                                              // Alert sound

input string             eopb                  = "";                                                                        // -- Opt. with 'Open prices only' --

input bool               EnableOncePerBar      = true;
input bool               UseMinMarginPercent   = false;
input double             MinMarginPercent      = 1500;
input string             eopb1                 = "";                                                                        //. 

input string			LabelTST				= "";                                                                        // ------   CUSTOM TESTER SETTINGS   ------
input double			TesterMinMarginPercent = 500;;
input int				TesterSelection = 1;;   // 1: Balance   2: (Balance^2 * min Drawdown * Trades)
input string			LabelTST2;				// .

input bool               B3Traditional         = true;;                                                                     // Stop/Limits for entry if true, Buys/Sells if false
input mktCond            ForceMarketCond       = 3;;                                                                        // Market condition

input bool               UseAnyEntry           = false;;                                                                    // true = ANY entry can be used to open orders, false = ALL entries used to open orders

input string             LabelLS               = "";                                                                        // -----------   LOT SIZE   -----------
input bool               UseMM                 = true;;                                                                     // UseMM   (Money Management)
input double             LAF                   = 0.5;;                                                                      // Adjusts MM base lot for large accounts
input double             Lot                   = 0.01;;                                                                     // Starting lots if Money Management is off
input double             Multiplier            = 1.4;;                                                                      // Multiplier on each level

input string             LabelGS               = "";                                                                        // ------     GRID SETTINGS    ------
input bool               AutoCal               = false;;                                                                    // Auto calculation of TakeProfit and Grid size;
input tFrame             ATRTF                 = 0;;                                                                        // TimeFrame for ATR calculation
input int                ATRPeriods            = 21;;                                                                       // Number of periods for the ATR calculation
input double             GAF                   = 1.0;;                                                                      // Widens/Squishes Grid in increments/decrements of .1
input int                EntryDelay            = 2400;;                                                                     // Time Grid in seconds, avoid opening lots of levels in fast market
input double             EntryOffset           = 5;;                                                                        // In pips, used in conjunction with logic to offset first trade entry
input bool               UseSmartGrid          = true;;                                                                     // True = use RSI/MA calculation for next grid order

input string             LabelTS               = "";                                                                        // =====    TRADING    =====
input int                MaxTrades             = 15;;                                                                       // Maximum number of trades to place (stops placing orders when reaches MaxTrades)
input int                BreakEvenTrade        = 12;;                                                                       // Close All level, when reaches this level, doesn't wait for TP to be hit
input double             BEPlusPips            = 2;;                                                                        // Pips added to Break Even Point before BE closure
input bool               UseCloseOldest        = false;;                                                                    // True = will close the oldest open trade after CloseTradesLevel is reached
input int                CloseTradesLevel      = 5;;                                                                        // will start closing oldest open trade at this level
input bool               ForceCloseOldest      = true;;                                                                     // Will close the oldest trade whether it has potential profit or not
input int                MaxCloseTrades        = 4;;                                                                        // Maximum number of oldest trades to close
input double             CloseTPPips           = 10;;                                                                       // After Oldest Trades have closed, Forces Take Profit to BE +/- xx Pips
input double             ForceTPPips           = 0;;                                                                        // Force Take Profit to BE +/- xx Pips
input double             MinTPPips             = 0;;                                                                        // Ensure Take Profit is at least BE +/- xx Pips

input string             LabelES               = "";                                                                        // -----------     EXITS    -----------
input bool               MaximizeProfit        = false;;                                                                    // Turns on TP move and Profit Trailing Stop Feature
input double             ProfitSet             = 70;;                                                                       // Profit trailing stop: Lock in profit at set percent of Total Profit Potential
input double             MoveTP                = 30;;                                                                       // Moves TP this amount in pips
input int                TotalMoves            = 2;;                                                                        // Number of times you want TP to move before stopping movement
input bool               UseStopLoss           = false;;                                                                    // Use Stop Loss and/or Trailing Stop Loss
input double             SLPips                = 30;;                                                                       // Pips for fixed StopLoss from BE, 0=off
input double             TSLPips               = 10;;                                                                       // Pips for trailing stop loss from BE + TSLPips: +ve = fixed trail; -ve = reducing trail; 0=off
input double             TSLPipsMin            = 3;;                                                                        // Minimum trailing stop pips if using reducing TS
input bool               UsePowerOutSL         = false;;                                                                    // Transmits a SL in case of internet loss
input double             POSLPips              = 600;;                                                                      // Power Out Stop Loss in pips
input bool               UseFIFO               = false;;                                                                    // Close trades in FIFO order

input string             LabelEE               = "";                                                                        // ---------   EARLY EXITS   ---------
input bool               UseEarlyExit          = false;;                                                                    // Reduces ProfitTarget by a percentage over time and number of levels open
input double             EEStartHours          = 3;;                                                                        // Number of Hours to wait before EE over time starts
input bool               EEFirstTrade          = true;;                                                                     // true = StartHours from FIRST trade: false = StartHours from LAST trade
input double             EEHoursPC             = 0.5;;                                                                      // Percentage reduction per hour (0 = OFF)
input int                EEStartLevel          = 5;;                                                                        // Number of Open Trades before EE over levels starts
input double             EELevelPC             = 10;;                                                                       // Percentage reduction at each level (0 = OFF)
input bool               EEAllowLoss           = false;;                                                                    // true = Will allow the basket to close at a loss : false = Minimum profit is Break Even

input string             LabelAdv              = "";                                                                        //.
input string             LabelGrid             = "";                                                                        // ---------    GRID SIZE   ---------
input string             SetCountArray         = "4,4";;                                                                    // Specifies number of open trades in each block (separated by a comma)
input string             GridSetArray          = "25,50,100";;                                                              // Specifies number of pips away to issue limit order (separated by a comma)
input string             TP_SetArray           = "50,100,200";;                                                             // Take profit for each block (separated by a comma)

input string             LabelEST0             = "";                                                                        // .
input string             LabelEST              = "";                                                                        // ==  ENTRY PARAMETERS  ==
input string             LabelMA               = "";                                                                        // -------------     MA     -------------
input entType            MAEntry               = 1;;                                                                        // MA Entry
input tFrame             MA_TF                 = 0;;                                                                        // Time frame for MA calculation, r.f. ********
input int                MAPeriod              = 100;;                                                                      // Period of MA (H4 = 100, H1 = 400)
input double             MADistance            = 10;;                                                                       // Distance from MA to be treated as Ranging Market

input string             LabelCCI              = "";                                                                        // -------------     CCI     -------------
input entType            CCIEntry              = 0;;                                                                        // CCI Entry
input int                CCIPeriod             = 14;;                                                                       // Period for CCI calculation

input string             LabelBBS              = "";                                                                        // -----   BOLLINGER BANDS   -----
input entType            BollingerEntry        = 0;;                                                                        // Bollinger Entry
input int                BollPeriod            = 10;;                                                                       // Period for Bollinger
input double             BollDistance          = 10;;                                                                       // Up/Down spread
input double             BollDeviation         = 2.0;;                                                                      // Standard deviation multiplier for channel

input string             LabelIchi             = "";                                                                        // -----   ICHIMOKU CLOUD  -----
input entType            IchimokuEntry         = 0;                                                                         // Ichimoku Entry    
input tFrame             ICHI_TF               = 0;                                                                         // TF setting, but only current will work
input int                Tenkan_Sen            = 9;                                                                         // Tenkan
input int                Kijun_Sen             = 26;                                                                        // Kijun
input int                Senkou_Span           = 52;                                                                        // Senkou
input bool               useCloudBreakOut      = true;                                                                      // Trade if price breaks cloud / Kumo
input crossType          useTenken_Kijun_cross = 2;                                                                         // Trade if Tenken crosses Kijun
input bool               usePriceCrossTenken   = false;                                                                     // Trade if Price crosses Tenken
input bool               usePriceCrossKijun    = false;                                                                     // Trade if price crosses Kijun
input bool               useChikuspan          = false;                                                                     // Trade if chiku crosses Price

input bool               useCloudSL            = false;                                                                     // Close all orders if price dives into the cloud/kumo

input string             LabelSto              = "";                                                                        // ---------   STOCHASTIC   --------
input entType            StochEntry            = 0;;                                                                        // Stochastic Entry
input int                BuySellStochZone      = 20;;                                                                       // Determines Overbought and Oversold Zones
input int                KPeriod               = 10;;                                                                       // Stochastic KPeriod
input int                DPeriod               = 2;;                                                                        // Stochastic DPeriod
input int                Slowing               = 2;;                                                                        // Stochastic Slowing

input string             LabelMACD             = "";                                                                        //  ------------    MACD    ------------
input entType            MACDEntry             = 0;;                                                                        // MACD Entry
input tFrame             MACD_TF               = 0;;                                                                        // Time frame for MACD calculation

input int                FastPeriod            = 12;;                                                                       // MACD EMA Fast Period
input int                SlowPeriod            = 26;;                                                                       // MACD EMA Slow Period
input int                SignalPeriod          = 9;;                                                                        // MACD EMA Signal Period

#ifdef __MQL5__
input ENUM_APPLIED_PRICE MACDPrice             = PRICE_CLOSE;;                                                              // MACD Applied Price
#else
input ENUM_APPLIED_PRICE MACDPrice             = 0;;                                                                        // MACD Applied Price
#endif // __MQL5__

input string             LabelSG               = "";                                                                        // ---------   SMART GRID   ---------
input tFrame             RSI_TF                = 3;;                                                                        // Timeframe for RSI calculation (should be lower than chart TF)
input int                RSI_Period            = 14;;                                                                       // Period for RSI calculation
#ifdef __MQL5__
input ENUM_APPLIED_PRICE RSI_Price             = PRICE_CLOSE;;                                                              // RSI Applied Price
#else
input ENUM_APPLIED_PRICE RSI_Price             = 0;;                                                                        // RSI Applied Price
#endif // __MQL5__
input int                RSI_MA_Period         = 10;;                                                                       // Period for MA of RSI calculation
input ENUM_MA_METHOD     RSI_MA_Method         = 0;;                                                                        // RSI MA Method

input string             LabelHS0              = "";                                                                        //.
input string             LabelHS               = "";                                                                        // ------   HEDGE SETTINGS   -----
input string             HedgeSymbol           = "";;                                                                       // Enter the Symbol of the same/correlated pair EXACTLY as used by your broker.
input int                CorrPeriod            = 30;;                                                                       // Number of days for checking Hedge Correlation
input bool               UseHedge              = false;;                                                                    // Turns DD hedge on/off
input string             DDorLevel             = "DD";;                                                                     // DD = start hedge at set DD;Level = Start at set level
input double             HedgeStart            = 20;;                                                                       // DD Percent or Level at which Hedge starts
input double             hLotMult              = 0.8;;                                                                      // Hedge Lots = Open Lots * hLotMult
input double             hMaxLossPips          = 30;;                                                                       // DD Hedge maximum pip loss - also hedge trailing stop
input bool               hFixedSL              = false;;                                                                    // true = fixed SL at hMaxLossPips
input double             hTakeProfit           = 30;;                                                                       // Hedge Take Profit
input double             hReEntryPC            = 5;;                                                                        // Increase to HedgeStart to stop early re-entry of the hedge
input bool               StopTrailAtBE         = true;;                                                                     // True = Trailing Stop will stop at BE;False = Hedge will continue into profit
input bool               ReduceTrailStop       = true;;                                                                     // False = Trailing Stop is Fixed;True = Trailing Stop will reduce after BE is reached

input string             LabelOS0   

Показано первые 50% кода (символов: 185892)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
18 589,20₽ ≈ $227.22