OrderSend() Вопросы - страница 5

 

Видимо, не совсем доходчиво пояснил предыдущую проблему. Попробую ещё раз.

За последний год описание списка значений перечисления ENUM_ORDER_TYPE_FILLING менялось, как минимум, трижды.   Предыдущее описание выглядело так:

ENUM_ORDER_TYPE_FILLING

Идентификатор

Описание

ORDER_FILLING_FOK

Сделка может быть совершена исключительно в указанном объеме и по цене равной или лучше указанной в ордере. Если на рынке в данный момент не присутствует достаточного объема предложений по символу ордера, то ордер не будет исполнен. Данный тип заполнения используется в режиме исполнения SYMBOL_TRADE_EXECUTION_INSTANT или SYMBOL_TRADE_EXECUTION_REQUEST.

ORDER_FILLING_IOC

Согласие совершить сделку по максимально доступному на рынке объему в пределах указанного в ордере и по цене равной или лучшей указанной. При этом на недостающий объем дополнительные ордера не выставляются. Данный тип заполнения может быть доступен только в режимах исполнения SYMBOL_TRADE_EXECUTION_MARKET и SYMBOL_TRADE_EXECUTION_EXCHANGE в зависимости от настроек символа на торговом сервере.

ORDER_FILLING_RETURN

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

Как нетрудно заметить, существовало взаимно-однозначное соответствие между ORDER_FILLING_RETURN и отложенными ордерами, а именно: ORDER_FILLING_RETURN могло применяться только к отложенным ордерам, и поле type_filling  всех отложенных ордеров могло заполняться только значением ORDER_FILLING_RETURN.

Для рыночных ордеров (action==TRADE_ACTION_DEAL) поле type_filling  необходимо было заполнять в зависимости от режимов исполнения, установленных на стороне сервера.

Тем самым, складывалась некая парадигма: если отложенный ордер, то  ORDER_FILLING_RETURN; если рыночный ордер, то ORDER_FILLING_FOK или ORDER_FILLING_IOC (в зависимости от режима).

Теперь же всё поставлено несколько с ног на голову, а именно:

ENUM_ORDER_TYPE_FILLING

Идентификатор

Описание

ORDER_FILLING_FOK

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

ORDER_FILLING_IOC

Означает согласие совершить сделку по максимально доступному на рынке объему в пределах указанного в ордере. В случае невозможности полного исполнения ордер будет исполнен на доступный объем, а неисполненный объем ордера будет отменен.

ORDER_FILLING_RETURN

Данный режим используется только для ордеров ORDER_TYPE_BUY_LIMIT и ORDER_TYPE_SELL_LIMIT. В случае частичного исполнения лимитный ордер с остаточным объемом не снимается, а продолжает действовать.

Для ордеров ORDER_TYPE_BUY_STOP_LIMIT и ORDER_TYPE_SELL_STOP_LIMIT при активации будет создан соответствующий лимитный ордер ORDER_TYPE_BUY_LIMIT/ORDER_TYPE_SELL_LIMIT с типом исполнения ORDER_FILLING_RETURN.

Ограничение на использование ORDER_FILLING_FOK и ORDER_FILLING_IOC только с рыночными ордерами - исчезло. Исчезло также ограничение на использование ORDER_FILLING_FOK и ORDER_FILLING_IOC с рыночными ордерами в зависимости от режима исполнения, установленного на сервере. Появилось ограничение на использование ORDER_FILLING_RETURN только с limit- и stop_limit-ордерами.

Поэтому и вопрос: Является ли допустимым применение режимов ORDER_FILLING_FOK и ORDER_FILLING_IOC вообще к всем ордерам (как рыночным, так и отложенным), в том числе и к limit- и stop_limit-ордерам? Кто-нибудь разобрался в изменениях? 

 

В Стандартной библиотеке есть такой метод (схематично):

