Comparación de la media móvil (y cualquier otro indicador) y el error

 

Hola a todos.

Estoy escribiendo un EA basado en el cruce de SMA (o más bien pensaba que ya lo había hecho, porque parece ser sencillo). Pero... Me he enfrentado a un problema. El Asesor Experto funciona según el siguiente principio: cuando aparece una nueva barra, analiza la SMA de las dos últimas barras, sin contar la última que acaba de aparecer (la penúltima y la anterior). Comparo los valores aparentemente de forma correcta como se describe aquí. La única excepción es que iMA se llama con el último parámetro (desplazamiento en barras) 1 y 2 respectivamente. Aproximadamente así (si se reescribe el código por analogía con el citado):

// берем два соседних значения Быстрой МА
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("Пересечение ВНИЗ");

El Asesor Experto funciona de forma primitiva en presencia de una señal de cruce según el principio de cerrar la operación anterior - abrir una nueva. Por supuesto, si se detectan todos los cruces, las operaciones se ejecutarán siempre una tras otra (VENTA - COMPRA - VENTA - COMPRA - ...). Es decir, el Asesor Experto sólo tiene una operación abierta en cualquier momento (bueno, excepto el momento antes de entrar en la primera operación). Así que aquí está el quid del problema... Para el marco de tiempo de un minuto y los períodos de SMA 5 y 34 para Cerrar en el probador de la estrategia en la barra de 17.02.2015 a las 01:24 me llamó una situación interesante. Los movimientos con estas características se cruzan directamente al cierre de la barra. Aquí está la imagen:

17.02.2015 01:24

Para la depuración, emito la información. La correspondencia en el registro comparado con el código dado es la siguiente:

SMAFastCurrent =fast0

SMASlowCurrent =slow0

SMAFastPrevious =fast1

SMASlowPrevious=slow1 y

SMACurDiferencia = SMAFastCurrent - SMASlowCurrent

SMAPrevDifference = SMAFastPrevious - SMASlowPreviousc (es decir, la diferencia entrefast0,slow0 yfast1,slow1 respectivamente).

Por lo tanto, cuando estas diferencias cambian de signo, significa que se trata de una señal para un cruce Mooving. Pero en este ejemplo concreto la comprobación de más o menos no funciona. Los valores de estas diferencias se muestran en el registro. El rectángulo rojo muestra los valores de las diferencias en la siguiente barra después del problema (a las 1:25), el naranja - en la siguiente (a las 1:26). Y está claro, que los valores de SMACurDifference en la barra anterior y SMAPrevDifference en la barra actual deben ser iguales (la barra actual se convierte en la anterior y la nueva barra ocupa su lugar). Así, como el cruce de Mooving se produce al cierre de la barra problemática a las 1:24, en la siguiente barra (a las 1:25) los valores de SMAFastCurrent y SMASlowCurrent son iguales (aproximadamente). El depurador los imprime generalmente iguales dentro de 5 dígitos (SMAFastCurrent = 1.13371 SMASlowCurrent = 1.13371 ver figura). Su diferencia es infinitesimal pero no 0 (SMACurDiferencia = 2,220446049250313e-016). En la siguiente barra su diferencia en los mismos valores exactos se convierte en exactamente cero (compare SMACurDifference en rojo y SMAPrevDifference en rectángulos naranjas). En realidad, no está claro cómo cortar estos errores, si incluso valores aparentemente idénticos dan una diferencia diferente. De ahí dos preguntas:

1. ¿Por qué la diferencia de los mismos muvings contados en el momento de la alternancia de dos compases adyacentes, da un resultado diferente?

2. Estaba pensando en introducir algún épsilon y comparar con él, en lugar de con el cero. Pero se suele hacer para comparar un infinitesimal con 0. ¿Y el caso de que tenga que determinar un cambio de signo de este infinitesimal?

Por supuesto que puedo analizar tres barras adyacentes, pero sigue siendo teóricamente posible que en los precios de sus cierres los muvings se toquen a una distancia infinitesimal. Soy consciente de que esta situación rara vez se produce (sobre todo si tomamos un marco temporal más amplio), pero aún así puede ocurrir. Y debe ser atrapado de alguna manera y el cruce de Mouveins debe ser detectado en este caso también.

