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

Blessing 3

blessing_3_v3.9.6.21.mq4

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

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

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

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

О программе

Blessing 3 — это торговый советник для MetaTrader 4, предназначенный для автоматической торговли на валютном рынке. Советник использует сеточную стратегию с возможностью управления корзиной ордеров, хеджирования и раннего выхода. В основе лежит анализ рыночных условий с помощью индикаторов: скользящей средней, CCI, полос Боллинджера, Ichimoku, стохастика и MACD. Советник поддерживает настройку денежного менеджмента, управление рисками, автоматический расчёт сетки на основе ATR, а также функции защиты от просадки и остановки торговли в праздничные дни.

Советник работает на платформе MetaTrader 4 и использует стандартные торговые функции MQL4. Он обрабатывает событие OnTick для анализа рыночной ситуации и принятия торговых решений. В коде реализованы механизмы управления открытыми позициями, включая перемещение стоп-лоссов и тейк-профитов, закрытие старейших ордеров, хеджирование с использованием коррелирующего символа и ранний выход для сокращения целевой прибыли.

Настройки советника позволяют гибко конфигурировать параметры торговли: размер лота, множитель для сетки, максимальное количество сделок, уровни тейк-профита и стоп-лосса, параметры индикаторов и условия входа. Также доступны настройки для управления просадкой, остановки торговли при достижении определённого процента потерь и уведомлений по электронной почте. Советник отображает информационную панель на графике с текущими параметрами и состоянием торговли.

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

