SL/TP 주문 수락

 

이 스레드는 열린 위치 의 SL/TP 수준을 트리거한 결과로 생성된 주문에 대해 설명합니다.

복잡하지만 작동하는 함수는 주어진 SL/TP 주문에 대한 트리거인 틱을 얻기 위해 작성되었습니다.

 #define SEARCH_TICK(A, B)                             \
{                                                     \
   if (!(Ticks[Pos]. ##A B Price) && ((Pos <= 1 ) ||     \
      (!StopLevel && (Ticks[Pos - 1 ]. ##A == Price)))) \
    Tick = Ticks[Pos];                                \
   else                                                 \
  {                                                   \
     while ((Pos >= 0 ) && !(Ticks[Pos]. ##A B Price))   \
      Tick = Ticks[Pos--];                            \
                                                      \
     if (!Tick.time)                                   \
    {                                                 \
       while ((Pos >= 0 ) && (Ticks[Pos]. ##A B Price))  \
        Pos--;                                        \
                                                      \
       while ((Pos >= 0 ) && !(Ticks[Pos]. ##A B Price)) \
        Tick = Ticks[Pos--];                          \
    }                                                 \
  }                                                   \
}

// Получение тика, который акцептировал TP/SL-ордер.
bool GetAcceptedTick( const ulong Ticket, MqlTick &Tick, const bool PrintFlag = false )
{
   bool Res = false ;

   if (! IsStopped () && HistoryOrderSelect2(Ticket))
  {
     const ENUM_ORDER_REASON Reason = ( ENUM_ORDER_REASON ) HistoryOrderGetInteger (Ticket, ORDER_REASON );

     if ((Reason == ORDER_REASON_TP ) || (Reason == ORDER_REASON_SL ))
    {
       const long CreateTime = HistoryOrderGetInteger (Ticket, ORDER_TIME_SETUP_MSC );
       const long DoneTime = HistoryOrderGetInteger (Ticket, ORDER_TIME_DONE_MSC );
       const string Symb = HistoryOrderGetString (Ticket, ORDER_SYMBOL );
       const ENUM_ORDER_STATE State = ( ENUM_ORDER_STATE ) HistoryOrderGetInteger (Ticket, ORDER_STATE );
       const ENUM_ORDER_TYPE Type = ( ENUM_ORDER_TYPE ) HistoryOrderGetInteger (Ticket, ORDER_TYPE );
       const double Price = HistoryOrderGetDouble (Ticket, ORDER_PRICE_OPEN );

       const ulong TicketOpen = HistoryOrderGetInteger (Ticket, ORDER_POSITION_ID );

       if ( SymbolInfoInteger (Symb, SYMBOL_EXIST ) && TicketOpen && HistoryOrderSelect2(TicketOpen))
      {
       #define TOSTRING(A) ", " + #A + " = " + ( string )(A)
         const int digits = ( int ) SymbolInfoInteger (Symb, SYMBOL_DIGITS );

         const int StopLevel = ( int ) SymbolInfoInteger (Symb, SYMBOL_TRADE_STOPS_LEVEL );
         long PositionCreated = HistoryOrderGetInteger (TicketOpen, ORDER_TIME_DONE_MSC );
        
         // Условие может сработать при частичном исполнении.
         if ((PositionCreated >= CreateTime) && HistorySelectByPosition (TicketOpen) && HistoryDealsTotal ())
        {
          PositionCreated = HistoryDealGetInteger ( HistoryDealGetTicket ( 0 ), DEAL_TIME_MSC );
          
           HistoryOrderSelect (TicketOpen); // Не HistoryOrderSelect2, т.к. нужно HistoryOrdersTotal() <= 1.
        }

       #define HOUR ( 3600 * 1000 )
         long From = MathMax (PositionCreated,     // Время открытия позиции
                            CreateTime - HOUR); // Час - просто с запасом.

         MqlTick Ticks[];

         ResetLastError ();
         int Pos = CopyTicksRange (Symb, Ticks, COPY_TICKS_INFO , From, CreateTime) - 1 ;

         if ((Pos < 0 ) && ! _LastError && (From == PositionCreated))
          Pos = CopyTicksRange (Symb, Ticks, COPY_TICKS_INFO , From -= HOUR, CreateTime) - 1 ;

         if (Pos >= 0 )
        {
           const MqlTick LastTick = Ticks[Pos];

          Tick.time = 0 ;

           if (Type == ORDER_TYPE_BUY )
          {
             if (Reason == ORDER_REASON_TP )
              SEARCH_TICK(ask, >)
             else
              SEARCH_TICK(ask, <)
          }
           else if (Reason == ORDER_REASON_TP )
            SEARCH_TICK(bid, <)
           else
            SEARCH_TICK(bid, >)

           if (!(Res = /*(Pos >= 0) && */ Tick.time))
             Alert ( __FUNCSIG__ + ": Error!" ); // Ошибка при расчетах
           else if (PrintFlag) // Выводим найденный тик.
          {
             Print ( "Last Tick " + TickToString(LastTick, digits));

             Print ( "Accepted Tick " + TickToString(Tick, digits));
             Print ( "Accepted Length = " + ( string )(CreateTime - Tick.time_msc) + " ms." );
          }
        }
         else // В случае ошибки CopyTicks - сообщаем.
           Alert ( __FUNCSIG__ + ": CopyTicksRange(" + Symb + ", " + TimeToString (From) + ", " +
                                                 TimeToString (CreateTime) + ") = " + ( string )(Pos + 1 ) + TOSTRING( _LastError ));

         if (PrintFlag || !Res) // Распечатываем данные ордера.
           Print ( "Order " + ( string )Ticket + " " + EnumToString (Type) + " " + Symb + " " + TimeToString (CreateTime) + " " +
                           DoubleToString (Price, digits) + " " + EnumToString (Reason) + " " + EnumToString (State) + " " +
                           TimeToString (DoneTime) + ", Position " + ( string )TicketOpen + " created " +
                           TimeToString (PositionCreated) + TOSTRING(StopLevel) + "\n" );
      }
    }
  }

   return (Res);
}

// Преобразование времени в миллисекундах в строку.
string TimeToString ( const long time, const int FlagTime = TIME_DATE | TIME_SECONDS )
{
   return ( TimeToString (( datetime )time / 1000 , FlagTime) + "." + IntegerToString (time % 1000 , 3 , '0' ));
}

// Преобразование тика в строку.
string TickToString( const MqlTick &Tick, const int digits )
{
   return ( TimeToString (Tick.time_msc) + " " + DoubleToString (Tick.bid, digits) + " " + DoubleToString (Tick.ask, digits));
}

// Правильный выбор исторического ордера.
bool HistoryOrderSelect2( const ulong Ticket)
{
   return ((( HistoryOrderGetInteger (Ticket, ORDER_TICKET ) == Ticket) || HistoryOrderSelect (Ticket)));
}


이 멋진 기능을 적용한 것이 이 분기를 만든 이유입니다. 나는 코드의 모든 버그를 포착하지 못했다고 확신하지만 , 역사와 이것이 실제로 쉽지 않다는 것을 이해하기 위해 전체 목록을 제공했습니다.

 

TP 주문 실행 문제를 연구하면서 일부 TP 주문이 승인된 틱보다 상당히 늦게 생성되었음을 알았습니다.

디브리핑 결과 이러한 상황은 다른 중개인뿐만 아니라 Trading Server와 동일한 기계에 있는 Terminal에서 거래가 이루어지는 상황에서도 반복되는 것으로 나타났습니다. 저것들. 매우 낮은 핑과 트레이딩 서버의 유일한 트레이딩 계정.



GetAcceptedTick 함수를 작성하여 문제를 철저히 연구하고 문제를 건설적으로 시연할 수 있었습니다.


스크립트.

따라서 예고편에는 다음 스크립트가 있습니다.

 // Скрипт выводит самое длительное или конкретное акцептирование SL/TP-ордера.
#property script_show_inputs

input datetime inFrom = D'2020.01.01' ; // С какого времени проверять ордера
input ulong inTicket = 0 ;               // Отдельно проверяемый тикет

// Возвращает самый медленный TP/SL-ордер с определенной даты.
ulong GetSlowestOrder( const datetime From );

// Распечатывает подробности акцепта SL/TP-ордера.
void PrintOrder( const ulong MaxTicket );

void OnStart ()
{
   Print ( "\n\nStart " + MQLInfoString ( MQL_PROGRAM_NAME ) + TOSTRING(inFrom) + TOSTRING(inTicket) + "\n" );
  
  PrintOrder(inTicket ? inTicket : GetSlowestOrder(inFrom));
}


MQ-Demo에서 실행한 결과입니다.

Total Orders (from 2020.09 . 01 00 : 00 : 00 ) = 58493 , calculated = 439
Calculation time = 00 : 00 : 11.328 , Performance = 38.0 orders/sec.

ServerName: MetaQuotes-Demo

Last Tick 2020.09 . 30 19 : 07 : 32.917 1.80181 1.80205
Accepted Tick 2020.09 . 30 19 : 07 : 32.716 1.80178 1.80202
Accepted Length = 357 ms.
Order 726444166 ORDER_TYPE_BUY GBPAUD 2020.09 . 30 19 : 07 : 33.073 1.80206 ORDER_REASON_TP ORDER_STATE_FILLED 2020.09 . 30 19 : 07 : 33.082 , Position created 2020.09 . 30 17 : 21 : 17.933 , StopLevel = 0

Orders ( 2 ) before 726444166 with PositionID = 725926764 :
------------------------
Checked Orders = 0
------------------------


스크립트는 TP 주문과 생성을 트리거한 틱(텍스트로 강조 표시됨)을 찾았다고 주장합니다. 거래 서버(특히 데모)에서 가격이 오픈 포지션의 TP 수준에 도달했다면 해당 TP 주문이 즉시 생성되어야 합니다(반드시 실행되지는 않음). 그러나 이 상황에서 이것은 즉시 발생하지 않고 357밀리초 후에 발생했습니다!


1밀리초의 지연도 충분하지 않다고 미리 말씀드립니다. To be in time은 알고리즘 거래에서 중요한 동사입니다.


시험.

우리는 스크립트를 맹목적으로 신뢰하지 않고 이 상황을 수동으로 확인합니다. 여기 우리의 주문이 있습니다.


그리고 여기에서 스크립트에서 찾은 해당 수락 틱을 볼 수 있습니다.


화살표는 TP 주문이 생성된 틱 사이를 보여줍니다. 스크린샷은 스크립트가 올바른 것으로 판명되었으며 TP 주문 생성이 Trade Server 측에서 엄청난 지연과 함께 발생했음을 분명히 보여줍니다.


결과.

이제 TP/SL 레벨을 통해 거래할 때 Trade Server 측면에 브레이크 양을 표시하는 도구가 있습니다. 현재 그들은 거대합니다. 그리고 이것은 분명히 수정해야 할 플랫폼의 심각한 마이너스입니다.

불행히도, 기탁의 수락을 감지할 수 없습니다. 이 정보는 터미널 측에서 사용할 수 없습니다. 그러나 거의 아이러니하게도 TP/SL 주문의 상당한 지연이 있으면 연기 실행 중 지연에 영향을 미칠 수 밖에 없습니다. 왜냐하면 원인은 같은 성격인 것 같습니다.


일반적으로 MT5 플랫폼은 특히 이러한 상황에서 현재 100% 느려집니다. 그리고 지연이 0이 될 때까지 수정이 필요합니다.


귀하의 계정에서 얻은 결과를 공유할 것을 촉구합니다. MT5 개선에 기여하세요!

파일:
 
fxsaber :

귀하의 계정에서 얻은 결과를 공유할 것을 촉구합니다. MT5 개선에 기여하세요!

Total Orders (from 2020.11 . 01 00 : 00 : 00 ) = 21725 , calculated = 10465
Calculation time = 00 : 04 : 33.609 , Performance = 38.0 orders/sec.

ServerName: RannForex-Server

Last Tick 2020.11 . 16 00 : 34 : 35.201 104.630 104.640
Accepted Tick 2020.11 . 16 00 : 34 : 06.309 104.627 104.639
Accepted Length = 28894 ms.
Order 1715452 ORDER_TYPE_SELL USDJPY 2020.11 . 16 00 : 34 : 35.203 104.627 ORDER_REASON_TP ORDER_STATE_REJECTED 2020.11 . 16 00 : 34 : 35.217 , Position created 2020.11 . 16 00 : 33 : 51.196 , StopLevel = 0

Orders ( 4 ) before 1715452 with PositionID = 1715287 :
-----------------------
Last Tick 2020.11 . 16 00 : 34 : 06.309 104.627 104.639
Accepted Tick 2020.11 . 16 00 : 34 : 06.309 104.627 104.639
Accepted Length = 3 ms.
Order 1715425 ORDER_TYPE_SELL USDJPY 2020.11 . 16 00 : 34 : 06.312 104.625 ORDER_REASON_TP ORDER_STATE_REJECTED 2020.11 . 16 00 : 34 : 06.327 , Position created 2020.11 . 16 00 : 33 : 51.196 , StopLevel = 0

Checked Orders = 1
------------------------

28초 지연! 아마도 그러한 상황에서는 이미 브로커에게 연락하는 것이 좋습니다.

 
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) ServerName: ICMarkets-MT5
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) 
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Last Tick 2020.11.24 23:00:49.327 1.33569 1.33570
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Accepted Tick 2020.11.24 23:00:49.327 1.33569 1.33570
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Accepted Length = 7 ms.
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Order 106887648 ORDER_TYPE_BUY GBPUSD 2020.11.24 23:00:49.334 1.33572 ORDER_REASON_TP ORDER_STATE_FILLED 2020.11.24 23:00:49.830, Position created 2020.11.24 22:57:47.071, StopLevel = 0
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) 
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) Orders (2) before 106887648 with PositionID = 106886713:
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:47:22.624 CheckOrders (EURUSD,H1) ServerName: ICMarkets-MT5
2020.11.25 02:47:22.624 CheckOrders (EURUSD,H1) 
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Last Tick 2020.11.18 12:44:37.354 1.18748 1.18748
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Accepted Tick 2020.11.18 12:44:37.354 1.18748 1.18748
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Accepted Length = 17 ms.
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Order 105637485 ORDER_TYPE_SELL EURUSD 2020.11.18 12:44:37.371 1.18749 ORDER_REASON_SL ORDER_STATE_FILLED 2020.11.18 12:44:37.476, Position created 2020.11.17 22:24:15.116, StopLevel = 0
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) 
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) Orders (2) before 105637485 with PositionID = 105516718:
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) ------------------------
 
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) ServerName: OctaFX-Real
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) 
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Last Tick 2020.11.23 18:14:35.081 1.18108 1.18115
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Accepted Tick 2020.11.23 18:14:35.081 1.18108 1.18115
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Accepted Length = 11 ms.
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Order 8950107 ORDER_TYPE_SELL EURUSD 2020.11.23 18:14:35.092 1.18105 ORDER_REASON_TP ORDER_STATE_FILLED 2020.11.23 18:14:35.104, Position created 2020.11.23 18:11:38.678, StopLevel = 20
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) 
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) Orders (2) before 8950107 with PositionID = 8950014:
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) ------------------------
 
2020.11.25 02:54:37.912 CheckOrders (EURUSD,H1) ServerName: Pepperstone-MT5-Live01
2020.11.25 02:54:37.912 CheckOrders (EURUSD,H1) 
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Last Tick 2020.09.03 01:00:02.426 106.199 106.199
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Accepted Tick 2020.09.03 01:00:02.426 106.199 106.199
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Accepted Length = 4 ms.
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Order 18982771 ORDER_TYPE_SELL USDJPY 2020.09.03 01:00:02.430 106.191 ORDER_REASON_TP ORDER_STATE_FILLED 2020.09.03 01:00:02.466, Position created 2020.09.02 22:57:47.081, StopLevel = 0
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) 
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) Orders (2) before 18982771 with PositionID = 18975080:
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) ------------------------
 

fxsaber의 또 다른 두뇌 폭발. 내가 무슨 말을 해야할지 모르겠어요.

브로커와 함께 병목 현상을 찾아내고 가능하면 해결해 보는 것이 유일한 해결책이라고 생각합니다.

정기적 인 수정을 위해

- 개발자들의 쏟아지는 비난을 견디고 랙이 발생했음을 증명합니다(예를 들어 브로커 서버 부분의 하드웨어와 같이 알 수 없는 뉘앙스를 고려)

