Типичные ошибки и способы их устранения при работе с торговым окружением - страница 3

 
fxsaber:

Правильный вариант на простом примере

Думаю правильней в случае когда ордер еще не учтен в позиции, просто подождать пока он учтется.
 
Комбинатор:
Думаю правильней в случае когда ордер еще не учтен в позиции, просто подождать пока он учтется.

Не уловил мысль.

 
Условная схема реализации штатной OrderSend (без таймаута)
static MqlTradeResult LastResult = {0};

void OnTradeTransaction( const MqlTradeTransaction&, const MqlTradeRequest&, const MqlTradeResult &Result )
{ 
  LastResult = Result;
}

// Условный алгоритм реализации штатной OrderSend
bool OrderSend( const MqlTradeRequest &Request, MqlTradeResult &Result )
{  
  bool Res = OrderSendAsync(Request, Result);
  
  if (Res)
  {
    while (LastResult.request_id != Result.request_id)
      OnTradeTransaction(); // условно-схематичный вызов
          
    Result = LastResult;    
    Res = (Result.retcode == TRADE_RETCODE_PLACED) ||
          (Result.retcode == TRADE_RETCODE_DONE) ||
          (Result.retcode == TRADE_RETCODE_DONE_PARTIAL);

    LastResult.request_id = 0;
  }
    
  return(Res);
}


Из этой схемы хорошо видно, что при выставлении маркет-ордера через OrderSendAsync на том же MetaQuotes-Demo невозможно гарантированно поймать событие выставления соответствующего ордера до момента, пока ордер не будет исполнен или отклонен. Т.е. в MT5 нет никаких простых механизмов оценивания промежуточных результатов своего OrderSendAsync.

 

Кажется в теме,

Хочу отметить что такой код :

if ( !OrderSend(request,result) ) PrintFormat("OrderSend error %d",GetLastError());
else Print(result.price);

на ДЕМО работает безупречно (result=request),

но на РЕАЛ - результат получить невозможно (result=0.0). ... если не подождать несколько секунд.

 
Ivan Ivanov:

Кажется в теме,

Хочу отметить что такой код :

на ДЕМО работает безупречно (result=request),

но на РЕАЛ - результат получить невозможно (result=0.0). ... если не подождать несколько секунд.

Не хватает данных - логи, значения полей структур после OrderSend, имя торгового сервера.

 
fxsaber:

Смысл вкратце таков: если стоит маркет-ордер, считай, что и это "позиция". В кавычках, потому что это оберточная позиция. Выделенный код, как правило, нигде не фигурирует. Но он позволяет избегать повторных открытий позиций. Самое интересное здесь - выделенное красным. Необходимость этой фишки не сразу осознать.

for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  // если мы сюда попадаем при проверке состояния, не запускать стратегию вообще, т.к. это промежуточное состояние.
 
Комбинатор:

На следующем тике может не быть торгового сигнала. Сам использую MT4-style, поэтому не могу не видеть такие "позиции", при этом проблем не получаю.

 
fxsaber:

Не хватает данных - логи, значения полей структур после OrderSend, имя торгового сервера.

//+------------------------------------------------------------------+
//|                                                      TestBUY.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{//--- объявление и инициализация запроса и результата
  MqlTradeRequest request={0};
  MqlTradeResult result={0};
//--- параметры запроса
  request.action =TRADE_ACTION_DEAL;
  request.symbol=_Symbol; 
  request.volume=0.01;
  request.type=ORDER_TYPE_BUY;
  request.price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
  request.deviation=5;
  request.magic=1234;
  request.tp=0.0;
  request.comment=DoubleToString(request.price,_Digits);
//--- отправка запроса
  if ( !OrderSend(request,result) )
    PrintFormat("OrderSend error %d",GetLastError()); // если отправить запрос не удалось, вывести
//--- информация об операции
  PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order," NewOrder");
}


2018.02.20 15:20:35.845    Trades     order #66745055 buy 0.01 / 0.01 EURUSDeur at market done in 610.625 ms

2018.02.20 15:20:35.935    Trades     deal #5461453 buy 0.01 EURUSDeur at 1.23403 done (based on order #66745055)

2018.02.20 15:20:35.845    TestBUY (EURUSDeur,M15)    retcode=10009 deal=0 order=66745055

Если запрос выполнен (10009) , то почему deal=0

 
Ivan Ivanov:

Если запрос выполнен (10009) , то почему deal=0 

Почти с этого и началось обсуждение. По ссылкам там все подробности.

Есть решение, чтобы OrderSend отрабатывал идеально, но это будет уже реклама.

 
fxsaber:

Правильный вариант на простом примере

Смысл вкратце таков: если стоит маркет-ордер, считай, что и это "позиция". В кавычках, потому что это оберточная позиция. Выделенный код, как правило, нигде не фигурирует. Но он позволяет избегать повторных открытий позиций. Самое интересное здесь - выделенное красным. Необходимость этой фишки не сразу осознать.

Дело в том, что есть так называемые закрывающие маркет-ордера. Те же SL/TP. Очевидно, что такие маркет-ордера видеть в виде "позиций" не хотелось бы. Да и те ордера, которые сам выставил для закрытия - аналогично. Вот выделенное условие и является соответствующим фильтром.

for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  

ЗЫ Вставьте этот код сюда и проверьте результат на демо-сервере.

Приглашаю всех заинтересованных к обсуждению данного вопроса. Моё мнение на этот счёт таково:


  1. Отправляем приказ на сервер
  2. Появляется маркет-ордер, который в итоге может быть отменён, но мы его уже посчитали за позицию?
for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  

Этот цикл добавляет одну позицию если нашёлся ордер, который не имеет идентификатора позиции (ID нулевой).

Мы вернули больше на одну позицию.

А если ордер будет отменён сервером?

...

Думается мне, что при учёте маркет-ордеров, необходимо - если таковой нашёлся - возвращать допустим WRONG_VALUE - позиций не может быть меньше нуля. Это будет сигналом, что есть неучтённый маркет-ордер. Но никак не добавлять число позиций.

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