¡Gracias de antemano por cualquier ayuda!

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

Prueba la normalización y la comparación.

El Manual de Referencia de MQL4 (y es lo mismo para MQL5) dice, abrir en"Tipos Reales (double, float)":

"...No se pueden comparar dos números reales para que sean iguales entre sí. En la mayoría de los casos, dos números aparentemente idénticos pueden resultar ser desiguales debido a la diferencia de 15 decimales. Para comparar correctamente dos números reales, hay que comparar la diferencia normalizada de esos números con un valor cero...."

"... se desaconseja encarecidamente comparar dos números reales entre sí para que sean iguales, ya que dicha comparación no es correcta.

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


Sin embargo, si es necesario comparar dos números reales para la igualdad, se puede hacer de dos maneras diferentes. La primera forma es comparar la diferencia entre los dos números con algún valor pequeño que defina la precisión de la comparación.

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


El segundo método consiste en comparar la diferencia normalizada de dos números reales con un valor cero. Es inútil comparar la diferencia de números normalizados con el cero, porque cualquier operación matemática con números normalizados da un resultado no normalizado.

...."

 
rosomah:

Prueba la normalización y la comparación.

El Manual de Referencia de MQL4 (y es lo mismo para MQL5) dice, abrir en"Tipos Reales (double, float)":

"...No se pueden comparar dos números reales para que sean iguales entre sí. En la mayoría de los casos, dos números aparentemente idénticos pueden resultar ser desiguales debido a la diferencia de 15 decimales. Para comparar correctamente dos números reales, hay que comparar la diferencia normalizada de esos números con un valor cero...."

"No se recomienda categóricamente comparar dos números reales entre sí para la igualdad, ya que esta comparación no es válida.

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


Sin embargo, si es necesario comparar dos números reales para la igualdad, se puede hacer de dos maneras diferentes. La primera forma es comparar la diferencia entre los dos números con algún valor pequeño que defina la precisión de la comparación.

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


La segunda forma es comparar la diferencia normalizada de dos números reales con el cero. Es inútil comparar la diferencia de números normalizados con el cero, porque cualquier operación matemática con números normalizados da un resultado no normalizado.

...."

Soy muy consciente de que la comparación de números reales para la igualdad no es posible. No hay comparaciones de igualdad en el código que he citado. Y tampoco es necesario. Lo que tenemos aquí es una situación en la que tenemos que captar los cambios de un signo infinitesimal que bien podría llegar a 0. Comparar simplemente todo a más o igual con 0 es peligroso también en este caso. Y la normalización puede ser aún más peligrosa aquí... Los valores iniciales de MA se normalizan a un número desconocido (cuanto menor sea el plazo, menor será el valor de MA). Si se aplica la normalización a un dígito constante después del punto decimal, puede resultar que todos los valores de MA sean exactamente 0. Para ser sincero, no entiendo muy bien cuál será la diferencia de dos valores de MA...

 

gammaray:

Soy muy consciente de que comparar números reales en igualdad no es posible. En el código que he citado, no hay comparaciones de igualdad. Y tampoco es necesario. Lo que tenemos aquí es una situación en la que necesitamos captar cambios de signo infinitesimal que bien pueden llegar a 0. Comparar simplemente todo a más o igual con 0 es peligroso también en este caso. Y la normalización puede ser aún más peligrosa aquí... Los valores iniciales de MA se normalizan a un número desconocido (cuanto menor sea el plazo, menor será el valor de MA). Si se aplica la normalización a un dígito constante después del punto decimal, puede resultar que todos los valores de MA sean exactamente 0. Para ser sincero, no entiendo muy bien cuál será la diferencia entre dos valores de MA...

¿Por qué es más peligrosa la normalización?

Así que:

...

Si necesitas comparar dos números reales para que sean iguales, puedes hacerlo de dos maneras diferentes. La primera forma es comparar la diferencia entre los dos números con algún valor pequeño que establezca la precisión de la comparación.