НастройкаОписание
Version_3_9_6_20 Версия — Версия советника.
TradeComment Комментарий — Комментарий к торговым операциям.
Notes Заметки — Поле для заметок.
EA Magic Number (EANumber) Номер советника — Уникальный номер советника (Magic Number).
CLOSE ALL NOW *** (EmergencyCloseAll) Экстренное закрытие — Немедленно закрыть все сделки.
. (s1) Разделитель 1 — Разделитель настроек.
NO NEW TRADES *** (ShutDown) Остановка торговли — Запретить открытие новых сделок.
. (s2) Разделитель 2 — Разделитель настроек.
== ACCOUNT SETTINGS == (LabelAcc) Метка аккаунта — Разделитель для настроек аккаунта.
Percentage of balance lost before trading stops (StopTradePercent) Процент остановки — Процент потери баланса до остановки торговли.
. (s3) Разделитель 3 — Разделитель настроек.
Percentage of account you want to trade on this pair (PortionPC) Процент порции — Процент счёта, используемый для торговли на этой паре.
Permitted Portion change with open basket (PortionChange) Изменение порции — Разрешённое изменение порции при открытой корзине.
Percent of portion for max drawdown level. (MaxDDPercent) Макс. просадка % — Процент от порции для максимального уровня просадки.
Maximum allowed spread while placing trades (MaxSpread) Макс. спред — Максимально допустимый спред при размещении сделок.
Enable holiday shut-downs (UseHolidayShutdown) Остановка в праздники — Включить остановку торговли в праздничные дни.
Comma-separated holiday list (format: [day]/[mth]-[day]/[mth]) (Holidays) Праздники — Список праздников через запятую в формате [день]/[месяц]-[день]/[месяц].
Audible alerts (PlaySounds) Звуковые оповещения — Включить звуковые оповещения.
Alert sound (AlertSound) Звук оповещения — Имя звукового файла для звуковых оповещений.
Opt. with 'Open prices only' -- (eopb) Оптимизация eopb — Оптимизация с режимом 'Open prices only'.
EnableOncePerBar Один раз за бар — Обрабатывать торговую логику только один раз за бар.
UseMinMarginPercent Мин. маржа — Использовать минимальный процент маржи для открытия сделок.
MinMarginPercent Мин. маржа % — Минимальный процент маржи для открытия новых сделок.
. (eopb1) Оптимизация eopb1 — Дополнительный параметр оптимизации.
Stop/Limits for entry if true, Buys/Sells if false (B3Traditional) Традиционный режим — Если true, используются стоп- и лимитные ордера для входа; если false — рыночные ордера.
Market condition (ForceMarketCond) Состояние рынка — Принудительное состояние рынка: восходящий тренд, нисходящий, диапазон или автоматически.
true = ANY entry can be used to open orders, false = ALL entries used to open orders (UseAnyEntry) Любой вход — Если true, любой сигнал входа может открыть ордера; если false — все сигналы должны совпасть.
LOT SIZE ----------- (LabelLS) Метка размера лота — Разделитель для настроек размера лота.
UseMM (Money Management) (UseMM) Денежный менеджмент — Использовать денежный менеджмент.
Adjusts MM base lot for large accounts (LAF) Коэффициент LAF — Корректировка базового лота для больших счетов.
Starting lots if Money Management is off (Lot) Лот — Начальный размер лота, если денежный менеджмент отключён.
Multiplier on each level (Multiplier) Множитель — Множитель для размера лота на каждом уровне.
GRID SETTINGS ------ (LabelGS) Метка сетки — Разделитель для настроек сетки.
Auto calculation of TakeProfit and Grid size; (AutoCal) Автоматический расчёт — Автоматический расчёт тейк-профита и размера сетки на основе ATR.
TimeFrame for ATR calculation (ATRTF) Таймфрейм ATR — Таймфрейм для расчёта ATR.
Number of periods for the ATR calculation (ATRPeriods) Периоды ATR — Количество периодов для расчёта ATR.
Widens/Squishes Grid in increments/decrements of .1 (GAF) Коэффициент сетки — Коэффициент расширения/сжатия сетки с шагом 0.1.
Time Grid in seconds, avoid opening lots of levels in fast market (EntryDelay) Задержка входа — Задержка в секундах между открытием уровней сетки для избежания открытия множества ордеров на быстром рынке.
In pips, used in conjunction with logic to offset first trade entry (EntryOffset) Смещение входа — Смещение в пунктах для первого входа.
True = use RSI/MA calculation for next grid order (UseSmartGrid) Умная сетка — Использовать расчёт RSI/MA для следующего ордера сетки.
===== TRADING ===== (LabelTS) Метка торговли — Разделитель для торговых настроек.
Maximum number of trades to place (stops placing orders when reaches MaxTrades) (MaxTrades) Макс. сделок — Максимальное количество сделок для размещения.
Close All level, when reaches this level, doesn't wait for TP to be hit (BreakEvenTrade) Сделка безубытка — Уровень, при достижении которого корзина закрывается по безубытку, не дожидаясь тейк-профита.
Pips added to Break Even Point before BE closure (BEPlusPips) Пункты к безубытку — Количество пунктов, добавляемых к точке безубыточности перед закрытием.
True = will close the oldest open trade after CloseTradesLevel is reached (UseCloseOldest) Закрывать старейшую — Если true, закрывает старейшую открытую сделку после достижения уровня CloseTradesLevel.
will start closing oldest open trade at this level (CloseTradesLevel) Уровень закрытия сделок — Уровень, начиная с которого начинается закрытие старейших открытых сделок.
Will close the oldest trade whether it has potential profit or not (ForceCloseOldest) Принудительное закрытие старейшей — Закрывать старейшую сделку независимо от наличия потенциальной прибыли.
Maximum number of oldest trades to close (MaxCloseTrades) Макс. закрытий — Максимальное количество старейших сделок для закрытия.
After Oldest Trades have closed, Forces Take Profit to BE +/- xx Pips (CloseTPPips) Пункты закрытия TP — Принудительный тейк-профит на уровне безубытка плюс/минус указанное количество пунктов после закрытия старейших сделок.
Force Take Profit to BE +/- xx Pips (ForceTPPips) Пункты принудительного TP — Принудительный тейк-профит на уровне безубытка плюс/минус указанное количество пунктов.
Ensure Take Profit is at least BE +/- xx Pips (MinTPPips) Мин. пункты TP — Гарантирует, что тейк-профит будет не менее безубытка плюс/минус указанное количество пунктов.
EXITS ----------- (LabelES) Метка выходов — Разделитель для настроек выходов.
Turns on TP move and Profit Trailing Stop Feature (MaximizeProfit) Максимизация прибыли — Включает функцию перемещения тейк-профита и трейлинг-стопа прибыли.
Profit trailing stop: Lock in profit at set percent of Total Profit Potential (ProfitSet) Установка прибыли — Процент от общего потенциала прибыли для фиксации прибыли трейлинг-стопом.
Moves TP this amount in pips (MoveTP) Перемещение TP — Перемещает тейк-профит на указанное количество пунктов.
Number of times you want TP to move before stopping movement (TotalMoves) Всего перемещений — Количество раз перемещения тейк-профита перед остановкой.
Use Stop Loss and/or Trailing Stop Loss (UseStopLoss) Использовать стоп-лосс — Использовать стоп-лосс и/или трейлинг-стоп-лосс.
Pips for fixed StopLoss from BE, 0=off (SLPips) Пункты SL — Пункты для фиксированного стоп-лосса от безубытка (0 = отключено).
Pips for trailing stop loss from BE + TSLPips: +ve = fixed trail; -ve = reducing trail; 0=off (TSLPips) Пункты TSL — Пункты для трейлинг-стопа от безубытка плюс TSLPips: положительное значение — фиксированный трейлинг; отрицательное — уменьшающийся; 0 = отключено.
Minimum trailing stop pips if using reducing TS (TSLPipsMin) Мин. пункты TSL — Минимальное количество пунктов трейлинг-стопа при использовании уменьшающегося трейлинга.
Transmits a SL in case of internet loss (UsePowerOutSL) Стоп-лосс при потере питания — Передавать стоп-лосс на случай потери интернет-соединения.
Power Out Stop Loss in pips (POSLPips) Пункты POSL — Стоп-лосс в пунктах для защиты при потере питания.
Close trades in FIFO order (UseFIFO) Использовать FIFO — Закрывать сделки в порядке FIFO.
EARLY EXITS --------- (LabelEE) Метка раннего выхода — Разделитель для настроек раннего выхода.
Reduces ProfitTarget by a percentage over time and number of levels open (UseEarlyExit) Ранний выход — Уменьшает целевую прибыль с течением времени и по количеству открытых уровней.
Number of Hours to wait before EE over time starts (EEStartHours) Часы начала EE — Количество часов ожидания перед началом раннего выхода по времени.
true = StartHours from FIRST trade: false = StartHours from LAST trade (EEFirstTrade) Первая сделка для EE — Если true, отсчёт времени начинается с первой сделки; если false — с последней.
Percentage reduction per hour (0 = OFF) (EEHoursPC) Процент часов EE — Процент сокращения целевой прибыли за каждый час (0 = отключено).
Number of Open Trades before EE over levels starts (EEStartLevel) Уровень начала EE — Количество открытых сделок перед началом раннего выхода по уровням.
Percentage reduction at each level (0 = OFF) (EELevelPC) Процент уровней EE — Процент сокращения целевой прибыли на каждом уровне (0 = отключено).
true = Will allow the basket to close at a loss : false = Minimum profit is Break Even (EEAllowLoss) Разрешить убыток — Если true, корзина может закрыться с убытком; если false, минимальная прибыль — безубыток.
. (LabelAdv) Метка дополнительно — Разделитель для дополнительных настроек.
GRID SIZE --------- (LabelGrid) Метка размера сетки — Разделитель для размера сетки.
Specifies number of open trades in each block (separated by a comma) (SetCountArray) Массив количества — Количество открытых сделок в каждом блоке (через запятую).
Specifies number of pips away to issue limit order (separated by a comma) (GridSetArray) Массив сетки — Количество пунктов до выставления лимитного ордера для каждого блока (через запятую).
Take profit for each block (separated by a comma) (TP_SetArray) Массив TP — Тейк-профит для каждого блока (через запятую).
. (LabelEST0) Метка параметров входа 0 — Разделитель для параметров входа.
== ENTRY PARAMETERS == (LabelEST) Метка параметров входа — Разделитель для параметров входа.
MA ------------- (LabelMA) Метка MA — Разделитель для настроек скользящей средней.
MA Entry (MAEntry) Вход по MA — Режим входа по скользящей средней: отключено, включено или реверс.
Time frame for MA calculation, r.f. ******** (MA_TF) Таймфрейм MA — Таймфрейм для расчёта скользящей средней.
Period of MA (H4 = 100, H1 = 400) (MAPeriod) Период MA — Период скользящей средней.
Distance from MA to be treated as Ranging Market (MADistance) Расстояние MA — Расстояние от скользящей средней для определения диапазона.
CCI ------------- (LabelCCI) Метка CCI — Разделитель для настроек CCI.
CCI Entry (CCIEntry) Вход по CCI — Режим входа по CCI: отключено, включено или реверс.
Period for CCI calculation (CCIPeriod) Период CCI — Период для расчёта CCI.
BOLLINGER BANDS ----- (LabelBBS) Метка Боллинджера — Разделитель для настроек полос Боллинджера.
Bollinger Entry (BollingerEntry) Вход по Боллинджеру — Режим входа по полосам Боллинджера: отключено, включено или реверс.
Period for Bollinger (BollPeriod) Период Боллинджера — Период для расчёта полос Боллинджера.
Up/Down spread (BollDistance) Расстояние Боллинджера — Дополнительное расстояние вверх/вниз от полос Боллинджера.
Standard deviation multiplier for channel (BollDeviation) Отклонение Боллинджера — Множитель стандартного отклонения для канала Боллинджера.
ICHIMOKU CLOUD ----- (LabelIchi) Метка Ichimoku — Разделитель для настроек Ichimoku.
Ichimoku Entry (IchimokuEntry) Вход по Ichimoku — Режим входа по Ichimoku: отключено, включено или реверс.
TF setting, but only current will work (ICHI_TF) Таймфрейм Ichimoku — Таймфрейм для расчёта Ichimoku (работает только текущий).
Tenkan (Tenkan_Sen) Tenkan — Период линии Tenkan в Ichimoku.
Kijun (Kijun_Sen) Kijun — Период линии Kijun в Ichimoku.
Senkou (Senkou_Span) Senkou — Период линии Senkou в Ichimoku.
Trade if price breaks cloud / Kumo (useCloudBreakOut) Пробой облака — Торговать при пробое облака Ichimoku.
Trade if Tenken crosses Kijun (useTenken_Kijun_cross) Пересечение Tenkan/Kijun — Торговать при пересечении Tenkan и Kijun.
Trade if Price crosses Tenken (usePriceCrossTenken) Пересечение цены и Tenkan — Торговать при пересечении цены и линии Tenkan.
Получить полный код

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

#property version   "396.21"
#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_20      = "EA Settings:";
input string             TradeComment          = "b3_v396.21";
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 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% кода (символов: 185434)

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

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

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

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

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

Стоимость полного кода
18 543,40₽ ≈ $226.66