Page 1 of 1

Не верный расчет простейших арифметических действий при использовании HLOC для баров.

Posted: 02 Feb 2017
by zysmn
Приветствую.
Обнаружил такой очень не хороший баг:
Найдем для примера среднее значение между Хай и Лоу любого бара следующим способом: averageVal = (Bars.High[0] + Bars.Low[0]) / 2;
Если затем произвести вычитание averageVal из того же Хай, то в качестве результата (diference) получается значение с неадекватным десятичным остатком (синий указатель на рис)
Если сложить averageVal и Хай, то на первый взгляд результат будет верный (summa). Однако, если результат сложения сравнить с таким же числом, но введенным вручную (handVal) перед началом работы скрипта, то результат будет, что они НЕ равны. (желтый указатель на рис1)
Если попробовать из полученной суммы (summa) вычесть введенное вручную (handVal), то результат будет просто не адекватный. (красный указатель на рис1)
Однако ситуация со сложением встречается не на всех барах, некоторые бары считает правильно (см. рис 2 соответствующие поля).
Таким образом, все возможные расчеты, базирующиеся на подобных вычислениях дают искаженный результат, что приводит к не правильному принятию решения.
Этот баг характерен для инструментов, имеющих шаг цены с десятичным остатком (т.е. Bars.Info.PriceScale > 1). Для инструментов с целочисленным остатком шага цены таких косяков не замечено.
Проверялось на двух разных машинах, и с разными версиями МС.NET: с 9 и с 10(Build 13630). Код используемого скрипта прилагаю.

Image
Image

Re: Не верный расчет простейших арифметических действий при использовании HLOC для баров.

Posted: 22 Feb 2017
by Henry MultiСharts
Здравствуйте, zysmn.

Дальнейший анализ показал, что на самом деле данное поведение не является некорректным. Вопрос заключается в сравнении double в языках программирования, в том числе и в C++, C#, VB. C# в MultiCharts .NET работает с числами по правилам и точностями, предоставляемыми самим языком. Примеры статей по данной тематике:
https://msdn.microsoft.com/ru-ru/librar ... .110).aspx
https://www.codeproject.com/Articles/38 ... -and-relat

Чтобы работать непосредственно с ценами мы предоставляем специальные структуры для работы с ними, это Price и PriceCtx, переводя в них цены Вы не потеряете точность при сравнении. Например:

Code: Select all

Price _close = new Price(Bars.CloseValue, new PriceCtx(Bars.Info));
Price _open = new Price(Bars.OpenValue, new PriceCtx(Bars.Info));
if (_open < _close) {
// do something
}

Re: Не верный расчет простейших арифметических действий при использовании HLOC для баров.

Posted: 21 Apr 2017
by zysmn
Спасибо за ссылки, почитал. Но понял не все, моего взорванного мозга хватило только понять, что бывают ситуации, когда одинаковые Doubl'ы (и не только), бывают не равны.
Однако полученное знание и использование класса Price так и не помогли найти решение для некоторых ситуаций.
Попробую описать одну из них.
Есть инструмент с шагом цены 0,01, есть некоторая величина targetPrice=Bars.High + Iks, по которой в дальнейшем будет выставлен ордер.
Здесь переменная Iks>=0, и есть некоторый коэффициент, полученный в ходе работы различными шаманскими плясками и алхимическими реакциями. Может иметь дробную часть вплоть до бесконечности.
Так вот, в случае если targetPrice имеет некоторый большой дробный остаток, то эту величину нужно округлить до ближайшего равного или большего приемлемого значения цены с учетом шага для данного инструмента.
Т.е. если targetPrice=38,9615735681 ближайшее большее приемлемое значение цены будет 38,97.
Я для этого использовал выражение вида:

Code: Select all

targetPrice=Math.Ceiling(targetPrice * Bars.Info.PriceScale) / Bars.Info.PriceScale;
Однако заметил, что при Iks=0 для некоторых баров когда фактически targetPrice=Bars.High данное округление возвращает вел-ну на тик больше входного Bars.High, хотя должно вернуть по сути такое же. Т.е. на некоторых барах targetPrice=Math.Ceiling(38,95 * Bars.Info.PriceScale) / Bars.Info.PriceScale=38,96;
Я догадываюсь, что ноги данной ситуации растут из контекста предложенный выше статетй, но в любом случае, что делать в таком случае и как быть толком для меня не ясно.
Использование структуры Price для округление соответственно не подходит. На текущий момент только смог придумать следующую конструкцию с выделением и некоторым округлением целой части

Code: Select all

targetPrice=Math.Ceiling(Math.Truncate(_value * Bars.Info.PriceScale * 1000000) / 1000000) / Bars.Info.PriceScale;
На мой взгляд несколько коряво, и в ее правильности я не уверен (хотя работает, и ошибок пока не заметил).
Может существует более "человеческое" решение?
А нужно еще по аналогии округлять "вниз"...

Re: Не верный расчет простейших арифметических действий при использовании HLOC для баров.  [SOLVED]

Posted: 27 Apr 2017
by Henry MultiСharts
Здравствуйте, zysmn.

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

Re: Не верный расчет простейших арифметических действий при использовании HLOC для баров.

Posted: 03 May 2017
by zysmn
Я понял, спасибо.