- 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
Obtener estadísticas financieras de prueba: TesterStatistics
Solemos evaluar la calidad de un Asesor Experto basándonos en un informe de trading, que es similar a un informe de simulación cuando se trata de un probador. Contiene un gran número de variables que caracterizan el estilo de trading, la estabilidad y, por supuesto, la rentabilidad. Todas estas métricas, con algunas excepciones, están disponibles para el programa MQL a través de una función especial TesterStatistics. Así, el desarrollador del Asesor Experto tiene la capacidad de analizar variables individuales en el código y construir sus propios criterios combinados de calidad de optimización a partir de ellas.
double TesterStatistics(ENUM_STATISTICS statistic)
La función TesterStatistics devuelve el valor de la variable estadística especificada, calculada en base a los resultados de una ejecución separada del Asesor Experto en el probador. Se puede llamar a una función en el manejador OnDeinit o OnTester, que aún está por discutir.
Todas las variables estadísticas disponibles se resumen en la enumeración ENUM_STATISTICS. Algunas de ellas son características cualitativas, es decir, números reales (normalmente beneficios totales, reducciones, ratios, etc.), y las otras son cuantitativas, es decir, números enteros (por ejemplo, el número de transacciones). Sin embargo, ambos grupos están controlados por la misma función con el resultado double.
En la siguiente tabla se muestran los indicadores reales (coeficientes e importes monetarios). Todos los importes monetarios se expresan en la divisa del depósito.
Identificador |
Descripción |
---|---|
STAT_INITIAL_DEPOSIT |
Depósito inicial |
STAT_WITHDRAWAL |
Importe de los fondos retirados de la cuenta |
STAT_PROFIT |
Beneficio o pérdida neta al final de la simulación, la suma de STAT_GROSS_PROFIT y STAT_GROSS_LOSS |
STAT_GROSS_PROFIT |
Beneficio total, la suma de todas las operaciones rentables (mayor o igual a cero) |
STAT_GROSS_LOSS |
Pérdida total, la suma de todas las operaciones perdedoras (menor o igual a cero) |
STAT_MAX_PROFITTRADE |
Beneficio máximo: el mayor valor de entre todas las operaciones rentables (mayor o igual a cero) |
STAT_MAX_LOSSTRADE |
Pérdida máxima: el valor más pequeño de entre todas las operaciones perdedoras (menor o igual a cero) |
STAT_CONPROFITMAX |
Beneficio máximo total en una serie de operaciones rentables (mayor o igual a cero) |
STAT_MAX_CONWINS |
Beneficio total en la serie más larga de operaciones rentables |
STAT_CONLOSSMAX |
Pérdida máxima total en una serie de operaciones perdedoras (menor o igual a cero) |
STAT_MAX_CONLOSSES |
Pérdida total en la serie más larga de operaciones perdedoras |
STAT_BALANCEEMIN |
Valor del saldo mínimo |
STAT_BALANCE_DD |
Disposición máxima del saldo en dinero |
STAT_BALANCEDD_PERCENT |
Disposición de saldo en porcentaje, que se registró en el momento de la máxima disposición de saldo en dinero (STAT_BALANCE_DD) |
STAT_BALANCE_DDREL_PERCENT |
Disposición máxima del saldo en porcentaje |
STAT_BALANCE_DD_RELATIVE |
Disposición de saldo en equivalente monetario, que se registró en el momento de la máxima disposición de saldo en porcentaje (STAT_BALANCE_DDREL_PERCENT) |
STAT_EQUITYMIN |
Valor mínimo de los fondos propios |
STAT_EQUITY_DD |
Disposición máxima en dinero |
STAT_EQUITYDD_PERCENT |
Disposición en porcentaje, que se registró en el momento de la disposición máxima de fondos en el dinero (STAT_EQUITY_DD) |
STAT_EQUITY_DDREL_PERCENT |
Disposición máxima en porcentaje |
STAT_EQUITY_DD_RELATIVE |
Disposición en dinero que se registró en el momento de la disposición máxima en porcentaje (STAT_EQUITY_DDREL_PERCENT) |
STAT_EXPECTED_PAYOFF |
Expectativa matemática de ganancias (media aritmética del beneficio total y el número de transacciones) |
STAT_PROFIT_FACTOR |
Rentabilidad, que es el cociente STAT_GROSS_PROFIT/STAT_GROSS_LOSS (si STAT_GROSS_LOSS = 0; la rentabilidad toma el valor DBL_MAX). |
STAT_RECOVERY_FACTOR |
Factor de recuperación: el ratio de STAT_PROFIT/STAT_BALANCE_DD |
STAT_SHARPE_RATIO |
Ratio de Sharpe |
STAT_MIN_MARGINLEVEL |
Nivel de margen mínimo alcanzado |
STAT_CUSTOM_ONTESTER |
El valor del criterio de optimización personalizado devuelto por la función OnTester. |
En la siguiente tabla muestra los indicadores enteros (importes).
Identificador |
Descripción |
---|---|
STAT_DEALS |
Número total de transacciones completadas |
STAT_TRADES |
Número de operaciones (transacciones de salida del mercado) |
STAT_PROFIT_TRADES |
Operaciones rentables |
STAT_LOSS_TRADES |
Operaciones perdedoras |
STAT_SHORT_TRADES |
Operaciones cortas |
STAT_LONG_TRADES |
Operaciones largas |
STAT_PROFIT_SHORTTRADES |
Operaciones cortas rentables |
STAT_PROFIT_LONGTRADES |
Operaciones largas rentables |
STAT_PROFITTRADES_AVGCON |
Duración media de una serie de operaciones rentables |
STAT_LOSSTRADES_AVGCON |
Duración media de una serie de operaciones perdedoras |
STAT_CONPROFITMAX_TRADES |
Número de operaciones que formaron STAT_CONPROFITMAX (beneficio máximo en la secuencia de operaciones rentables) |
STAT_MAX_CONPROFIT_TRADES |
Número de operaciones en la serie más larga de operaciones rentables STAT_MAX_CONWINS |
STAT_CONLOSSMAX_TRADES |
Número de operaciones que formaron STAT_CONLOSSMAX (pérdida máxima en la secuencia de operaciones perdedoras) |
STAT_MAX_CONLOSS_TRADES |
Número de operaciones en la serie más larga de operaciones perdedoras STAT_MAX_CONLOSSES |
Intentemos utilizar las métricas presentadas para crear nuestro propio criterio complejo de calidad de Asesor Experto. Para ello, necesitamos algún tipo de ejemplo «experimental» de un programa MQL. Tomemos el Asesor Experto MultiMartingale.mq5 como punto de partida, pero lo simplificaremos: eliminaremos la multidivisa, el tratamiento de errores integrados y la programación. Además, elegiremos para ella una estrategia de trading de señales con un único cálculo en la barra, es decir, a los precios de apertura. Esto acelerará la optimización y ampliará el campo de experimentación.
La estrategia se basará en las condiciones de sobrecompra y sobreventa determinadas por el indicador OsMA. El indicador de Bandas de Bollinger superpuesto a OsMA le ayudará a encontrar dinámicamente los límites del exceso de volatilidad, lo que se traduce en señales de trading.
Cuando OsMA regrese dentro del corredor, cruzando el borde inferior de abajo hacia arriba, abriremos una operación de compra. Cuando OsMA cruce el límite superior de la misma forma de arriba a abajo, venderemos. Para salir de las posiciones, utilizamos la media móvil, también aplicada a OsMA. Si OsMA muestra un movimiento inverso (hacia abajo para una posición larga o hacia arriba para una posición corta) y toca MA, la posición se cerrará. Esta estrategia se ilustra en la siguiente captura de pantalla.
Estrategia de trading basada en los indicadores OsMA, BBands y MA
La línea vertical azul corresponde a la barra en la que se abre la compra, ya que en las dos barras anteriores, la banda inferior de Bollinger fue atravesada por el histograma OsMA de abajo arriba (este lugar está marcado con una flecha azul hueca en la subventana). La línea vertical roja es la ubicación de la señal inversa, por lo que se cerró la compra y se abrió la venta. En la subventana, en este lugar (o mejor dicho, en las dos barras anteriores, donde se encuentra la flecha roja hueca), el histograma OsMA cruza la banda de Bollinger superior de arriba a abajo. Por último, la línea verde indica el cierre de la venta, debido a que el histograma comenzó a subir por encima de la MA roja.
Llamemos al Asesor Experto BandOsMA.mq5. Los ajustes generales incluirán un número mágico, un lote fijo y una distancia de Stop Loss en puntos. Para el Stop Loss, utilizaremos TrailingStop del ejemplo anterior. Aquí no se utiliza el Take Profit.
input group "C O M M O N S E T T I N G S"
|
Hay tres grupos de ajustes destinados a los indicadores.
input group "O S M A S E T T I N G S"
|
En el Asesor Experto de MultiMartingale.mq5 no teníamos señales de trading, mientras que la dirección de apertura la fijaba el usuario. Aquí tenemos señales de trading, y tiene sentido organizarlas como una clase separada. En primer lugar, describamos la interfaz abstracta TradingSignal.
interface TradingSignal
|
Es tan sencillo como nuestra otra interfaz TradingStrategy. Y esto es bueno. Cuanto más sencillas sean las interfaces y los objetos, más probable es que hagan una sola cosa, lo cual es un buen estilo de programación porque minimiza los errores y hace más comprensibles los grandes proyectos de software. Debido a la abstracción en cualquier programa que utilice TradingSignal, será posible sustituir una señal por otra. También podemos sustituir la estrategia. Nuestras estrategias se encargan ahora de preparar y enviar las órdenes, y las señales las inician basándose en el análisis del mercado.
En nuestro caso, vamos a empaquetar la implementación específica de TradingSignal en la clase BandOsMaSignal. Por supuesto, necesitamos variables para almacenar los descriptores de los 3 indicadores. Las instancias del indicador se crean y eliminan en el constructor y el destructor, respectivamente. Todos los parámetros se pasarán desde las variables de entrada. Tenga en cuenta que iBands y iMA se basan en el manejador hOsMA.
class BandOsMaSignal: public TradingSignal
|
La dirección de la señal de trading actual se coloca en la variable direction: 0 - sin señales (situación indefinida), +1 - compra, -1 - venta. Rellenaremos esta variable en el método signal. Su código repite la descripción verbal anterior de las señales en MQL5.
virtual int signal(void) override
|
Como puede ver, los valores del indicador se leen para las barras 1 y 2, ya que trabajaremos en la apertura de una barra, y la barra 0 acaba de abrirse cuando llamamos al método signal.
La nueva clase que implemente la interfaz TradingStrategy se llamará SimpleStrategy.
La clase proporciona algunas características nuevas, al tiempo que utiliza algunas partes ya existentes. En concreto, ha conservado los punteros automáticos para PositionState y TrailingStop y tiene un nuevo puntero automático para la señal TradingSignal. Además, como vamos a operar sólo en la apertura de barras, necesitamos la variable lastBar, que almacenará la hora de la última barra procesada.
class SimpleStrategy: public TradingStrategy
|
Los parámetros globales se pasan al constructor SimpleStrategy. También pasamos un puntero al objeto TradingSignal: en este caso, será BandOsMaSignal el que tendrá que crear el código de llamada. A continuación, el constructor intenta encontrar entre las posiciones existentes aquellas que tengan el número y el símbolo magic requeridos y, si lo consigue, añade un trailing stop. Esto será útil si el Asesor Experto tiene una interrupción por una razón u otra, y la posición ya ha sido abierta.
public:
|
La implementación del método trade es similar al ejemplo de la martingala. No obstante, hemos eliminado las multiplicaciones de lotes y hemos añadido la llamada al método signal.
virtual bool trade() override
|
Los métodos auxiliares openBuy, openSell y otros han sufrido cambios mínimos, por lo que no los enumeraremos (se adjunta el código fuente completo).
Dado que siempre tenemos una sola estrategia en este Asesor Experto, en contraste con la martingala multidivisa en la que cada símbolo requería su propia configuración, vamos a excluir el grupo de estrategias y gestionar el objeto estrategia directamente.
AutoPtr<TradingStrategy> strategy;
|
Ahora tenemos un Asesor Experto listo que podemos utilizar como herramienta para estudiar el probador. En primer lugar, vamos a crear una estructura auxiliar TesterRecord para consultar y almacenar todos los datos estadísticos.
struct TesterRecord
|
En este caso, el campo de cadena feature sólo es necesario para la salida de registro informativo. Para guardar todos los indicadores (por ejemplo, para poder generar más tarde su propio formulario de informe), basta con un simple array del tipo double de longitud adecuada.
Utilizando la estructura del manejador OnDeinit, nos aseguramos de que la API de MQL5 devuelva los mismos valores que el informe del probador.
void OnDeinit(const int)
|
Por ejemplo, al ejecutar el Asesor Experto en EURUSD, H1 con un depósito de 10000 y sin ninguna optimización (con la configuración por defecto), obtendremos aproximadamente los siguientes valores para 2021 (fragmento):
[feature] [value]
|
Conociendo todos estos valores, podemos inventar nuestra propia fórmula para la métrica combinada de la calidad del Asesor Experto y, al mismo tiempo, la función de optimización objetivo. Pero, en cualquier caso, el valor de este indicador deberá comunicarse al probador. Y eso es lo que hace la función OnTester.