Discusión sobre el artículo "Recetas MQL5 - Creando el búfer circular para calcular rápidamente los indicadores en la ventana móvil"
Foro sobre Trading, Sistemas de Trading Automatizados y Pruebas de Estrategias de Trading
fxsaber, 2016.09.16 14:32
void OnStart() { double Index = -345.23; double Size = -432.98; double Array[]; // Cualquier tamaño (y no entero) funcionará. ArrayResize(Array, (int)Size < 0 ? (int)MathAbs(Size) : (int)Size); // En cualquier índice (y no entero) SIEMPRE (excepto cero - si el tamaño del array es cero) se ejecutará sin errores. // Así la matriz se convierte en una copia infinita de sí misma en ambas direcciones Array[(int)Index < 0 ? ArraySize(Array) + ((int)Index % ArraySize(Array)) : (int)Index % ArraySize(Array)] = 1; }
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- bool calc = false; for(int i = prev_calculated; i < rates_total; i++) { Sma.AddValue(price[i]); buff[i] = Sma.SMA(); calc = true; } if(!calc) { Sma.ChangeValue(MaPeriod-1, price[rates_total-1]); buff[rates_total-1] = Sma.SMA(); } return(rates_total-1); }
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- if (prev_calculated < rates_total) for(int i = prev_calculated; i < rates_total; i++) { Sma.AddValue(price[i]); buff[i] = Sma.SMA(); } else { Sma.ChangeValue(MaPeriod-1, price[rates_total-1]); buff[rates_total-1] = Sma.SMA(); } return(rates_total-1); }
ZY Si prev_calculated se pone a cero, habrá errores.
Muy buen artículo sobre un tema muy importante.
Lamemoria cíclica es un mecanismo crucial.
Además del artículo me gustaría añadir mi idea de cómo se puede desarrollar más el uso de las memorias cíclicas:
Si, paralelamente al registro de los valores de un parámetro en una memoria cíclica, se crea una segunda memoria cíclica para este parámetro, que registrará el tiempo entre los cambios de valores en la primera memoria cíclica, se puede construir una curva de los cambios de valores en el periodo actual a partir de los datos de ambas memorias cíclicas. Además, con la ayuda de operaciones matemáticas es posible extraer el carácter del cambio de valor del parámetro, es decir, su firma actual, y trabajar no con valores específicos, sino con el contexto del cambio del parámetro para todo el periodo actual.
P.D. Sería genial si alguien pudiera implementar esto como un mecanismo independiente. ¿Intentarlo?
¡Gracias por el artículo! Tengo algunas preguntas y comentarios cáusticos )
По возможности избегайте запросов по получению данных множества таймфреймов. Вместо этого для расчетов воспользуйтесь одним (наименьшим) таймфреймом. Например, если вам требуется рассчитать два индикатора на M1 и H1, получите данные M1, сконвертируйте их в H1 и затем подайте эти данные для расчета индикатора на H1. Такой подход сложнее, но позволит существенно сэкономит память.
¿A qué se debe el ahorro?
¿La serie temporal H1 generada por el terminal ocupa más memoria que la misma serie temporal generada dentro del Asesor Experto?
Sin embargo, todavía necesitamos casi 3 GB de RAM. ¿Hay alguna otra forma de reducir esta cifra? Podemos, si optimizamos el número de plazos. Vamos a tratar de cambiar el código de prueba un poco y utilizar sólo un marco de tiempo en lugar de 21 - PERIOD_M1. El número de indicadores seguirá siendo el mismo, sólo que algunos de ellos se duplicarán:
Ahora los mismos 504 indicadores en el modo de cálculo interno ocupan 548 MB de RAM.
No entiendo este movimiento en absoluto. ¿Cómo se puede comparar el cálculo de indicadores para 21 timeframes con el cálculo para 1 TF? Los resultados de los cálculos son muy diferentes, ¿qué diferencia hay en la cantidad de memoria utilizada?
Es difícil encontrar una aplicación más relevante de las memorias cíclicas que en el trading. Es aún más sorprendente que este algoritmo de construcción de datos no ha sido cubierto en la comunidad MQL hasta ahora.
Konstantin Gruzdev publicó su clase y algunos ejemplos allá por 2012. Una búsqueda los encontrará.
En general, por supuesto, la técnica es buena. Una desventaja es que todos los indicadores deben ser reescritos.
¡Gracias por el artículo! Tengo algunas preguntas y comentarios cáusticos )
Si es posible, evite las consultas para recuperar datos de múltiples marcos temporales. En su lugar, utilice un (más pequeño) marco de tiempo para los cálculos. Por ejemplo, si necesita calcular dos indicadores en M1 y H1, obtenga los datos de M1, conviértalos a H1 y luego alimente estos datos para calcular el indicador en H1. Este enfoque es más complicado, pero ahorrará memoria.
¿Qué ahorrará memoria?
¿La serie temporal H1 generada por el terminal ocupa más memoria que la misma serie temporal generada dentro del Asesor Experto?
Por desgracia, sí. Y mucho más. Y no importa si ha solicitado una barra o todo el historial disponible. Todos los datos para el marco temporal especificado se copiarán en la memoria interna. No sé exactamente cuánto se copiará, pero según mis mediciones de memoria, se vio que casi todo se copia.
Sin embargo, seguimos necesitando casi 3 GB de RAM. ¿Hay alguna forma de reducir esta cifra? Se puede, si se optimiza el número de plazos. Vamos a tratar de cambiar el código de prueba un poco y utilizar sólo un marco de tiempo en lugar de 21 - PERIOD_M1. El número de indicadores seguirá siendo el mismo, sólo que algunos de ellos se duplicarán:
Ahora los mismos 504 indicadores en el modo de cálculo interno ocupan 548 MB de RAM.
No entiendo este movimiento en absoluto. ¿Cómo se puede comparar el cálculo de indicadores para 21 timeframes con el cálculo para 1 TF? Los resultados de los cálculos son muy diferentes, ¿qué diferencia hace la cantidad de memoria que se utiliza?
Si utiliza sólo un marco temporal más pequeño para calcular varios indicadores en diferentes marcos temporales, ahorrará memoria. Supongamos que hay dos indicadores, uno cuenta valores en M1 y el otro en H1. Podemos cargar cotizaciones para M1 y para H1. Podemos cargar cotizaciones para cada indicador y obtener valores de ellas. Sin embargo, sólo por el hecho de que se cargará H1, el uso de memoria aumentará mucho. Por lo tanto, si solicitamos M1, luego convertimos M1 a H1 y alimentamos estos datos al indicador en H1, la memoria se ahorrará significativamente. Este ahorro se consigue debido al hecho de que los buffers internos de MetaTrader asignan mucha más memoria para almacenar las cotizaciones H1 que si estas cotizaciones se almacenaran dentro del Asesor Experto.
Hay otra característica interesante que no se mencionó en el artículo. El modelo de asignación de memoria en el probador de estrategias es diferente y mucho más económico. Asigna mucha menos memoria cuando se utilizan múltiples marcos temporales, pero todo se calcula normalmente.
...
En general, había tres objetivos al escribir el artículo:
- Crear algoritmos rápidos para cálculos de indicadores dentro del Asesor Experto (completado).
- Crear una interfaz conveniente para los cálculos en el ring buffer (completado).
- Crear un cálculo que ahorre memoria (no implementado).
Muy buen artículo sobre un tema muy importante.
La memoria cíclica es un mecanismo crucial.
Además del artículo me gustaría añadir mi idea de cómo se puede desarrollar más el uso de las memorias cíclicas:
Si, paralelamente al registro de los valores de un parámetro en una memoria cíclica, se crea una segunda memoria cíclica para este parámetro, que registrará el tiempo entre los cambios en los valores de la primera memoria cíclica, entonces se puede construir una curva de los cambios de valor en el período actual a partir de los datos de ambas memorias cíclicas. Además, con la ayuda de operaciones matemáticas es posible extraer el carácter del cambio de valor del parámetro, es decir, su firma actual, y trabajar no con valores específicos, sino con el contexto del cambio del parámetro para todo el periodo actual.
P.D. Sería genial si alguien pudiera implementar esto como un mecanismo independiente. ¿Intentarlo?
Lo que describes es sólo un indicador. Crea una clase, digamos CTradeChange. Dentro de ella coloca dos buffers anulares síncronos: uno almacena N últimos precios, el otro N últimos valores de tiempo:
CTradeChange change;
...
change.Add(value, TimeCurrent());A continuación, en el método Add, calcula la diferencia entre el valor temporal actual y el anterior.
En general, la redacción del artículo perseguía tres objetivos:
- Crear algoritmos rápidos para cálculos de indicadores dentro del Asesor Experto (completado).
- Crear una interfaz conveniente para los cálculos en el búfer de anillo (completado).
- Crear un cálculo de ahorro de memoria (no implementado).
Gracias por sus respuestas.
Al desarrollar el panel mencionado en el artículo, llegué a la necesidad de limitar el número de barras que se muestran en los gráficos (5000). Precisamente por la memoria...
En MT4 era mucho más fácil: primero, cada TF se cargaba independientemente, por lo que no requería cargar M1, y segundo, los buffers de indicadores ocupaban tanto espacio como los llenaras (incluso 100 barras, si no necesitas más).
En 5, se ha vuelto más universal e integral debido a la generación de TFs desde M1, pero la memoria puede ser difícil.
Lo que describes es sólo un indicador. Crea una clase, digamos CTradeChange. Dentro de ella coloca dos buffers anulares síncronos: uno almacena N últimos precios, el otro N últimos valores temporales:
Luego, en el método Add, calcula la diferencia entre el valor temporal actual y el anterior.
Has dado una respuesta extraña. Parece que no has entendido la idea en absoluto. Voy a citar de nuevo:
"Si paralelamente al registro de los valores del parámetro en la memoria cíclica, creas para este parámetro una segunda memoria cíclica, que registrará el tiempo entre los cambios de valores en la primera memoria cíclica, entonces en base a los datos de ambas memorias cíclicas puedes construir una curva de cambios de valores en el periodo actual. Además, utilizando operaciones matemáticas, se puede extraer la naturaleza del cambio en el valor del parámetro, es decir, su firma actual, y trabajar no con valores específicos, sino con el contexto del cambio del parámetro durante todo el período actual."
Ojo, yo no he preguntado cómo construir dos memorias cíclicas síncronas, ya que su mecanismo es bastante sencillo, sino que he sugerido intentar desarrollar el ámbito de aplicación de las memorias cíclicas más allá de lo descrito en el artículo.
El ámbito de aplicación propuesto por usted en el artículo es la obtención de valores específicos por índices dentro del período actual.
Mi propuesta de ampliación del ámbito es obtener firmas de cambios de valores dentro del periodo actual. Esto se puede hacer trazando una curva (no en un gráfico) basada en datos de dos buffers de anillos:
1. buffer con valores del periodo actual.
2. tampón con intervalos de tiempo entre los valores del primer tampón.
Combinando los datos es posible trazar la curva matemáticamente (no necesariamente en un gráfico) y representarla y estudiarla algorítmicamente dentro del programa. Para ello, es necesario escanear ambas memorias intermedias y considerar la firma del cambio de parámetro.
Esta solución abre la posibilidad de operar no sólo con valores concretos del parámetro dentro de un periodo, sino con la firma de su cambio a lo largo de todo el periodo.
Por ejemplo, será posible especificar al programa:
if(Характер_изменения_значения_параметра_за_период == BIG_WAVE)Лот += 10;
La constante BIG_WAVE es la firma, que expresa el carácter del cambio de valor para el período actual.
Por ejemplo, podemos construir 5 patrones de firmas:
FLAT, RISING, BIG_WAVE, FALLING, SMALL_WAVES.
Cada una de estas constantes es un patrón de un determinado carácter del cambio del parámetro dentro del periodo actual.
Tenemos que desarrollar el formato del registro de firmas, y crear estas plantillas. A continuación, el algoritmo leerá la firma actual y la comparará con las plantillas, encontrando las coincidencias más cercanas (no puede haber coincidencia absoluta) entre la naturaleza del cambio actual y una de las plantillas.
Las ventajas de este enfoque sobre el uso estándar de valores específicos son evidentes.
El uso de firmas permite basar las decisiones en el contexto extraído del conjunto de datos y no tratar de extraer ese contexto a partir de valores individuales.
P.D. Espero que esta vez me hayas entendido.
Es una respuesta extraña la que has dado. Parece que no has entendido nada. Lo citaré de nuevo:
...
Mi propuesta de extensión del dominio es obtener firmas de cambios en los valores dentro del periodo actual. Esto se puede hacer trazando una curva (no en un gráfico) basada en los datos de los dos buffers anulares:
P.D. Espero que esta vez me hayas entendido.
Yo también lo entendí perfectamente la primera vez.
¿Qué es una "firma de cambio de valor"? Es un valor que cambia en la dinámica. Por lo tanto, es un indicador. No es necesario desarrollar un tampón anular para este fin, sino que basta con crear sobre la base de varios de estos indicadores anulares un algoritmo para calcular el propio "carácter de cambio" del que hablas.
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso
Artículo publicado Recetas MQL5 - Creando el búfer circular para calcular rápidamente los indicadores en la ventana móvil:
El búfer circular es el modo más simple y al mismo tiempo más eficaz en la organización de datos para los cálculos en una ventana móvil. En este artículo se describe la estructura de este algoritmo, y se muestra cómo se puede hacer a través de él que el cálculo en la ventana móvil sea un proceso simple y eficaz.
La visualización gráfica del indicador equivale al indicador estándar homónimo MovingAverage:
Fig. 1. Visualización de la media móvil simple calculada en el búfer circular.Autor: Vasiliy Sokolov