MetaTrader 4 - Ejemplos Bases teóricas de la construcción de indicadores de grupo para FOREX Introducción Cualquier instrumento financiero que se negocia en el mercado es una posición de algunos activos hacia alguna moneda. FOREX difiere de otros mercados sólo en el hecho de que otra moneda se utiliza como un activo. Como resultado en el mercado FOREX siempre tratamos con la correlación de dos monedas, llamadas pares de divisas. El proyecto que comenzó hace más de un año, ayudó a desarrollar un grupo de indicadores bajo un nombre conjunto de indicadores de cluster. Su tarea era dividir los pares de divisas en monedas separadas. Desde entonces los indicadores fueron cambiados varias veces. Además, el interés de los usuarios y las discusiones activas en foros permitieron desarrollar métodos de trabajo con indicadores y crear sistemas de comercio basados en ellos. Características de Operación de los Indicadores de Cluster La primera característica distintiva de los indicadores de clúster está en el hecho de que para la operación necesitan simultáneamente cotizaciones de un cierto grupo de pares de divisas. Los indicadores pueden trabajar con un par de divisas aparte, pero en opinión de los autores es inútil en la práctica. La ventaja de los indicadores radica precisamente en la capacidad de analizar una gran cantidad de pares de divisas, dividiéndolos en monedas independientes. Cuanto más pares analizan, más precisa es la información proporcionada. Para ver la fluctuación de tres monedas, por ejemplo, EUR, USD, GPB, necesitamos cotizaciones de tres pares de divisas: EURUSD, GBPUSD y EURGBP. Y si desea agregar por ejemplo JPY, necesita cotizaciones de GBPGPY, USDJPY, EURJPY - totalmente 6 pares de divisas, donde cada moneda tiene tres relaciones con otras monedas. Gráficamente puede presentarse como un cuadrado con monedas en sus ángulos, las relaciones (lados y diagonales del cuadrado) entre las monedas denotan pares de divisas. De cada ángulo del cuadrado se dibujará una línea a todos los demás ángulos. Esta red autocontenida se llamaba un grupo. Explica los indicadores de nombre - cluster. Por regla general, en el terminal de comercio, los indicadores de MetaTrader 4 se muestran en una subventana separada bajo un cuadro de precios y su forma depende del par de divisas examinado. A su vez, los indicadores de clúster parecen iguales en todas partes, independientemente del gráfico al que estén conectados. Esta es la segunda característica distintiva de los indicadores del cluster. Imagen La figura 1 muestra el indicador CCFp (porcentaje de ComplexCommonFrame). A pesar de su vinculación con el gráfico EURUSD, tendrá la misma forma en cualquier otro par de divisas, aunque este par no pertenezca al cluster analizado. Conceptos Básicos de Trabajar con Indicadores de Cluster En la figura 1 hay ocho líneas de color diferente. Cada línea corresponde a una moneda definida. Los indicadores de cluster no reflejan los índices de divisas, sino sus fluctuaciones entre sí. Los indicadores representan un sistema autónomo, lo que hace que el modelo de mercado sea más sencillo, pero esta simplificación no impide una negociación exitosa de los indicadores. Las monedas se miden en unidades relativas, es por eso que en cada unidad de tiempo la suma de todas las monedas será igual a cero. Por lo tanto, uno de los elementos básicos de los indicadores de clúster es una línea cero, o línea de equilibrio. Si una moneda está por debajo de la línea de saldo, se dice que está sobreventa en comparación con otras monedas. En consecuencia, si una moneda está por encima de la línea cero, se dice que es sobrecompra. Si una divisa está sobrecomprada, tarde o temprano comenzará a disminuir con respecto a todas las demás monedas, la línea de divisas bajará y puede llegar a la línea de saldo o incluso entrar en la zona de sobreventa. La proximidad de una divisa a la línea de saldo significa que la moneda está en el estado de equilibrio hacia otras monedas. Un elemento más importante de los indicadores de cluster es el punto de intersección de líneas, que apunta al cambio de tendencia o que da una señal. Además, sobre la base de indicadores se puede extraer divergencia y convergencia, pero vamos a discutir estos elementos en detalles en el próximo artículo Aplicación práctica de los indicadores de cluster en el mercado FOREX. Me gustaría llamar su atención sobre un hecho que no es evidente durante el análisis de los indicadores de los grupos. Normalmente los indicadores se construyen sobre la base del precio de un par de divisas definido. Pero los indicadores de clúster se construyen sobre la base de todos los pares de divisas del complejo. Observando el indicador debes entender que observamos los precios de todos los veinticuatro pares de divisas simultáneamente, y no sólo el derivado del precio de un par de divisas actual, al que está unido el indicador. Si el indicador se muestra bajo el par EURUSD, al lado de este par de divisas se calculan los pares EURGBP, USDGBP, USDCHF, EURJPY y así sucesivamente, es decir, todos los demás pares, que incluyen USD y EUR. Y cuando llega una señal de comercio, hay que recordar que no se negocia un par definido, sino todo el mercado, o un cluster de mercado para ser más preciso. Este hecho es una ventaja, pero al mismo tiempo una desventaja. Las señales de estos indicadores son más seguras porque se basan en todos los pares de divisas. Pero al mismo tiempo siempre existe el riesgo de que el par de divisas elegido se destaque entre todo el complejo de monedas. Por ejemplo, en el mercado puede ocurrir así, que grandes cantidades de libras se venden por USD. La influencia de una moneda en todo el cluster es un poco más de 4 (en el par de veinticuatro). En este caso, los indicadores son más valiosos como informativos, no comerciales. Aunque los sistemas de comercio se crean sobre la base de los indicadores. Requisitos para los indicadores de clúster Operación Terminal MetaTrader 4 hace algunas restricciones, que no permiten utilizar indicadores de clúster para todos los instrumentos financieros. El número máximo de líneas en el indicador es ocho. Ése es porqué el racimo más grande puede contener solamente ocho monedas. Este conjunto incluye: USD, EUR, GBP, CHF, JPY, CAD, AUD, NZD. Y para su operación, los indicadores necesitan cotizaciones de veinticuatro pares de divisas: EURUSD, EURGBP, EURCHF, EURJPY, EURCAD, EURAUD, EURNZD, GBPUSD, GBPCHF, GBPJPY, GBPCAD, GBPAUD, GBPNZD, USDCHF, USDJPY, AUDCAD, AUDNZD, NZDUSD, NZDCHF, NZDCAD, NZDJPY. La necesidad de cotizar en los pares indicados hasta hace poco estaba limitando el número de empresas de corretaje, en cuyas plataformas los indicadores podrían operar. Hoy en día en las últimas modificaciones del indicador los requisitos se hicieron más bajos, ahora usted necesita tener todos los cruces que incluyen USD. Asi que. Para que los indicadores operen, los siguientes pares de divisas son suficientes: EURUSD, GBPUSD, USDCHF, USDJPY, USDCAD, AUDUSD, NZDUSD. Como el autor sabe, todas las compañías de corretaje que trabajan en la plataforma MetaTrader 4 proporcionan cotizaciones para los pares de divisas mencionados. Pero hay que recordar que las versiones antiguas de los indicadores, que todavía se pueden cumplir en Internet, solicitan el conjunto completo, es decir, veinticuatro pares de divisas. Cabe señalar que los indicadores de clúster, especialmente los de versiones anteriores, eran muy exigentes para la capacidad informática y la capacidad del Canal de Internet. Ahora los requisitos son más bajos, sin embargo los indicadores de cluster siguen siendo más intensivos en recursos que la mayoría de otros indicadores y osciladores. Además, la experiencia demuestra que la instalación primaria de los indicadores generalmente revela la deficiencia de cotizaciones en algunos pares de divisas, lo que sugiere su descarga forzada. Tipos de Indicadores de Cluster Durante el desarrollo del complejo de indicadores de clusters, un gran número de ideas se realizó en indicadores separados. Sin embargo ahora el autor sugiere que la vivienda en tres tipos principales. El primero es el indicador CCFp, se muestra en la figura Fig. 1. CCFp (porcentaje de ComplexCommonFrames) es un indicador de tendencia siguiente. Su antecesor CCF estimó la divergencia de las monedas en puntos, mientras que CCFp trabaja con valores específicos, lo que permite evitar distorsiones, como resultado de la pesadez de monedas separadas. La pesadez aquí significa que, por ejemplo, la libra es casi dos veces más cara que la USD (Febrero de 2007 - hora de la redacción del artículo). Como resultado - los puntos para cada moneda tienen un valor diferente. Así que se tomó la decisión de contar el porcentaje. El segundo indicador es CC (ComplexCommon). Es un impulso, o indicador de señal. Es muy sensible y reacciona rápidamente sobre los movimientos de precios. El indicador se muestra en la figura Fig 2. La imagen muestra el par de divisas EURUSD. Dos ventanas abajo contienen el mismo indicador. La ventana superior muestra todas las monedas, las líneas de USD y el euro son semi-negrita. La ventana inferior contiene el mismo indicador, pero todas las demás monedas están ocultas, muestra las monedas sólo del par correspondiente. El tercer indicador ComplexPair1 es un derivado del indicador CC. En la imagen Fig 2 la ventana inferior muestra sólo dos líneas: EUR y USD. La suma de estos indicadores es el indicador ComplexPair1, que refleja sólo una línea de impulso (señal). Usted puede ver este indicador en la imagen Fig. 3. Debe señalarse, que el indicador ComplexPair fue desarrollado en primer lugar. Pero era demasiado intensivo en recursos. El desarrollo posterior encontró otra forma de construir el mismo indicador, pero utilizando un algoritmo rápido, que permitió extraer la misma información, pero ahora desde el cuadro de precios de una sola moneda. A pesar del hecho de que ComplexPair y ComplexPair1 recibían la información de diferentes maneras, su identidad visual en los plazos más altos era absoluta. En los plazos más bajos había alguna diferencia, pero ComplexPair 1 puede trabajar en cualquier instrumento financiero - acciones, futuros o materias primas. El autor de los indicadores de clúster especifica que el algoritmo del indicador ComplexPair1 fue desarrollado por otra persona. (Foro del sitio Onix. Desarrollador - arzuma, enlace a un mensaje). Una breve descripción de los algoritmos de los indicadores de clúster Operación La idea de dividir un grupo completo de pares de divisas en pares separados es simple. Supongamos que se utiliza un clúster pequeño para los pares de divisas EURUSD, GBPUSD, EURUSD y la tarea es separar las monedas: EUR, USD, GBP. Si dentro de un cierto período de tiempo un par EURUSD creció, la diferencia se agregará a EUR y se resta de USD. Si al mismo tiempo el par de GBPUSD sube, los cambios de precio se suman a GBP y se restan de USD. Y, finalmente, es necesario considerar los cambios de precio del par EURGBP. Supongamos que el par se hundió, luego la diferencia se sumará a la libra esterlina y se restará de EUR. Al igual que en Forex es imposible determinar un denominador común, que podría ser un modelo estable en el tiempo, al separar las monedas, no se normalizan y todos los cambios se cuentan en unidades relativas. Hasta hace poco se aceptó un punto como tal unidad. Pero como el valor del punto es variable en el tiempo y es diferente para diferentes monedas, en las últimas modificaciones de los indicadores del cluster, el cambio de precio se calculó en porcentaje. Además, la experiencia demostró que los servidores de citas contemporáneos ahora permiten una diferencia significativa de cruces de divisas. Es por eso que para reducir el tráfico de cotizaciones de bombeo y para aumentar la velocidad de operación de los indicadores, los cálculos de todos los pares de divisas se realizan sobre la base de cruces de dólares solamente. Así que el algoritmo general de los indicadores se parece a esto: Determinación de las monedas, que entrará en un grupo. Se establece por los ajustes de los usuarios Cálculo matemático de cruces no dólar basado en dólares, incluso si USD se excluye del clúster Filtrado de ruido por el promedio móvil. Los parámetros son establecidos por el usuario Análisis de todos los pares de divisas del cluster sobre el cambio de precio y el cumplimiento de la matriz de monedas, incluido en el cluster Siguiente es la realización lógica de un determinado tipo de indicador, es decir, Procesado (no sólo el actual), las transformaciones simples se utilizan para un indicador de impulso. Los archivos fuente de los indicadores CCFp, CC, CFP, Complexpairs1 se adjuntan al artículo. Parámetros de los indicadores de agrupación Las siguientes entradas disponibles para la configuración se determinan en la última versión de los indicadores. Las entradas se dividen en varios grupos. El primer grupo de entradas determina el método de filtración MAMethod - método para determinar una media móvil, puede ser una de las siguientes variantes: 0 - Media móvil simple 1 - Media móvil exponencial 2 - Media móvil suavizada 3 - Media ponderada linealmente. El parámetro 3 se fija por defecto Precio - precio usado, puede aceptar uno de los siguientes valores: 0 - Precio cerrado 1 - Precio abierto 2 - Precio máximo, (Alto) 3 - Precio mínimo, (Bajo) 4 - Precio medio, ( HighLow) / 2 5 - Precio típico, (HighLowClose) / 3 6 - Precio de cierre ponderado, (HighLowCloseClose) / 4. El parámetro 6 está configurado por defecto. Rápido - un período de promedio rápido, por defecto - 3. Lento - un período de promedio lento, por defecto - 5. El segundo grupo de entradas permite formar diferentes tipos de clusters Este grupo incluye ocho parámetros lógicos, los cuales pueden asumir un valor Verdadero / falso (1/0). Cada parámetro incluye esta o aquella moneda en un clúster o la desactiva: USD - incluye en el clúster o excluye del grupo Dólar estadounidense (por defecto - verdadero) EUR - incluye en el clúster o excluye del grupo Euro (en default - true ) GBP - incluye en el clúster o excluye del clúster Libra británica (por defecto - true) CHF - incluye en el clúster o excluye del clúster Franco suizo (en default - true) JPY - incluye en el clúster o excluye del clúster Dólar canadiense (por defecto - verdadero) Dólar canadiense (por defecto - verdadero) Dólar canadiense (por defecto - verdadero) Dólar canadiense (por defecto - verdadero) El clúster o excluye del grupo dólar neozelandés (en default - true). El tercer grupo de entradas gestiona la visión externa de los indicadores. Debe observarse que el grosor y el color de la línea deben estar mejor ajustados a través de estas entradas y no a través de una pestaña común presente en ningún indicador. Cuando una línea está configurada en un color invisible (color de fondo), las líneas no se mostrarán en el indicador, pero las monedas se calcularán. Una divisa puede ser excluida del cluster sólo a través del segundo grupo de entradas, descrito anteriormente. ColorUSD color de una línea para el dólar de los EE. UU. ColorEUD color de una línea para el color Euro ColorGBP de una línea para la libra esterlina ColorCHF color de una línea para el franco suizo ColorJPY color de una línea para el yen japonés ColorCAD color de una línea para el dólar canadiense ColorAUD color of Una línea para el dólar australiano ColorNZD color de una línea para el dólar neozelandés LineThickness preestablece el grosor de línea de un par de divisas visualizado. A veces es conveniente. Por ejemplo, si analizamos el gráfico EURUSD, es más conveniente cuando EUR y USD se diferencian de otros no sólo en color, sino también en el espesor de línea. Al mismo tiempo, los indicadores se pueden configurar para que otras monedas no se vea en absoluto sólo las monedas necesarias se verá. El ejemplo de este ajuste está en la imagen Fig. 3. El cuarto grupo de entradas incluye sólo un parámetro, pero ahora hay una idea para incluir parámetros adicionales en este grupo. AllBars determina el número de las barras de historial calculadas. Si este parámetro es igual a 0 (es así por defecto), se calcula todo el historial disponible. Pero, como se mencionó anteriormente, los indicadores son de uso intensivo de recursos, por lo que su uso en computadoras de bajo rendimiento es problemático. Este parámetro permite deshacerse de la máquina limitando el historial de cotizaciones analizado. Se observa que a los valores 1000 y 500 la velocidad de operación de los indicadores es significativamente mayor. Conclusión La ventaja de los indicadores de clusters radica en su capacidad para mostrar en una ventana dinámica de fluctuación monetaria relativa, lo que permite descubrir pares de divisas prometedores, que probablemente experimentarán movimientos de tendencia. Los indicadores de cluster permiten seguir las tendencias iniciales y pueden dar señales a posiciones abiertas o cerradas. Puede encontrar más información sobre el funcionamiento de indicadores del artículo Uso práctico de indicadores de clúster en el mercado FOREX. Puede leer sobre la historia del desarrollo de indicadores en el sitio Onix. Sección Indicadores de clústers. RAP Break Un punto más importante que podría hacer este EA más robusto. La lógica de la ruptura de ATR es comparar si el precio ha roto el nivel (para los largos) LowestPoint (multiplicador ATR) Cuando ponemos algún valor como multiplicador, también estamos estimando el número de barras necesarias para llegar a este nivel. Ejemplo: Cuando ponemos un criterio de 3 como multiplicador también estamos diciendo que necesitamos 9 barras, sin darnos cuenta de que este es el resultado final. Estoy basando esta lógica en la raíz cuadrada de la regla del tiempo, que es simplemente la volatilidad actual de FutureVolatility raíz cuadrada del tiempo De acuerdo con esta regla, el método ATR breakout también necesitaría el número de barras de la figura para alcanzar el nivel de ruptura ATR. Por lo tanto, yo sugeriría este criterio de ruptura dinámica, en lugar de multiplicador fijo. De acuerdo con sqrtof tiempo regla 1 bar volatilidad sería igual a 8,84 pips (estoy usando el valor de cálculo de la muestra en mi post anterior) 2 bar volatilidad sqrt (2) 8,84 3 bar volatilidad sqrt (3) 8,84 etc Así que el cálculo es Desde la volatilidad aquí es una especie de desviación estándar de la volatilidad, para averiguar si un precio ha roto el umbral ATR (punto de entrada), tenemos que usar ZScores: EntryLevelForLong HighestPoint Sqrt (número de barras desde el punto más bajo) Número de barras desde el punto más bajo) 8.84 ZScore En las estadísticas los valores de Z-Score para varios niveles de confianza serían 1, 1.645, 1.96, 2.58 Por lo tanto, la optimización de la EA estaría ligada a los 4 valores de ZScore anteriores. Esto haría que el sistema matemáticamente sonido, y resistente a los cambios de comportamiento de los precios de las parejas en el futuro. Por favor dé sus comentarios y pensamientos .. Un punto más importante que podría hacer este EA más robusto. La lógica de la ruptura de ATR es comparar si el precio ha roto el nivel (para los largos) LowestPoint (multiplicador ATR) Cuando ponemos algún valor como multiplicador, también estamos estimando el número de barras necesarias para llegar a este nivel. Ejemplo: Cuando ponemos un criterio de 3 como multiplicador también estamos diciendo que necesitamos 9 barras, sin darnos cuenta de que este es el resultado final. Estoy basando esta lógica en la raíz cuadrada de la regla del tiempo, que es simplemente la volatilidad actual de FutureVolatility. Gracias por su valiosa entrada GTH, La idea original era el precio para romper el nivel x en la barra actual. Si no lo hace, se creará un nuevo nivel x para la barra siguiente, y así sucesivamente hasta que se rompa el nivel quotdynamicquot x cuando se inicia un comercio. (Donde xlevel actual precio abierto ATR multiplicador). La idea era captar el ímpetu mientras sucedía. Mis preguntas a usted son: 1. ¿Está sugiriendo que los niveles quotestáticos sean para un número de barras igual al multiplicador seleccionado. Antes de crear un nuevo nivel. 2. ¿Cuál es el punto más bajo al que se refiere. Como estoy usando el precio abierto de la barra actual (o el cierre de la barra anterior). Si la oportunidad no llama, construye una puerta. Gracias por su valiosa entrada GTH, La idea original era que el precio rompiera el xlevel en la barra actual. Si no lo hace, se creará un nuevo xlevel para la siguiente barra, y así sucesivamente hasta que se rompa el xlevel quotdynamicquot cuando se inicia una operación. (Donde xlevel actual precio abierto ATR multiplicador). La idea era captar el ímpetu mientras sucedía. Mis preguntas a usted son: 1. ¿Está sugiriendo que los niveles quotestáticos sean para un número de barras igual al multiplicador seleccionado. Antes de crear un nuevo nivel. 2. ¿Cuál es el punto más bajo que. Bueno, me di cuenta de que estaba en una pista diferente. Pensé que seguías el canal ATR. Ejemplo: Punto de oscilación más bajo (multiplicador de ATR) Su punto de entrada para largo Por otra parte, ahora entiendo que usted está buscando siempre (abierto (multiplicador de ATR)) para entrar largo. Así que usted está buscando un quotlonger que usualquot barra para entrar. Ok que para su método de entrada mi sugerencia de Daily ATR (30) definitivamente funcionaría. En el próximo post voy a tratar de explicar la lógica del canal ATR, que he sugerido recientemente. Pido disculpas por cualquier confusión causada. Gracias por su valiosa entrada GTH, La idea original era que el precio rompiera el xlevel en la barra actual. Si no lo hace, se creará un nuevo xlevel para la siguiente barra, y así sucesivamente hasta que se rompa el xlevel quotdynamicquot cuando se inicia una operación. (Donde xlevel actual precio abierto ATR multiplicador). La idea era captar el ímpetu mientras sucedía. Mis preguntas a usted son: 1. ¿Está sugiriendo que los niveles quotestáticos sean para un número de barras igual al multiplicador seleccionado. Antes de crear un nuevo nivel. 2. ¿Cuál es el punto más bajo que. Como respuestas a sus preguntas y una breve explicación de mi quotChannelquot lógica es la siguiente: En el post 321, traté de explicar quotSquare Raíz de Time Rulequot. Siguiendo esta regla, comenzamos con un swing bajo (es decir, el punto más bajo de la baja después de que un canal se rompa). Para cada barra después calculamos el siguiente EntryLevelForLong HighestPoint Sqrt (número de barras desde el punto más bajo) 8.84 ZScore Así que en cada barra estamos calculando un nuevo nivel dinámico para entrar largo. Aquí está un ejemplo usando 8.84 como valor de ATR Punto más bajo 1.3500 1 bar cerrado, estamos en la 2ª barra Nivel de entrada 2ª barra 1.3500 (sqrt (2) 0.000884 1.96) 1.35245 Nivel de entrada 3rd bar 1.3500 0.000884 1.96) 1.3530 Así Esto se mantiene actualizando con cada nuevo bar. Esto es exactamente como el indicador SuperTrend, con la característica añadida de la función sqrt (barras). Si usted no tiene ese indicador voy a tratar de encontrarlo para usted. Espero que esto haga mi lógica clara. Si no, por favor hágamelo saber. MetaTrader 5 - Trading Systems Guía paso a paso para escribir un asesor experto en MQL5 para principiantes Introducción Este artículo está dirigido a principiantes que deseen aprender a escribir asesores expertos en el nuevo lenguaje MQL5. Empezaremos primero definiendo lo que queremos que haga nuestro EA (Asesor Experto), y luego pasemos a cómo queremos que la EA lo haga. 1. Estrategia de Negocio Lo que hará nuestra EA: Vigilará un determinado indicador, y cuando se cumpla una cierta condición (o se cumplan ciertas condiciones), colocará una operación (Short / Sell o Long / Buy), dependiendo Sobre la condición presente que se ha cumplido. Lo anterior se llama una estrategia comercial. Antes de poder escribir una EA, primero debe desarrollar la estrategia que desea automatizar en la EA. Así que en este caso, modifiquemos la declaración anterior para que refleje la estrategia que queremos desarrollar en una EA. Utilizaremos un indicador llamado Media móvil con un período de 8 (puede elegir cualquier período, pero para el propósito de nuestra estrategia, vamos a utilizar 8) queremos que nuestra EA para colocar un largo (compra) de comercio cuando la media móvil - 8 (para el bien de nuestra discusión, me referiré a ella como MA-8) está aumentando hacia arriba y el precio está cerca por encima de él y se colocará un corto (Sell) cuando MA-8 está disminuyendo hacia abajo y el precio está cerca Por debajo de eso. También vamos a utilizar otro indicador denominado Movimiento Direccional Promedio (ADX) con el período 8 también para ayudarnos a determinar si el mercado está tendiendo o no. Estamos haciendo esto porque sólo queremos entrar en el comercio cuando el mercado está en tendencia y relajarse cuando el mercado está variando (es decir, no tendencias). Para lograr esto, sólo pondremos nuestro comercio (Compra o Venta) cuando se cumplan las condiciones anteriores y el valor de ADX sea mayor que 22. Si ADX es mayor que 22 pero decreciente o ADX es menor que 22, no negociaremos, Incluso aunque se haya cumplido la condición B. Queremos también protegernos poniendo una Parada de pérdidas de 30 pips, y para nuestro objetivo de Beneficio nos centraremos en una ganancia de 100 pips. También queremos que nuestra EA busque oportunidades de Compra / Venta sólo cuando se forme una nueva barra y también nos aseguremos de abrir una posición de Compra si se cumplen las condiciones de Compra y no tenemos una abierta y abrimos una Venta Cuando las condiciones de venta se cumplan y no tenemos una abierta. Ahora hemos desarrollado nuestra estrategia ahora es hora de comenzar a escribir nuestro código. 2. Escribir un Asesor Experto Comience lanzando MetaQuotes Language Editor 5. A continuación, presione CtrlN o haga clic en el botón Nuevo de la barra de menú Figura 1. Inicio de un nuevo documento MQL5 En la ventana Asistente MQL5, seleccione Asesor experto y haga clic en Siguiente como Mostrado en la Fig. 2: Figura 2. Selección del tipo de programa En la ventana siguiente, escriba el Nombre que desea dar a su EA en el cuadro Nombre. En este caso, escribí MyFirstEA. A continuación, puede escribir su nombre en el cuadro Autor y también su dirección de sitio web o dirección de correo electrónico en el cuadro de enlace (si tiene uno). Figura 3. Propiedades generales del Asesor Experto Como queremos ser capaces de cambiar algunos de los parámetros de nuestra EA para ver cuál de los valores puede dar el mejor resultado, los añadiremos haciendo clic en el botón Añadir. Figura 4. Configuración de los parámetros de entrada de EA En nuestra EA, queremos ser capaces de experimentar con nuestros parámetros de Stop Loss, Take Profit, ADX Period y Moving Average Period, por lo que los definiremos en este punto. Haga doble clic en la sección Nombre y escriba el nombre del parámetro, luego haga doble clic en Tipo para Seleccionar el tipo de datos para el parámetro y haga doble clic en la sección Valor inicial y escriba el valor inicial del parámetro. Una vez que haya terminado, debería verse algo así: Figura 5. Tipos de datos de los parámetros de entrada de EA Como se puede ver arriba, he seleccionado el tipo de datos integer (int) para todos los parámetros. Hablemos un poco acerca de los tipos de datos. Char: El tipo char toma 1 byte de memoria (8 bits) y permite expresar en los valores de la notación binaria 28256. El tipo char puede contener tanto valores positivos como negativos. El rango de valores es de -128 a 127. uchar: El tipo entero uchar también ocupa 1 byte de memoria, así como el tipo char, pero a diferencia de uchar se destina sólo para valores positivos. El valor mínimo es cero, el valor máximo es 255. La primera letra u en el nombre del tipo uchar es la abreviatura de unsigned. El tamaño del tipo corto es 2 bytes (16 bits) y, en consecuencia, permite expresar el rango de valores igual a 2 a la potencia 16: 216 65 536. Dado que el tipo corto es un signo uno, y contiene ambos Positivos y negativos, el rango de valores está entre -32 768 y 32.767. Ushort: El tipo corto sin signo es el tipo ushort. Que también tiene un tamaño de 2 bytes. El valor mínimo es 0, el valor máximo es 65 535. int: El tamaño del tipo int es 4 bytes (32 bits). El valor mínimo es -2 147 483 648, el máximo es 2 147 483 647. uint: El tipo entero sin signo es uint. Toma 4 bytes de memoria y permite expresar enteros de 0 a 4 294 967 295. long: El tamaño del tipo largo es de 8 bytes (64 bits). El valor mínimo es -9 223 372 036 854 775 808, el valor máximo es 9 223 372 036 854 775 807. ulong: El tipo ulong también ocupa 8 bytes y puede almacenar valores de 0 a 18 446 744 073 709 551 615. Desde La descripción anterior de los diversos tipos de datos, los tipos enteros sin signo no están diseñados para almacenar valores negativos, cualquier intento de establecer un valor negativo puede dar lugar a consecuencias inesperadas. Por ejemplo, si desea almacenar valores negativos, no puede almacenarlos dentro de los tipos sin signo (por ejemplo, uchar, uint, ushort, ulong). Volver a nuestro EA. En cuanto a los tipos de datos, estarás de acuerdo conmigo que se supone que debemos usar tipos de datos char o uchar ya que los datos que pretendemos almacenar en estos parámetros son menores que 127 o 255 respectivamente. Para una buena gestión de la memoria, esta es la mejor cosa que hacer. Sin embargo, por el bien de nuestra discusión, todavía se pegarán al tipo del int. Una vez que haya terminado de configurar todos los parámetros necesarios, haga clic en el botón Finished y el Editor de MetaQuotes creará el esqueleto del código para usted como se muestra en la siguiente figura. Permite romper el código en las diversas secciones para una mejor comprensión. La parte superior (encabezado) del código es donde se define la propiedad de la EA. En esta sección del código, puede definir parámetros adicionales como la descripción (breve descripción de texto del EA), declarar constantes, incluir archivos adicionales o importar funciones . Cuando una sentencia comienza con un símbolo, se denomina directiva de preprocesador y no termina con un punto y coma otro ejemplo de directivas de preprocesador incluye: La directiva define se utiliza para una declaración de constantes. Se escribe en la forma define identifier tokenstring Lo que esto hace es sustituir cada ocurrencia de identificador en su código con el valor tokenstring. Define ABC 100 define COMPANYNAME MetaQuotes Software Corp. reemplazará cada ocurrencia de COMPANYNAME con la cadena MetaQuotes Software Corp. o reemplazará cada ocurrencia de ABC con el carácter (o entero) 100 en su código. Puede leer más acerca de las directivas de preprocesador en el manual MQL5. Continuemos con nuestra discusión. La segunda parte del encabezado de nuestro código es la sección de parámetros de entrada: especificamos todos los parámetros, que se utilizarán en nuestro EA en esta sección. Estas incluyen todas las variables que serán utilizadas por todas las funciones que estaremos escribiendo en nuestra EA. Las variables declaradas en este nivel se denominan variables globales porque son accesibles para todas las funciones de nuestra EA que pueden necesitarlas. Los parámetros de entrada son parámetros que sólo se pueden cambiar fuera de nuestro EA. También podemos declarar otras variables que manipularemos en el curso de nuestra EA, pero que no estarán disponibles fuera de nuestra EA en esta sección. A continuación se muestra la función de inicialización de EA. Esta es la primera función que se llama cuando el EA se inicia o se adjunta a un gráfico y se llama sólo una vez. Esta sección es el mejor lugar para hacer algunos cheques importantes para asegurarnos de que nuestra EA funcione muy bien. Podemos decidir si el gráfico tiene bastantes barras para que nuestra EA funcione, etc. También es el mejor lugar para obtener los identificadores que usaremos para nuestros indicadores (ADX y indicadores de media móvil). Para nuestro EA, liberaremos las asas creadas para nuestros Indicadores durante la inicialización en esta sección. Esta función procesa el evento NewTick. Que se genera cuando se recibe una nueva cotización para un símbolo. Tenga en cuenta que el Asesor experto no puede realizar operaciones comerciales si no se permite el uso de Asesores expertos en el terminal de clientes (Button Auto Trading). Figura 6. Autotrading está habilitado La mayoría de nuestros códigos que implementarán nuestra estrategia de trading, desarrollada anteriormente, se escribirán en esta sección. Ahora que hemos mirado las varias secciones del código para nuestro EA, comencemos agregando la carne al esqueleto. 2.2 SECCIÓN DE PARÁMETROS DE ENTRADA Como puede ver, hemos añadido más parámetros. Antes de continuar discutiendo los nuevos parámetros, discutamos algo que puedes ver ahora. Las dos barras diagonales // nos permite poner comentarios en nuestros códigos. With comments, we are able to know what our variables stand for, or what we are doing at that point in time in our code. It also gives a better understanding of our code. There are two basic ways of writing comments: This is a single line comment This is a multi-line comment This is a multi-line comment. Multi-line comments start with the / pair of symbols and end with the / one. The compiler ignores all comments when compiling your code. Using single-line comments for the input parameters is a good way of making our EA users understand what those parameters stands for. On the EA Input properties, our users will not see the parameter itself, but instead they will see the comments as shown below: Figure 7. Expert Advisor input parameters Now, back to our code We have decided to add additional parameters for our EA. The EAMagic is the magic number for all orders by our EA. The minimum ADX value ( AdxMin ) is declared as a double data type. A double is used to store floating point constants, which contain an integer part, a decimal point, and a fraction part. double mysum 123.5678 double b7 0.09876 The Lot to trade ( Lot ) represents the volume of the financial instrument we want to trade. Then we declared other parameters that we will be using: The adxHandle is to be used for storing the ADX indicator handle, while the maHandle will store the handle for the Moving Average indicator. The plsDI, minDI, adxVal are dynamic arrays that will hold the values of DI, - DI and main ADX (of the ADX Indicator) for each bar on the chart. The maVal is a dynamic array that will hold the values of the Moving Average indicator for each bar on the chart. By the way, what are dynamic arrays A dynamic array is an array declared without a dimension. In other words, no value is specified in the pair of square brackets. A static array, on the other hand has its dimensions defined at the point of declaration. double allbars 20 // this will take 20 elements pclose is a variable we will use to store the Close price for the bar we are going to monitor for checking of our Buy/Sell trades. STP and TKP are going to be used to store the Stop Loss and the Take Profit values in our EA. 2.3. EA INTIALIZATION SECTION Here we obtain the handles of our indicator using the respective indicator functions. The ADX indicator handle is obtained by using the iADX function. It takes the chart symbol ( NULL also means the current symbol on the current chart), the chart period/timeframe ( 0 also means the current timeframe on the current chart), the ADX averaging period for calculating the index (which we defined earlier under input parameters section) as parameters or arguments. int iADX ( string symbol , // symbol name ENUMTIMEFRAMES period , // period int adxperiod // averaging period ) The Moving Average indicator handle is obtained by using the iMA function. It has the following arguments: the chart symbol (which can be obtained using symbol . symbol() or NULL for the current symbol on the current chart), the chart period/timeframe (which can be obtained using period . period() . or 0 for the current timeframe on the current chart), the Moving Average averaging period (which we defined earlier under input parameters section), the shift of the indicator relative to the price chart (shift here is 0 ), the Moving average smoothing type (could be any of following averaging methods: Simple Averaging-MODESMA, Exponential Averaging-MODEEMA, Smoothed Averaging-MODESMMA or Linear-Weighted Averaging-MODELWMA ), and the price used for the averaging (here we use the close price). int iMA ( string symbol . // symbol name ENUMTIMEFRAMES period . // period int maperiod . // averaging period int mashift . // horizontal shift ENUMMAMETHOD mamethod . // smoothing type ENUMAPPLIEDPRICE appliedprice // type of price or handle ) Please read the MQL5 manual to get more details about these indicator functions. It will give you a better understanding of how to use each indicator. We again try to check for any error in case the function did not successfully return the handle, we will get an INVALIDHANDLE error. We use the alert function to display the error using the GetlastError function. We decides to store the Stop Loss and the Take Profit values in the variables STP and TKP we declared earlier. Why are we doing this Its because the values stored in the INPUT parameters are read-only, they cannot be modified. So here we want to make sure that our EA works very well with all brokers. Digits or Digits() r eturns the number of decimal digits determining the accuracy of price of the current chart symbol. For a 5-digit or 3-digit price chart, we multiply both the Stop Loss and the Take Profit by 10. 2.4. EA DEINTIALIZATION SECTION Since this function is called whenever the EA is disabled or removed from a chart, we will release all the indicators handles that were created during the initialization process here. We created two handles, one for ADX indicator and another handle for the Moving Average indicator. We will use the IndicatorRelease() function to accomplish this. It takes only one argument (the indicator handle ) bool IndicatorRelease ( int indicatorhandle . // indicator handle ) The function removes an indicator handle and release the calculation block of the indicator, if its not been used. 2.5 THE EA ONTICK SECTION The first thing we have to do here is to check if we have enough bars on the present chart. We can get the total bars in history of any chart using the Bars function. It takes two parameters, the symbol (can be obtained using Symbol or Symbol(). These two return the current symbol for the current chart on which our EA is attached) and the period or timeframe of the present chart (can be obtained using Period or Period() . This two will return the timeframe of the current chart on which the EA is attached). If the total available bars are less than 60, we want our EA to relax until we have enough bars available on the chart. The Alert function displays a message on a separate window. It takes any values separated by commas as parameters/arguments. In this case, we have only one string value. The return exits the initialization of our EA. The Expert Advisor will perform trade operations at the beginning of a new bar, so its necessary to solve the problem with the new bar identification. In order words, we want to be sure that our EA does not check for Long/Short setups on every tick, we only want our EA to check for Long/Short positions when there is a new bar. We begin by declaring a static datetime variable OldTime . which will store the Bar time. We declared it as static because we want the value to be retained in memory until the next call of the OnTick function. Then we will be able to compare its value with the NewTime variable (also of datetime data type), which is an array of one element to hold the new(current) bar time. We also declared a bool data type variable IsNewBar and sets its value to false . This is because we want its value to be TRUE only when we have a new bar. We use the CopyTime function to get the time of the current bar. It copies the bar time to the array NewTime with one element if it is successful, we compare the time of a new bar with the previous bar time. If the times arent equal, it means that we have a new bar, and we set the variable IsNewBar to TRUE and save the value of the current bar time to the variable OldTime . The IsNewBar variable indicates that we have a new bar. If its FALSE, we finish the execution of OnTick function. Take a look at the code it checks for the debug mode execution, it will print the message about the bar times when debug mode, we will consider it further. The next thing we want to do here is to check if we have enough bars to work with. Why repeat it We just want to be sure that our EA works correctly. It should be noted that while the OnInit function is called only once when the EA is attached to a chart, the OnTick function is called every time there is a new tick (price quote). You observe that we have done it again differently here. We decide to store the total bars in history which we obtained from the expression in a new variable, Mybars . declared within the OnTick function. This type of variable is a local variable, unlike the variable we declared at the INPUT PARAMETERS section of our code. While the variables, declared at the Input Parameters section of our code, are available to all functions, within our code that may need them, variables declared within a single function is limited and available to that function alone. It can not be used outside of that function. Next, we declared a few variables of MQL5 structure types which will be used in this section of our EA. MQL5 has quite a number of built in Structures which makes things pretty easy for EA developers. Lets take the Structures one after the other. This is a structure used for storing the latest prices of symbols. struct MqlTick datetime time // Time of the last prices update double bid // Current Bid price double ask // Current Ask price double last // Price of the last deal (Last) ulong volume // Volume for the current Last price Any variable declared to be of the MqlTick type can easily be used to obtain the current values of Ask, Bid, Last and Volume once you call the SymbolInfoTick() function. So we declared latestprice as a MqlTick type so that we could use it to get the Ask and Bid prices This structure is used to perform all trade requests for a trade operation. It contains, in its structure, all the fields necessary for performing a trade deal. struct MqlTradeRequest ENUMTRADEREQUESTACTIONS action // Trade operation type ulong magic // Expert Advisor ID (magic number) ulong order // Order ticket string symbol // Trade symbol double volume // Requested volume for a deal in lots double price // Price double stoplimit // StopLimit level of the order double sl // Stop Loss level of the order double tp // Take Profit level of the order ulong deviation // Maximal possible deviation from the requested price ENUMORDERTYPE type // Order type ENUMORDERTYPEFILLING typefilling // Order execution type ENUMORDERTYPETIME typetime // Order execution time datetime expiration // Order expiration time (for the orders of ORDERTIMESPECIFIED type) string comment // Order comment Any variable declared to be of the MqlTradeRequest type can be used to send orders for our trade operations. Here we declared mrequest as a MqlTradeRequest type. The result of any trade operation is returned as a special predefined structure of MqlTradeResult type. Any variable declared to be of MqlTradeResult type will be able to access the trade request results. struct MqlTradeResult uint retcode // Operation return code ulong deal // Deal ticket, if it is performed ulong order // Order ticket, if it is placed double volume // Deal volume, confirmed by broker double price // Deal price, confirmed by broker double bid // Current Bid price double ask // Current Ask price string comment // Broker comment to operation (by default it is filled by the operation description) The Price (Open, Close, High, Low), the Time, the Volumes of each bar and the spread for a symbol is stored in this structure. Any array declared to be of the MqlRates type can be used to store the price, volumes and spread history for a symbol. struct MqlRates datetime time // Period start time double open // Open price double high // The highest price of the period double low // The lowest price of the period double close // Close price long tickvolume // Tick volume int spread // Spread long realvolume // Trade volume Here we have declared an array mrate which will be used to store these information. Next we decide to set all the arrays we will be using to store Bars details as series. This is to ensure that the values that will be copied to the arrays will be indexed like the timeseries, that is, 0, 1, 2, 3, (to correspond with the bars index. So we use the ArraySetAsSeries() function. bool ArraySetAsSeries( void array . // array by reference bool set // true denotes reverse order of indexing ) It should be noted that this can also be done once at the initialization section of our code. However, I have decided to show it at this point for the sake of our explanation. We now use the SymbolInfoTick function to obtain the latest price quote. This function takes two arguments chart symbol and the MqlTick structure variable ( latestprice ). Again, if there is error, we reported it. Next we copied the information about the latest three bars into our Mqlrates type array using the CopyRates function. The CopyRates function is used to get history data of MqlRates structure of a specified Symbol-Period in specified quantity into a MqlRates type array. int CopyRates ( string symbolname . // symbol name ENUMTIMEFRAMES timeframe . // period int startpos . // start position int count . // data count to copy MqlRates ratesarray // target array to copy ) The symbol name is obtained by using symbol . the current period/timeframe is obtained by using period . For the start position, we will start from the current bar, Bar 0 and we will count only three Bars, Bars 0, 1, and 2 . The result will be store in our array, mrate. The mrate array now contains all the price, time, volumes and spread information for bars 0. 1 and 2. Therefore to get the details of any bar, we will use the following: for example, we can have the following information about each bar: mrate1.time // Bar 1 Start time mrate1.open // Bar 1 Open price mrate0.high // Bar 0 (current bar) high price, etc Next we, copied all the indicator values into the dynamic arrays we have declared using the CopyBuffer function. int CopyBuffer ( int indicatorhandle , // indicator handle int buffernum , // indicator buffer number int startpos , // start position int count , // amount to copy double buffer // target array to copy ) The indicator handle is the handle we created in the OnInit section. Concerning buffer numbers, the ADX indicator has three (3) buffers: The Moving Average indicator has only one (1) buffer: We copy from the present bar (0) to the past two bars. So amount of records to copy is 3 (bars 0, 1 and 2). The buffer is the target dynamic arrays we had earlier declared adxVal, plsDI, minDI and maVal. As you can see here again, we try to capture any error that may occur in the copying process. If there is error, no need to go further. It is important to note that the CopyBuffer() and the CopyRates() function returns the total number of records copied on success while it returns -1 incase of an error. That is why we are checking for a value less than 0 (zero) in the error checking functions here. At this point we want to check if we already have a Buy or Sell position opened, in order words, we want to make sure we have only ONE Sell or Buy trade opened at a time. We do not want to open a new Buy if we already have one, and we do not want to open a new Sell if we already have one opened. To achieve we will first of all declare two bool data type variables ( Buyopened and Sellopened ) which will hold a TRUE value if we already have a position opened for either Buy or Sell. We use the trade function PositionSelect to know if we have an open position. This function returns TRUE if we have a position opened already and FALSE if we have none. It takes, as the major argument/parameter, the symbol (currency pair) we want to check. Here, we use symbol because we are checking the current symbol(currency-pair). If this expression returns TRUE, then we want to check if the position opened is a Buy or a Sell. We use the PositionGetInteger function for this. it gives us the type of position opened when we use it with the POSITIONTYPE modifier. It returns the Position type identifier which can either be POSITIONTYPEBUY or POSITIONTYPESELL In our case, we used it to determine which of the position we already have opened. If it is a Sell, we store a TRUE value in Sellopened and if it is a Buy, we store a TRUE value in Buyopened . We will be able to use these two variables later when we are checking for Sell or Buy conditions later in our code. It is now time to store the close price for the bar we will be using for our Buy/Sell setup. Remember we declared a variable for that earlier Having done this, we will now proceed to the next step. It is now time to start checking for a Buy opportunity. Let us analyze the expression above as it represents the strategy we designed earlier. We are declaring a bool type variable for each of our conditions that must be met before an order can be placed. A bool type variable can only contain TRUE or FALSE. So, our Buy strategy has been broken down into four conditions. If any of the conditions is met or satisfied, then a value of TRUE is stored in our bool type variable, otherwise, a value of FALSE will be stored. Let us look at them one by one. Here we are looking at the MA-8 values on Bars 0, 1 and 2 . If value of MA-8 on the current bar is greater than its value on the previous Bar 1 and also the MA-8 value on Bar 1 is greater than its value on Bar 2 . it means that MA-8 is increasing upwards . This satisfies one of our conditions for a Buy setup. This expression is checking to see if Bar 1 Close price is higher than the value of MA-8 at the same period (Bar 1 period). If the price is higher, then our second condition has also been satisfied, then we can check for other conditions. However, if the two conditions we have just considered were not met, then there will be no need to check other conditions. That is why we decide to include the next expressions within these two initial conditions (expressions). Now we want to check if the current value of ADX (ADX value on Bar 0) is greater than the Minimum ADX value declared in the input parameters. If this expression is true, that is, the current value of ADX is greater than the Minimum required value we also want to be sure that the plusDI value is greater than the minusDI value. This is what we achieved in the next expression If all these conditions are met, that is, if they return true, then we want to be sure that we do not open a new Buy position if we already have one. It is now time to check the value of the Buyopened variable we declared earlier in our code. If Buyopened is true, we do not want to open another Buy position, so, we display an alert to inform us and then return so that our EA will now wait for the next Tick. However, if Buyopened is FALSE, then we prepare our records using the MqlTradeRequest type variable ( mrequest ) which we declared earlier to send our order. The action here, which is the trade operation type, is TRADEACTIONDEAL because we are placing a trade order for an immediate execution. If we are modifying an order, then we will use TRADEACTIONMODIFY . To delete an order we will use TRADEACTIONREMOVE. We used our MqlTick type latestprice to get the latest Ask price . The order Stop loss price is obtained by subtracting our StopLoss in points from the Ask price while the order take profit price is obtained by adding our TakeProfit in points to the Ask price. You will also observe that we used the NormalizeDouble function for the Ask price, the StopLoss and TakeProfit values, it is good practice to always normalize these prices to the number of digits of currency pair before sending it to the trade server. The symbol is the current symbol (Symbol or Symbol() ). The order type is the type of order we are placing, here we are placing a buy order ORDERTYPEBUY . For a Sell order, it will be ORDERTYPESELL . The order typefilling is the order execution type ORDERFILLINGFOK means that the deal can be executed exclusively with a specified volume at the equal or better price than the order specified price. If there is no sufficient volume of offers on the order symbol, the order will not be executed. The OrderSend() function takes two arguments, the MqlTradeRequest type variable and the MqlTradeResult type variable. As you can see, we used our MqlTradeRequest type variable and the MqlTradeResult type variable in placing our order using OrderSend. Having sent our order, we will now use the MqlTradeResult type variable to check the result of our order. If our order is executed successfully, we want to be informed, and if not, we want to know too. With the MqlTradeResult type variable mresult we can access the Operation return code and also the order ticket number if the order is placed. The return code 10009 shows that the OrderSend request was completed successfully, while 10008 shows that our order has been placed. That is why we have checked for any of these two return codes. If we have any of them, we are sure that our order has been completed or it has been placed. To check for a Sell Opportunity, we check for the opposite of what we did for Buy Opportunity except for our ADX that must be greater than the Minimum value specified. Just as we did in the buy section, we are declaring a bool type variable for each of our conditions that must be met before an order can be placed. A bool type variable can only contain TRUE or FALSE. So, our Sell strategy has been broken down into four conditions. If any of the conditions is met or satisfied, then a value of TRUE is stored in our bool type variable, otherwise, a value of FALSE will be stored. Let us look at them one by one as we did for the Buy section Here we are looking at the MA-8 values on Bars 0, 1 and 2 . If value of MA-8 on the current bar is less than its value on the previous Bar 1 and also the MA-8 value on Bar 1 is less than its value on Bar 2 . it means that MA-8 is decreasing downwards . This satisfies one of our conditions for a Sell setup. This expression is checking to see if Bar 1 Close price is lower than the value of MA-8 at the same period (Bar 1 period). If the price is lower, then our second condition has also been satisfied, then we can check for other conditions. However, if the two conditions we have just considered were not met, then there will be no need to check other conditions. That is why we decide to include the next expressions within these two initial conditions (expressions). Now we want to check if the current value of ADX (ADX value on Bar 0) is greater than the Minimum ADX value declared in the input parameters. If this expression is true, that is, the current value of ADX is greater than the Minimum required value we also want to be sure that the MinusDI value is greater than the plusDI value. This is what we achieved in the next expression If these conditions are met, that is, if they return true, then we want to be sure that we do not open a new Buy position if we already have one. It is now time to check the value of the Buyopened variable we declared earlier in our code. If Sellopened is true, we do not want to open another Sell position, so, we display an alert to inform us and then return so that our EA will now wait for the next Tick. However, if Sellopened is FALSE, then we setup our Sell trade request as we did for Buying order. The major difference here is the way we calculated our stop loss price and take profit price. Also since we are selling, we sell at the Bid price that is why we used our MqlTick type variable latestprice to get the latest bid price. The other type here, as explained earlier, is ORDERTYPESELL. Also here, we used the NormalizeDouble function for the Bid price, the StopLoss and TakeProfit values, it is good practice to always normalize these prices to the number of digits of currency pair before sending it to the trade server. Just as we did for our Buy order, we must also check if our Sell order is successful or not. So we used the same expression as in our Buy order. 3. Debugging and Testing our Expert Advisor At this point, we need to test our EA to know it our strategy works or not. Also, it is possible that there are one or two errors in our EA code. This will be discovered in the next step. Debugging our code helps us to see how our code performs line by line (if we set breakpoints) and there and then we can notice any error or bug in our code and quickly make the necessary corrections before using our code in real trade. Here, we are going to go through the step by step process of debugging our Expert Advisor, first of all, by setting breakpoints and secondly, without breakpoints. To do this, Make sure you have not closed the Editor. First of all, let us select the chart we want to use to test our EA. On the Editor Menu bar, click on Tools and click on Options as shown below: Figure 8. Setting Debugging options Once the Options window appears, select the currency pair, and the period/timeframe to use and click the OK button: Before we start the debugger, let us set breakpoints. Breakpoints allow us to monitor the behavior/performance of our code at certain selected locations or lines. Rather than running through all the code at once, the debugger will stop whenever it see a breakpoint, waiting for your net action. By this we will be able to analyze our code and monitor its behavior as it reaches every set break-points. We will also be able to evaluate the values of some of our variables to see if things are actually the way we envisaged. To insert a breakpoint, go to the line in your code where you want to set the breakpoint. By the left hand side, on the gray field near the border of the code line, double-click and you will see a small round blue button with a white square inside it. Or on the alternative, place the cursor of your mouse anywhere on the code line where you want the breakpoint to appear and press F9 . To remove the breakpoint, press F9 again or double-click on it. Figure 10. Setting a breakpoint For our code, we are going to set breakpoint on five different lines. I will also label them form 1 to 5 for the sake of explanation. To continue, set breakpoint at the seven code lines as shown in the figure below. Breakpoint 1 is the one we have created above. Figure 11. Setting additional breakpoints Once we have finished setting our breakpoints, we are now set to start debugging our code. To start the debugger, press F5 or click the green button on the Toolbar of the MetaEditor: Figure 12. Starting the Debugger The first thing the editor does is to compile the code, if there is any error at the point, it will display it and if no error, it will let you know that the code compiled successfully. Figure 13. Compilation Report Please note that the fact that the code compiled successfully does not mean there may not be errors in your code. Depending on how your code is written, there may be runtime errors. For example, if any of our expressions does not evaluate correctly due to any little oversight, the code will compile correctly but may not run correctly. Too much of the talk, lets see it in action Once the debugger has finished compiling the code, it takes you to the trading terminal, and attach the EA to the chart you have specified on the MetaEditor Options settings. At the same time, it shows you the Input parameters section of the EA. Since we are not adjusting anything yet, just click the OK button. Figure 14. Expert Advisor Input Parameters for Debugging You will now see the EA clearly on the top-right hand corner of the chart. Once it starts the OnTick() . it will stop as soon as it gets to our breakpoint 1. Figure 15. Debugger stops at the first breakpoint You will notice a green arrow at that code line. That tells you that previous code line had been executed we are now ready to execute the present line. Let me make some explanations before we proceed. If you look at the Editors Tool Bar, you will observe that the three buttons with curved arrows which were earlier grayed out are now activated. This is because we are now running the debugger. These buttons/commands are used to step through our code (Step into, Step over or Step out) Figure 16. Step into command The Step Into is used to go from one step of the program execution into the next step, entering into any called functions within that code line. Click on the button or press F11 to invoke the command. (We will use this command in our Step-by-Step debugging of our code.) Figure 17. Step over command The Step over . on the other hand does not enter into any called function within that code line. Click on the button or press F10 to invoke the command Figure 18. Step out command To execute a program step that is one level higher, you click this button or press ShiftF11 . Also, at the lower part of the Editor, you will see the Toolbox window . The Debug tab in this window has the following headings: File : This displays the name of the file been called Function : This displays the present function from the file been called Line : This displays the number of the code line in the file from which the function is called. Expression : This is where you can type the name of any expression/variable you are interested in monitoring from our code. Value : This will display the value of the expression/variable we typed at the Expression area. Type : This will display the data type of the expression/variable been monitored. Back to our debugging process The next thing we want to do is now to type in the variables/expressions from our code that we are interested in monitoring. Make sure you only monitor the variables/expressions that really matters in your code. For our example, we will monitor the following: OldTime (old bar time) NewTime0 (current bar time) IsNewBar (flag that indicates the new bar) Mybars (Total bars in History) Our EA depends on it You can add other ones like the ADX values, the MA-8 values, etc. To add the expression/variable, double-click under the Expressions area or right-click under the Expressions area and select Add as shown in the figure above. Type the expression/variable to monitor or watch. Figure 19. The expressions watching window Type all the necessary variables/expressions Figure 20. Adding expressions or variables to watch If the variable hasnt been declared yet, its type is Unknown identifier (except the static variables). Now, lets move on Figure 21. Step into command in action Click the Step into button or press F11 and observe what happens. Keep on pressing this button or F11 until you get to breakpoint no 2 . continue until you get to breakpoint no 4 as shown below and observe the expressions watching window. Figure 22. Watching the expressions or variables Figure 23. Watching the expressions or variables Figure 24. Watching the expressions or variables Once there is a new tick, it will return to the fist code line of the OnTick() function. And all the values of our variables/expression will now be reset because this is a new tick except if any of them is declared as a static variable. In our case we have one static variable OldTime. Figure 25. Values of variables on NewTick event To go over the process again, continue pressing the F11 key and keep monitoring the variables at the expressions watching window. You can stop the debugger and then remove all the breakpoints. As we see, in Debug mode it prints the message We have new bar here. . Figure 26. Expert Advisor prints the message in Debug mode Start the debugging process again but this time without breakpoints. Keep watching at every tick and if any of our Buy/Sell condition is met, it will place a trade and since we have written our code to tell us if an order is placed successful or otherwise, we will see an alert. Figure 27. Expert Advisor places trade during debugging I think you can leave the EA to work for a few more minutes while you take a coffee. Once you are back and you have made some money ( just kidding ), then click the STOP (Red) button on the MetaEditor to stop debugging. Figure 28. Stopping the debugger What we have actually done here is to see that our EA only checks for a trade at the opening of a new Bar and that our EA actually works. There is still a lot of room for adjustments to our EA code. Let me make it clear, at this point that, the Trading terminal must be connected to the internet, otherwise, debugging will not work because the terminal will not be able to trade. 3.2 TESTING OUR EA STRATEGY At this point we now want to test our EA using the Strategy Tester built into the Trading Terminal. To start the Strategy Tester, press CONTROLR or click the View menu on the Terminal Menu Bar and click on Strategy Tester as shown below Figure 26. Starting the Strategy Testing The Tester (Strategy Tester) is shown at the lower part of the terminal. For you to see all the Testers settings, you need to expand/resize it. To do this, move your mouse pointer to the point shown by the red arrow (as shown below) Figure 27. The Strategy Tester window The mouse pointer changes to a double-end arrow, hold down the mouse and drag the line upwards. Stop when you discover that you can see everything on the settings tab. Figure 28. The Strategy Tester Settings Tab Select the EA you want to test Select the Currency pair to use for the test Select the Period/Timeframe to use for the test Select Custom Period and set the dates in 5 Set the dates for the custom period to be used for the test Execution is Normal Select the deposit amount in USD to be used for the test Set Optimization to Disable (We are not optimizing now, we just want to test) Click this button when you are ready to start test. Before we click the Start button, lets look at the other tabs on the Tester The processor used by the Tester for the Test. Depending on your Computers processor type. Mine is only one (1) core processor. Figure 29. The Strategy Tester Agents tab Once the agent, you will see something similar to the figure below Figure 30. The Strategy Tester Agents tab during a test This is where all the events going on during the test period is displayed Figure 31. The Strategy Tester Journal tab showing trade activities This is where you can specify the input parameters for the EA. Figure 32. The Strategy Tester Inputs tab If we are optimizing our EA, then we will need to set the values in the circled area. The Start is the values you want the Tester to begin with. The Step is the increment rate for the value you selected, and The Stop is the value at which the Tester will stop incrementing the value for that parameter. However, in our case we are not optimizing our EA, so we will not need to touch that for now. Once everything is set, we now go back to the Settings tab and click the Start button. Then the tester begins its work. All you need to do now is to go and take another cup of coffee if you like, or, if you are like me, you may want to monitor every event, then turn to the Journal tab. Once you begin to see messages about orders been sent on the Journal Tab, you may then wish to turn to a NEW tab named Graph which has just been created. Once you switch to the Graph tab, you will see the graph keep on increasing or decreasing as the case may be depending on the outcome of your trades. Figure 33. The graph result for the Expert Advisor Test Once the test is completed, you will see another tab called Results . Switch to the Results tab and you will see the summary of the test we have just carried out. Figure 34. The Strategy Tester Results tab showing test results summary You can see the total Gross Profit, Net Profit, total trades total loss trades and many more. Its really interesting to see that we have about USD 1,450.0 within the period we selected for our test. At least we have some profit. Let me make something very clear to you here. You will discover that the settings for the EA parameters that you see in the Strategy tester is different from the initial settings in the Input parameters of the EA. I have just demonstrated to you that you can change any of those input parameters to get the best out of your EA. Instead of using a period of 8 each for the Moving Average and ADX, I changed it to 10 for Moving Average and 14 for ADX. I also change the Stop Loss from 30 to 35. Last but not the least, I decided to use 2 Hour timeframe. Remember, this is the Strategy Tester. If you want to view a complete report of the test, then right-click on anywhere in the Results tab, you will see a menu. From this menu, Select Save as Report . Figure 35. Saving the result of the test The save dialog window will appear, type a name for your report (if you want, otherwise leave the default name) and click the save button. The whole report will be saved in HTML format for you. To view the chart for the test that was carried out, click Open Chart and you will see the chart displayed Figure 36. The chart showing the test Thats it, we have successfully written and tested our EA and we now have a result to work with. You can now go back to the strategy tester Settings tab and make the test for other Timeframes/Period. I want you to carry out the test using different currency pairs, different timeframes, different Stop Loss, different Take profit and see how the EA performs. You can even try new Moving Average and ADX values. As I said earlier, that is the essence of the Strategy tester. I will also like you to share your results with me. Conclusion In this step by step guide, we have been able to look at the basic steps required in writing a simple Expert Advisor based on a developed trading strategy. We have also looked at how we check our EA for errors using the debugger. We also discussed how to test the performance of our EA using the Strategy Tester. With this, we have been able to see the power and robustness of the new MQL5 language. Our EA is not yet perfect or complete as many more adjustments must still be made in order to used it for real trading. There is still more to learn and I want you to read the article over again together with the MQL5 manual, and try everything you have learn in this article, I can assure you that you will be a great EA developer in no distant future.
No comments:
Post a Comment