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

Questions about QUIK trading plugin for Russian brokers and general MultiCharts questions can be asked here in Russian; they will be answered in Russian by our staff. No registration necessary.
zysmn
Posts: 57
Joined: 27 Feb 2014
Has thanked: 7 times
Been thanked: 4 times

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

Postby zysmn » 02 Feb 2017

Приветствую.
Обнаружил такой очень не хороший баг:
Найдем для примера среднее значение между Хай и Лоу любого бара следующим способом: 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
Attachments
calcBug.pln
(1.66 KiB) Downloaded 18 times

User avatar
Henry MultiСharts
Posts: 8504
Joined: 25 Aug 2011
Has thanked: 1213 times
Been thanked: 2732 times

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

Postby Henry MultiСharts » 22 Feb 2017

Здравствуйте, zysmn.

Дальнейший анализ показал, что на самом деле данное поведение не является некорректным. Вопрос заключается в сравнении double в языках программирования, в том числе и в C++, C#, VB. C# в MultiCharts .NET работает с числами по правилам и точностями, предоставляемыми самим языком. Примеры статей по данной тематике:
https://msdn.microsoft.com/ru-ru/librar ... s(v=vs.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
}

zysmn
Posts: 57
Joined: 27 Feb 2014
Has thanked: 7 times
Been thanked: 4 times

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

Postby zysmn » 21 Apr 2017

Спасибо за ссылки, почитал. Но понял не все, моего взорванного мозга хватило только понять, что бывают ситуации, когда одинаковые 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;

На мой взгляд несколько коряво, и в ее правильности я не уверен (хотя работает, и ошибок пока не заметил).
Может существует более "человеческое" решение?
А нужно еще по аналогии округлять "вниз"...

User avatar
Henry MultiСharts
Posts: 8504
Joined: 25 Aug 2011
Has thanked: 1213 times
Been thanked: 2732 times

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

Postby Henry MultiСharts » 27 Apr 2017

Здравствуйте, zysmn.

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



Return to “MultiCharts QUIK”