...

La segunda forma consiste en comparar la diferencia normalizada de dos números reales con un valor cero. Comparar la diferencia de los números normalizados con el cero es inútil, porque cualquier operación matemática con números normalizados da un resultado no normalizado.

Ejemplo:

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
  }
  • Y mi experiencia práctica personal (por decirlo modestamente, no es pequeña en cuanto al número de comprobaciones meticulosas del funcionamiento del programa, donde apliqué y sigo aplicando para comparar números con el doble, en cuanto a la corrección de las condiciones que se disparan en base a dichas comparaciones),
Esto me permite considerar que tales comparaciones no sólo no son amenazantes:
if(NormalizeDouble(number1-number2,dig)==0)
if(NormalizeDouble(number1-number2,dig)>0)
if(NormalizeDouble(number1-number2,dig)<0)

// dig=Digits();

sino, a la inversa, una variación de una de las dos formas que puede, como dice la Documentación, aplicarse a las comparaciones de números dobles.

Desde entonces:

No se pueden comparar dos números reales para que sean iguales entre sí. En la mayoría de los casos, dos números aparentemente idénticos pueden resultar ser desiguales por una diferencia de valor de 15 decimales. Para comparar correctamente dos números reales, la diferencia normalizada de estos números debe compararse con cero.



P./S.: Sucede que el primer método de la Documentación me resultaba menos cómodo de utilizar, también en base a las tareas que, por regla general, resuelvo yo mismo. En consecuencia, no tengo mucha experiencia con la primera forma.

Pero al utilizar la segunda forma (es decir, comparando la diferencia normalizada de dos números reales con el valor cero en la expresión del operador condicional), no surgieron problemas de forma inequívoca.

Pero si hice una comparación de números no normalizados (aquí me refiero, incluso, a lo que hice sin usar el primer método), entonces sí, hubo, que encontré una activación incorrecta de las condiciones sobre la base de las comparaciones de los números de tipo doble.

 
gammaray:

Estas son las frases de la Documentación:

El segundo método consiste en comparar la diferencia normalizada de dos números reales con cero. Comparar la diferencia de números normalizados con el cero es inútil, porque cualquier operación matemática con números normalizados da un resultado no normalizado.

Para mí se percibe que, en términos simplistas, en las operaciones matemáticas (e incluyendo varias transformaciones) no se debe hacer algo así:

// dig=Digits();

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

if (delta>0)


Es decir, en el post anterior di ejemplos de comparaciones de la diferencia normalizada de dos números reales con valor cero. Y en este post, comparando la diferencia de los números normalizados con cero (a mi entender el texto de las frases anteriores de la Documentación).

Eso es todo, en pocas palabras.

 

gammaray:

...

Lo que hará la normalización de la diferencia entre los dos valores de MA, para ser honesto, no lo entiendo realmente

P./S.: En este punto, puedes poner Print() en tu código por un tiempo para ver lo que saldrá en una gran cantidad de datos. En Imprimir imprime los valores no normalizados y normalizados (hasta algún decimal, incluso más grande que en la tabla donde harás los experimentos) obtenidos de las operaciones matemáticas. Incluyendo simplemente los valores de iMA no normalizados y normalizados, ya que se forman en base a operaciones matemáticas.

Por si acaso, permítanme también especificar que cuando se imprimen valores no normalizados y normalizados de tipo doble, deben ser convertidos adicionalmente, por supuesto, de valor numérico a valor de texto utilizando DoubleToString (y en DoubleToString experimentar con el número de decimales).

 
gammaray:

P./S.: También quiero añadir que creo que en los ejemplos de cualquier esquema escrito para los programadores de MQL4, la normalización de los valores de los cálculos matemáticos puede no estar prescrita o/y no indicada expresamente:

  • para facilitar la comprensión de los esquemas de formación de cualquier condición;
  • No siempre y/o no en todas partes puede ser necesaria la normalización (incluyendo que se puede suponer que se aplica para diferentes por tareas niveles de errores tolerables y, en consecuencia, diferente normalización adicional (o falta de ella) de los resultados de las operaciones matemáticas en el número de decimales para algunas tareas individuales);
  • y/o, lo más probable, es que se suponga que un desarrollador está familiarizado con la Documentación y/o la ha leído, para aclarar sus dudas.
Algo así.
 
Es más preciso.
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<=slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>=slow1) Print("Пересечение ВНИЗ");

Es decir, no tuvo en cuenta que los valores de ma también podían ser iguales.

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

ligeramente diferente.
 
Aleksey Lebedev:
Un poco de algo más.

Depende de lo que tenga en mente y para qué tareas/objetivos.

Así que, al escribir los posts de este hilo, me baso en:

  • El pantallazo y las preguntas en el primer post;
  • el segundo post del autor del hilo (sobre los peligros de la normalización),

y, en consecuencia, de aquí y, por decirlo brevemente, del sentido de mis mensajes anteriores:

Con la ayuda de la normalización es posible establecer/ajustar el nivel requerido de precisión de las comparaciones (y/o los valores de salida) y/o los errores tolerables para algunas tareas y objetivos, lo que a su vez permite desencadenar las condiciones del programa exactamente donde y como se pretendía al prescribir condiciones específicas en el código. Y la comparación de la diferencia normalizada con el cero, permite ajustar/reajustar no sólo para las comparaciones que utilizan la operación de relaciones: "==".


P./S.: Así en cualquier caso voy a especificar una vez más, que la comparación de los números reales por la primera manera de dos enumerados aquí, debido a la comparación de una diferencia de números con cualquier valor pequeño, no puedo nombrar peor, que la aplicación de la normalización, cuando es necesario ajustar el nivel de las comparaciones (incluyendo, como para mí la segunda manera parecía más conveniente, la primera y no consideró por sí mismo más detallada para la aplicación práctica).


 

En principio, esto no tiene nada que ver con mql. Tomemos un lenguaje de programación abstracto. En este ejemplo concreto que he puesto, el principal problema es que los valores de la diferencia de muwings en una misma barra no son iguales (2e-16 en el primer cálculo y exactamente 0 en el segundo). En este caso, esta intersección no puede determinarse de ninguna manera. Si volvemos a mql, la normalización implica redondear el número (o más bien, simplemente dejar caer todos los números después de un determinado signo, como en la función Sish floor, pero hasta un determinado decimal). Entonces, ¿cómo sé a qué dígito debo normalizar? Si se elige un dígito incorrecto, todos los valores pueden redondearse SIEMPRE a exactamente 0. Por lo tanto, la normalización es peligrosa en este caso y generalmente no resuelve el problema.

En cuanto a lo que escribió Alexey Lebedev. Sí, estaba pensando en esta dirección. Pero si comparamos ambas diferencias por más o igual a 0, existe la probabilidad de obtener una señal falsa (por ejemplo, la situación teóricamente posible cuando los muwings entre barras vecinas tienen exactamente los mismos valores). Entonces su diferencia no cambia el signo (no hay cruce), pero la señal de cruce se determinará programáticamente. Podrías poner sólo una comparación en más o en igual, como has sugerido. Pero entonces el problema es que en el cálculo en esta situación primero no será igual a 0 (2e-16), y en la siguiente barra será exactamente 0 pero será una comparación estricta.

Es importante entender por qué la misma diferencia, cuando se calcula en diferentes barras, NO produce el mismo resultado. Si el resultado fuera el mismo, el problema se resolvería siempre introduciendo una comparación no estricta

 

gammaray:

Pero entonces todo el problema es que al calcular en esta situación al principio no será igual a 0 (2e-16), y en la siguiente barra ya será exactamente 0, pero ya habrá una comparación estricta.

Es importante entender por qué la misma diferencia, cuando se calcula en diferentes barras, NO produce el mismo resultado. Si el resultado fuera el mismo, el problema se resolvería siempre introduciendo una comparación no estricta

Lo más probable es que el cálculo de la función iMA esté optimizado. Primer valor = suma(cierre)/N, segundo = valor anterior de MA+(nuevo cierre-viejo cierre)/N.

Razón de la queja: