Está en la página 1de 43

Artículos Entrada Crear una cuenta

Create a paid channel Share important information


with subscribers in an invite­ LEARN MORE
in Chats only community

MetaTrader 5

Ejemplos

Indicadores
Guía paso a paso para escribir un Expert
Asesores Expertos Advisor en MQL5 para principiantes
Probador
MetaTrader 5 — Sistemas comerciales | 17 diciembre 2013, 15:49
Trading
42 076 9
Sistemas comerciales

Integración

Indicadores
Samuel Olowoyo
Asesores Expertos Introducción

Aprendizaje automático Este artículo está dirigido a los principiantes que quieren aprender
a escribir Expert Advisors sencillos en el nuevo lenguaje MQL5. En
Estadística y análisis primer lugar, vamos a definir lo que se requiere de nuestro EA (de
sus siglas en inglés, Expert Advisor), y luego a cómo queremos que
lo haga.
Entrevista

MetaTrader 4
1. Estrategia de trading
Ejemplos
Lo que va hacer nuestro EA:
Indicadores
Hará el seguimiento de un indicador concreto, y cuando se
cumpla una determinada condición (o condiciones), hará una
Asesores Expertos operación de trading (ya sea de Compra/Corto o
Venta/Largo), dependiendo de la condición que se haya
Probador cumplido.
Trading A esto se le conoce como estrategia de trading. Antes de que
puedas escribir un EA, debes primero desarrollar la estrategia que
Sistemas comerciales quieres automatizar en un EA. Así que vamos a modificar, en este
caso, la afirmación anterior para que refleje la estrategia que
Integración queremos desarrollar en un EA.

Indicadores Usaremos el indicador de Promedio Móvil "Moving Average",


con un período 8 (puedes elegir cualquier período, pero para
Asesores Expertos el propósito de nuestra estrategia, usaremos 8).

Estadística y análisis Queremos que nuestro EA haga una operación de trading


Larga (Compra) "Long (Buy)" cuando el Moving Average‐8 (que
llamaremos MA‐8, para simplificar) aumenta al alza y el
¿Le ha gustado el artículo? precio de cierre está por encima de él, y que haga una
operación de trading Corta (Venta ) "Short (Sell)" cuando el
Ponga el enlace al artículo —
MA‐8 cae decreciendo y el precio de cierre está por debajo
que los demás también lo lean de él.
Utilizaremos también otro indicador llamado Índice de
Utilice nuevas posibilidades de Movimiento Direccional Medio "Average Directional
Esta página
MetaTrader 5 utiliza cookies. Aprenda más sobre ellas en nuestra Política sobre Cookies.
Movement Index" (ADX) con un período 8 también para
ayudarnos a determinar si hay una tendencia en el mercado.
Hacemos esto, porque lo único que queremos es realizar
transacciones cuando haya una tendencia en el mercado, y
relajarnos cuando el mercado está sin tendencia. Para
conseguirlo, sólo tendremos que poner nuestra transacción
(Compra o Venta) cuando se cumplan las condiciones
mencionadas anteriormente y el que valor de ADX sea
superior a 22. Si ADX es superior a 22 pero decreciendo, o
ADX es inferior a 22, no haremos transacciones, aunque se
haya cumplido la condición B.
Además, queremos protegernos y minimizar las perdidas,
estableciendo Stop Loss a 30 puntos, y para nuestro objetivo
de beneficios, ponemos Take Profit a 100 puntos.
We have updated Queremos también que nuestro EA busque oportunidades de
MQL5.com Chats! Compra/Venta únicamente cuando se forma una nueva barra,
además de asegurarnos de abrir una posición de Compra si se
Find out what's new cumplen las condiciones de Compra y que no hayan
posiciones abiertas, y abrir una posición de Venta si se
cumplen las condiciones de Venta y que hayan posiciones
abiertas.

Nuestra estrategia ya está desarrollada, ahora es el momento de


empezar a escribir nuestro código.

LEARN MORE
2. Escribir un Expert Advisor

Artículos similares 2.1 MQL5 Wizard (asistente)


Empieza con la ejecución de MetaQuotes Language Editor 5. A
Redes neuronales: así de continuación presiona Ctrl+N o haz clic en el botón Nuevo en la
sencillo (Parte 46): Aprendizaje barra de del menú
por refuerzo dirigido a
objetivos (GCRL)

Iniciamos MetaTrader VPS por


primera vez: instrucciones paso
a paso

Estrategia comercial de
reversión a la media simple

Redes neuronales: así de


sencillo (Parte 45): Entrenando
habilidades de exploración de
estados

Desarrollando un canal de
Donchian personalizado con la
ayuda de MQL5

Figura 1. Crear un nuevo documento MQL5

En la ventana de MQL5 Wizard, selecciona Expert Advisor y haz clic


en "Siguiente" como se muestra en la Fig.2:
Figura 2. Selección del tipo de programa

En la siguiente ventana, escribe el nombre que quieres dar a tu EA


en el campo Nombre. En este caso, he puesto My_First_EA. A
continuación escribe tu nombre en el campo Autor, así que la
dirección de tu sitio web o correo electrónico en el campo Enlace
(si la tienes).

Figura 3. Propiedades generales del Expert Advisor

Puesto que queremos poder cambiar algunos de los parámetros de


nuestro EA, con el objetivo de saber cuál es el valor que nos puede
dar el mejor resultado, los vamos a añadir haciendo clic en el
botón "Añadir".
Figura 4. Ajustes de los parámetros de entrada de EA

En nuestro EA, queremos poder hacer pruebas con nuestro ajustes


de Stop Loss, Take Profit, Período de ADX y Período de Moving
Average, por ello los vamos a definir en este punto.
Haz un doble clic en la columna Nombre y escribe el nombre del
parámetro, a continuación, haz un doble clic sobre el Tipo para
elegir el tipo de datos del parámetro, y luego haz doble clic sobre
la columna del Valor inicial y escribe el valor inicial del parámetro.
Una vez hayas terminado, deberías ver algo como esto:

Figura 5. Parámetros de entrada de los tipos de datos del EA

Como puedes ver más arriba, he seleccionado datos de tipo entero


(int) para todos los parámetros. Hablemos un poco sobre los tipos
de datos.

char: El tipo char ocupa 1 byte de memoria (8 bits) y permite


expresar en notación binaria 2^8=256 valores. El tipo char
puede tener valores positivos y negativos. Sus valores están
entre ‐128 y 127.
uchar : El tipo entero uchar ocupa también 1 byte de
memoria, igual que el tipo char, pero a diferencia de este,
uchar está destinado únicamente a los 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.
short: El tamaño del tipo short es de 2 bytes (16 bits) y, por
consiguiente, permite expresar un rango de valores igual a 2
elevado a 16: 2^16 = 65 536. Dado que el tipo short tiene
signo, y puede tener valores positivos y negativos, tiene un
rango de valores entre ‐32 768 y 32 767.
ushort: El tipo short 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 de 4 bytes (32 bits). El valor
mínimo es ‐2 147 483 648 y el máximo es 2 147 483 647.
uint: El tipo entero sin signo es el uint. Ocupa 4 bytes de
memoria y permite expresar enteros desde 0 hasta 4 294 967
295.
long: El tamaño del tipo long 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 desde 0 hasta 18 446 744 073 709 551 615.

Como puede verse en la descripción de los distintos tipos de


datos, los tipos enteros sin signo no están diseñados para
almacenar valores negativos, cualquier intento de asignarles
valores negativos puede llevar a unos resultados impredecibles. Si
quieres almacenar valores negativos, no lo puedes hacer en los
tipos sin signo (es decir, uchar, uint, ushort, ulong).
Volvamos a nuestro EA. Con respeto a los tipos de datos, estarás de
acuerdo conmigo que se supone que tenemos que utilizar los tipos
de datos char o uchar, ya que los datos que pretendemos
almacenar en ellos son inferiores a 127 y 255 respectivamente. Para
una buena administración de la memoria, es la mejor opción. Pero
aún así, por conveniencia, escogeremos el tipo int.
Un vez hayas terminado de configurar todos los parámetros
necesarios, pulsa el botón Finalizar, y MetaQuotes Editor te va a
generar la estructura del código, como se muestra en la siguiente
figura.
Para una mejor comprensión, vamos a dividir el código en
diferentes secciones.
En la parte superior del código (encabezado) están definidas las
propiedades del EA. Como puedes ver, estos son los valores que se
especificaron en el MQL5 Wizard en la figura 3.
En esta sección del código, puedes especificar parámetros
adicionales, como description (una breve descripción del EA),
declarar constantes, incluir archivos adicionales o importar
funciones.

Cuando una declaración empieza con el símbolo #, se le llama


directiva de preprocesador y no acaba con punto y coma ‘;’ a
continuación, otro ejemplo de directivas de preprocesador:
#define :
La directiva #define se usa para la declaración de constantes. Se
escribe así
#define identifier token_string
Lo que hace es remplazar identifier cada vez que aparece en tu
código por el valor de token_string.
Ejemplo:

#define ABC 100


#define COMPANY_NAME "MetaQuotes Software Corp."

Se reemplazará cada aparición de COMPANY_NAME con la


cadena "MetaQuotes Software Corp." o reemplazará cada aparición
de ABC por el char (o entero) 100 en tu código.
Puedes encontrar más detalles sobre las directivas de
preprocesador en el Manual de MQL5. Vamos a seguir.
La segunda parte del encabezado de nuestro código es la sección
parámetros de entrada:

En esta sección, especificamos todos parámetros que usaremos en