bool CTrade::PositionClose(const string symbol,ulong deviation)
  {
   do
     {
      //--- checking
      if(PositionSelect(symbol))
        {
         if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
           {
            //--- prepare request for close BUY position
            m_request.type =ORDER_TYPE_SELL;
            m_request.price=SymbolInfoDouble(symbol,SYMBOL_BID);
           }
         else
           {
            //--- prepare request for close SELL position
            m_request.type =ORDER_TYPE_BUY;
            m_request.price=SymbolInfoDouble(symbol,SYMBOL_ASK);
           }
        }
      else
        {
         //--- position not found
         m_result.retcode=retcode;
         return(false);
        }
      m_request.action      =TRADE_ACTION_DEAL;
      m_request.volume      =PositionGetDouble(POSITION_VOLUME);
      //--- check volume
      double max_volume=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
      if(m_request.volume>max_volume)
        {
         m_request.volume=max_volume;
         partial_close=true;
        }
      else
         partial_close=false;
      //--- order send
      if(!OrderSend(m_request,m_result))
        {
         if(--retry_count!=0) continue;
         if(retcode==TRADE_RETCODE_DONE_PARTIAL)
            m_result.retcode=retcode;
         return(false);
        }
      retcode=TRADE_RETCODE_DONE_PARTIAL;
      if(partial_close) Sleep(1000);
     }
   while(partial_close);
   return(true);
  }

 Здесь, в случае, когда объём позиции больше максимального объема для заключения сделки, предпринимаются последовательные попытки частичного закрытия позиции.

При этом после удачного вызова функции OrderSend() ставится секундная задержка и затем в теле цикла do-while вызывается функция PositionSelect(). Т.е. предполагается, что в случае удачного принятия сервером рыночного ордера достотаточно одной секунды, чтобы обновились сведения об открытой позиции в базе терминала, и чтобы на следующей итерации можно было получать обновлённые данные о позиции (в данном примере - об объёме позиции). Но два года назад задержка в этом же методе перед вызовом функции PositionSelect() составляла три секунды. Поэтому вопрос:

Достаточно ли во всех случаях одной секунды для того, чтобы после удачного вызова функции OrderSend() база данных терминала гарантированно получила обновлённые данные о позиции (и, тем самым, позволила корректно обработать на стороне терминала оставшийся объём позиции)? Каково максимальное время, в течение которого база данных терминала должна гарантированно получить обновлённые данные о позиции в описываемом случае?

 

На чемпионате есть такое правило:

 Торговые условия будут максимально приближены к реальным:

  • время обработки торговых заявок от 2 до 7 секунд
На реале у одного брокера (после вывода денег) обработка стала порядка 3 секунд (открытие-закрытие-модификация).Сразу перешел на NDD.Доволен пока. 
 
Karlson:

На чемпионате есть такое правило:

 Торговые условия будут максимально приближены к реальным:

  • время обработки торговых заявок от 2 до 7 секунд

ОК, спасибо за подсказку! Получается, что одной секунды недостаточно для того, чтобы после удачного вызова функции OrderSend() база данных терминала гарантированно получила обновлённые данные о позиции?

Из такого вывода следует, что метод Стандартной  библиотеки, который я привёл, вообще не гарантирует от того, что вместо закрытия позиции будет переворот. Т.е. если метод PositionClose() задерживает очередную итерацию на одну секунду, а торговые заявки могут обрабатываться в 2 - 7 раз дольше, то не исключено, что на новых итерациях функция PositionSelect() будет получать прежние сведения о состоянии позиций из базы терминала и бомбить сервер ордерами-дубликатами, совокупный объём которых в таком случае окажется больше, чем первоначальный объём  закрываемой позиции.

Зачем тогда в методе  PositionClose()  установлена односекундная задержка, если она допускает переворот позиции вместо её закрытия? И не согласуется с "торговыми условиями, максимально приближенными к реальным"?

В общем, нужна более подробная информация о том, в течение какого времени база данных терминала  после удачного вызова функции OrderSend()  гарантированно получит обновлённые данные о позиции, и чем обоснованна односекундная задержка в стандартном методе PositionClose().

 
начнем с того, что
if(PositionSelect(symbol))

ничего не гарантирует. Её применять нельзя.

во вторых - на обновление данных терминала тоже нет никаких гарантий.  Нужно самому организовывать искусственное TradeContextBusy и ожидать отработки всех ваших приказов. 
Сразу и влоб в MQL5 нельзя. Временных гарантий нет.

 

sergeev:

начнем с того, что

if(PositionSelect(symbol))

ничего не гарантирует. Её применять нельзя.

во вторых - на обновление данных терминала тоже нет никаких гарантий.  Нужно самому организовывать искусственное TradeContextBusy и ожидать отработки всех ваших приказов. 
Сразу и в лоб в MQL5 нельзя. Временных гарантий нет. 

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

