Ненормализованные цены в MT4 - страница 3

 
А вот ситуация гораздо хуже, и при этом на MQ-Demo
// 15326434
// wmefo5sa
// MetaQuotes-Demo
void OnStart()
{
  const double Price1 = HistoryOrderSelect(356138100) ? HistoryOrderGetDouble(HistoryOrderGetTicket(0), ORDER_PRICE_CURRENT) : 0;
  const double Price2 = PositionSelectByTicket(356138100) ? PositionGetDouble(POSITION_PRICE_OPEN) : 0;  
  
  Print(Price1 - Price2); // -2.220446049250313e-16
}


Цена открытия текущей позиции не равна цене своих ордера/сделки.

 

Как продолжение этой и другой темы, написал проверочный скрипт.

// Проверка нормализованности цен в истории торгов и котирования.

#property script_show_inputs

input datetime inFrom = __DATE__; // Анализ истории торгов с этой даты.

bool IsNorm( const double Price, const int digits )
{
  return(NormalizeDouble(Price, digits) == Price);
}

string ToString( const datetime time, const ulong Ticket, const string PriceName, const double Price, const int digits )
{
  const double Norm = NormalizeDouble(Price, digits);
  
  return((string)time + " Ticket = " + (string)Ticket + ", " + PriceName + " = " + (string)Price +
        ", Normalize = " + (string)Norm + ", Diff = " + (string)(Price - Norm));
}

// Проверяет нормализацию цен в истории торгов.
void HistoryCheckNorm( const datetime From )
{
  if (HistorySelect(From, INT_MAX))
  {
    for (int i = HistoryDealsTotal() - 1; i >= 0; i--)
    {
      const ulong Ticket = HistoryDealGetTicket(i);
      
      const int digits = (int)SymbolInfoInteger(HistoryDealGetString(Ticket, DEAL_SYMBOL), SYMBOL_DIGITS);
      const double Price = HistoryDealGetDouble(Ticket, DEAL_PRICE);
      
      const datetime time = (datetime)HistoryDealGetInteger(Ticket, DEAL_TIME);
      
      if (!IsNorm(Price, digits))
        Print(ToString(time, Ticket, "DEAL_PRICE", Price, digits));
    }

    for (int i = HistoryOrdersTotal() - 1; i >= 0; i--)
    {
      const ulong Ticket = HistoryOrderGetTicket(i);
      
      const int digits = (int)SymbolInfoInteger(HistoryOrderGetString(Ticket, ORDER_SYMBOL), SYMBOL_DIGITS);
      const double PriceOpen = HistoryOrderGetDouble(Ticket, ORDER_PRICE_OPEN);
      const double PriceCurrent = HistoryOrderGetDouble(Ticket, ORDER_PRICE_CURRENT);

      const datetime time = (datetime)HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE);      
      
      if (!IsNorm(PriceOpen, digits))
        Print(ToString(time, Ticket, "ORDER_PRICE_OPEN", PriceOpen, digits));

      if (!IsNorm(PriceCurrent, digits))
        Print(ToString(time, Ticket, "ORDER_PRICE_CURRENT", PriceCurrent, digits));
    }
  }
}

// Проверяет нормализацию цен в тиковой истории.
void TicksCheckNorm( const datetime From, const string Symb = NULL )
{
  MqlTick Ticks[];
  
  const int digits = (int)SymbolInfoInteger(Symb, SYMBOL_DIGITS);
  
  for (int i = CopyTicksRange(Symb, Ticks, COPY_TICKS_ALL, From * 1000) - 1; i >= 0; i--)
  {
    if (!IsNorm(Ticks[i].bid, digits))
      Print(ToString(Ticks[i].time, 0, "bid", Ticks[i].bid, digits));

    if (!IsNorm(Ticks[i].ask, digits))
      Print(ToString(Ticks[i].time, 0, "ask", Ticks[i].ask, digits));

    if (!IsNorm(Ticks[i].last, digits))
      Print(ToString(Ticks[i].time, 0, "last", Ticks[i].last, digits));
  }
}