nuestro EA. Esto incluye todas las variables que van a ser utilizadas
por todas las funciones que escribiremos en nuestro EA.
Las variables declaradas en este nivel se llaman Variables globales
ya que están disponibles para cualquier función que los pueda
requerir en nuestro EA. Los parámetros de entrada son parámetros
que se pueden cambiar únicamente fuera de nuestro EA. También
podemos declarar otras variables, que manejaremos a lo largo de
nuestro EA, pero en esta sección no van a estar disponibles fuera
de nuestro EA.
Lo siguiente es la función de inicialización del EA. Es la primera
función a la que se llama cuando se ejecuta nuestro EA o se vincula
a un gráfico, y se le llama una sola vez.

Esta sección es el mejor sitio para hacer algunas comprobaciones


importantes para asegurarnos de que nuestro EA funciona muy
bien.
Podemos comprobar si hay suficientes barras para que nuestro EA
funcione, etc.
Representa también el mejor sitio para obtener los identificadores
que usaremos con nuestros indicadores (indicadores ADX y Moving
Average).

Se llama a la función OnDeinit cuando se elimina el EA del gráfico.


Para nuestro EA, lanzaremos los identificadores creados 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.
Ten en cuenta, que el Expert Advisor no puede realizar operaciones
de trading si no está autorizado el uso del Expert Advisor en el
terminal del cliente (Botón "Auto Trading").

Figura 6. El trading automático está puesto en marcha


Figura 6. El trading automático está puesto en marcha

En esta sección, se va a escribir la mayor parte de nuestros códigos


que va a implementar nuestra estrategia de trading, desarrollada
anteriormente.
Ahora que hemos visto las diferentes secciones del código de
nuestro EA, vamos a empezar a afinar los detalles de la estructura.
2.2 SECCIÓN DE LOS PARÁMETROS DE ENTRADA

//­­­ parámetros de entrada


input int StopLoss=30; // Stop Loss
input int TakeProfit=100; // Take Profit
input int ADX_Period=8; // Período ADX
input int MA_Period=8; // Período Moving Avera
input int EA_Magic=12345; // Magic Number EA
input double Adx_Min=22.0; // El valor mínimo de A
input double Lot=0.1; // Lotes de trading
//­­­ Otros parámetros
int adxHandle; // identificador para nuestro indicador A
int maHandle; // identificador para nuestro indicador M
double plsDI[],minDI[],adxVal[]; // Arrays dinámicos par
double maVal[]; // Array dinámico para guardar los valor
double p_close; // Variable para almacenar el valor de l
int STP, TKP; // A utilizar con los valores de Stop Lo

Como puedes ver, hemos añadido más parámetros. Antes de seguir


hablando sobre los nuevos parámetros, vamos a comentar algo que
se ve ya en el código. Las dos barras inclinadas ‘//’ nos permiten
poner comentarios en nuestros códigos. Con los comentarios,
podemos saber lo que representan nuestras variables, o que
estamos haciendo en este instante concreto en nuestro código.
Además, nos ofrece una mejor comprensión de nuestro código. Hay
dos maneras básicas de escribir comentarios:

// Otros parámetros …

Es un comentario de una sola línea

/*

Es un comentario de varias líneas

*/

Es un comentario de varias líneas. Los comentarios de varias líneas


empiezan con los símbolos /* y se acaban con */.
El compilador ignora todos los comentarios cuando compila tu
código.
La utilización de comentarios de una sola línea, para los
parámetros de entrada es una buena opción para que nuestros
usuarios de EA puedan entender lo que representan estos
parámetros. En las propiedades de entrada de EA, nuestros usuarios
no podrán ver el parámetro en sí, pero en su lugar, podrán ver los
comentarios, tal como se muestran a continuación:
Figura 7. Parámetros de entrada del Expert Advisor

Volvamos a nuestro código...


Hemos decidido añadir más parámetros EA. EA_Magic es el número
mágico "magic number" para todos los pedidos de nuestro EA. El
valor mínimo de ADX (Adx_Min) se declara como dato de tipo
double. El double se utiliza para almacenar constantes de punto
flotante, formadas por una parte entera, un punto decimal y una
parte fraccionaria.
Ejemplo:

double mysum = 123.5678;

double b7 = 0.09876;

El lote de trading "Lot to trade" (Lot) representa el volumen del


instrumento financiero que queremos para el trading. A
continuación hemos declarado otros parámetros que utilizaremos:
adxHandle se usará para almacenar el identificador del indicador
ADX, mientras maHandle se usará para almacenar el identificador
del indicador Moving Average. Los parámetros plsDI[], minDI[],
adxVal[] son arrays dinámicos que van a almacenar los valores de
+DI, ‐DI y el ADX principal (del indicador ADX) para cada barra en el
gráfico. maVal[] es un array dinámico que almacena los valores del
indicador Moving Average para cada barra en el gráfico.
Por cierto, ¿qué son los arrays dinámicos? Un array dinámico es un
array declarado sin dimensión. En otras palabras, no se especifica
ningún valor entre el par de corchetes para indicar su tamaño. De
lo contrario, un array estático, tiene definidas sus dimensiones en
la declaración.
Ejemplo:

double allbars[20]; // este va ocupar 20 elementos

p_close es una variable que usaremos para almacenar el Close price


para la barra a la que vamos a realizar un seguimiento para la
comprobación de nuestras transacciones de Compra/Venta.
STP y TKP son para almacenar los valores del Stop Loss y el Take
Profit en nuestro EA.
2.3. SECCIÓN DE INICIALIZACIÓN DEL EA

int OnInit()
{
{
//­­­ Obtener el identificador para el indicador ADX
adxHandle=iADX(NULL,0,ADX_Period);
//­­­ Obtener el identificador para el indicador Moving
maHandle=iMA(_Symbol,_Period,MA_Period,0,MODE_EMA
//­­­ Qué pasa si el identificador devuelve un valor no
if(adxHandle<0 || maHandle<0)
{
Alert("Ha ocurrido un error al crear los identific
}

Obtenemos aquí los identificadores de nuestro indicador, mediante


las respectivas funciones de indicadores.
El identificador del indicador ADX se obtiene mediante la función
iADX. sus parámetros u argumentos son el símbolo del gráfico
(chart symbol)(NULL significa también el símbolo actual en el
gráfico actual), el período/intervalo (period/timeframe) del
gráfico (0 significa también el período actual en el gráfico actual) y
el período del promedio del ADX (ADX averaging period) para
calcular el índice (que hemos definido anteriormente en la sección
parámetros de entrada).

int iADX(
string symbol, // nombre del
símbolo
ENUM_TIMEFRAMES period, // período
int adx_period // período del
promedio

El identificador del indicador Moving Average se obtiene


mediante la función iMA. Tiene los siguientes argumentos:

el símbolo del gráfico (que se puede obtener mediante


_symbol, symbol() o NULL para el símbolo actual en el
gráfico actual),
el período/intervalo del gráfico (que se puede obtener
mediante _period, period(), o 0 para el período actual en el
gráfico actual),
el período del promedio de Moving Average (que hemos
definido anteriormente en la sección parámetros de
entrada),
el desplazamiento "shift " del indicador en relación al gráfico
del precio (aquí el desplazamiento es 0),
El tipo de Suavizado promedio móvil "Moving average
smoothing" (puede ser cualquiera de los siguientes métodos
de promediación: Simple Averaging‐MODE_SMA, Exponential
Averaging‐MODE_EMA, Smoothed Averaging‐MODE_SMMA o
Linear‐Weighted Averaging‐MODE_LWMA), y
el precio "price" que se utiliza para el promedio (aquí
utilizamos el precio de cierre).

int iMA(
string symbol, // nombre del
símbolo
ENUM_TIMEFRAMES period, // período
int ma_period, // período de
promedio
int ma_shift, // desplazami
horizontal
ENUM_MA_METHOD ma_method, // tipo de
suavizado
suavizado
ENUM_APPLIED_PRICE applied_price // tipo de pr
o identificador

Consulta el manual de MQL5 para obtener más detalles sobre estas


funciones de indicadores. Esto te ayudará a comprender mejor
cómo utilizar cada indicador.
Comprobamos otra vez si hay algún error, en el caso de que la
función no consiga devolver el identificador, tendremos el error
INVALID_HANDLE. Utilizamos la función de aviso para mostrar el
error, mediante la función GetlastError.

//­­­ Vamos a procesar pares de divisas con precios de 5


STP = StopLoss;
TKP = TakeProfit;
if(_Digits==5 || _Digits==3)
{
STP = STP*10;
TKP = TKP*10;
}

Hemos decidido almacenar los valores de Stop Loss y Take Profit en


las variables STP y TKP que hemos definido previamente. ¿Por qué
hacemos esto?
Porque los valores almacenados en los parámetros de ENTRADA
"INPUT" son de sólo lectura, no se pueden modificar. Nos tenemos
que asegurar ahora de que nuestro EA funciona correctamente con
todos los brokers. Digits oDigits() devuelve el número de decimales
que definen la precisión del precio actual del símbolo en el gráfico
actual. Para un gráfico de precios de 5 o 3 dígitos, multiplicamos
tanto el Stop Loss y el Take Profit por 10.
2.4. SECCIÓN DE DESINICIALIZACIÓN DEL EA

Puesto que se llama a esta función siempre que se desactiva el EA


o se quita de un gráfico, lanzaremos todos los identificadores de
indicadores que se crearon durante el proceso de inicialización.
Hemos creado dos identificadores, uno para el indicador ADX y el
otro para el indicador Moving Average.
Para lograrlo usaremos la función IndicatorRelease(). Sólo necesita
un argumento (el identificador del indicador "indicator handle")

bool IndicatorRelease(
int indicator_handle, // identificador
del indicador

La función elimina el identificador del indicador y lanza el bloque


de cálculo del indicador, si no se ha utilizado.
2.5 LA SECCIÓN ONTICK DEL EA
Lo primero que tenemos que hacer, es comprobar si tenemos
bastantes barras en nuestro gráfico. Podemos encontrar el número
de barras en el historial de cualquier gráfico, mediante la función
Bars. Requiere dos parámetros, el símbolo (se puede obtener
mediante _Symbol o Symbol(). Estos dos parámetros devuelven el
símbolo actual para el gráfico actual en el cual está nuestro EA) y el
período o intervalo del gráfico actual (se puede obtener mediante
Period o Period(). Estos dos devuelven el período del gráfico actual
de nuestro EA).
Si el número de barras disponibles es inferior a 60, paramos nuestro
EA, ya que tenemos bastantes barras en el gráfico. La función Alert
muestra un mensaje en una ventana separada. Toma cualquier
valor separado por coma, como parámetros/argumentos. En este
caso, tenemos solamente una cadena. La inicialización de nuestro
EA deja de funcionar según el resultado.

//+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
//| Función Expert tick
//+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
void OnTick()
{
// ¿Tenemos bastantes barras para trabajar con ellas?
if(Bars(_Symbol,_Period)<60) // si el número de barra
{
Alert("Tenemos menos de 60 barras, EA va a salir a
return;
}
// Usaremos la variable estática Old_Time para el tiempo
// A cada ejecución de OnTick compararemos el tiempo de
// Si el tiempo de barra no es igual al tiempo guardado,
static datetime Old_Time;
datetime New_Time[1];
bool IsNewBar=false;

// copiando el último tiempo de barra al elemento New_Ti


int copied=CopyTime(_Symbol,_Period,0,1,New_Time);
if(copied>0) // de acuerdo, se han copiado los datos
{
if(Old_Time!=New_Time[0]) // si el tiempo anterior
{
IsNewBar=true; // si no es la primera llamada
if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("Tene
Old_Time=New_Time[0]; // guardando e
}
}
else
{
Alert("Ha ocurrido un error al copiar los datos de
ResetLastError();
return;
}

//­­­ EA debe comprobar si hay una nueva operación de tr


if(IsNewBar==false)
{
return;
}

//­­­ ¿Tenemos bastantes barras para trabajar con ellas?


int Mybars=Bars(_Symbol,_Period);
if(Mybars<60) // si el número de barras es inferior a
{
{
Alert("Tenemos menos de 60 barras, EA va a salir a
return;
}

//­­­ Define algunas estructuras MQL5 que usaremos en nu


MqlTick latest_price; // Se utiliza para obtener
MqlTradeRequest mrequest; // Se utiliza para enviar
MqlTradeResult mresult; // Se utiliza para obtener
MqlRates mrate[]; // Se utiliza para almacena
ZeroMemory(mrequest); // Inicialización de la estruc

El Expert Advisor realizará las operaciones de trading al inicio de


cada barra nueva, por lo que es necesario resolver el problema con
la identificación de una nueva barra. En otras palabras, queremos
asegurarnos de que el EA no va estar comprobando las posiciones
Largas/Cortas "Long/Short" en cada tick, queremos que el EA
compruebe las posiciones Largas/Cortas sólo cuando haya una barra
nueva.
Empezamos declarando una variable estática de fecha y hora
Old_Time, que va almacenar el tiempo de barra. La hemos
declarado estática, porque queremos que se guarde el valor en la
memoria, hasta la siguiente llamada de la función OnTick.
Entonces, podremos comparar sus valores con la variable
New_Time variable (además del tipo de fecha y hora), que es un
array de un elemento para almacenar el nuevo (reciente) tiempo
de barra. Declaramos también una variable IsNewBar de tipo
booleano y definimos su valor como false. Se hace así, porque
queremos que tenga el valor TRUE solamente cuando tenemos una
barra nueva.
Utilizamos la función CopyTime para obtener el tiempo de la barra
actual. Está función copia el tiempo de barra al array New_Time de
un elemento; y si hay éxito, se compara el tiempo de la nueva
barra con en el tiempo de la barra anterior. Si los tiempos no son
iguales, significa que tenemos una barra nueva, y establecemos la
variable IsNewBar a TRUE y guardamos el valor del tiempo de barra
actual en la variable Old_Time.
La variable IsNewBar indica que tenemos una barra nueva. Si su
valor es FALSE, terminamos la ejecución de la función OnTick.
Echa un vistazo a este código

if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("Tenemos una b

Comprueba la ejecución del modo de depuración y mostrará el


mensaje acerca de los tiempos de barras durante el modo de
depuración, lo abordaremos más detenidamente.
Lo siguiente que queremos hacer, es comprobar si tenemos
bastantes barras para trabajar con ellas. ¿Porqué hacerlo de nuevo?
Sólo queremos estar seguros de que nuestro EA funciona
correctamente. Cabe señalar que, aunque se llame a la función
OnInit sólo una vez cuando está vinculada a un gráfico, se llama a
la función OnTick cada vez que haya un nuevo tick (cotización de
precio).
Como puedes ver, lo hemos hecho otra vez aquí, pero de manera
distinta. Decidimos almacenar el número total de barras en el
historial que obtenemos de la expresión
int Mybars=Bars(_Symbol,_Period);

en una nueva variable, Mybars, declarada dentro de la función


OnTick. Es un variable de tipo local, a diferencia de la variable que
hemos declarado en la sección de los PARÁMETROS DE ENTRADA de
nuestro código. Mientras las variables declaradas en la sección
Parámetros de entrada de nuestro código, están disponibles para
todas las funciones que las puedan necesitar, dentro de nuestro
código, las variables declaradas dentro de una única función son
limitadas y están disponibles sólo para esa función. No se pueden
utilizar fuera de la misma.
A continuación, hemos declarado algunas variables de tipos de
estructuras MQL5, que se utilizarán en esta sección de nuestro EA.
MQL5 tiene un buen número de estructuras hechas, lo que
simplifica bastante las cosas a los desarrolladores de EA. Vamos a
ver las estructuras, una tras otra.
MqlTick
Esta es la estructura utilizada para almacenar los últimos precios
de los símbolos.

struct MqlTick
{
datetime time; // Momento de la
última actualización de precio
double bid; // Precio de Venta
"Bid" actual
double ask; // Precio de Compra
"Ask" actual
double last; // Precio de la
última transacción (Last)
ulong volume; // Volumen del
precio "Last" actual

Cualquier variable que se declara del tipo MqlTick se puede


fácilmente utilizar para obtener los valores actuales de Ask, Bid,
Last yVolume una vez hayas llamado la función SymbolInfoTick().
Así que declaramos latest_price como tipo MqlTick para que
podamos utilizarla en la obtención de los precios de Compra "Ask" y
Venta "Bid".
MqlTradeRequest
Se utiliza esta estructura para llevar a cabo todas las peticiones de
trading para una operación de trading. En su estructura, contiene
todos los campos necesarios para realizar una transacción de
trading.

struct MqlTradeRequest
{
ENUM_TRADE_REQUEST_ACTIONS action; // Tipo
de operación de trading
ulong magic; // ID
del Expert Advisor (magic number)
ulong order; // Ticket
de orden
string symbol; // Símbol
de la operación de trading
double volume; // El
volumen solicitado en lotes
volumen solicitado en lotes
double price; // Precio
double stoplimit; // nivel
StopLimit de la orden
double sl; // Nivel
Stop Loss de la orden
double tp; // Nivel
Take Profit de la orden
ulong deviation; // Desvia
máxima aceptable del precio de venta
ENUM_ORDER_TYPE type; // Tipo
de orden
ENUM_ORDER_TYPE_FILLING type_filling; // Tipo
de ejecución de orden
ENUM_ORDER_TYPE_TIME type_time; // Momen
de ejecución de la orden
datetime expiration; // Momen
de expiración de la orden (para ordenes del
tipo ORDER_TIME_SPECIFIED)
string comment; // Comen
de la orden

Cualquier variable que se declara del tipo MqlTradeRequest puede


ser utilizada para enviar órdenes a nuestras operaciones de trading.
Aquí, hemos declarado mrequest del tipo MqlTradeRequest.
MqlTradeResult
Se devuelve el resultado de cualquier operación de trading como
una estructura predefinida MqlTradeResult de tipo especial.
Cualquier variable que se declara del tipo MqlTradeResult podrá
acceder a los resultados de la petición de trading.

struct MqlTradeResult
{
uint retcode; // Código del
resultado de la operación
ulong deal; // Ticket de la
transacción, si se hace
ulong order; // Ticket de la
orden, si se coloca
double volume; // Volumen de
transacciones, confirmado por el broker
double price; // Precio de la
transacción, confirmado por el broker
double bid; // Precio Venta
"Bid" actual
double ask; // Precio de Compra
"Ask" actual
string comment; // Comentario del
broker de la operación (por defecto, se pone la
descripción de la operación)

Aquí, hemos declarado mresult del tipo MqlTradeResult.


MqlRates
Se almacena el precio (Open, Close, High, Low), el tiempo, los
volúmenes de cada barra y el diferencial de un símbolo en esta
estructura. Se puede utilizar cualquier array declarado del tipo
MqlRates para almacenar el precio, los volúmenes y el historial de
los diferenciales de un símbolo.
struct MqlRates
{
datetime time; // Inicio del período
double open; // Precio de apertura
double high; // El precio más alto
del período
double low; // El Precio más bajo
del período
double close; // Precio de cierre
long tick_volume; // Volumen del tick
int spread; // Diferencial
long real_volume; // Volumen de trading

Aquí, hemos declarado un array mrate[] que servirá para


almacenar esta información.

/*
Vamos a asegurarnos de que los valores de nuestros
*/
// los arrays de tasas
ArraySetAsSeries(mrate,true);
// el array de los valores de ADX DI+
ArraySetAsSeries(plsDI,true);
// el array de los valores de ADX DI­
ArraySetAsSeries(minDI,true);
// los arrays de los valores de ADX
ArraySetAsSeries(adxVal,true);
// los arrays de los valores de MA­8
ArraySetAsSeries(maVal,true);

A continuación, decidimos establecer los arrays que vamos a


utilizar para almacenar los detalles de las barras en series. Esto nos
garantiza que los valores que se van a copiar en los array se van a
indexar igual que las series de tiempo, es decir, 0, 1, 2, 3, para
coincidir con los índices de las barras. Esto se hace mediante l
función ArraySetAsSeries().

bool ArraySetAsSeries(
void array[], // array por referencia
bool set // true indica inversión del
orden de indexación

Cabe señalar que esto también se puede hacer sólo una vez, en la
sección de inicialización de nuestro código. Sin embargo, y para
simplificar la explicación, he decidido mostrarlo en este punto.

//­­­ Obtener la última cotización de precio mediante la


if(!SymbolInfoTick(_Symbol,latest_price))
{
Alert("Ha ocurrido un error al obtener la última c
return;
}

Utilizamos ahora la función SymbolInfoTick para obtener la última


cotización de precio. Esta función tiene dos argumentos – el
símbolo del gráfico y la variable de estructura MqlTick
(latest_price). Un vez más, si hay un error, lo reportamos.
//­­­ Obtener los detalles de las últimas 3 barras
if(CopyRates(_Symbol,_Period,0,3,mrate)<0)
{
Alert("Ha ocurrido un error al copiar los datos ta
return;
}

A continuación, copiamos la información sobre las últimas tres


barras en nuestro array tipo Mqlrates mediante la función
CopyRates. La función CopyRates sirve para obtener el historial de
los datos con estructura MqlRates de un determinado Símbolo‐
Período para una cantidad determinada en el array tipo MqlRates.

int CopyRates(
string symbol_name, // nombre
del símbolo
ENUM_TIMEFRAMES timeframe, // período
int start_pos, // posición
de inicio
int count, // número
de datos que se desea copiar
MqlRates rates_array[] // array donde
se copia

El nombre del símbolo se obtiene mediante ‘_symbol’, y el


período/intervalo se obtiene mediante ‘_period’. Para la posición
e inicio, empezaremos desde la barra actual, Bar 0 y contaremos
sólo tres barras, Barras 0, 1, y 2. El resultado se almacena en
nuestro array mrate[].
El array mrate[] contiene ahora toda la información sobre el
precio, tiempo, volúmenes y diferencial de las barras 0 , 1 y 2. Por
lo tanto, para obtener los detalles de cualquier barra, utilizaremos
lo siguiente:

mrate[bar_number].bar_property

Por ejemplo, podemos conseguir la siguiente información sobre


cada barra:

mrate[1].time // Tiempo de inicio Barra 1


mrate[1].open // Precio de apertura Barra 1
mrate[0].high // Precio máximo barra 0 (barra
actual), etc.

Luego, se copian todos los valores del indicador en los arrays


dinámicos que hemos declarado mediante la función CopyBuffer.

int CopyBuffer(
int indicator_handle, //
identificador del indicador
int buffer_num, // número de
buffer del indicador
int start_pos, // posición de
inicio
inicio
int count, // cantidad a
copiar
double buffer[] // array donde
se copiarán los datos

El identificador del indicador es el identificador que hemos creado


en la sección OnInit. En cuanto al número de buffers, el indicador
ADX tiene tres (3) buffers:

0 ‐ MAIN_LINE,
1 ‐ PLUSDI_LINE,
2 ‐ MINUSDI_LINE.

El indicador Moving Average tiene sólo un (1) indicador:

0 – MAIN_LINE.

Copiamos desde la barra actual (0) hasta las dos últimas barras. De
esta manera, el número total de barras a copiar es 3 (barras 0,1 y
2). buffer[] es el array dinámico de destino que habíamos
declarado anteriormente – adxVal, plsDI, minDI y maVal.
Como puedes observar de nuevo aquí, intentamos capturar
cualquier error que pueda ocurrir durante el proceso de copia. Si
hay un error, no hace falta seguir.
Es importante señalar que las funciones CopyBuffer() y CopyRates()
devuelven el número total de los registros copiados con éxito, y
devuelven ‐1 en caso de error. Es por eso que estamos
comprobando los valores inferiores a 0 (cero), en las siguientes
funciones de comprobación de error.

//­­­ Copiar los nuevos valores de nuestros indicadores


if(CopyBuffer(adxHandle,0,0,3,adxVal)<0 || CopyBuffer
|| CopyBuffer(adxHandle,2,0,3,minDI)<0)
{
Alert("Ha ocurrido un error al copiar los buffers
return;
}
if(CopyBuffer(maHandle,0,0,3,maVal)<0)
{
Alert("Ha ocurrido un error al copiar el buffer de
return;
}

En este momento queremos comprobar si ya tenemos una posición


de Compra "Buy" o Venta "Sell" abierta, en otras palabras,
queremos asegurarnos de que tenemos UNA sola operación de
trading de Compra o Venta abierta a la vez. No queremos abrir una
nueva Compra, si ya tenemos una abierta, y tampoco queremos
abrir una nueva Venta, si ya tenemos una abierta.
Para conseguirlo tenemos, antes que nada, que declarar dos
variables de tipo booleano (Buy_opened y Sell_opened) que van a
tomar el valor TRUE si ya tenemos una posición abierta, que sea de
Compra o Venta.

//­­­ no tenemos errores, así que continuamos


//­­­ ¿Tenemos posiciones abiertas ya?
bool Buy_opened=false; // variable que almacena el
bool Sell_opened=false; // variable que almacena el
if (PositionSelect(_Symbol) ==true) // tenemos una
{
if (PositionGetInteger(POSITION_TYPE) == POSITI
{
Buy_opened = true; // Es una Compra
}
else if(PositionGetInteger(POSITION_TYPE) ==
{
Sell_opened = true; // Es una Venta
}
}

Para saber si tenemos una posición abierta, utilizamos la función


PositionSelect. Esta función devuelve TRUE si ya tenemos una
posición abierta y FALSE si no hay ninguna.

bool PositionSelect(
string symbol // Nombre del Símbolo

Y tiene como principal argumento/parámetro, el símbolo (par de


divisas) que queremos comprobar. Aquí, utilizamos _symbol,
puesto que estamos comprobando el símbolo actual (par de
divisas).
Si la expresión devuelve TRUE, entonces queremos comprobar si la
posición abierta es de Compra o Venta. Para ello, utilizamos la
función PositionGetInteger, que nos devuelve el tipo de posición
abierta al utilizarla con el modificador POSITION_TYPE. Nos
devuelve el Identificador del tipo de posición que puede
ser POSITION_TYPE_BUY o POSITION_TYPE_SELL

long PositionGetInteger(
ENUM_POSITION_PROPERTY property_id // Identific

En nuestro caso, lo utilizamos para averiguar cuál de las posiciones


está ya abierta. Si es una Venta, almacenamos el valor TRUE en
Sell_opened y si es una Compra, almacenamos el valor TRUE en
Buy_opened. Vamos a poder utilizar estas dos variables más
adelante, cuando estaremos haciendo las comprobaciones de las
condiciones de Venta o Compra en nuestro código.
Ahora es el momento de almacenar el precio de cierre
correspondiente a la barra que vamos a utilizar en nuestra
configuración de Compra/Venta. Recuerda que anteriormente
hemos declarado una variable para eso.

// Copiar el precio de cierre de la barra anterior a la

p_close=mrate[1].close; // precio de cierre de la ba

Hecho esto, pasamos a la siguiente etapa.

/*
1. Configuración de búsqueda de Compra (long/Buy): M
el precio de cierre anterior lo supera, ADX > 22, +D
el precio de cierre anterior lo supera, ADX > 22, +D
*/
//­­­ Declarar variables de tipo booleano para almacenar
bool Buy_Condition_1 = (maVal[0]>maVal[1]) && (maVal[
bool Buy_Condition_2 = (p_close > maVal[1]);
bool Buy_Condition_3 = (adxVal[0]>Adx_Min);
bool Buy_Condition_4 = (plsDI[0]>minDI[0]);

//­­­ Poniendo todo junto


if(Buy_Condition_1 && Buy_Condition_2)
{
if(Buy_Condition_3 && Buy_Condition_4)
{
// ¿alguna posición de Compra abierta?
if (Buy_opened)
{
Alert("Ya tenemos una posición de Compra abi
return; // No abras una nueva posición de
}
mrequest.action = TRADE_ACTION_DEAL;
mrequest.price = NormalizeDouble(latest_price.a
mrequest.sl = NormalizeDouble(latest_price.ask
mrequest.tp = NormalizeDouble(latest_price.ask
mrequest.symbol = _Symbol;
mrequest.volume = Lot;
mrequest.magic = EA_Magic;
mrequest.type = ORDER_TYPE_BUY;
mrequest.type_filling = ORDER_FILLING_FOK;
mrequest.deviation=100;
//­­­ enviar orden
OrderSend(mrequest,mresult);

Ahora es el momento de empezar a comprobar las condiciones de


Compra.
Analicemos la expresión anterior, ya que representa la estrategia
que hemos diseñado anteriormente. Estamos declarando una
variable del tipo booleano para cada una las condiciones que se
deben cumplir antes de colocar una orden. Una variable del tipo
booleano sólo puede tener los valores TRUE o FALSE. Por lo tanto,
nuestra estrategia de Compra se ha dividido en cuatro condiciones.
Si alguna de las condiciones se cumple, se almacena el valor TRUE
en nuestra variable booleana, de lo contrario, se almacena el valor
FALSE. Vamos a verlas una por una.

bool Buy_Condition_1 = (maVal[0]>maVal[1]) && (maVal[

Aquí estamos comprobando los valores de MA‐8 en las Barras 0, 1 y


2. Si el valor de MA‐8 en la barra actual es superior a su valor en la
barra anterior Barra 1 y si también el valor de MA‐8 en la Barra 1 es
superior a su valor en la Barra 2, significa que MA‐8 está creciendo.
Esto satisface una de nuestras condiciones de Compra.

bool Buy_Condition_2 = (p_close > maVal[1]);

Esta expresión comprueba si la precio de cierre de la Barra 1 es


mayor que el valor de MA‐8 en el mismo período (período de la
Barra 1). Si el precio es mayor, eso quiere decir que nuestra
segunda condición también se ha cumplido, así que podemos
comprobar las otras condiciones. Si no se cumplen las dos
condiciones que acabamos de describir, ya no hace falta comprobar
las otras condiciones. Es por ello que hemos decidido incluir las
siguientes expresiones en estas dos condiciones iniciales
(expresiones).

bool Buy_Condition_3 = (adxVal[0]>Adx_Min);

Ahora queremos comprobar si el valor actual de ADX (el valor de


ADX en la Barra 0) es superior al valor mínimo de ADX que hemos
declarado en los parámetros de entrada. Si esta condición se
cumple, es decir, que el valor de ADX es superior al valor mínimo
necesario; queremos también asegurarnos de que el valor plusDI es
superior al valor de minusDI. Es lo que hacemos en la siguiente
expresión

bool Buy_Condition_4 = (plsDI[0]>minDI[0]);

Si se cumplen todas estas condiciones, es decir, devuelven el valor


TRUE, entonces queremos asegurarnos de no abrir ninguna posición
de Compra nueva si ya tenemos una abierta. Ahora es el momento
de comprobar el valor de la variable Buy_opened que hemos
declarado anteriormente en nuestro código.

// ¿alguna posición de Compra abierta?


if (Buy_opened)
{
Alert("Ya tenemos una posición de Compra abierta!!
return; // No abras una nueva posición de compr
}

Si Buy_opened es TRUE, no queremos abrir otra posición de


Compra, por lo que, se muestra un aviso para informarnos y luego
volvemos para que nuestro EA espere el próximo tick. Sin embargo,
si Buy_opened es FALSE, preparamos nuestros registros mediante la
variable MqlTradeRequest del tipo (mrequest) que hemos
declarado anteriormente para enviar nuestra orden.

La acción aquí, que es el tipo de la operación de trading, es


TRADE_ACTION_DEAL ya que estamos colocando una orden
de trading para una ejecución inmediata. Así que, Para
modificar una orden, usaremos TRADE_ACTION_MODIFY.
Para borrar una orden, usaremos TRADE_ACTION_REMOVE.
Para obtener el último precio de Compra (Ask), usaremos
nuestro latest_price de tipo MqlTick. El precio Stop loss de
la orden se obtiene restando nuestro StopLoss en puntos del
precio de Compra, mientras se obtiene el precio take profit
de la orden sumando nuestro TakeProfit en puntos al precio
de Compra. También puedes observar que hemos utilizado la
función NormalizeDouble para los valores del precio de
Compra, StopLoss y TakeProfit, es una buena práctica para
redondear siempre estos precios al número de dígitos del par
de divisas antes de enviarlos al servidor de trading.
symbol es el símbolo actual _Symbol o Symbol()). type es el
tipo de orden que estamos colocando, aquí estamos
colocando una orden de Compra ORDER_TYPE_BUY. Para
una orden de Venta, sería ORDER_TYPE_SELL.
type_filling es el tipo de ejecución de la orden;
ORDER_FILLING_FOK significa que la transacción se debe
ejecutar únicamente para un volumen determinado y a un
precio igual o mejor que el precio indicado en la orden. Si no
hay volumen suficiente de ofertas en el símbolo de la orden,
no se ejecutará la orden.
La función OrderSend() tiene dos argumentos, la variable de tipo
MqlTradeRequest y la variable de tipo MqlTradeResult.

bool OrderSend(
MqlTradeRequest& request // estructura de la pe
MqlTradeResult& result // estructura de la re

Como puedes observar, hemos utilizado nuestra variable de tipo


MqlTradeRequest y la variable de tipo MqlTradeResult para la
colocación de nuestra orden mediante OrderSend.

// obtener el código resultante


if(mresult.retcode==10009 || mresult.retcode==
{
Alert("Se ha colocado con éxito una orden de
}
else
{
Alert("No se ha podido completar la orden de
ResetLastError();
return;
}

Después de enviar nuestra orden, vamos a utilizar ahora la variable


de tipo MqlTradeResult para comprobar el resultado de nuestra
orden. Si se ejecuta nuestra orden con éxito, queremos saberlo, y
si no se ejecuta, queremos saberlo también. Con la variable
‘mresult’ de tipo MqlTradeResult podemos acceder al return code
de la Operación y también al número de ticket de la orden "order
ticket number" si se coloca una orden.
El código de retorno 10009 significa que la petición OrderSend fue
llevada a cabo con éxito, mientras 10008 significa que nuestra
orden se ha colocado. Por eso hemos comprobado ambos códigos
de retorno. Si obtenemos cualquiera de los dos, estamos seguros
de que nuestra orden se ha completado o se ha colocado.
Para comprobar una oportunidad de Venta, hacemos las
comprobaciones de manera opuesta a lo que hicimos para la
oportunidad de Compra, excepto para nuestro ADX que debe ser
superior al valor Mínimo indicado.

/*
2. Comprobación de la condición de Venta (Short/Sell
el precio de cierre anterior inferior a él, ADX > 22
*/
//­­­ Declarar variables de tipo booleano para almacenar
bool Sell_Condition_1 = (maVal[0]<maVal[1]) && (maVal
bool Sell_Condition_2 = (p_close <maVal[1]);
bool Sell_Condition_3 = (adxVal[0]>Adx_Min);
bool Sell_Condition_4 = (plsDI[0]<minDI[0]);

//­­­ Poniendo todo junto


if(Sell_Condition_1 && Sell_Condition_2)
{
if(Sell_Condition_3 && Sell_Condition_4)
{
// ¿alguna posición de Venta abierta?
if (Sell_opened)
{
{
Alert("Ya tenemos una posición de Venta
return; // No abras una nueva posició
}
mrequest.action = TRADE_ACTION_DEAL;
mrequest.price = NormalizeDouble(latest_pric
mrequest.sl = NormalizeDouble(latest_price.b
mrequest.tp = NormalizeDouble(latest_price.b
mrequest.symbol = _Symbol;
mrequest.volume = Lot;
mrequest.magic = EA_Magic;
mrequest.type= ORDER_TYPE_SELL;
mrequest.type_filling = ORDER_FILLING_FOK
mrequest.deviation=100;
//­­­ enviar orden
OrderSend(mrequest,mresult);

Igual que hicimos en la sección de Compra, estamos declarando


una variable del tipo booleano para cada una las condiciones que
se deben cumplir antes de colocar una orden. Una variable del tipo
booleano sólo puede tener los valores TRUE o FALSE. Por lo tanto,
nuestra estrategia de Venta se ha dividido en cuatro condiciones.
Si alguna de las condiciones se cumple, se almacena el valor TRUE
en nuestra variable booleana, de lo contrario, se almacena el valor
FALSE. Vamos a verlas una por una, como hicimos en la sección
Compra

bool Sell_Condition_1 = (maVal[0]<maVal[1]) && (maVal

Aquí estamos comprobando los valores de MA‐8 en las Barras 0, 1 y


2. Si el valor de MA‐8 en la barra actual es inferior a su valor en la
barra anterior Barra 1 y si también el valor MA‐8 de la Barra 1 es
inferior a su valor en la Barra 2, significa que MA‐8 está
decreciendo. Esto satisface una de nuestras condiciones de Venta.

bool Sell_Condition_2 = (p_close <maVal[1]);

Esta expresión comprueba si el precio de cierre de la Barra 1 es


inferior al valor de MA‐8 en el mismo período (período de la Barra
1). Si el precio es inferior, eso quiere decir que nuestra segunda
condición también se ha cumplido, así que podemos comprobar las
otras condiciones. Si no se cumplen las dos condiciones que
acabamos de describir, ya no hace falta comprobar las otras
condiciones. Es por ello que hemos decidido incluir las siguientes
expresiones en estas dos condiciones iniciales (expresiones).

bool Sell_Condition_3 = (adxVal[0]>Adx_Min);

Ahora queremos comprobar si el valor actual de ADX (el valor de


ADX en la Barra 0) es superior al valor mínimo de ADX que hemos
declarado en los parámetros de entrada. Si esta condición se
cumple, es decir, que el valor de ADX es superior al valor mínimo
necesario; queremos también asegurarnos de que el valor MinusDI
es superior al valor de plusDI. Es lo que hacemos en la siguiente
expresión

bool Sell_Condition_4 = (plsDI[0]<minDI[0]);

Si se cumplen todas estas condiciones, es decir, devuelven el valor


TRUE, entonces queremos asegurarnos de no abrir ninguna posición
de Venta nueva si ya tenemos una abierta. Ahora es el momento
de comprobar el valor de la variable Buy_opened que hemos
declarado anteriormente en nuestro código.

// ¿alguna posición de Venta abierta?


if (Sell_opened)
{
Alert("Ya tenemos una posición de Venta
return; // No abras una nueva posició
}

Si Sell_opened es TRUE, no queremos abrir otra posición de Venta,


por lo que, se muestra un aviso para informarnos y luego volvemos
para que nuestro EA espere el próximo tick. Sin embargo, si
Sell_opened es FALSE, configuramos nuestra operación de Venta,
del mismo modo que lo hicimos en la operación de compra.
La principal diferencia reside en la manera de calcular nuestro
precio Stop Loss y Take Profit. Además, mientras estamos
vendiendo, vendemos todo al precio de Venta "Bid"; es por lo que
utilizamos nuestra variable latest_price del tipo MqlTick para
obtener el último precio de Venta. Hay otro tipo de orden, que
hemos comentado antes, es ORDER_TYPE_SELL.
También, hemos utilizado la función NormalizeDouble para los
valores del precio de Venta, StopLoss y TakeProfit, es una buena
práctica para redondear siempre estos precios al número de dígitos
del par de divisas antes de enviarlos al servidor de trading.
Igual que hicimos con la orden de Compra, también debemos
comprobar si nuestra orden de Venta se ha realizado con éxito o
no. Así que usamos la misma expresión que en nuestra orden de
Compra.

if(mresult.retcode==10009 || mresult.retcode==
{
Alert("Se ha colocado con éxito una orden de
}
else
{
Alert("No se ha podido completar la orden de
ResetLastError();
return;
}
}

3. Depuración y pruebas de nuestro Expert Advisor


En este punto, necesitamos probar nuestro EA, para saber si
nuestra estrategia funciona o no. También es posible que haya un
error o dos en el código de nuestro EA. Veremos esto en la
siguiente etapa.
3.1 LA DEPURACIÓN
La depuración de nuestro código nos permite ver su rendimiento
línea por línea (si establecemos unos puntos de interrupción
"breakpoints") y si observamos algunos errores o fallos en algunos
puntos de nuestro código, efectuamos las correcciones necesarias
rápidamente, antes de utilizar nuestro código en operaciones de
trading en condiciones reales.
Vamos a ver paso a paso el proceso de depuración de nuestro
Expert Advisor, primero, estableciendo los puntos de interrupción y
después, sin puntos de interrupción. Para ello, asegúrate de que
no has cerrado el Editor. En primer lugar, vamos a elegir la gráfica
que queremos utilizar para probar nuestro EA. En la barra del menú
del Editor, haz clic en Herramientas y luego en Opciones como se
muestra a continuación:

Figura 8. Ajustes de las opciones de depuración

Una vez que aparezca la ventana de las Opciones, selecciona el par


de divisas y el período/intervalo a utilizar y haz clic en Aceptar:

Antes de iniciar el depurador, vamos a definir los puntos de


interrupción. Los Puntos de interrupción nos permiten controlar el
comportamiento/rendimiento de nuestro código en unas líneas o
puntos determinados. En lugar de recorrer el código de una vez, lo
que hace el depurador es detenerse en cada punto de
interrupción, esperando que hagas algo. Esto nos permite analizar
nuestro código y controlar su comportamiento en cada uno de los
puntos de interrupción que hemos definido. Podemos también
evaluar los valores de algunas de nuestras variables para ver si todo
está funcionando según lo previsto.
Para insertar un punto de interrupción, hay que situarse en la línea
de código donde queremos fijar el punto. Hacer un doble clic
izquierdo en el campo gris situado en el borde izquierdo de línea
de código, verás un pequeño botón azul redondo con un cuadro
blanco en su interior. Otra manera de hacerlo, es situar el cursor en
cualquier parte de la línea en la que queremos colocar un punto de
interrupción y pulsar F9. Para eliminar el punto de interrupción,
haz doble clic sobre él o pulsa F9 otra vez.

Figura 10. Colocación de un punto de interrupción

Vamos a definir los puntos de interrupción en cinco líneas distintas


de nuestro código.
Para simplificar la explicación, los vamos a etiquetar del 1 al 5.
Para continuar, establece los puntos de interrupción en las 5 líneas
de código, como se muestra en la siguiente figura. El punto de
interrupción 1 es el que habíamos creado más arriba.

Figura 11. Colocación de puntos de interrupción adicionales

Ahora que hemos acabado de establecer de los puntos de


referencia, estamos ya preparados para iniciar el proceso de
depuración de nuestro código.
Para iniciar el depurador, pulsa F5 o haz clic en el botón verde de la
barra de herramientas del MetaEditor:
Figura 12. Iniciando el depurador

Lo primero que hace el editor es compilar el código, si detecta


errores, los mostrará y si no hay ninguno, te indicará que el código
se ha compilado con éxito.

Figura 13. Informe de compilación

Ten en cuenta que el hecho de que el código se haya compilado


con éxito no significa que está exento de errores. Dependiendo de
cómo se ha escrito tu código, puede haber errores de tiempo de
ejecución. Por ejemplo, si cualquiera de nuestras expresiones no
evalúa correctamente debido a una control escaso, el código se
compilará correctamente, pero puede que no funcione
correctamente. Ahora pasamos a la acción...
Un vez se haya completado la depuración del código, te va a dirigir
al terminal de trading, y vincular el EA al gráfico que has señalado
en los ajustes de las opciones de MetaEditor. Al mismo tiempo, te
muestra la parte de los parámetros de Entrada del EA. Puesto que
no estamos configurando nada, le damos un clic a Aceptar.

Figura 14. Parámetros de entrada del Expert Advisor para la compilación

Ahora verás claramente nuestro EA en la esquina superior izquierda


del gráfico.
Una vez empieza OnTick(), se detendrá nada más llegar al punto
de interrupción 1.
Figura 15. El depurador se detiene en el primer punto de interrupción.

Verás una flecha verde en esta la línea de código. Esto te indica


que la línea de código anterior se ha ejecutado; ahora estamos
preparados para ejecutar la línea actual.
Antes de continuar, voy a dar algunas explicaciones. Si te fijas en la
barra de herramientas del Editor, te darás cuenta de que los tres
botones con flechas curvas que antes eran grises, se han habilitado
ahora. Esto se debe a que estamos ejecutando el depurador. Estos
botones/comandos sirven para ir paso a paso por el código (Paso
con entrada "Step into", Paso sin entrada "Step over" o Paso fuera
"Step out").

Figura 16. Comando Paso con entrada

Se utiliza el Paso con entrada para pasar de una etapa de la


ejecución del programa a la siguiente etapa, entrando a las
funciones a las que se llama en la línea de código. Para ejecutar
este comando, haz clic en el botón o pulsa F11. (Usaremos este
comando para la depuración Paso a paso de nuestro código).

Figura 17. Comando Paso sin entrada

Por otra parte, Paso sin entrada no entra en las funciones a las que
se llama en esta línea de código. Para ejecutar este comando, haz
clic en el botón o pulsa F10.

Figura 18. Comando Paso fuera

Haz clic en el botón o pulsa Shift+F11 para ejecutar una etapa del
programa que está en un nivel superior.
También verás en la parte baja del Editor la ventana Caja de
Herramientas. La pestaña Depurar de esta ventana tiene las
siguientes columnas:

Archivo: Muestra el nombre del archivo al que se ha llamado.


Función: Muestra la función actual del archivo al que se ha
llamado.
Línea: Muestra el número de la línea de código a partir de la
cual se ha llamado a la función en el archivo.
Expresión: En esta columna, se puede especificar el nombre
de cualquier expresión/variable a la que quieres controlar a
lo largo de nuestro código.
Valor: Muestra el valor de la expresión/variable que hemos
introducido en la columna Expresión.
Tipo: Muestra el tipo de dato de la expresión/variable de la
columna Expresión.

Volvamos al proceso de depuración...


Lo siguiente que queremos hacer ahora es introducir las
variables/expresiones que queremos controlar de nuestro código.
Asegúrate de controlar solamente las variables/expresiones que
son realmente importantes. Por ejemplo, vamos a controlar lo
siguiente:

Old_Time (tiempo de la barra anterior)


New_Time[0] (tiempo de la barra actual)
IsNewBar (señal o "flag" que indica una barra nueva)
Mybars (total de barras en el historial) –Nuestro EA lo utiliza

Puedes añadir más variables, como los valores de ADX, los valores
de MA‐8, etc.
Para añadir una expresión/variable, haz doble clic debajo del título
Expresión o un clic derecho en la columna Expresión y selecciona
Add , como se indica en la figura de abajo.
Introduce la expresión/variable a controlar u observar.

Figura 19. Ventana de observación de las expresiones

Introduce todas las variables/expresiones necesarias...

Figura 20. Añadir las expresiones o variables a observar

Si aún no se ha declarado la variable, su tipo es "Unknown


identifier" (excepto las variables estáticas).
Vamos a seguir...

Figura 21. Comando Paso con entrada en acción

Haz un clic en Paso con entrada o pulsa el botón F11 y observa lo


que ocurre. Mantén pulsado este botón o F11 hasta llegar al punto
de interrupción nº 2, continúa hasta llegar al punto de interrupción
nº 4 como se muestra a continuación y observa la ventana de
observación de expresiones.

Figura 22. Observación de las expresiones o variables


Figura 23. Observación de las expresiones o variables

Figura 24. Observación de las expresiones o variables

Una vez que haya un nuevo tick, se vuelve a la primera línea de


código de la función OnTick(). Y se van a reiniciar todos los valores
de nuestras variables/expresiones, debido a este nuevo tick,
excepto las variables estáticas. En este caso, tenemos una variable
estática Old_Time.
Figura 25. Valores de las variables cuando hay un evento NewTick

Para volver otra vez al proceso, continúa pulsando la tecla F11 y


sigue observando las variables en la ventana de observación de
expresiones. Puedes detener el depurador y a continuación quitar
todos los puntos de interrupción.
Como podrás ver, en el modo de depuración aparece el mensaje
"Tenemos una nueva barra aquí...".

Figura 26. El Expert Advisor muestra el mensaje en el modo de depuración

Ejecuta el proceso de depuración de nuevo; pero esta vez sin


puntos de interrupción. Sigue observando cada tick y comprobando
si se cumple alguna de nuestras condiciones de Compra/Venta,
estas colocaran una operación de trading, y puesto que hemos
escrito el código de manera que nos informe si se ha colocado una
orden con éxito o no, veremos una aviso.

Figura 27. El Expert Advisor coloca una operación de trading durante la depuración
Figura 27. El Expert Advisor coloca una operación de trading durante la depuración

Creo que se puede dejar el EA funcionando unos minutos más,


mientras te tomas un café. Una vez hayas vuelto y que hayas
ganado un poco de dinero (es broma), haz clic en el botón Detener
la depuración (Rojo) del MetaEditor para detener la depuración.

Figura 28. Deteniendo el depurador

Lo que acabamos de hacer realmente aquí es ver que nuestro EA


sólo comprueba si hay una operación de trading en la apertura de
una nueva barra y que nuestro EA funciona realmente. Todavía hay
mucho margen para los ajustes del código de nuestro EA.
Que quede claro que en este punto el Terminal de trading debe
estar conectado a Internet, de lo contrario, no funcionará la
depuración al no estar en marcha el terminal.
3.2 PROBANDO LA ESTRATEGIA DE NUESTRO EA
Ahora queremos probar nuestro EA mediante el Simulador de
Estrategias integrado en el Terminal de trading. Para ejecutar el
Simulador de Estrategias, pulsa CONTROL+R o haz un clic en el
menú Ver de la barra de menú del Terminal y luego haz clic en el
Simulador de Estrategias, como se muestra a continuación.

Figura 26. Ejecución del Simulador de Estrategias

El Simulador (Simulador de Estrategias) aparece en la parte inferior


del terminal. Para poder ver todos los ajustes del Simulador, hay
que expandir/reajustar la ventana. Para ello, mueve el puntero del
ratón hasta la línea señalada con la flecha roja (como se muestra a
continuación).
Figura 27. La ventana del Simulador de Estrategias

El puntero del ratón se convierte en una flecha de doble punta,


mantén pulsado el ratón y arrastra la línea hacia arriba. Continúa
hasta que puedas ver todos los parámetros de la pestaña de
configuración.

Figura 28. Pestaña de configuración del Simulador de Estrategias

1. Selecciona el EA que quieres probar


2. Selecciona el par de divisas a utilizar en la prueba
3. Selecciona el Período/Intervalo a utilizar en la prueba
4. Selecciona Período Personalizado y establece las fechas
5. Define las fechas del período personalizado para la prueba
6. Ejecución en modo Normal
7. Selecciona la cantidad del depósito a utilizar en la prueba en
USD
8. Pon Optimización en Deshabilitado (no estamos optimizando
ahora, sólo queremos probar)
9. Haz clic en este botón cuando estás listo para ejecutar la
prueba.

Antes de pulsar el botón Empezar, vamos a ver las otras pestañas


del Simulador.
La pestaña Agentes
El procesador utilizado por el Simulador para la prueba. Dependerá
del tipo de procesador de tu ordenador. El mío es un procesador de
un (1) sólo núcleo.

Figura 29. La Pestaña Agentes del Simulador de Estrategias

Para un solo agente, verás algo parecido a la siguiente figura:


Figura 30. La Pestaña de Agentes del Simulador de Estrategias durante una prueba

La pestaña Diario
Es aquí donde se muestran todas las actividades durante la prueba.

Figura 31. La pestaña Diario mostrando las actividades de las operaciones

La pestaña Parámetros de entrada


En esta pestaña se indican los parámetros de entrada del EA.

Figura 32. La Pestaña Parámetros de entrada del Simulador de Estrategias

Si queremos optimizar nuestro EA, tendemos que definir los


valores de los parámetros del área rodeada.

Empezar indica los valores iniciales de nuestro Simulador.


Paso es la tasa de incremento del valor elegido, y
Parar es el valor final del Simulador.

Sin embargo, en nuestro caso no estamos optimizando nuestro EA,


por lo que no vamos a tocar estos parámetros por ahora.
Una vez todo configurado, volvemos a la pestaña Configuración y
hacemos clic en el botón Empezar. A continuación, se inicia el
Simulador. Todo lo que tienes que hacer ahora, es tomar otra taza
de café, si quieres, o, si eres como yo, querrás observar todo el
proceso, entonces dirígete a la pestaña Diario.
La pestaña Gráfico
A medida que vayas observando los mensajes en la Pestaña Diario,
verás una nueva pestaña, llamada Gráfico, y que acaba de ser
generada. Cuando cambias a la pestaña Gráfico, verás como
aumenta o disminuye el gráfico en función de los resultados de tus
operaciones.

Figura 33. El resultado gráfico del la prueba del Expert Advisor


Figura 33. El resultado gráfico del la prueba del Expert Advisor

La pestaña Resultados
Una vez finalizada la prueba, verás otra pestaña, llamada
Resultados. Al cambiar a la pestaña Resultados, verás el informe de
la prueba.

Figura 34. La pestaña Resultados del Simulador de Estrategias, mostrando el informe de


la prueba

Puedes ver el Beneficio bruto (Gross Profit), el Beneficio neto (Net


Profit), el Total de transacciones, el total de transacciones no
rentables y mucho más. Es muy interesante observar que tenemos
unos 1 450,00 USD en el período que hemos elegido para nuestra
prueba. Por lo menos, tenemos algo de beneficio.
Quiero dejar algo muy claro aquí. Descubrirás que los ajustes de los
parámetros del EA que ves en el Simulador de Estrategias son
distintos a los ajustes iniciales de los parámetros de entrada del
EA. Acabo de demostrar que puedes cambiar cualquiera de estos
parámetros de entrada para aprovechar mejor de tu EA. En lugar de
utilizar un período de 8 para el Moving Average y el ADX, lo he
cambiado a 10 para el Moving Average y a 14 para el ADX. He
cambiado también el Stop Loss de 30 a 35. Por último, pero no
menos importante, he decido utilizar un intervalo de 2 horas. Y
recuerda, este es el Simulador de Estrategias.
Si quieres ver un informe completo de la prueba, haz un clic
derecho en cualquier sitio de la pestaña Resultados, aparecerá un
menú. Desde este menú, selecciona ‘Guardar como Informe’.

Figura 35. Almacenamiento de los resultados de la prueba

Aparecerá la ventana de diálogo de Guardar, escribe un nombre


para tu informe (si quieres, sino deja el nombre por defecto) y haz
clic en el botón Guardar. Se guardará el informe completo en
formato HTML.
Para ver el gráfico de la prueba realizada, haz clic en Abrir Gráfico
y se mostrará el gráfico.
Figura 36. Gráfico de los resultados de la prueba

Eso es todo, hemos escrito y probado con éxito nuestro EA y ahora


tenemos un resultado con el cual podemos trabajar. Puedes volver
a la pestaña de Configuración del Simulador de Estrategias y hacer
la prueba con otros intervalos de tiempo/períodos.
Tarea
Quiero que lleves a cabo pruebas con diferentes pares de divisas,
diferentes períodos, diferentes Stop Loss, diferentes Take Profit y
comprobar el rendimiento del EA. Puedes incluso probar otros
valores de Moving Average y ADX. Como he dicho antes, está es la
esencia del Simulador de Estrategias. Me gustaría también que
compartáis vuestros resultados conmigo.
Conclusión
En esta guía paso a paso, hemos podido ver cuáles son los pasos
básicos para escribir un Expert Advisor sencillo, basándonos en una
elaborada estrategia de trading. También hemos visto cómo se
hace la comprobación de errores de nuestro EA mediante el
depurador. Además, hemos explicado la forma de probar el
rendimiento de nuestro EA mediante el Simulador de Estrategias.
Con esto, hemos podido ver el potencial y la solidez del nuevo
lenguaje MQL5. Nuestro EA aún no es perfecto ni completo, ya que
todavía se le deben aplicar muchas mejoras antes de poder
utilizarlo en condiciones reales.
Aún queda mucho por aprender y te recomiendo leer el artículo de
nuevo, junto al manual de MQL5, y probar todo lo que has
aprendido en este artículo, y te aseguro que podrás escribir Expert
Advisors en un futuro no muy lejano.
Feliz codificación.

Traducción del inglés realizada por MetaQuotes Ltd.


Artículo original: https://www.mql5.com/en/articles/100

Archivos adjuntos | Descargar ZIP


my_first_ea.mq5 (11.73 KB)

Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda

Otros artículos del autor

La escritura de un Asesor Experto mediante las


librerías estándar de las clase de trading de MQL5
Guía de Simulación y Optimización de Asesores
Expertos en MQL5
Escribir un Expert Advisor mediante la
programación orientada a objetos de MQL5

Últimos comentarios | Pasar a la discusión en el foro de los


operadores (9)

Libni Colina | 7 may. 2020 en 02:16


El ódigo de ejemplo me gusta bastante, soy nuevo
en esto tambien, arregle el codigo tal como aparece
en los comentarios y ya no da errores.
El problema es que el robot no abre operacciones,
ni siquiera abre una operación
¿Alguno pudo resolver este problema?

Estoy usando La opción "Unico" del probador de


estrategías: ¿Es un error mio?

Gracias por su tiempo y en apoyarme

Libni Colina | 7 may. 2020 en 03:00

Me di cuenta que el Robot intenta abris las ordenes


pero siempre da error:

Salida:
2020.05.06 20:35:16.141 Core 1 2020.04.20
20:25:00 failed market sell 0.10 EURUSD sl: 1.08965
tp: 1.07665 [Invalid request]

He cambiado Varias cosas en el código pero ne se


me da, les agrego el código que tengo:

Original: mrequest.type_filling = "Lo he puesto de


las 3 formas que estan en la documentación"

mrequest.action = TRADE_ACTION_DEAL;
mrequest.price = NormalizeDouble
mrequest.sl = NormalizeDouble(latest_
mrequest.tp = NormalizeDouble(latest_
mrequest.symbol = _Symbol;
mrequest.volume = Lot;
mrequest.magic = EA_Magic;
mrequest.type = ORDER_TYPE_BUY;
mrequest.type_filling = ORDER_FILLING
mrequest.deviation=100;
Tambien he probado este codigo:

//­­­ declaracion e inicializacion de la soli


MqlTradeRequest request={
MqlTradeResult result={0
//­­­ parametros de la solicitud
request.action =TRADE_ACTION_
request.symbol =Symbol();
request.volume =0.1;
request.type =ORDER_TYPE_BU
request.price =SymbolInfoDou
request.deviation=5;
request.magic =EA_Magic;

//­­­ envio de la solicitud


if(!OrderSend(request,result))
PrintFormat("OrderSend error %d
//­­­ informacion sobre la oper
PrintFormat("retcode=%u deal=%

Yaiza Martin Sousa | 12 may. 2020 en 22:01

Libni Colina:

Me di cuenta que el Robot intenta abris las


ordenes pero siempre da error:

Salida:
2020.05.06 20:35:16.141 Core 1 2020.04.20
20:25:00 failed market sell 0.10 EURUSD sl:
1.08965 tp: 1.07665 [Invalid request]

He cambiado Varias cosas en el código pero


ne se me da, les agrego el código que tengo:

Original: mrequest.type_filling = "Lo he


puesto de las 3 formas que estan en la
documentación"

Añade esto arriba del codigo:

#include <Trade\Trade.mqh>

Y luego para abrir una operacion solo tienes que


escribir esto:

double volumen= 0.01; // O el volumen que quie


CTrade m_trade;

m_trade.Buy(volumen); // Compra

m_trade.Sell(volumen); // Vende

dhlaldo | 14 jun. 2020 en 21:15


Buen día, Si alguien me pudiera ayudar por favor. A
mi entender, hice todo lo que se indica en el
articulo. Pero no logro poder tener dos operaciones
simultaneas abiertas, mas allá de lo que entiendo
que el autor quiso hacer de no colocar compra si ya
había compra o venta si ya había venta. Mi
estrategia, manda por ejemplo señal de venta
cuando tengo una orden abierta de compra, y en
lugar de abrir una venta, el codigo me cierra la
operación de compra sin que esta pueda tocar el
tp/sl. Y asi me quedo sin venta ni compra. La venta
cierra compra y compra cierra venta. Estoy usando
en mi estrategia solo un par, solo una temporalidad
y solo un tamaño de lote. Me podrían decir como
puedo tener compra y venta abiertas al mismo
tiempo si así lo llega a activar la estrategia? Es decir,
que las ordenes ÚNICAMENTE se cierren mediante
tp/sl. De antemano, muchas gracias.

maabypm | 28 jun. 2021 en 20:05


Hola,
Muchas gracias por el artículo Samuel. ¡Eres un
crack!
Me ha costado un poco que me funcionase con mi
broker porque el artículo es en versión en modo
"net" y he tenido que buscar información para
ponerlo en modo "hedging". El primer problema que
me encontré es con el mrequest.type_filling.
Para el broker XM, el que funciona es:

mrequest.type_filling = ORDER_FILLING_IOC

Si no sabes cual es la que permite tu MT5, mi


recomendación es que uses la función TypeFilling()
en un Print(TypeFilling()) o un Comment(
TypeFilling()) y este devuelve el tipo; si te dice que
es 1 (ORDER_FILLING_FOK) o 2
(ORDER_FILLING_IOC) ya sabes cual tienes que
poner
(https://www.mql5.com/es/docs/constants/tradingconstant
ya que a mi el ORDER_FILLING_FOK (1) no me
funciona con este broker.

Una vez arreglado eso, el problema es que con el


PositionSelect abre muchísimas posiciones. Aunque
no lo dice Samuel en su estrategia, entiendo que el
objetivo es abrir una única posición buy o sell (la
que primero se de) con el criterio establecido (los 4
pasos booleanos) y que hasta que no se cierre esta
posición, no podemos abrir otra.
Yo lo que he hecho es cambiar este código ...

//­­­ no tenemos errores, así que continuamos


//­­­ ¿Tenemos posiciones abiertas ya?
bool Buy_opened=false; // variable que al
bool Sell_opened=false; // variable que al

if (PositionSelect(_Symbol) ==true)
{
if (PositionGetInteger(POSITION_TYPE
{
Buy_opened = true; // Es una Comp
}
else if(PositionGetInteger(POSITION_T
{
Sell_opened = true; // Es una Vent
}
}

Por este...

//­­­ No tenemos errores así que continuamos


//­­­ ¿Tenemos posiciones abiertas ya?
bool Buy_opened = false;
bool Sell_opened = false;

// Vamos a recorrer todas las órdenes para


for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket
PositionSelectByTicket(ticket);

if(PositionGetInteger(POSITION_TYPE) ==
{
Buy_opened = true; // es una c
}
else if(PositionGetInteger(POSITION_T
{
Sell_opened = true; // es una v
}
}

// si hay una posición abierta esperamos hasta


if (Buy_opened || Sell_opened) return

Nota: Justo después viene la linea...

//­­­ Copiar el precio de cierre de la barra a


p_close=mrate[1].close;

De esta forma me ha funcionado bien. Espero que os


sirva.
Un saludo.
MQL5: Crea tu propio indicador
¿Qué es un indicador? Se trata de un conjunto de valores
calculados y que queremos que se muestren en la pantalla
de manera cómoda para nosotros. Los conjuntos de
valores se representan en los programas en forma de
matrices. De este modo, la creación del indicador consiste
en escribir un algoritmo que maneja algunas matrices
(matrices de precios) y graba los resultados del
procesamiento de otras matrices (valores del indicador).
Mediante la descripción de la creación de True Strength
Index (Índice de fuerza verdadera), el autor muestra
cómo escribir indicadores en MQL5.

Creación de indicadores de tick en MQL5


En este artículo vamos a ver la creación de dos
indicadores: el indicador de tick, que representa el
gráfico de tick del precio, y el indicador de vela de tick,
que representa las velas con el número de ticks
especificados. Cada uno de los indicadores escribe los
precios de llegada en un archivo y utiliza los datos
guardados tras el reinicio del indicador (estos datos
pueden ser usados también por los demás programas).

Aplicar un Indicador a Otro


Al escribir un indicador que usa la forma corta de la
llamada de función OnCalculate(), puede que no se dé
cuenta del hecho de que un indicador se puede calcular no
solo por datos de precio, sino también por datos de otro
indicador (independientemente de si viene incorporado o
es personalizado). ¿Desea mejorar un indicador para su
correcta aplicación a los datos del otro indicador? En este
artículo, revisaremos todos los pasos para realizar tal
modificación.

Los estilos de representación en MQL5


Hay 6 estilos de representación en MQL4 y 18 en MQL5.
Por ello, merece la pena dedicar un artículo a una
introducción sobre los estilos de representación en MQL5.
En este artículo vamos a tratar en profundidad los estilos
de representación en MQL5. Además, crearemos un
indicador para mostrar estos estilos y configurar el
trazado.

i
Join the t
u
updated a
LEARN MORE
Chats t
i

Plataforma comercial Sobre el proyecto MetaTrader 5


MetaTrader 5
Crónica de la página
Últimas actualizaciones de
Condiciones de uso
MetaTrader 5
Acuerdo de Pago Recurrente
Noticias, implementaciones
MQL5 Channels
y tecnologías Contrato de Representación ‐
Oferta
Guía del usuario de
MetaTrader 5 Política de Privacidad y
Protección de Datos Economic Calendar
Lenguaje de estrategias
comerciales MQL5 Política sobre cookies
MQL5 Cloud Network Información y contacto
Analítica integral No es un bróker, no hay cuentas
Descargar MetaTrader 5 comerciales reales
Instalar la plataforma 35 Dodekanisou str, Germasogeia,
4043, Limassol, Cyprus
Eliminar programas
Copyright 2000‐2023, MetaQuotes Ltd

También podría gustarte