Новая версия платформы MetaTrader 4 build 1353 - страница 6

 
Alexey Viktorov #:

А ничего, что в предыдущем вопросе была input переменная, а тут простая?

Мне лениво проверять… Так-что можете не обращать внимания…

Input должен соответствовать размерности принимаемых данных. Datetime - восьмибайтовый формат.
 
Sergey Gridnev #:
Input должен соответствовать размерности принимаемых данных. Datetime - восьмибайтовый формат.
Конечно не три года прошло, но отвечать я не буду…
 

Столкнулся в билде 1353 с такой ситуацией.

void Test()
{  double lTmp;
   
   lTmp=0.93256;
   Print("Origin=",lTmp);
   Print("Norm=",NormalizeDouble(lTmp, Digits));
   Print("String=",DoubleToStr(lTmp));
   Print("FromString=",StrToDouble(DoubleToStr(lTmp)));
}

И на выходе получаю вот такое:

2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: FromString=0.9325599999999999
2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: String=0.93256000
2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: Norm=0.9325599999999999
2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: Origin=0.9325599999999999

Число с конечными значениями после запятой - разрушается. Если у кого есть решение этой ситуации, буду рад узнать.
 

После последнего обновления МТ4 не происходит подключение счетов.

Версия 1355 от 16 марта 2022

 
Alexandr Gershkevich #:

Столкнулся в билде 1353 с такой ситуацией.

И на выходе получаю вот такое:

2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: FromString=0.9325599999999999
2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: String=0.93256000
2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: Norm=0.9325599999999999
2022.03.28 11:15:05.500 2022.02.03 00:00:00  EA_Lock_ver2 EURUSD,H4: Origin=0.9325599999999999

Число с конечными значениями после запятой - разрушается. Если у кого есть решение этой ситуации, буду рад узнать.

Это обычное дело при работе с вещественными числами.

Решение для отображения значения: установить нужную точность (у DoubleToString есть второй аргумент, указывающий точность).

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

double fDelta = Point() / 10.0;
double fFirstValue = ...;
double fSecondValue = ...;

if (fabs(fFirstValue - fSecondValue) < fDelta)
{
   // значения fFristValue и fSecondValue равны
}
else
{
   // значения fFristValue и fSecondValue не равны
}
 
Ihor Herasko #:

Это обычное дело при работе с вещественными числами.

Решение для отображения значения: установить нужную точность (у DoubleToString есть второй аргумент, указывающий точность).

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

Спасибо за ответ, он верный, все будет работать правильно. Но мой вопрос был немного в другом. Я говорю о "рассыпании" исходного числа. Я задаю переменной конкретное, конечное значение (lTmp= 0.93256), но после вызова функции NormalizeDouble для этой переменной - функция возвращает другое число (0.9325599999999999). Эта ошибка функция NormalizeDouble() сыграла плохую роль в реальной ситуации: есть некий расчет цены, на уровне которой надо создать стоповый ордер. В результате вычислений последним действием стоит вызов функции нормализации и уже после этого вызывается функция создания стопового ордера. Так вот, функция создания ордера стала возвращать ошибку и ордер не создавался. Пошаговый разбор выявил эту ситуацию: расчетное число было 0.93256, а в функцию создания ордера передавалось число после нормализации немного другое о ордер не создавался. Эта ошибка именно с этим числом 0.93256. С другими числами такого бага не обнаружено. 

 
Alexandr Gershkevich #:

Спасибо за ответ, он верный, все будет работать правильно. Но мой вопрос был немного в другом. Я говорю о "рассыпании" исходного числа. Я задаю переменной конкретное, конечное значение (lTmp= 0.93256), но после вызова функции NormalizeDouble для этой переменной - функция возвращает другое число (0.9325599999999999). Эта ошибка функция NormalizeDouble() сыграла плохую роль в реальной ситуации: есть некий расчет цены, на уровне которой надо создать стоповый ордер. В результате вычислений последним действием стоит вызов функции нормализации и уже после этого вызывается функция создания стопового ордера. Так вот, функция создания ордера стала возвращать ошибку и ордер не создавался. Пошаговый разбор выявил эту ситуацию: расчетное число было 0.93256, а в функцию создания ордера передавалось число после нормализации немного другое о ордер не создавался. Эта ошибка именно с этим числом 0.93256. С другими числами такого бага не обнаружено. 

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

 
Ihor Herasko #:

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

Согласен. Как решить эту ситуацию, чтобы ордера могли открываться по этой цене ?

 
Alexandr Gershkevich #:

Согласен. Как решить эту ситуацию, чтобы ордера могли открываться по этой цене ?

Если речь о том, чтобы установить отложенный ордер по такой цене, то цену нужно привести к точности тика. Вот так:

double NP(double value, double tickSize)
{
   if (tickSize == 0)
      return (0.0);
      
   return (MathRound(value / tickSize) * tickSize);
}

Если речь о том, чтобы открыть рыночный ордер по заданной цене, то следует учитывать, что такой цены может и не быть (цена перепрыгнет через этот уровень). Таким образом, можно говорить лишь о том, что ордер открывается в случае пересечения ценой заданного значения. Поэтому ставятся условия для пересечения уровня вниз и вверх. Вниз: предыдущий тик был выше значения, а текущий - ниже или равен. Вверх: предыдущий тик был ниже значения, а текущий - выше или равен. 

 
Ihor Herasko #:

Если речь о том, чтобы установить отложенный ордер по такой цене, то цену нужно привести к точности тика. Вот так:

Если речь о том, чтобы открыть рыночный ордер по заданной цене, то следует учитывать, что такой цены может и не быть (цена перепрыгнет через этот уровень). Таким образом, можно говорить лишь о том, что ордер открывается в случае пересечения ценой заданного значения. Поэтому ставятся условия для пересечения уровня вниз и вверх. Вниз: предыдущий тик был выше значения, а текущий - ниже или равен. Вверх: предыдущий тик был ниже значения, а текущий - выше или равен. 

согласен, спасибо. Но все же, я считаю, что в MQL4 ошибка по работе с этим, конкретным числом (0.93256). Если это так - чтобы ее поправили разработчики. В других языках программирования округление до 5 знаков этого значения типа double - работает как надо. 

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