Как правильно работать с историей ордеров?

 

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

Если критически важно знать, что ордер не был открыт, хватит ли тех сведений, что его нет среди рыночных и нет в истории ордеров? Или может возникнуть ситуация, когда у ордера сработал TP/SL и его уже нет среди рыночных, но и в историю он еще не попал?

Если конкретнее, опираясь на это, могу ли я на 100% утверждать, что мы не еще не открывались по данному сигналу?

if(trend.dir == TREND_UP && !isBuyOrderExist && history.lastOpTimeBuy < trend.startDt)
     {
      // Код, который выполняется если еще не открывались по сигналу, который возник в trend.startDt
     }

Полный код (сильно упрощено):

#property strict

enum ENUM_TREND_DIR
  {
   TREND_UP,
   TREND_DN
  };

struct STRUCT_TREND
  {
   long startDt;       // Время смены тренда
   ENUM_TREND_DIR dir;
  };

struct STRUCT_HISTORY
  {
   datetime lastOpTimeBuy;
   datetime lastOpTimeSell;
   int prevTickTotal;
   bool isActual;
   STRUCT_HISTORY(){lastOpTimeBuy = 0; lastOpTimeSell = 0; prevTickTotal = 0; isActual = false;}
  };

input int inpMagic = 1;

STRUCT_HISTORY history;

int OnInit()
  {
   historyClear();
   return(INIT_SUCCEEDED);
  }

void OnTick()
  {
   historyUpdate();
   if(!history.isActual)
      return;
   bool isBuyOrderExist = false;
   bool isSellOrderExist = false;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!orderSelect(i, SELECT_BY_POS, MODE_TRADES, __LINE__))
         return;
      if(OrderType() == 0)
         isBuyOrderExist = true;
      else if(OrderType() == 1)
         isSellOrderExist = true;
     }
   STRUCT_TREND trend = getTrend();
   if(trend.dir == TREND_UP && !isBuyOrderExist && history.lastOpTimeBuy < trend.startDt)
     {
      //...
     }
  }

STRUCT_TREND getTrend()
  {
   STRUCT_TREND result;
   int trendChangeBarIndex;
   // Какие-то вычисления...
   result.startDt = Time[trendChangeBarIndex];
   return(result);
  }

void historyUpdate()
  {
   int historyTotal = OrdersHistoryTotal();
   if(history.prevTickTotal > historyTotal)
     {
      PrintFormat("Orders history error. The current size: %i, the size on the previous tick: %i.", historyTotal, history.prevTickTotal);
      historyClear();
     }
   for(int i = history.prevTickTotal; i < historyTotal; i++)
     {
      if(!orderSelect(i, SELECT_BY_POS, MODE_HISTORY, __LINE__))
        {
         historyClear();
         return;
        }
      if(OrderSymbol() != _Symbol || OrderMagicNumber() != inpMagic)
         continue;
      if(OrderType() == 0)
        {
         if(OrderOpenTime() > history.lastOpTimeBuy)
            history.lastOpTimeBuy = OrderOpenTime();
        }
      else if(OrderType() == 1)
        {
         if(OrderOpenTime() > history.lastOpTimeSell)
            history.lastOpTimeSell = OrderOpenTime();
        }
     }
   history.prevTickTotal = historyTotal;
   history.isActual = true;
  }

void historyClear()
  {
   history.lastOpTimeBuy = 0;
   history.lastOpTimeSell = 0;
   history.prevTickTotal = 0;
   history.isActual = false;
  }

bool orderSelect(int index, int select, int pool, int line)
  {
   ResetLastError();
   if(OrderSelect(index, select, pool))
      return(true);
   if(select == SELECT_BY_TICKET)
      PrintFormat("Failed to select order by ticket %i. Error %i, line %i.", index, GetLastError(), __LINE__);
   else
     {
      if(pool == MODE_TRADES)
         PrintFormat("Failed to select an order among open and pending orders. Order index %i, number of orders %i, error %i, line %i.",
                     index, OrdersTotal(), GetLastError(), __LINE__);
      else PrintFormat("Failed to select an order among closed and deleted orders. Order index %i, number of orders %i, error %i, line %i.",
                       index, OrdersHistoryTotal(), GetLastError(), __LINE__);
     }
   return(false);
  }
 
Vladislav Boyko:

Или может возникнуть ситуация, когда у ордера сработал TP/SL и его уже нет среди рыночных, но и в историю он еще не попал?

Если да, то подойдет ли такое решение (не проверял, надеюсь смысл понятен)?

