Библиотеки: MT4Orders - страница 12

 
Пример того, насколько лаконичной и надежной может быть торговая часть советника при использовании библиотеки на нетто-счете.

Торговые сигналы для MetaTrader 5 с автоматическим исполнением на вашем счете

LCHI2017

MetaTrader 5
Бесплатно

Торгует советник на биржевых инструментах.

#include <MT4Orders.mqh>     // https://www.mql5.com/ru/code/16006
#include <TypeToBytes.mqh>   // https://www.mql5.com/ru/code/16280
#include <Price_Compare.mqh> // https://www.mql5.com/ru/code/16169

sinput double exLots = 1;

int OrderScan( const int Type0, const int Type1 = -1, const int Type2 = -1, const int Type3 = -1 )
{
  int Res = -1;

  int Types[4];
    
  Types[0] = Type0;
  Types[1] = Type1;
  Types[2] = Type2;
  Types[3] = Type3;
  
  for (int i = 0; (i < 4) && (Types[i] != -1) && (Res == -1); i++)
    for (int j = OrdersTotal() - 1; j >= 0; j--)
      if (OrderSelect(j, SELECT_BY_POS) && (OrderType() == Types[i]) && (OrderSymbol() == _Symbol))
      {
        Res = Types[i];
        
        break;
      }
      
  return(Res);    
}

bool MyOrderModify( const double Price )
{
  return((CP(Price) != OrderOpenPrice()) && OrderModify(OrderTicket(), Price, 0, 0, 0));
}

bool MyOrderSend( const int Type, const double Price )
{
  const double Lots = exLots + OrderLots();      
  
  return((OrderScan(Type) == -1) ? OrderSend(_Symbol, Type, Lots, Price, 0, 0, 0) : MyOrderModify(Price));
}

MqlTick Ticks[];

void OnTick( void )
{  
  static const MqlTick NullTick = {0};
  
  const MqlTick Level = GetLevel(Ticks);
  
  if (_R(Level) != NullTick)
  {
    const int Type = OrderScan(OP_BUY, OP_SELL, OP_BUYLIMIT, OP_SELLLIMIT);
    
    if (Type == OP_BUY)
      MyOrderSend(OP_SELLLIMIT, Level.bid);
    else if (Type == OP_SELL)
      MyOrderSend(OP_BUYLIMIT, Level.ask);
    else if (Type != -1)
      MyOrderModify((OrderScan(OP_BUYLIMIT, OP_SELLLIMIT) == OP_BUYLIMIT) ? Level.ask : Level.bid);
    else
      OrderSend(_Symbol, OP_BUYLIMIT, exLots, Level.ask, 0, 0, 0);
  }
  
  return;
}
 

Скрипт, показывающий особенность реализации OrderSelect  в режиме SELECT_BY_POS+MODE_TRADES

#include <MT4Orders.mqh>
#include <MQL4_To_MQL5.mqh>

void OnStart()
{
  OrderSend(_Symbol, OP_BUYLIMIT, 1, Ask - 100 * _Point, 0, 0, 0);  // Установили BuyLimit
  OrderSend(_Symbol, OP_SELLLIMIT, 1, Bid + 100 * _Point, 0, 0, 0); // Установили SellLimit
  OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, 0);                    // Открыли Buy-позицию
  
  bool FirstRun = true;
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS))
    {
      OrderPrint();
      
      if (FirstRun)
      {
        OrderSend(_Symbol, OP_SELL, 1, Bid, 100, 0, 0); // Открыли Sell-позицию
        
        FirstRun = false;
      }
    }    
}

MT4

#196155484 2017.05.04 15:38:07 buy 1.00 EURUSD 1.09229 0.00000 0.00000 1.09221 0.00 0.00 -8.00  0
#196155480 2017.05.04 15:38:06 sell limit 1.00 EURUSD 1.09321 0.00000 0.00000 1.09221 0.00 0.00 0.00  0
#196155479 2017.05.04 15:38:06 buy limit 1.00 EURUSD 1.09129 0.00000 0.00000 1.09229 0.00 0.00 0.00  0

MT5

#147352190 2017.05.04 15:38:06 sell limit 1.00 EURUSD 1.09322 0.00000 0.00000 1.09222 0.00 0.00 0.00 0
#147352193 2017.05.04 15:38:06 sell 1.00 EURUSD 1.09222 0.00000 0.00000 1.09231 0.00 0.00 -9.00 0
#147352191 2017.05.04 15:38:06 buy 1.00 EURUSD 1.09231 0.00000 0.00000 1.09222 0.00 0.00 -9.00 0