Подскажите, а вот если в истории появляется сделка со свойством

DEAL_ENTRY_OUT

Выход из рынка

то означает ли это , что все сведения в базе данных терминала автоматически изменились (обновились до актуального состояния)? Или же сделка может уже появиться в истории, а сведения о позиции всё ещё будут необновленными? Иными словами, интересует вопрос: изменяются ли одновременно сведения о сделках в истории и  сведения о соответствующих позициях? Или же и в этом случае сделки и позиции обновляются в терминале асинхронно? Из статьи Роша я этого уловить не смог - там, насколько я понял, описана асинхронность между обновлением базы терминала и возвращением результата торгового запроса.

 

модель обмена данными в терминале как вы заметили асинхронна.

поэтому при торговле (получение свойств ордеров/сделок/поз) необходимо анализировать успешность получения данных. И в случае любой ошибки (false/0) обрывать анализ торговой логики.

Все выполненные и неподтвержденные OrderSend запоминать и ожидать появления ордера, самостоятельно блокируя новые отправки ордеров, если ответа от прошлой отправки еще нет.

А, например, PositionSelect лучше заменить на конструкцию

for(int i=PositionsTotal()-1;i>=0;i--) 
{
  if(PositionGetSymbol(i)==Symbol())
  {
    ....
  }

В общем логика проведения торговых операций должна быть асинхронна. Так как асинхронен терминал, асинхронен МТ-сервер и сервер провайдера ликвидности.

Задача проверки синхронизации полностью ложится на MQL программиста.

Документация по MQL5: Стандартные константы, перечисления и структуры / Торговые константы / Типы торговых операций
Документация по MQL5: Стандартные константы, перечисления и структуры / Торговые константы / Типы торговых операций
  • www.mql5.com
Стандартные константы, перечисления и структуры / Торговые константы / Типы торговых операций - Документация по MQL5
 

С использованием этого ответа на прошлом чемпионате у меня проблема не возникала

https://www.mql5.com/ru/forum/4342#comment_88688 

Дублирование запросов на открытие позиций.
Дублирование запросов на открытие позиций.
  • www.mql5.com
Дублирование запросов на открытие позиций.
 
sergeev:

А, например, PositionSelect лучше заменить на конструкцию

for(int i=PositionsTotal()-1;i>=0;i--) 
{
  if(PositionGetSymbol(i)==Symbol())
  {
    ....
  }

Поясните, пожалуйста, если не трудно, в чём преимущество использования связки PositionsTotal() + PositionGetSymbol()  перед использованием PositionSelect()? Все три функции обращаются к одной и той же базе терминала, при этом функции PositionGetSymbol()  и PositionSelect() могут завершиться неудачно. Т.е., если позиция имеется в базе терминала, то неудачно может завершиться как функция PositionSelect(), так и предложенная конструкция. Всё равно придётся проверять код ошибки.

В чём особенность/надёжность  Вашей конструкции? Так и не смог разобраться.

Документация по MQL5: Торговые функции / PositionSelect
Документация по MQL5: Торговые функции / PositionSelect
  • www.mql5.com
Торговые функции / PositionSelect - Документация по MQL5
 

сламал себе всю голову.. не ставит стоп и все тут.. и куча ошибок. уже вот что осталось от експерта, и дальше не работает

void OnTick(){ if(PositionsTotal()<1){OPEN();}}

bool OPEN(){
             MqlTradeRequest request;
             MqlTradeResult result;
             

             request.symbol       = _Symbol;
             request.action       = TRADE_ACTION_DEAL;
             request.type_filling = ORDER_FILLING_FOK;
             request.deviation    = 100;
             request.volume       = NormalizeDouble(2,2);
             request.type         = ORDER_TYPE_BUY;
             request.price        = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
             request.tp           = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK) + 500*_Point,_Digits);
             request.sl           = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK) - 500*_Point,_Digits);

             OrderSend(request,result);     
                        
             if(result.retcode==10009 || result.retcode==10008)  Print("Succsesful open");
             else                                               Print("Error open: ",DoubleToString(GetLastError(),0),"  response code: ",result.retcode);
    
   return(true);}

 если сделать так, то ошибок нету, но стоплосс все равно не устанавливается

MqlTradeRequest request={0};MqlTradeResult result={0};
Причина обращения: