ФОРТС Установка, удаление и модификация ордера - страница 2

 
Михаил:
Спрашивайте здесь, что будет не понятно...

К сожалению вопрос остаётся открытым =(

Проверяю догадку так:

1) OrderSend в result сообщила TRADE_RETCODE_PLACED

2) После этого выделяю ордер по тикету и OrderGetInteger(ORDER_STATE,state) сообщила в state ORDER_STATE_REQUEST_ADD.

Из документации это значит:

"Ордер в состоянии регистрации (выставление в торговую систему)"


Как переводится эта фраза на язык биржевого исполнения для ФОРТС?

Это проблема задержки синхронизации статусов и реального состояния дел?

Или это факт? То есть после TRADE_RETCODE_PLACED ордер нифига не на бирже в очереди?

Надо бы проверить однозначно, но сейчас у меня нет возможности.

Можно проверить последовательность возврата кода TRADE_RETCODE_PLACED с тикетом ордера и момент регистрации биржевого ID у заявки в очереди.


 
Постараюсь описать ситуацию предельно коротко:

1) отправляю ордер или удаляю его
2) момент неопределённости (нельзя считать, что ордера нет, нельзя считать, что ордер есть)
3) ордер размещён на бирже(удалён с биржи), либо "ордер/запрос отклонён из-за..."

Весь вопрос в том, когда наступает состояние (2)?

Если внутри функции OrderSend() до возврата из неё, то (2) - не наши проблемы.
Если возврат из OrderSend() происходит когда ещё длится момент неопределённости, то это уже серьёзные проблемы для нас.
 
Fry:
Постараюсь описать ситуацию предельно коротко:

1) отправляю ордер или удаляю его
2) момент неопределённости (нельзя считать, что ордера нет, нельзя считать, что ордер есть)
3) ордер размещён на бирже(удалён с биржи), либо "ордер/запрос отклонён из-за..."

Весь вопрос в том, когда наступает состояние (2)?

Если внутри функции OrderSend() до возврата из неё, то (2) - не наши проблемы.
Если возврат из OrderSend() происходит когда ещё длится момент неопределённости, то это уже серьёзные проблемы для нас.

Когда функция OrderSEnd вернула значение а TRADE_RETCODE_PLACED

Это означает,что ордер выставлен на биржу и мы можем получить его билет.

 
Михаил:

Когда функция OrderSEnd вернула значение а TRADE_RETCODE_PLACED

Это означает,что ордер выставлен на биржу и мы можем получить его билет.

Спасибо! Для меня это очень важно. Просто у меня сейчас в коде ошибки типа таких:

Лимит установлен > позиция открывается > новый лимит (частичного тейк профита) установлен > позиция мгновенно закрылась (на стоп вынесли быстрым рынком - отрабатывают такой редкий сценарий).

Так вот, почему-то в моём коде, на запрос "отменить частичный тейк профит сразу после установки" от сервера время от времени приходит реткод 100013.

Стал разбираться и выяснил, что вообще не могу удалять ордера мгновенно. Надо ждать после выставления.

Стал проверять статус и тут бах! Статус ордера говорит о том, что он ещё не на бирже =/

Спасибо ещё раз. Буду считать, что этот факт установлен наверняка.

Ошибку буду искать у себя в рассуждениях.

 
Fry:

Спасибо! Для меня это очень важно. Просто у меня сейчас в коде ошибки типа таких:

Лимит установлен > позиция открывается > новый лимит (частичного тейк профита) установлен > позиция мгновенно закрылась (на стоп вынесли быстрым рынком - отрабатывают такой редкий сценарий).

Так вот, почему-то в моём коде, на запрос "отменить частичный тейк профит сразу после установки" от сервера время от времени приходит реткод 100013.

Стал разбираться и выяснил, что вообще не могу удалять ордера мгновенно. Надо ждать после выставления.

Стал проверять статус и тут бах! Статус ордера говорит о том, что он ещё не на бирже =/

Спасибо ещё раз. Буду считать, что этот факт установлен наверняка.

Ошибку буду искать у себя в рассуждениях.

Всё очень просто.

OrderSend() - синхронная команда - отправили ордер и пока не получили ответ, то и делать ничего не надо.

В промежутке между запросом и ответом ничего опрашивать не нужно (не имеет никакого смысла). 

 
Михаил:

Всё очень просто.

OrderSend() - синхронная команда - отправили ордер и пока не получили ответ, то и делать ничего не надо.

В промежутке между запросом и ответом ничего опрашивать не нужно (не имеет никакого смысла). 

Если бы так просто! =(

Михаил, помогите, пожалуйста, понять, почему мой тестовый эксперт не работает на RTS во время активного рынка... Точнее эксперт-то работает, а вот ордера удаляются через раз.

Когда статус ордера ORDER_STATE_PLACED - ордер удаляется, а вот когда статус ORDER_STATE_STARTED или ORDER_STATE_REQUEST_ADD - ордер 100% всегда не удаляется.

Почему такая фигня происходит?

Вопрос к разработчикам: неужели нельзя отправлять самый критически важный торговый запрос без сложного и крайне ненадёжного опроса сервера о статусе ордера?

Или вы считаете, что это нормально, когда сервер возвращает мне TRADE_RETCODE_INVALID (Неправильный запрос) на вполне адекватный код с просьбой удалить 100% существующий и действующий лимитный ордер?


Вот код эсперта для фьючерса на RTS:

#property copyright "Fry"
#property version   "1.01"

MqlTradeResult  result;
MqlTradeRequest req;

uint     retcode=0;
ulong    ticket =0;
int      count  =0;

int OnInit(){Print("Инициализация тестового эксперта"); return(INIT_SUCCEEDED);}

void OnTick()
{
   if(ticket) // если ордер уже открыт
   {
      PrintOrderState();
      Delete();
      count++;
      if(count>50) ExpertRemove();
   }
   else Open(); // открываем ордер
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Удаляет лимитный ордер ticket
 !!! Все проблемы здесь !!!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void Delete()
{
   ZeroMemory(result);
   ZeroMemory(req);
   req.action=TRADE_ACTION_REMOVE;
   req.order =ticket;

   Print("Попытаемся удалить тестовый лимитный ордер №(",ticket,")...");

   bool noneed=OrderSend(req,result);
   retcode=result.retcode;                        // результат
   
   if(retcode==TRADE_RETCODE_PLACED) {ticket=0; Print("...Ордер успешно удалён.");}
   else Print("------======!!! Сервер сообщил (",RetCodeToString(),") !!!======------");
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Сообщает в лог текущий статус ордера ticket
 !!! Работает как надо. Код проверен !!!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void PrintOrderState()
{
   ResetLastError();
   //выделяем ордер для выяснения статуса
   if(OrderSelect(ticket))
   {
      ResetLastError();
      long state=OrderGetInteger(ORDER_STATE);
      if (!state)Print("OrderGetInteger() не сообщила статус. Ошибка№(",GetLastError(),")!");
      else       Print("Действующий ордер №(",ticket,"). Его текущий статус (",EnumToString((ENUM_ORDER_STATE)state),").");
   }
   // убедимся, что ордера действительно нет в списке действующих
   else if(GetLastError()!=ERR_TRADE_ORDER_NOT_FOUND) Print("Провал OrderSelect(). Ошибка№(",GetLastError(),")!");
   // ордера действительно нет в списке действующих
   else Print("В данный момент ордер №(",ticket,") действующий, но его почему-то нет в списке действующих ордеров терминала.");   
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Открывает лимитный ордер (на покупку объёмом 1 лот с удалением от рынка 500 и со стопом 2000)
 !!! Работает как надо. Код проверен !!!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void Open()
{
   ZeroMemory(result);
   ZeroMemory(req);

   // получаем адекватную инфу о свежем тике
   MqlTick tick;
   if(!SymbolInfoTick(Symbol(),tick)){Print("Не удалось получить свежую котировку. Ошибка№", GetLastError()); return;}

   req.price       =int(tick.ask-500);            // цена BUY-ордера складывается из текущего аска минус отступ ордера
   req.sl          =int(tick.ask-2000);           // стоп лосс на 2000 удаляем от аска

   req.action      =TRADE_ACTION_PENDING;         // Тип выполняемого действия (Установить отложенный ордер)
   req.symbol      =Symbol();                     // Имя торгового инструмента
   req.type_filling=ORDER_FILLING_RETURN;         // Тип исполнения (исполниять до полного набора позиции)
   req.type_time   =ORDER_TIME_DAY;               // Время действия ордера (до конца дня)
   req.volume      =1;                            // объём позиции
   req.type        =ORDER_TYPE_BUY_LIMIT;         // отложенный ордер на покупку
   req.comment     ="test limit order";           // комментарий к ордеру

   Print("Открываем тестовый лимитный ордер на покупку по цене (",req.price,")...");

   bool noneed=OrderSend(req,result);
   retcode=result.retcode;                        // результат
   Print("...сервер сообщил (",RetCodeToString(),").");
   
   if(retcode==TRADE_RETCODE_PLACED) {ticket=result.order; Print("Ордер размещен на бирже. Тикет ордера =",ticket);}
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Возвращает значение кода возврата согласно документации
 !!! Работает как надо. Код проверен !!!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
string RetCodeToString()
{      
   switch(retcode)
   {
      case TRADE_RETCODE_REQUOTE           : return("Реквота");
      case TRADE_RETCODE_DONE              : return("Выполнено");
      case TRADE_RETCODE_DONE_PARTIAL      : return("Выполнено частично");
      case TRADE_RETCODE_REJECT            : return("Запрос отвергнут");
      case TRADE_RETCODE_CANCEL            : return("Запрос отменен трейдером");
      case TRADE_RETCODE_PLACED            : return("Приказ принят");
      case TRADE_RETCODE_ERROR             : return("Ошибка обработки запроса");
      case TRADE_RETCODE_TIMEOUT           : return("Запрос отменен по истечению времени");
      case TRADE_RETCODE_INVALID           : return("Неправильный запрос");
      case TRADE_RETCODE_INVALID_VOLUME    : return("Неправильный объем в запросе");
      case TRADE_RETCODE_INVALID_PRICE     : return("Неправильная цена в запросе");
      case TRADE_RETCODE_INVALID_STOPS     : return("В запросе неправильный стоп или тейк профит");
      case TRADE_RETCODE_TRADE_DISABLED    : return("Торговля запрещена");
      case TRADE_RETCODE_MARKET_CLOSED     : return("Рынок закрыт");
      case TRADE_RETCODE_NO_MONEY          : return("Нет достаточных денежных средств для выполнения запроса");
      case TRADE_RETCODE_PRICE_CHANGED     : return("Цены изменились");
      case TRADE_RETCODE_PRICE_OFF         : return("Отсутствуют котировки для обработки запроса");
      case TRADE_RETCODE_INVALID_EXPIRATION: return("Неверная дата истечения ордера в запросе");
      case TRADE_RETCODE_ORDER_CHANGED     : return("Состояние ордера изменилось");
      case TRADE_RETCODE_TOO_MANY_REQUESTS : return("Слишком частые запросы");
      case TRADE_RETCODE_NO_CHANGES        : return("В запросе нет изменений");
      case TRADE_RETCODE_SERVER_DISABLES_AT: return("Автотрейдинг запрещен сервером");
      case TRADE_RETCODE_CLIENT_DISABLES_AT: return("Автотрейдинг запрещен клиентским терминалом");
      case TRADE_RETCODE_LOCKED            : return("Запрос заблокирован для обработки");
      case TRADE_RETCODE_FROZEN            : return("Ордер или позиция заморожены");
      case TRADE_RETCODE_INVALID_FILL      : return("Указан неподдерживаемый тип исполнения ордера по остатку");
      case TRADE_RETCODE_CONNECTION        : return("Нет соединения с торговым сервером");
      case TRADE_RETCODE_ONLY_REAL         : return("Операция разрешена только для реальных счетов");
      case TRADE_RETCODE_LIMIT_ORDERS      : return("Достигнут лимит на количество отложенных ордеров");
      case TRADE_RETCODE_LIMIT_VOLUME      : return("Достигнут лимит на объем ордеров и позиций для данного символа");
      case TRADE_RETCODE_INVALID_ORDER     : return("Неверный или запрещённый тип ордера");
      case TRADE_RETCODE_POSITION_CLOSED   : return("Позиция с указанным POSITION_IDENTIFIER уже закрыта");
      default                              : return("Неизвестный код возврата: "+(string)retcode);
   }
}

Приоритеты в коде:

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

2) сделать код таким, чтобы запрос на удаление ордера наверняка отправлялся (то есть предельно упростить все проверки перед OrderSend())

3) сделать код таким, чтобы ордер удалялся как можно быстрее (в рамках возможностей OrderSend()), то есть не пропускать лишние тики в ожидании статуса.


ЗЫ Кто из разработчиков отвечает за ФОРТС?

 
Fry:

Если бы так просто! =(

Михаил, помогите, пожалуйста, понять, почему мой тестовый эксперт не работает на RTS во время активного рынка... Точнее эксперт-то работает, а вот ордера удаляются через раз.

Когда статус ордера ORDER_STATE_PLACED - ордер удаляется, а вот когда статус ORDER_STATE_STARTED или ORDER_STATE_REQUEST_ADD - ордер 100% всегда не удаляется.

Почему такая фигня происходит?

Вопрос к разработчикам: неужели нельзя отправлять самый критически важный торговый запрос без сложного и крайне ненадёжного опроса сервера о статусе ордера?

Или вы считаете, что это нормально, когда сервер возвращает мне TRADE_RETCODE_INVALID (Неправильный запрос) на вполне адекватный код с просьбой удалить 100% существующий и действующий лимитный ордер?


Вот код эсперта для фьючерса на RTS:


Приоритеты в коде:

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

2) сделать код таким, чтобы запрос на удаление ордера наверняка отправлялся (то есть предельно упростить все проверки перед OrderSend())

3) сделать код таким, чтобы ордер удалялся как можно быстрее (в рамках возможностей OrderSend()), то есть не пропускать лишние тики в ожидании статуса.


ЗЫ Кто из разработчиков отвечает за ФОРТС?

Разработчики тут не причём.

Советую Вам почитать о приложениях КЛИЕНТ-СЕРВЕР.

У Вас не правильная логика советника. 

Вот так будет работать: 

void OnTick()
{
  if ( ticket > 0 )
  {
    if ( OrderSelect( ticket ) )
    {
      Delete();
    }
    else ticket = 0;
  }
  else Open(); // открываем ордер
}
 
Михаил:

Разработчики тут не причём.

Советую Вам почитать о приложениях КЛИЕНТ-СЕРВЕР.

У Вас не правильная логика советника. 

Вот так будет точно работать: 

неа. Не работает =(

(я тоже слегка исправил код выше, но суть не менял, только каменты)

Про КЛИЕНТ-СЕРВЕР... Естественно мой рабочий движок для лимитных ордеров обрабатывает события OnTrade, а логику совершения торговых действий я выстраиваю совсем не так.

Здесь я предельно упростил код, чтобы показать сам факт того, что ордер "не совсем чтобы на бирже" после OrderSend() или если он на бирже, то "не совсем чтобы всегда доступен для удаления".

И даже когда ордер выделяется - не всегда он удаляется!

ЗЫ только что проверял на демо счёте.

 
Fry:

неа. Не работает =(

(я тоже слегка исправил код выше, но суть не менял, только каменты)

Про КЛИЕНТ-СЕРВЕР... Естественно мой рабочий движок для лимитных ордеров обрабатывает события OnTrade, а логику совершения торговых действий я выстраиваю совсем не так.

Здесь я предельно упростил код, чтобы показать сам факт того, что ордер "не совсем чтобы на бирже" после OrderSend() или если он на бирже, то "не совсем чтобы всегда доступен для удаления".

И даже когда ордер выделяется - не всегда он удаляется!

ЗЫ только что проверял на демо счёте.

Я тоже только что проверил - всё работает! (У Вас демо в Открывашке или БКС ?)

2015.10.14 20:38:47.814 Fry_test (RTS-12.15,H1) ...Ордер успешно удалён.
2015.10.14 20:38:47.805 Fry_test (RTS-12.15,H1) Попытаемся удалить тестовый лимитный ордер №(6497077)...
2015.10.14 20:38:47.583 Fry_test (RTS-12.15,H1) ------======!!! Сервер сообщил (Неправильный запрос) !!!======------
2015.10.14 20:38:47.583 Fry_test (RTS-12.15,H1) Попытаемся удалить тестовый лимитный ордер №(6497077)...
2015.10.14 20:38:47.550 Fry_test (RTS-12.15,H1) Ордер размещен на бирже. Тикет ордера =6497077
2015.10.14 20:38:47.550 Fry_test (RTS-12.15,H1) ...сервер сообщил (Приказ принят).
2015.10.14 20:38:47.541 Fry_test (RTS-12.15,H1) Открываем тестовый лимитный ордер на покупку по цене (86480.0)...
2015.10.14 20:38:47.332 Fry_test (RTS-12.15,H1) ...Ордер успешно удалён.
2015.10.14 20:38:47.324 Fry_test (RTS-12.15,H1) Попытаемся удалить тестовый лимитный ордер №(6497076)...
2015.10.14 20:38:46.871 Fry_test (RTS-12.15,H1) Ордер размещен на бирже. Тикет ордера =6497076
2015.10.14 20:38:46.871 Fry_test (RTS-12.15,H1) ...сервер сообщил (Приказ принят).
2015.10.14 20:38:46.862 Fry_test (RTS-12.15,H1) Открываем тестовый лимитный ордер на покупку по цене (86480.0)...
2015.10.14 20:38:43.612 Fry_test (RTS-12.15,H1) Инициализация тестового эксперта
Файлы:
Fry_test.mq5  8 kb
 
Михаил:
Я тоже только что проверил - всё работает!

Ну как это работает? Запустил Ваш код.

Множество раз сообщает подобный бред:

2015.10.14 20:49:14.793    Fry_test (RTS-12.15,M1)    ------======!!! Сервер сообщил (Неправильный запрос) !!!======------

Кроме того... Хотите удивлю Вас?

1) То что OrderSelect() выделяет ордер, вовсе не означает, что ордер действующий =). Часто ордер ещё ~ секунду после исполнения выделяется, а уже потом переходит в список истории.

2) А может быть и так, что ордер 100% существует (даже действующий, или выполняется сейчас, или ещё что-то с ним). При этом он вообще ничем не выделяется! Ни OrderSelect(), ни HistoryOrderSelect()! И это происходит довольно часто!

3) Правильно обрабатывать возврат из OrderSelect() надо так как я показал внутри PrintOrderState().

Вот такая вот фигня =(

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