Несмотря на то, что торговый результат скрипта идентичен на обеих платформах, OrderSelect работает по-разному. Отсюда разные логи.

Скрипт специально высосан, и не могу рекомендовать такой стиль написания торговой логики, т.к. он чреват на каждой из платформ трудноуловимыми логическими ошибками. И подобный код перестает быть на 100% идентичным по выполнению.

Поэтому править библиотеку, чтобы такие редкие кривые MT4-коды выполнялись в MT5 абсолютно идеально, как это происходит с нормальным кодом, видится сейчас нецелесообразным.

Если ошибаюсь на счет кривости и редкости таких торговых MT4-конструкций, прошу внести ясность.

 
Как-то даже забавно получается с замедлением.
 
Vitaly Muzichenko:
Как-то даже забавно получается с замедлением.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

MT4-Tester VS MT5-Tester

fxsaber, 2017.05.08 01:11

Если есть сомнения, что MT5-замедление вызвано использованием сторонней библиотеки, желающие могут переписать простую MT4-логику данного советника на MQL5 на свой лад и проверить гипотезу.
 
fxsaber:

Скрипт, показывающий особенность реализации OrderSelect  в режиме SELECT_BY_POS+MODE_TRADES

Скрипт специально высосан, и не могу рекомендовать такой стиль написания торговой логики

При другом крайне не рекомендуемом стиле написания торговой логики можно нарваться на еще одну особенность OrderSelect, но уже в режиме SELECT_BY_TICKET+MODE_HISTORY

#include <MT4Orders.mqh>

#define Ask (::SymbolInfoDouble(_Symbol, SYMBOL_ASK))

void OnTick()
{
  static bool FirstRun = true;
  
  if (FirstRun && OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0), SELECT_BY_TICKET) &&
      OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 0))  
  {
    Print(OrderTicket()); // 2 - ОТКРЫТАЯ позиция была с таким тикетом
    
    Print(OrderSelect(OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)); // false, потому что тикет ЗАКРЫТОЙ позиции равен тикету закрывающей сделки.
    Print(OrderSelect(OrderTicket() + 1, SELECT_BY_TICKET, MODE_HISTORY)); // true, по причине выше.
      
    FirstRun = false;
  }
}