Господа, которые часто упоминают "боевых" роботов, поделитесь опытом, пожалуйста

#property strict

struct STRUCT_HISTORY
  {
   datetime lastOpTimeBuy;
   datetime lastOpTimeSell;
   int prevTickTotal;
   bool isActual;
   STRUCT_HISTORY(){lastOpTimeBuy = 0; lastOpTimeSell = 0; prevTickTotal = 0; isActual = false;}
  };

struct STRUCT_MARKET
  {
   datetime lastOpTimeBuy;
   datetime lastOpTimeSell;
   bool isActual;
   STRUCT_MARKET(){lastOpTimeBuy = 0; lastOpTimeSell = 0; isActual = false;}
  };

input int inpMagic = 1;

STRUCT_HISTORY history;
datetime lastOpTimeBuy;
datetime lastOpTimeSell;

int OnInit()
  {
   historyClear();
   lastOpTimeBuy = 0;
   lastOpTimeSell = 0;
   return(INIT_SUCCEEDED);
  }

void OnTick()
  {
   historyUpdate();
   if(!history.isActual)
      return;
   STRUCT_MARKET market;
   getMarket(market);
   if(!market.isActual)
      return;
   updateLastOpTime(market);
   // После этого использовать глобальные lastOpTimeBuy и lastOpTimeSell
  }

void updateLastOpTime(const STRUCT_MARKET &market)
  {
   if(history.lastOpTimeBuy > lastOpTimeBuy)
      lastOpTimeBuy = history.lastOpTimeBuy;
   if(market.lastOpTimeBuy > lastOpTimeBuy)
      lastOpTimeBuy = market.lastOpTimeBuy;
   if(history.lastOpTimeSell > lastOpTimeSell)
      lastOpTimeSell = history.lastOpTimeSell;
   if(market.lastOpTimeSell > lastOpTimeSell)
      lastOpTimeSell = market.lastOpTimeSell;
  }

void getMarket(STRUCT_MARKET &market)
  {
   market.isActual = false;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!orderSelect(i, SELECT_BY_POS, MODE_TRADES, __LINE__))
         return;
      if(OrderType() == 0)
        {
         if(OrderOpenTime() > market.lastOpTimeBuy)
            market.lastOpTimeBuy = OrderOpenTime();
        }
      else if(OrderType() == 1)
        {
         if(OrderOpenTime() > market.lastOpTimeSell)
            market.lastOpTimeSell = OrderOpenTime();
        }
     }
   market.isActual = true;
  }

void historyUpdate()
  {
   int historyTotal = OrdersHistoryTotal();
   if(history.prevTickTotal > historyTotal)
     {
      PrintFormat("Orders history error. The current size: %i, the size on the previous tick: %i.", historyTotal, history.prevTickTotal);
      historyClear();
     }
   for(int i = history.prevTickTotal; i < historyTotal; i++)
     {
      if(!orderSelect(i, SELECT_BY_POS, MODE_HISTORY, __LINE__))
        {
         historyClear();
         return;
        }
      if(OrderSymbol() != _Symbol || OrderMagicNumber() != inpMagic)
         continue;
      if(OrderType() == 0)
        {
         if(OrderOpenTime() > history.lastOpTimeBuy)
            history.lastOpTimeBuy = OrderOpenTime();
        }
      else if(OrderType() == 1)
        {
         if(OrderOpenTime() > history.lastOpTimeSell)
            history.lastOpTimeSell = OrderOpenTime();
        }
     }
   history.prevTickTotal = historyTotal;
   history.isActual = true;
  }

void historyClear()
  {
   history.lastOpTimeBuy = 0;
   history.lastOpTimeSell = 0;
   history.prevTickTotal = 0;
   history.isActual = false;
  }

bool orderSelect(int index, int select, int pool, int line)
  {
   ResetLastError();
   if(OrderSelect(index, select, pool))
      return(true);
   if(select == SELECT_BY_TICKET)
      PrintFormat("Failed to select order by ticket %i. Error %i, line %i.", index, GetLastError(), __LINE__);
   else
     {
      if(pool == MODE_TRADES)
         PrintFormat("Failed to select an order among open and pending orders. Order index %i, number of orders %i, error %i, line %i.",
                     index, OrdersTotal(), GetLastError(), __LINE__);
      else PrintFormat("Failed to select an order among closed and deleted orders. Order index %i, number of orders %i, error %i, line %i.",
                       index, OrdersHistoryTotal(), GetLastError(), __LINE__);
     }
   return(false);
  }
 
Vladislav Boyko:

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

Это касалось MT5.

 
fxsaber #:

Это касалось MT5.

Та вот вроде для МТ4

(я видел, что 12 лет прошло)

Ну не суть.

Если ордер закрывается по SL/TP, может ли быть такое, что его уже не будет среди рыночных и еще не будет в истории (в MT4)?

 
Vladislav Boyko #:

Та вот вроде для МТ4

(я видел, что 12 лет прошло)

Ну не суть.

Если ордер закрывается по SL/TP, может ли быть такое, что его уже не будет среди рыночных и еще не будет в истории (в MT4)?

Попробуйте воспроизвести на MT4. На MT5 это делается легко, а вот на MT4 - сомневаюсь.

 
в мт4 у ордера только 2 состояния (открыт и закрыт), функция не может потерять ордер где-то между, может быть несоответствие состояния из-за запаздывания ответа, но чтоб потерять
 
Aleksey Semenov #:
в мт4 у ордера только 2 состояния (открыт и закрыт), функция не может потерять ордер где-то между, может быть несоответствие состояния из-за запаздывания ответа, но чтоб потерять

в мт4 насколько понимаю, не факт что правильно, после ордерсенд рыночного ордера или срабатывания отложек терминал ждет появления позиции, и если ее нет, он будет слать предупреждения, и после открытия позиции, появления рыночного ордера, терминал после ордерклоз или срабатывания стопов ждет закрытия позиции, или шлет предупреждения. Нормальная логика для простых инструментов типа форекса))))

 

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

Если Вам нужно просто выяснить, закрылся ли ордер, то есть 2 пути: 1) счётчик рыночных ордеров уменьшился на 1. Следоватьельно 1 ордер закрылся; 2) Ордер сенд возвращает тикет. Если он больше нуля, то вносим его в массив тикетов рыночных ордеров. Если на очередном тике среди рыночных ордеров отсутствует ордер с очередным тикетом, то ордер закрыт.

Если Вам нужно не просто знать, закрылся ли ордер, но опираясь на то КАК он закрылся, принимать дальнейшее решение, то включаете счётчик пустых тиков и по его обнулении идёте в историю чтоб вынуть инфу о том, КАК закрылся ордер. Потсмотрите вот тут: https://www.mql5.com/ru/forum/427739

Расчудесное поведение тестера стратегий МТ4 - Проверяем в истории наличие байстопа, закрытого по стопу или по тейку
Расчудесное поведение тестера стратегий МТ4 - Проверяем в истории наличие байстопа, закрытого по стопу или по тейку
  • 2022.06.27
  • www.mql5.com
что спред фиксированный и что если бай стоп сработал - бывшая лимитка точно закрылась по тейку. что бай стоп срабатывает одновременно с тейком бывшего бай лимит. Но тут вот в чем загвоздка в процессе торгов лимитник может оказаться закрыт по стоплоссу
 
fxsaber #:

Это касалось MT5.

Если Вы говорите о темах, открытых мной, то это касалось исключительно МТ4.

 
Vitaly Murlenko #:

Если Вы говорите о темах, открытых мной, то это касалось исключительно МТ4.

Не увидел в темах метода воспроизведения.

 
Vitaly Murlenko #:

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

Если Вам нужно просто выяснить, закрылся ли ордер, то есть 2 пути: 1) счётчик рыночных ордеров уменьшился на 1. Следоватьельно 1 ордер закрылся; 2) Ордер сенд возвращает тикет. Если он больше нуля, то вносим его в массив тикетов рыночных ордеров. Если на очередном тике среди рыночных ордеров отсутствует ордер с очередным тикетом, то ордер закрыт.

Если Вам нужно не просто знать, закрылся ли ордер, но опираясь на то КАК он закрылся, принимать дальнейшее решение, то включаете счётчик пустых тиков и по его обнулении идёте в историю чтоб вынуть инфу о том, КАК закрылся ордер. Потсмотрите вот тут: https://www.mql5.com/ru/forum/427739

Я читал ту ветку, спасибо.

Сам пользуюсь этим сейчас. Так спокойней.

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

Если нужны другие свойства последнего ордера , то можно делать так:

if(lastOpTimeBuy != history.lastOpTimeBuy || lastOpTimeSell != history.lastOpTimeSell) // Данные истории ордеров не актуальны
   return(false);                                                                      // На этом тике их не используем (пропускаем тик)

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