void OnStart()
{
  HistoryCheckNorm(inFrom);
//  TicksCheckNorm(inFrom);
}


Результат.

2021.04.30 02:25:45 Ticket = 3098120, DEAL_PRICE = 1.07299, Normalize = 1.07299, Diff = 2.220446049250313e-16
2021.04.30 02:25:45 Ticket = 3098119, DEAL_PRICE = 1.07299, Normalize = 1.07299, Diff = 2.220446049250313e-16
2021.04.30 02:18:54 Ticket = 3098111, DEAL_PRICE = 1.07299, Normalize = 1.07299, Diff = 2.220446049250313e-16


Найденные DEAL_PRICE не нормализованы. Из-за этого одинаковые цены на скрине ниже оказываются разными:

что, наверное, является ошибкой.


ЗЫ Два разных числа преобразуются в string одинаково. Это баг?

void OnStart()
{
  const double Num = 1.07299;
  const double Norm = NormalizeDouble(Num, 5);
   
  Print(Num);  // 1.07299
  Print(Norm); // 1.07299

  Print(Num - Norm); // 2.220446049250313e-16
}

Ситуация похожа на эту тему.

 
fxsaber:

Как продолжение этой и другой темы, написал проверочный скрипт.


Результат.


Найденные DEAL_PRICE не нормализованы. Из-за этого одинаковые цены на скрине ниже оказываются разными:

что, наверное, является ошибкой.


ЗЫ Два разных числа преобразуются в string одинаково. Это баг?

Ситуация похожа на эту тему.

Разница везде составляет одну и ту же величину?

Часом, не вес самого младшего значащего разряда?

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

 
JRandomTrader:

Разница везде составляет одну и ту же величину?

Да, везде разница совпадает. Не равна DBL_MIN.
 
fxsaber:
Да, везде разница совпадает. Не равна DBL_MIN.

И не может быть равна, если мы рассматриваем плавающую точку.

Она, вероятно, равна весу МЗР мантиссы при данном значении порядка.

 
JRandomTrader:

И не может быть равна, если мы рассматриваем плавающую точку.

Она, вероятно, равна весу МЗР мантиссы при данном значении порядка.

void OnStart()
{
  const double Num = 1.07299;
  const double Norm = NormalizeDouble(Num, 5);
   
  Print(Num);  // 1.07299
  Print(Norm); // 1.07299

  Print(Num == Norm); // false
  Print(Num == Norm + DBL_EPSILON); // true
}
 
fxsaber:
void OnStart()
  {
   const double Num1 = 10;
   const double Num2 = 0.1;
   
   Print(Num1 == Num1 + DBL_EPSILON);    // true
   Print(Num2 == Num2 + DBL_EPSILON/10); // false
  }
 

Выглядит, как баг. В общем, ненормализованные цены в истории торгов отличают от нормализованных всегда на DBL_EPSILON.

 
fxsaber:

Выглядит, как баг. В общем, ненормализованные цены в истории торгов отличают от нормализованных всегда на DBL_EPSILON.

Именно это - не баг. Нормальное поведение двоичного представления чисел с плавающей точкой.

   Print(2.0 == 2.0 + DBL_EPSILON);      // true
   Print(2.0 == 2.0 + DBL_EPSILON*2);    // false

   Print(0.5 == 0.5 + DBL_EPSILON);      // false
   Print(0.5 == 0.5 + DBL_EPSILON/2);    // false
   Print(0.5 == 0.5 + DBL_EPSILON/4);    // true

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

 
JRandomTrader:

Именно это - не баг. Нормальное поведение двоичного представления чисел с плавающей точкой.

В истории торгов и другие значения оказались.

void OnStart()
{
  const double Num = 10.07233;
  const double Norm = NormalizeDouble(Num, 5);
   
  Print(Num);  // 10.07233
  Print(Norm); // 10.07233

  Print(Num - Norm); // -1.77635683940025e-15
}
Причина обращения: