- Generar ticks en el probador
- Gestión del tiempo en el comprobador: temporizador, Sleep, GMT
- Pruebas de visualización: gráfico, objetos, indicadores
- Pruebas multidivisa
- Criterios de optimización
- Obtener estadísticas financieras de prueba: TesterStatistics
- Evento OnTester
- Sintonización automática: ParameterGetRange y ParameterSetRange
- Grupo de eventos OnTester para el control de la optimización
- Enviar marcos de datos de los agentes al terminal
- Obtener marcos de datos en terminal
- Directivas del preprocesador para el probador
- Gestionar la visibilidad de los indicadores: TesterHideIndicators
- Emulación de operaciones de depósito y retirada
- Parada forzada de la prueba: TesterStop
- Ejemplo de Gran Asesor Experto
- Cálculos matemáticos
- Depuración y creación de perfiles
- Limitaciones de las funciones del probador
Sintonización automática: ParameterGetRange y ParameterSetRange
En la sección anterior aprendimos a pasar un criterio de optimización al probador. Sin embargo, hemos pasado por alto un punto importante. Si echa un vistazo a nuestros registros de optimización, podrá ver muchos mensajes de error, como los que aparecen a continuación:
...
|
En otras palabras: cada pocas pasadas de prueba, algo falla en los parámetros de entrada y la pasada en cuestión no se realiza. El manejador OnInit contiene la siguiente comprobación:
if(FastOsMA >= SlowOsMA) return INIT_PARAMETERS_INCORRECT; |
Por nuestra parte, es bastante lógico imponer la restricción de que el periodo de la media móvil (MA) lenta sea mayor que el periodo de la media móvil rápida. Sin embargo, el probador no sabe esas cosas sobre nuestro algoritmo, por lo que intenta clasificar una gran variedad de combinaciones de periodos, incluidas las incorrectas. Esta podría ser una situación común para la optimización que, sin embargo, tiene una consecuencia negativa.
Como aplicamos la optimización genética, en cada generación hay varias muestras rechazadas que no participan en mutaciones posteriores. El optimizador de MetaTrader 5 no compensa estas pérdidas, es decir, no genera un sustituto para ellas. Un menor tamaño de la población puede afectar entonces negativamente a la calidad. Por lo tanto, es necesario idear una forma de garantizar que las configuraciones de entrada se enumeran sólo en las combinaciones correctas. Y aquí vienen en nuestra ayuda dos funciones de la API de MQL5: ParameterGetRange y ParameterSetRange.
Ambas funciones tienen dos prototipos sobrecargados que difieren en los tipos de parámetros: long y double. Así se describen las dos variantes de la función ParameterGetRange:
bool ParameterGetRange(const string name, bool &enable, long &value, long &start, long &step, long &stop)
bool ParameterGetRange(const string name, bool &enable, double &value, double &start, double &step, double &stop)
Para la variable de entrada especificada por nombre, la función recibe información sobre su valor actual (value), rango de valores (start, stop) y paso de cambio (step) durante la optimización. Además, se escribe un atributo en la variable enable de si la optimización está activada para la variable de entrada llamada 'nombre'.
La función devuelve un indicador de éxito (true) o de error (false).
La función sólo puede invocarse desde tres manejadores especiales relacionados con la optimización: OnTesterInit, OnTesterPass y OnTesterDeinit. Hablaremos de ellos en la sección siguiente. Como se puede adivinar por los nombres, OnTesterInit se llama antes de que comience la optimización, OnTesterDeinit después de la finalización de la optimización, y OnTesterPass después de cada pasada en el proceso de optimización. Por ahora, sólo nos interesa OnTesterInit. Al igual que las otras dos funciones, no tiene parámetros y puede declararse con el tipo void, es decir, no devuelve nada.
Dos versiones de la función ParameterSetRange tienen prototipos similares y realizan la acción opuesta: establecen las propiedades de optimización del parámetro de entrada del Asesor Experto.
bool ParameterSetRange(const string name, bool enable, long value, long start, long step, long stop)
bool ParameterSetRange(const string name, bool enable, double value, double start, double step, double stop)
La función establece las reglas de modificación de la variable input con el nombre name al realizar la optimización: valor, paso de modificación, valores inicial y final.
Esta función sólo puede ser llamada desde el manejador OnTesterInit cuando se inicia la optimización en el probador de estrategias.
Así, utilizando las funciones ParameterGetRange y ParameterSetRange, puede analizar y establecer nuevos valores de rango y paso, así como excluir completamente o, viceversa, incluir ciertos parámetros de la optimización, a pesar de los ajustes en el probador de estrategias. Esto le permite crear sus propios scripts para gestionar el espacio de parámetros de entrada durante la optimización.
La función permite utilizar en la optimización incluso aquellas variables que se declaran con el modificador sinput (no están disponibles para su inclusión en la optimización por parte del usuario).
¡Atención! Después de la llamada de ParameterSetRange con un cambio en los ajustes de una variable de entrada específica, las llamadas posteriores de ParameterGetRange no «verán» estos cambios y seguirán volviendo a los ajustes originales. Esto imposibilita el uso conjunto de funciones en productos de software complejos, en los que las configuraciones pueden ser gestionadas por diferentes clases y bibliotecas de desarrolladores independientes.
Mejoremos el Asesor Experto BandOsMA utilizando las nuevas funciones. La versión actualizada se denomina BandOsMApro.mq5 («pro» puede descodificarse condicionalmente como «optimización del rango de parámetros»).
Así, tenemos el manejador OnTesterInit, en el que leemos la configuración de los parámetros FastOsMA y SlowOsMA, y comprobamos si están incluidos en la optimización. Si es así, hay que desactivarlos y ofrecer algo a cambio.
void OnTesterInit()
|
Por desgracia, debido a la adición de OnTesterInit, el compilador también requiere que añada OnTesterDeinit, aunque no necesitamos esta función, pero nos vemos obligados a aceptar y añadir un manejador vacío.
void OnTesterDeinit()
|
La presencia de las funciones OnTesterInit/OnTesterDeinit en el código conducirá al hecho de que cuando se inicie la optimización, se abrirá un gráfico adicional en el terminal con una copia de nuestro Asesor Experto ejecutándose en él. Funciona en un modo especial que le permite recibir datos adicionales (los llamados frames) de copias probadas en agentes, pero exploraremos esta posibilidad más adelante. Por ahora, es importante que tengamos en cuenta que todas las operaciones con archivos, registros, gráficos y objetos funcionan en esta copia auxiliar del Asesor Experto directamente en el terminal, como de costumbre (y no en el agente). En concreto, todos los mensajes de error y las llamadas a Print se mostrarán en el registro de la pestaña Experts del terminal.
Tenemos información sobre los rangos de cambio y los pasos de estos parámetros, podemos literalmente recalcular todas las combinaciones correctas. Esta tarea se asigna a una función separada Iterate porque una operación similar tendrá que ser reproducida por copias del Asesor Experto en agentes, en el manejador OnInit.
En la función Iterate tenemos dos bucles anidados sobre los periodos de MA rápida y lenta en los que contamos el número de combinaciones válidas, es decir, cuando el periodo i es inferior a j. Necesitamos el parámetro opcional find al llamar a Iterate desde OnInit para devolver el par por el número de secuencia de la combinación i y j. Dado que se requiere devolver 2 números, declaramos la estructura PairOfPeriods para ellos.
struct PairOfPeriods
|
Al llamar a Iterate desde OnTesterInit, no utilizamos el parámetro find y seguimos contando hasta el final, y devolvemos la cantidad resultante en el primer campo de la estructura. Este será el rango de valores de algún nuevo parámetro de sombra, para el que debemos activar la optimización. Vamos a llamarlo FastSlowCombo4Optimization y a añadirlo al nuevo grupo de parámetros auxiliares de entrada. Pronto añadiremos más.
input group "A U X I L I A R Y"
|
Volvamos a OnTesterInit y organicemos una optimización de MQL5 por el parámetro FastSlowCombo4Optimization en el rango deseado utilizando ParameterSetRange.
void OnTesterInit()
|
Tenga en cuenta que el número de iteraciones resultante para el nuevo parámetro debe aparecer en el registro del terminal.
Cuando realice pruebas en el agente, utilice el número de FastSlowCombo4Optimization para obtener un par de períodos llamando de nuevo a Iterate, esta vez con el parámetro find lleno. Pero el problema es que para esta operación se requiere conocer los rangos iniciales y el paso de cambio de parámetros FastOsMA y SlowOsMA. Esta información sólo está presente en el terminal, por lo que tenemos que transferirla de alguna manera al agente.
Ahora aplicaremos la única solución que conocemos por el momento: añadiremos otros 3 parámetros de optimización de sombras y estableceremos algunos valores para ellos. En el futuro nos familiarizaremos con la tecnología de transferencia de archivos a los agentes (véase Directivas del preprocesador para el probador). Entonces podremos escribir en el archivo todo el array de índices calculado por la función Iterate y enviarlo a los agentes. Esto evitará tres parámetros adicionales de optimización de sombras.
Por lo tanto, vamos a añadir tres parámetros de entrada:
sinput ulong FastShadow4Optimization = 0; // (reserved for optimization)
|
Utilizamos el tipo ulong para ser más económicos: para empaquetar 2 números int en cada valor. Así se rellenan en OnTesterInit.
void OnTesterInit()
|
Los 3 parámetros no son optimizables (false en el segundo argumento).
Con esto concluyen nuestras operaciones con la función OnTesterInit. Pasemos al lado receptor: el manejador OnInit.
int OnInit()
|
Utilizando la función MQLInfoInteger podemos determinar todos los modos del Asesor Experto, incluidos los relacionados con el probador y la optimización. Habiendo especificado uno de los elementos de la enumeración ENUM_MQL_INFO_INTEGER como parámetro, obtendremos como resultado un signo lógico (true/false):
- MQL_TESTER - el programa funciona en el probador
- MQL_VISUAL_MODE - el probador se ejecuta en modo visual
- MQL_OPTIMIZATION - la pasada de prueba se realiza durante la optimización (no por separado)
- MQL_FORWARD - la pasada de prueba se realiza en el período forward después de la optimización (si se especifica por la configuración de optimización)
- MQL_FRAME_MODE - el Asesor Experto se está ejecutando en un modo de servicio especial en el gráfico del terminal (y no en el agente) para controlar la optimización (encontrará más información al respecto en la sección siguiente)
Modos del probador de programas MQL
Todo está listo para iniciar la optimización. En cuanto se inicie, con la configuración mencionada Presets/MQL5Book/BandOsMA.set, veremos un mensaje en el registro Experts del terminal:
Parameter FastSlowCombo4Optimization is enabled with maximum: 698 |
Esta vez no debería haber errores en el registro de optimización y todas las generaciones se realizan sin bloquearse.
...
|
Esto puede determinarse incluso por el aumento del tiempo total de optimización: antes, algunas pasadas se rechazaban en una fase temprana, y ahora todas se procesan en su totalidad.
No obstante, nuestra solución tiene un inconveniente: ahora, los ajustes de trabajo del Asesor Experto incluyen no sólo un par de períodos en los parámetros FastOsMA y SlowOsMA, sino también el número ordinal de su combinación entre todas las posibles (FastSlowCombo4Optimization). Lo único que podemos hacer es dar salida a los periodos descodificados en la función OnInit, que se ha demostrado anteriormente.
Así, una vez encontrados unos buenos ajustes con la ayuda de la optimización, el usuario, como es habitual, realizará una única ejecución para afinar el comportamiento del sistema de trading. Al principio del registro de pruebas debe aparecer una inscripción del siguiente tenor:
MA periods are restored from shadow: FastOsMA=27 SlowOsMA=175 |
A continuación, puede introducir los periodos especificados en los parámetros del mismo nombre y restablecer todos los parámetros de sombra.