- 그가 비판적인지 확인

- 수정을 기다리다

- 서버 부분을 최신 빌드로 업데이트하기 위해 부지런히 브로커를 시작합니다. 이는 이전의 모든 포인트보다 훨씬 어려울 수 있습니다.

 
음, hackneyed MT는 HFT용이 아닙니다)
 
ServerName: RannForex-Server
Accepted Length = 28894 ms.

여기에 당신이 그와 거래하는 매우 멋진 중개인 기술에 대한 심각한 의심이 있습니다.

사용자 정의 제한 처리를 위해 플러그인에서 속도가 느려집니다.

 
Andrey Khatimlianskii :

여기에 당신이 그와 거래하는 매우 멋진 중개인 기술에 대한 심각한 의심이 있습니다.

... 또는 교환 섹션의 지연에 대한 스레드를 에코하면 추측할 수 있습니다. 서버의 각 브로커는 무엇이든 가질 수 있습니다.

 
Andrei Trukhanovich :

정기적 인 수정을 위해

- 개발자들의 쏟아지는 비난을 견디고 랙이 발생했음을 증명합니다(예를 들어 브로커 서버 부분의 하드웨어와 같이 알 수 없는 뉘앙스를 고려)

거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼

SL/TP 주문 수락

fxsaber , 2020.11.25 00:47

MQ-Demo 에서 실행한 결과입니다.

Total Orders (from 2020.09 . 01 00 : 00 : 00 ) = 58493 , calculated = 439
Calculation time = 00 : 00 : 11.328 , Performance = 38.0 orders/sec.

ServerName: MetaQuotes-Demo


다른 스레드에서는 터미널조차도 엄청난 수의 요인으로 인해 느려진다고 반복해서 언급되었습니다. 결과적으로 훨씬 더 복잡한 Trade Server는 훨씬 더 느려질 수밖에 없습니다. 그러나 알고리즘 최적화가 여전히 가능하기를 바랍니다. 5ms 지연조차도 이미 매우 나쁩니다. 수백 밀리초에 대해 무엇을 말할 수 있습니까?