ФОРТС: OnTradeTransaction() коды возврата - страница 9

 
Михаил:

Ты не понял.

Это сервер не присылал состояние ордера PLASED 20 секунд. 

Я имел ввиду разработчиков сервера.
 
Михаил:

На лицо ОЧЕВИДНАЯ ошибка терминала, в котором "зависает" состояние ордера ORDER_STATE_STARTED 

Неужели разобрались, наконец?

А что конкретно про этот ордер говорит биржа? Он был выставлен быстро? Если да, то очевидна ошибка сервера или терминала МТ, который не обновляет статус. И вот с этим уже можно в сервис-деск. 

 

По результата обсуждения проблемы с Михаилом в Сервисдеске:

Видимо нужно объяснить как работает система ордеров и что означает placed.

Итак:

1. Вы отправляете запрос

buy limit 5.00 SNGR-3.16 at 35501

2. Сервер МТ5 проверяет это запрос (параметры, претрейд и т.д.). Если есть проблемы, то в ответ на запрос вы получите получите соответствующий код ошибки.

После чего заводит у себя новый ордер присваивая ему тикет (#24025010) - у ордера при этом выставляется состояние started. Проставлять тикет ордера нужно для того чтобы в момент выставления ордера на бирже связать идентификатор ордера в МТ5 с ордером на бирже.
Терминалу отправляется транзакция о добавлении нового ордера в состоянии started - это можно отследить в OnTradeTransaction.

3. Далее торговый сервер (через шлюз) отправляет вашу заявку на биржу, если заявка успешно отправилась, то на ваш запрос отправляется ответ placed - это значит
"что заявка отправлена", результаты её работы будут выполняться асинхронно, т.к. заранее не известно через какое время ответит биржа.

Соответственно именно в этот момент вы видите в журнале запись

2015.11.26 10:48:23.726 Trades  'xxxxxx': buy limit 5.00 SNGR-3.16 at 35501 placed for execution in 7 ms

4. Спустя какое то время, биржа устанавливает ордер в своей системе, присваивает ему свой идентификатор, после чего уведомляет об этом шлюз и сервер МТ5.
Если биржа установила ордера - то в ордер в МТ5 прописывается идентификатор ордера на бирже, и состояние ордера меняется со started => placed.
Если биржа по какой-то причине отказала в выставлении ордера, то ордер снимается.

Это всё можно отследить простым журналирование транзакций приходящих в OnTradeTransaction.

================================================================================

Что происходит:

1. Вы отправляете заявку на ордер - см. пп.1-3.

2. И в момент когда ордер в МТ5 уже есть, а на бирже его ещё нет, вы отправляете заявку на снятие этого ордера.
Но поскольку этот ордер в начальном состоянии (started) и наличие для него заявки не определено, вы получаете отказ от снятия ордера
поскольку в этом случае поведение не определено.

Вам нужно внести соответствующие проверки-коррекции в логику работы вашего эксперта.


З.Ы. Другое дело, что в течении секунды

2015.11.26 10:48:24.583 Trades  'xxxxxx': failed cancel order #24025010 buy limit 5.00 SNGR-3.16 at 35501.00000 [Invalid request]
(и тем более 20 секунд) ордер должен бы выставиться, с этим разбираемся, одну из потенциальных проблем нашли - исправляем.
 
MQ Alexander:
Спасибо за объяснения! Добавьте это, пожалуйста, в документацию!
 
MQ Alexander:

По результата обсуждения проблемы с Михаилом в Сервисдеске:

Видимо нужно объяснить как работает система ордеров и что означает placed.

Итак:

1. Вы отправляете запрос


2. Сервер МТ5 проверяет это запрос (параметры, претрейд и т.д.). Если есть проблемы, то в ответ на запрос вы получите получите соответствующий код ошибки.

После чего заводит у себя новый ордер присваивая ему тикет (#24025010) - у ордера при этом выставляется состояние started. Проставлять тикет ордера нужно для того чтобы в момент выставления ордера на бирже связать идентификатор ордера в МТ5 с ордером на бирже.
Терминалу отправляется транзакция о добавлении нового ордера в состоянии started - это можно отследить в OnTradeTransaction.

3. Далее торговый сервер (через шлюз) отправляет вашу заявку на биржу, если заявка успешно отправилась, то на ваш запрос отправляется ответ placed - это значит
"что заявка отправлена", результаты её работы будут выполняться асинхронно, т.к. заранее не известно через какое время ответит биржа.

Соответственно именно в этот момент вы видите в журнале запись

4. Спустя какое то время, биржа устанавливает ордер в своей системе, присваивает ему свой идентификатор, после чего уведомляет об этом шлюз и сервер МТ5.
Если биржа установила ордера - то в ордер в МТ5 прописывается идентификатор ордера на бирже, и состояние ордера меняется со started => placed.
Если биржа по какой-то причине отказала в выставлении ордера, то ордер снимается.

Это всё можно отследить простым журналирование транзакций приходящих в OnTradeTransaction.

================================================================================

Что происходит:

1. Вы отправляете заявку на ордер - см. пп.1-3.

2. И в момент когда ордер в МТ5 уже есть, а на бирже его ещё нет, вы отправляете заявку на снятие этого ордера.
Но поскольку этот ордер в начальном состоянии (started) и наличие для него заявки не определено, вы получаете отказ от снятия ордера
поскольку в этом случае поведение не определено.

Вам нужно внести соответствующие проверки-коррекции в логику работы вашего эксперта.


З.Ы. Другое дело, что в течении секунды

(и тем более 20 секунд) ордер должен бы выставиться, с этим разбираемся, одну из потенциальных проблем нашли - исправляем.
Осталось непонятным, в какой момент состояние ордера "started" меняется на состояние "placed". Это происходит в соответствии с п.3 Ваших пояснений, в соответствии с п.4 Ваших пояснений или в обоих случаях п.3 и п.4 ?
 
Yury Kirillov:
Осталось непонятным, в какой момент состояние ордера "started" меняется на состояние "placed". Это происходит в соответствии с п.3 Ваших пояснений, в соответствии с п.4 Ваших пояснений или в обоих случаях п.3 и п.4 ?
MQ Alexander:

4. Спустя какое то время, биржа устанавливает ордер в своей системе, присваивает ему свой идентификатор, после чего уведомляет об этом шлюз и сервер МТ5.
Если биржа установила ордера - то в ордер в МТ5 прописывается идентификатор ордера на бирже, и состояние ордера меняется со started => placed.

 
MQ Alexander:

3. Далее торговый сервер (через шлюз) отправляет вашу заявку на биржу, если заявка успешно отправилась, то на ваш запрос отправляется ответ placed - это значит

"что заявка отправлена", результаты её работы будут выполняться асинхронно, т.к. заранее не известно через какое время ответит биржа.

Соответственно именно в этот момент вы видите в журнале запись

2015.11.26 10:48:23.726 Trades  'xxxxxx': buy limit 5.00 SNGR-3.16 at 35501 placed for execution in 7 ms

4. Спустя какое то время, биржа устанавливает ордер в своей системе, присваивает ему свой идентификатор, после чего уведомляет об этом шлюз и сервер МТ5.
Если биржа установила ордера - то в ордер в МТ5 прописывается идентификатор ордера на бирже, и состояние ордера меняется со started => placed.

Вот еще одна причина путаницы: в журнале написано, что ордер уже placed, а по факту состояние еще не поменялось.

Может, писать что-то типа "отправлен", а не "размещен", по ордер реально не принят биржей? 

 

Получается следующее.

Перед тем ( или после ), как совершить какое-либо действие над ордером,

нужно каждый раз "смотреть" его состояние (поправьте, если что не додумал):

enum ENUM_ORD_REAL_STATE
{
  ORD_NOT_SPECIFIED         = 0, //Состояние ордера не определено
  ORD_NONE_CANCELED         = 1, //Ордера нет, отменён пользователем
  ORD_NONE_PARTIAL_CANCELED = 2, //Ордера нет, исполнился частично (не был залит вторым объёмом)
  ORD_NONE_PARTIAL          = 3, //Ордера нет, исполнился частично
  ORD_NONE_EXPIRED          = 4, //Ордера нет, удалён по сроку
  ORD_NONE_FILLED           = 5, //Ордера нет, исполнился полностью
  ORD_NONE_REJECTED         = 6, //Ордера нет, отклонён брокером(биржей)
  ORD_BUSY                  = 7, //Ордер находится в переходном состоянии
  ORD_EXIST                 = 8, //Ордер выставлен на биржу, возможны действия над ним
  ORD_EXIST_PARTIAL         = 9  //Ордер выставлен на биржу, частично исполнился, возможны действия над ним
};
//
ENUM_ORD_REAL_STATE CheckOrderState( const ulong ticket )
{
  if ( ticket > 0 )
  {
    if ( HistoryOrderSelect( ticket ) ) //Только не существующий ордер может находится в истории
    {
      ENUM_ORDER_STATE ord_state = ENUM_ORDER_STATE( HistoryOrderGetInteger( ticket, ORDER_STATE ) );
      double init_volume = HistoryOrderGetDouble( ticket, ORDER_VOLUME_INITIAL );
      double cur_volume = HistoryOrderGetDouble( ticket, ORDER_VOLUME_CURRENT );
//---      
      switch( ord_state )
      {
                                                           
        case ORDER_STATE_CANCELED:       if ( init_volume == init_volume )
                                         {
                                           return( ORD_NONE_CANCELED );
                                         }
                                         else
                                         {
                                           return( ORD_NONE_PARTIAL_CANCELED );
                                         }  
                                         break;
                                         
        case ORDER_STATE_PARTIAL:        return( ORD_NONE_PARTIAL );
                                         break;
                                         
        case ORDER_STATE_EXPIRED:        return( ORD_NONE_EXPIRED );
                                         break;
                                                                              
        case ORDER_STATE_FILLED:         return( ORD_NONE_FILLED );
                                         break;
                                         
        case ORDER_STATE_REJECTED:       return( ORD_NONE_REJECTED );
                                         break;   
 
       
      }
    }
    else
    if ( OrderSelect( ticket ) ) 
    {
      ENUM_ORDER_STATE ord_state = ENUM_ORDER_STATE( OrderGetInteger( ORDER_STATE ) );
//---      
      switch( ord_state )
      {
        case ORDER_STATE_STARTED:
        case ORDER_STATE_REQUEST_ADD:
        case ORDER_STATE_REQUEST_MODIFY:
        case ORDER_STATE_REQUEST_CANCEL: return( ORD_BUSY );
                                         break; 
 
        case ORDER_STATE_PARTIAL:        return( ORD_EXIST_PARTIAL );
                                         break;
                                          
        case ORDER_STATE_PLACED:         return( ORD_EXIST );
                                         break;
      }
    }
  }
  return( ORD_NOT_SPECIFIED );
}
 
Михаил:

Получается следующее.

Перед тем ( или после ), как совершить какое-либо действие над ордером,

нужно каждый раз "смотреть" его состояние (поправьте, если что не додумал):

Неправильно,

Если смотрим в истории HistoryOrderSelect( ticket ), то нужно применять  HistoryOrderGetInteger()HistoryOrderGetDouble()

 
Sergey Chalyshev:

Неправильно,

Если смотрим в истории HistoryOrderSelect( ticket ), то нужно применять  HistoryOrderGetInteger()HistoryOrderGetDouble()

Правильно, опечатка :)

спасибо, поправил... 

Причина обращения: