Сравнение значеий Moving Average (и любых других индикаторов) и погрешности

 

Всем привет!

Пишу советника на основании пересечения SMA (точнее думал, что уже написал, ибо вроде все просто). Но... Столкнулся с проблемой. Советник функционирует по следующими принципу: при появлении нового бара происходит анализ значений SMA для двух последних баров, не считая только что появивишийся (предпоследний и пред-предпоследний). Сравниваю значения вроде бы как правильно, как описано тут. За одним лишь исключением, что iMA вызывается с последним параметром (смещение в барах) 1 и 2 соответственно. Примерно так (если код по аналогии с процитированным переделать):

// берем два соседних значения Быстрой МА
double fast0=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double fast1=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// берем два значения Медленной МА
double slow0=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double slow1=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>slow1) Print("Пересечение ВНИЗ");

 Советник функционирует в примитивном виде при наличии сигнала о пересечении по принципу закрыть предыдущую сделку - открыть новую. При этом, естественно, если определяются все пересечения, то сделки всегда будут идти поочередно (SELL - BUY - SELL - BUY - ...). То есть советник в любой момент времени имеет только одну открытую сделку (ну за исключением момента до вхождения в самую первую сделку). Так вот суть проблемы... Для минутного таймфрейма и SMA периодов 5 и 34 для Close в тестере стратегий в баре от 17.02.2015 в 01:24 отловил интересную ситуацию. Мувинги с таким характеристиками аккурат пересекаются непосредственно при закрытии бара. Вот картинка:

17.02.2015 01:24 

 Для отладки вывожу информацию. В журнале по сравнению с приведенным кодом соответствие следующее: 

SMAFastCurrent = fast0

SMASlowCurrent = slow0

SMAFastPrevious = fast1 

SMASlowPrevious = slow1, а

SMACurDifference  =  SMAFastCurrent - SMASlowCurrent

SMAPrevDifference = SMAFastPrevious  - SMASlowPreviousс (то есть разницы между fast0, slow0 и fast1, slow1 соответственно).

Так вот когда эти разницы меняют знак, то это и означает сигнал на пересечение Мувингов. Но дело в том, что в данном конкретном примере проверка на больше-меньше не срабатывает. Значения этих разниц выведены в журнале. Красным пряумоугольником выделены значения разниц на следующем после проблеменого баре (в 1:25), оранжевым на следующем (в 1:26). При чем очевидно, что значения SMACurDifference на предыдущем баре и SMAPrevDifference на текущем баре должны быть  равны (текущий бар как бы становится предыдущим, а место текущего занимает новые бар). Так вот, поскольку пересечение Мувингов происходит непосредственно при закрытии проблемного бара в 1:24, то на следующем баре (в 1:25) значения SMAFastCurrent и SMASlowCurrent  равны (приблизительно). Отладчик их выводит вообще равными с точностью до 5 знака (SMAFastCurrent = 1.13371 SMASlowCurrent = 1.13371 см. рис). При этом их разница бесконечно мала, но не 0 (SMACurDifference = 2.220446049250313e-016). На следующем же баре их разница  при таких же точно значениях становится ровно нулем (сравнить SMACurDifference в красном и SMAPrevDifference в оранжевом прямоугольниках). Собственно вообще тут тогда непонятно, как эти погрешности отсекать, если даже вроде бы как одинаковые величины дают разную разность. Отсюда два вопроса:

1. Почему разница одних и тех же мувингов, просто считаемая в момент поочередного возникновения двух соседних баров, дает разный результат?

2.  Думал над введением некоего эпсилона и сравнения с ним, а не с нулем. Но это делают обычно для сравнения бесконечно малого с 0. А как быть в случае, когда мне надо определить смену знака этого бесконечно малого?

Можно конечно анализировать и три соседних бара, но все равно теоретически возможно, что при ценах их закрытий мувинги будут друг друга касаться на бесконечном малом расстоянии.  Да, и я понимаю, что такая ситуация возникает редко (особенно если таймфрейм брать побольше), но все же она может возникать. И ее как-то надо отлавливать и определять пересечение Мувингов и в этом случае.

 Заранее спасибо за любую помощь! 

Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
  • www.mql5.com
Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
 

Попробуйте нормализовать и посравнивать.

В Справочнике по MQL4 (и по MQL5 он такой же) сказано, откройте на "Вещественные типы (double, float)":

"...Нельзя сравнивать два вещественных числа на равенство друг другу. В большинстве случаев два вроде бы одинаковых числа могут оказаться неравными из-за разницы значения в 15-ом знаке после запятой. Для корректного сравнения двух вещественных чисел необходимо сравнивать нормализованную разницу этих чисел с нулевым значением...."

"...категорически не рекомендуется сравнивать между собой два вещественных числа на равенство, так как такое сравнение не является корректным.

..............


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

.............


Второй способ предполагает сравнивать нормализованную разность двух вещественных чисел с нулевым значением. Сравнивать разность нормализованных чисел с нулём бесполезно, так как в результате любой математической операции с нормализованными числами результат получается ненормализованным.

...."

 
rosomah:

Попробуйте нормализовать и посравнивать.

В Справочнике по MQL4 (и по MQL5 он такой же) сказано, откройте на "Вещественные типы (double, float)":

"...Нельзя сравнивать два вещественных числа на равенство друг другу. В большинстве случаев два вроде бы одинаковых числа могут оказаться неравными из-за разницы значения в 15-ом знаке после запятой. Для корректного сравнения двух вещественных чисел необходимо сравнивать нормализованную разницу этих чисел с нулевым значением...."

"...категорически не рекомендуется сравнивать между собой два вещественных числа на равенство, так как такое сравнение не является корректным.

..............


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

.............


Второй способ предполагает сравнивать нормализованную разность двух вещественных чисел с нулевым значением. Сравнивать разность нормализованных чисел с нулём бесполезно, так как в результате любой математической операции с нормализованными числами результат получается ненормализованным.

...."

Я прекрасно понимаю, что сравнивать вещественные числа на равенство нельзя. В приведенном мной коде нет сравнений на равенство. Да и оно тут не требуется. Тут ситуация, когда надо отлавливать изменение знака бесконечно малого, которое может и четко в 0 попасть. Тупо все сравнивать на больше или равно с 0 в этом случае тоже опасно. А нормализация тут может быть еще опаснее... Исходные значения MA нормализовать непонятно до какой цифры (чем меньше таймфрейм, тем меньше значения MA). Если нормализацию до константной цифры после запятой поставить, то может получится, что все значения MA будут ровно 0. Что даст нормализация разности двух значений MA честно говоря не очень понимаю...

 

gammaray:

Я прекрасно понимаю, что сравнивать вещественные числа на равенство нельзя. В приведенном мной коде нет сравнений на равенство. Да и оно тут не требуется. Тут ситуация, когда надо отлавливать изменение знака бесконечно малого, которое может и четко в 0 попасть. Тупо все сравнивать на больше или равно с 0 в этом случае тоже опасно. А нормализация тут может быть еще опаснее... Исходные значения MA нормализовать непонятно до какой цифры (чем меньше таймфрейм, тем меньше значения MA). Если нормализацию до константной цифры после запятой поставить, то может получится, что все значения MA будут ровно 0. Что даст нормализация разности двух значений MA честно говоря не очень понимаю...

Почему нормализация опаснее?

Так-то:

...

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

...

Второй способ предполагает сравнивать нормализованную разность двух вещественных чисел с нулевым значением. Сравнивать разность нормализованных чисел с нулём бесполезно, так как в результате любой математической операции с нормализованными числами результат получается ненормализованным.

Пример:

bool CompareDoubles(double number1,double number2)
  {
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
  }
void OnStart()
  {
   double d_val=0.3;
   float  f_val=0.3;
   if(CompareDoubles(d_val,f_val)) Print(d_val,"equals",f_val);
   else Print("Different: d_val = ",DoubleToString(d_val,16),
              "  f_val = ",DoubleToString(f_val,16));
// Результат: Different: d_val= 0.3000000000000000   f_val= 0.3000000119209290
  }
  • и мой личный практический опыт (если скромно сказать, так-то очень не малый по количествам дотошных выверок работы программ, где применялось и применяется у меня сравнение чисел double, в части корректности срабатывания условий на основе таких сравнений),
 позволяют мне считать такие сравнения не только не опасными:
if(NormalizeDouble(number1-number2,dig)==0)
if(NormalizeDouble(number1-number2,dig)>0)
if(NormalizeDouble(number1-number2,dig)<0)

// dig=Digits();

но и, наоборот, разновидностями одного из двух способов, которые можно, как и говорится в Документации, применять для сравнений чисел типа double.

Поскольку:

Нельзя сравнивать два вещественных числа на равенство друг другу. В большинстве случаев два вроде бы одинаковых числа могут оказаться неравными из-за разницы значения в 15-ом знаке после запятой. Для корректного сравнения двух вещественных чисел необходимо сравнивать нормализованную разницу этих чисел с нулевым значением.



P./S.: Так сложилось, что первый способ из Документации мне оказался менее удобен в применении, в т.ч., исходя из задач, что, как правило, решала для себя. Соответственно, у меня нет большого накопленного опыта по первому способу.

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

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

 
gammaray:

Вот эти фразы из Документации:

Второй способ предполагает сравнивать нормализованную разность двух вещественных чисел с нулевым значением. Сравнивать разность нормализованных чисел с нулём бесполезно, так как в результате любой математической операции с нормализованными числами результат получается ненормализованным.

для меня воспринимаются, что, если упрощённо, при математических операциях (и в т.ч., различных преобразованиях) не стоит делать как-то так:

// dig=Digits();

double delta=NormalizeDouble(number1-number2,dig);

if (delta>0)


Т.е., в предыдущем посте выше я привела примеры сравнений нормализованной разности двух вещественных чисел с нулевым значением. А в этом посте, сравнение разности нормализованных чисел с нулём (в моём понимании текста фраз выше из Документации).

Как-то так, если кратко.

 

gammaray:

...

Что даст нормализация разности двух значений MA честно говоря не очень понимаю

P./S.: По этому вопросу вы можете просто поставить Print() на какое-то время в код, чтоб посмотреть, что будет выводиться на большом количестве данных. В принт выведите ненормализованные и нормализованные (до какого-либо десятичного знака, в т.ч., и побольше, чем на чарте, где будете проводить эксперименты) значения, полученные на основе математических операций. В т.ч., просто ненормализованные и нормализованные значения iMA, поскольку они формируются на основе математических операций.

На всякий случай ещё уточню, что при выводе на печать ненормализованных и нормализованных значений типа double, их ещё дополнительно нужно преобразовать, естественно, из числового значения в текстовое с помощью DoubleToString (и в DoubleToString поэкспериментируйте с количеством десятичных знаков).

 
gammaray:

P./S.: Ещё добавлю, что полагаю, что в примерах каких-либо схем, написанных для осваивающих программирование на MQL4, где-то нормализация значений математических вычислений может не прописываться и/или прямо не оговариваться:

  • для простоты восприятия схем формирования каких-либо условий;
  • не всегда и/или не везде нормализация может требоваться (включая то, что может предполагаться применение для различных по задачам уровней допустимых погрешностей и, соответственно, различная дальнейшая нормализация (или её отсутствие) результатов математических операций по количеству десятичных знаков под какие-то индивидуальные задачи);
  • и/или потому, что, скорее всего, по умолчанию предполагается, что осваивающий программирование уже знаком с Документацией и/или будет её штудировать, в т.ч., для уточнения своих вопросов.
Как-то так.
 
правильнее таки
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<=slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>=slow1) Print("Пересечение ВНИЗ");

в смысле, небыло учтено, что значения ма могут оказаться и равными.

сравнивать вещественные числа на равенство нельзя

Несколько о другом.
 
Aleksey Lebedev:
Несколько о другом.

Это зависит от того, что вы имеете в виду и для каких задач/целей.

Так-то, при написании постов в этой теме я исходила из:

  • скрина и вопросов в первом посте;
  • второго поста автора темы (об опасности нормализации),

и, соответственно, отсюда и, если кратко сказать, смысл моих постов выше:

О возможности с помощью нормализации настраивать/регулировать требуемый уровень точности сравнений (и/или вывода значений) и/или допустимых для каких-то задач и целей погрешностей, что в свою очередь, в т.ч., позволяет срабатыванию условий программы именно там и так, где и как задумывалось при прописывании конкретных условий в коде. А сравнение нормализованной разницы с нулём, позволяет настроить/регулировать не только при сравнениях с помощью операции отношений: "==".


P./S.: При этом на всякий случай ещё раз уточню, что сравнение вещественных чисел первым способом из двух здесь перечисленных, за счёт сравнения разницы чисел с какой-то малой величиной, не могу назвать хуже, чем применение нормализации, когда нужно отрегулировать уровень сравнений (в т.ч., поскольку для меня второй способ оказался более удобен, то первый и не рассматривала для себя более детально для практического применения).


 

Тут mql в принципе не причем. Возьмем абстрактный язык программирования. В данном конкретном примере, приведенным мной, основная проблема заключается в том, что значения для разности мувингов в одном и том же баре не равны (2e-16 при первом вычислении и ровно 0 - при втором). В этом случае вообще можно это пересечение никак не определить. Если возвращаться к mql, то нормализация подразумевает округление числа (точнее просто отбрасывание всех чисел после определенного знака на подобии сишной функции floor только до определенного знака после запятой). Так вот как определить, до какой цифры нормализовать? Если неправильно выбрать цифру, то все значения могут ВСЕГДА округляться в ровно 0. Поэтому нормализация тут опасна и в общем случае не решает проблему.

Что касается того, что написал Alexey Lebedev. Да, думал в эту сторону. Но если сравнивать на больше или равно с 0 обе разности, то есть вероятность получения ложного сигнала (например, теоретически возможная ситуация, когда мувинги между соседними барами идут с полностью одинаковыми значениями). Тогда их разность как бы знак не меняет (пересечения нет), но программно будет определяться сигнал к пересечению. Можно поставить только одно сравнение на больше или равно, как вы предложили. Но тогда вся проблема в том, что при вычислении в этой ситуации вначале не будет равно 0 (2e-16), а на следующем баре уже будет ровно 0, но там уже будет стоять строгое сравнение.

Тут важно понять все таки, почему одна и та же разность при вычислении ее на разных барах дает НЕ одинаковый результат??? Если бы результат был одинаковый, то вроде бы как проблема всегда бы решалась введением одного нестрого сравнения

 

gammaray:

Но тогда вся проблема в том, что при вычислении в этой ситуации вначале не будет равно 0 (2e-16), а на следующем баре уже будет ровно 0, но там уже будет стоять строгое сравнение.

Тут важно понять все таки, почему одна и та же разность при вычислении ее на разных барах дает НЕ одинаковый результат??? Если бы результат был одинаковый, то вроде бы как проблема всегда бы решалась введением одного нестрого сравнения

Скорее всего расчёт функции iMA оптимизирован. Первое значение =сумма(close)/N, второе =предыдущее значение МА+(новый close-устаревший close)/N.