Это советник для тестера. В комментариях причина такого поведения. И это правильно из-за

  • Тикет открытой позиции (как правило) равен тикету открывающего ордера (не сделки). (термины MT5)
  • При этом если позиция закрывается частично, то тикеты закрытых соответствующих позиций делать равными тикету открытой позиции никак нельзя, чтобы избежать неоднозначности. (термины MT5)

  • Т.е. сам MT5 сделан так "криво", что другое поведение MT4Orders сложно придумать. Конечно, если сделать сначала SELECT_BY_POS по истории, записав все тикеты, то по ним SELECT_BY_TICKET будет работать без проблем.

    В общем, если торговая MT4-логика написана "плохо", то могут быть непривычные для MT4-понимания расхождения результатов MT5+MT4Orders и MT4. Если же придерживаться "правильного" MT4-стиля написания, то никаких проблем в библиотеке не выявлено.

     
    fxsaber:

    При другом крайне не рекомендуемом стиле написания торговой логики можно нарваться на еще одну особенность OrderSelect, но уже в режиме SELECT_BY_TICKET+MODE_HISTORY

    В общем, если торговая MT4-логика написана "плохо", то могут быть непривычные для MT4-понимания расхождения результатов MT5+MT4Orders и MT4. Если же придерживаться "правильного" MT4-стиля написания, то никаких проблем в библиотеке не выявлено.


    Библиотека шикарная, большое спасибо :) После добавления синхронизации истории вообще незаменима. Работает быстро даже для hft стратегий

    Я бы добавил ее в стандартную поставку мт5

     

    Обновление

    // Список изменений:
    // 14.06.2017:
    //   Add: Включена изначально заложенная реализация определения SL/TP закрытых позиций (закрытых через OrderClose).
    //   Add: MagicNumber теперь имеет тип long - 8 байт (раньше был int - 4 байта).
    //   Add: Если в OrderSend, OrderClose или OrderModify цветовой входной параметр (самый последний) задать равным INT_MAX, то будет сформирован
    //        соответствующий торговый MT5-запрос (MT4ORDERS::LastTradeRequest), но отправлен он НЕ будет. Вместо этого будет проведена его MT5-проверка,
    //        результат которой станет доступен в MT4ORDERS::LastTradeCheckResult.
    //        В случае успешной проверки OrderModify и OrderClose вернут true, иначе - false.
    //        OrderSend вернет 0 в случае успеха, иначе - -1.
    //
    //        Если же соответствующий цветовой входной параметр задать раным INT_MIN, то ТОЛЬКО в случае успешной MT5-проверки сформированного
    //        торгового запроса(как в случае с INT_MAX) он БУДЕТ отправлен.
    //   Add: Добавлены асинхронные аналоги MQL4-торговым функциям: OrderSendAsync, OrderModifyAsync, OrderCloseAsync, OrderDeleteAsync.
    //        Возвращают соответствующий Result.request_id в случае удачи, иначе - 0.

    INT_MIN-режим позволяет полностью избавиться от засорения логов тестера - особенно критично при оптимизации, т.к. из-за ошибочной торговой логики обильные сообщения могут в разы уменьшать производительность оптимизации и, соответственно, увеличивать не только временные, но и денежные издержки (Облако).

    Также это удобно при анализе гипотетических ошибок тестера.

    INT_MAX-режим целесообразно использовать для быстрого формирования максимально корректного торгового MT5-торгового запроса, чтобы использовать его, как базу для будущих MT5-приказов (именно так реализованы Async-функции - см. ниже).

    Определение SL/TP закрытых позиций реализовано так

    Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

    Ошибки, баги, вопросы

    fxsaber, 2017.05.18 20:31

    При акцептировании TP/SL прошу формировать торговым сервером соответствущий ордер закрытия вместе с заполненными полями TP/SL.

    Такое решение позволит, наконец, определять TP/SL закрытых позиций.

    Возможно, когда-нибудь такой функционал сделают штатным для MT5.


    Пример использования асинхронных MQL4-функций

    #property script_show_inputs
    
    sinput int Amount = 5; // Количество тестовых OrderSend(Async)
    
    #include <MT4Orders2.mqh>
    
    #define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)
    #define PRINT(A) Print(#A + " = " + (string)(A));
    
    void OnStart()
    {  
    // OrderSendAsync  
      const ulong StartTime1 = GetMicrosecondCount();
      
      for (int i = 0; i < Amount; i++)
        PRINT(OrderSendAsync(NULL, OP_BUY, 0.1, Ask, 100, 0, 0))
        
      PRINT(GetMicrosecondCount() - StartTime1)
    
    // OrderSend
      const ulong StartTime2 = GetMicrosecondCount();
      
      for (int i = 0; i < Amount; i++)
      {
        PRINT(OrderSend(NULL, OP_BUY, 0.1, Ask, 100, 0, 0))
        Print(MT4ORDERS::LastTradeResult.comment);
      }
        
      PRINT(GetMicrosecondCount() - StartTime2)
      
      PRINT(TerminalInfoInteger(TERMINAL_PING_LAST))
    }


    Результат

    OrderSendAsync(NULL,OP_BUY,0.1,Ask,100,0,0) = 117
    OrderSendAsync(NULL,OP_BUY,0.1,Ask,100,0,0) = 118
    OrderSendAsync(NULL,OP_BUY,0.1,Ask,100,0,0) = 119
    OrderSendAsync(NULL,OP_BUY,0.1,Ask,100,0,0) = 120
    OrderSendAsync(NULL,OP_BUY,0.1,Ask,100,0,0) = 121
    GetMicrosecondCount()-StartTime1 = 403
    
    OrderSend(NULL,OP_BUY,0.1,Ask,100,0,0) = 153496331
    Request executed 221.820 + 0.013 ms
    OrderSend(NULL,OP_BUY,0.1,Ask,100,0,0) = 153496331
    Request executed 252.067 + 0.008 ms
    OrderSend(NULL,OP_BUY,0.1,Ask,100,0,0) = 153496331
    Request executed 220.909 + 0.005 ms
    OrderSend(NULL,OP_BUY,0.1,Ask,100,0,0) = 153496331
    Request executed 189.578 + 0.005 ms
    OrderSend(NULL,OP_BUY,0.1,Ask,100,0,0) = 153496331
    Request executed 180.182 + 0.010 ms
    GetMicrosecondCount()-StartTime2 = 1064775
    
    TerminalInfoInteger(TERMINAL_PING_LAST) = 97942
     
    fxsaber:

    Обновление

    // Список изменений:
    // 14.06.2017:
    //   Add: Включена изначально заложенная реализация определения SL/TP закрытых позиций (закрытых через OrderClose).

    Пример, как это работает

    Forum on trading, automated trading systems and testing trading strategies

    MT5 versus MT4 Terminal Screens - Disappointed with changes in MT 5

    fxsaber, 2017.07.07 08:46

    First run this script

    #include <MT4Orders.mqh> // https://www.mql5.com/en/code/16006
    
    #define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)
    #define SLIPPAGE 100
    #define OFFSET (SLIPPAGE * _Point)
    
    void OnStart()
    {
      if (OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, SLIPPAGE, 0, 0), SELECT_BY_TICKET))
      {
        OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice() - OFFSET, OrderOpenPrice() + OFFSET, 0);
        
        if (OrderSelect(OrderTicket(), SELECT_BY_TICKET))
          OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), SLIPPAGE);
      }
    }

    Result:

    '6145767': instant buy 1.00 EURUSD at 1.14156 (deviation: 100)
    '6145767': accepted instant buy 1.00 EURUSD at 1.14156 (deviation: 100)
    '6145767': deal #140159795 buy 1.00 EURUSD at 1.14156 done (based on order #156755661)
    '6145767': order #156755661 buy 1.00 / 1.00 EURUSD at 1.14156 done in 252.283 ms
    '6145767': modify #156755661 buy 1.00 EURUSD sl: 0.00000, tp: 0.00000 -> sl: 1.14056, tp: 1.14256
    '6145767': accepted modify #156755661 buy 1.00 EURUSD sl: 0.00000, tp: 0.00000 -> sl: 1.14056, tp: 1.14256
    '6145767': modify #156755661 buy 1.00 EURUSD -> sl: 1.14056, tp: 1.14256 done in 109.586 ms
    '6145767': instant sell 1.00 EURUSD at 1.14147, close #156755661 buy 1.00 EURUSD 1.14156 (deviation: 100)
    '6145767': accepted instant sell 1.00 EURUSD at 1.14147, close #156755661 buy 1.00 EURUSD 1.14156 (deviation: 100)
    '6145767': deal #140159796 sell 1.00 EURUSD at 1.14147 done (based on order #156755662)
    '6145767': order #156755662 sell 1.00 / 1.00 EURUSD at 1.14147 done in 219.817 ms


    Then run this

    #include <MT4Orders.mqh> // https://www.mql5.com/en/code/16006
    
    void OnStart()
    {
      if (OrderSelect(OrdersHistoryTotal() - 1, SELECT_BY_POS, MODE_HISTORY))
        OrderPrint();
    }

    Result

    #140159796 2017.07.07 09:38:31 buy 1.00 EURUSD 1.14156 1.14056 1.14256 2017.07.07 09:38:32 1.14147 0.00 0.00 -7.88 0


    In this way it is possible to learn the SL/TP of closed positions.

     

    MT4 содержит меньше информации, чем MT5. Но ничто не мешает одновременно использовать MT4/5 торговые API

    // Скрипт показывает Reason-поле всех закрытых позиций
    #include <MT4Orders.mqh>
    
    void OnStart()
    {
      for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
        if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderType() <= OP_SELL))
        {
          OrderPrint();
          
          Print(EnumToString((ENUM_DEAL_REASON)HistoryDealGetInteger(OrderTicket(), DEAL_REASON)));
        }      
    }


    Результат

    #141705115 2017.07.18 15:02:37 sell 0.01 EURUSD 1.15508 0.00000 0.00000 2017.07.19 13:04:05 1.15309 0.00 -0.01 1.99 0
    DEAL_REASON_CLIENT
    

    #140517682 2017.07.11 12:06:48 buy 0.01 EURUSD 1.13941 1.13926 0.00000 2017.07.11 12:07:10 1.13926 0.00 0.00 -0.15 [sl 1.13926] 0 DEAL_REASON_SL

    #137746488 2017.06.20 01:22:26 sell 2.00 EURUSD 1.11474 0.00000 0.00000 2017.06.20 01:22:41 1.11484 0.00 0.00 -20.00 0 DEAL_REASON_EXPERT
    Причина обращения: