Sunteți pe pagina 1din 148

LENGUAJE DE PROGRAMACIN MQL

RESUMEN DE http://book.mql4.com

Conceptos Bsicos
Comentarios
El comentario de una lnea es cualquier secuencia de caracteres que van a continuacin de una doble
barra (//). Una lnea de comentario queda terminada con el salto de lnea.
El comentario multi-lnea comienza con / * y termina con * /
Comentario de una lnea:
//Hola mundo
Comentario multi-lnea:
/*
Hola mundo
esto es una prueba
*/
Maysculas Minsculas
MQL4 distingue entre maysculas y minsculas.
Variables
Ejemplo de nombres de variables: Alfa, alFa, beta, el_nmero, Num, A_37, A37, qwerty_123
El valor de una variable puede ser cambiado por el programa. El nombre de la variable es siempre el
mismo.
Ejemplo de Constantes y Variables en un programa
Constantes y variables se pueden encontrar en los operadores de un programa. En el cdigo que aparece
a continuacin, A y B son variables, 7 y 3 son constantes:
A = 7; // Lnea 1
B = A + 3; // Lnea 2.
El valor de una variable puede ser cambiado durante la operacin del programa. Por ejemplo, puede
haber una lnea en el programa que contenga lo siguiente:
B = 33 // Lnea 3

Tipos de Datos
int (integer) nmeros enteros
Hay dos tipos:
Decimales: estos valores se presentan en forma de dgitos del 0 al 9 y pueden ser positivos o
negativos: 10, 11, 12, 1, 5, -379, 25, -12345, -1, 2.
Hexadecimales: estn formados por las letras de la A a la F y los dgitos del 0 al 9. Deben
comenzar con 0x o 0x y tomar valores positivos o negativos: 0x1a7b, 0xff340, 0xAC30X2DF23,
0X13AAB, 0x1.
Los valores de tipo int deben estar dentro del rango de -2.147.483.648 a 2.147.483.647.
Ejemplos:
int Art = 10; // Ejemplo variable integer
int B_27 = - 1; // Ejemplo variable integer
int num = 21; // Ejemplo variable integer
int Max = 2147483647 // Ejemplo variable integer
int min = - 2147483648; // Ejemplo variable integer
double - nmeros reales
Los valores de tipo double son nmeros reales que contienen una parte decimal. Puede ser
cualquier valor que tenga una parte decimal, por ejemplo: inclinacin de la lnea de apoyo.
Ejemplo:
De qu tipo debe ser la variable A, si considera la cantidad media diaria de rdenes abiertas por
el programa en una semana? Suponiendo que la cantidad total de rdenes que abri en el plazo
de una semana es de 10, se puede pensar que si 2 (10 rdenes / 5 das = 2) no tiene parte decimal,
esta variable puede ser considerada como int. Sin embargo, este razonamiento es errneo. El
valor actual de una variable puede tener una pequea parte que consta slo de ceros. Es
importante saber que el valor de esa variable es real, por su propia naturaleza. En este caso, esa
variable debe ser de tipo double.
La separacin del punto decimal tambin debe ser mostrada en el registro del programa: Z = 2.0
Los valores reales (double) de constantes y variables constarn de una parte entera, un punto
decimal, y una parte decimal. Los valores pueden ser positivos o negativos. La parte entera y la
parte decimal se forman con los dgitos del 0 al 9. La cantidad de cifras significativas despus del
punto decimal puede alcanzar el valor de 15.
Ejemplos:
double Arte = 10.123; // Ejemplo de variable real
double B_27 = - 1.0; // Ejemplo de variable real
double Num = 0.5; // Ejemplo de variable real
doble MMM = - 12.07; // Ejemplo de variable real
doble Price_1 = 1.2756; // Ejemplo de variable real
Notas personales:
Entre el signo menos (-) y el nmero, hay un espacio en blanco.
Despus de cada nmero hay un punto y coma (;)
bool - bolean de valores lgicos
Los valores de tipo bool son valores boleanos (lgicos) que contienen valores de tipo true
(verdadero) o false (falso). Ejemplo:
bool aa = True; // la variable Boolean __ tiene el valor de verdadero
bool B17= TRUE // la variable Boolean B17 tiene el valor de verdadero
bool Hamma = 1; // la variable Boolean Hamma tiene el valor de verdadero
bool TEA = False; // la variable Boolean TEA tiene el valor de falso
bool Nol = false; // la variable Boolean Nol tiene el valor de falso
bool Prim = 0; // la variable Boolean Prim tiene el valor de falso
Notas personales:
Por ejemplo, para verdadero se puede poner: True, true, TRUE o el nmero 1.
string- valores de tipo cadena de caracteres
Un valor tipo string es un conjunto de caracteres colocados entre comillas dobles (no pueden
incluirse dobles comillas simples).
Si hay necesidad de introducir dobles comillas ( "), se debe poner una barra diagonal inversa (\)
antes. Cualquier carcter especial puede ser introducido en una constante de tipo string tras la
barra inversa (\).
La longitud de una constante de tipo string va de 0 a 255 caracteres.
Combinaciones especiales: Una combinacin de dos caracteres, el primero de los cuales es la
barra inversa (\), es comnmente aceptado y percibido por la mayora de los programas como una
instruccin para ejecutar un determinado formato de texto. Esta combinacin no se muestra en el
texto. Por ejemplo, la combinacin de \n indica la necesidad de un salto de lnea; \t demanda de
tabulacin, etc.
Ejemplos:
string prefix = "MetaTrader 4"; // Ejemplo variable string
string Postfix = "_of_my_progr. OK"; // Ejemplo variable string
string Name_Mass = "Historial"; // Ejemplo variable string
string texto = "Lnea Alta \n Bajo la lnea" //el texto contiene caracteres de salto de lnea
color - valores de tipo color
Los valores constantes y variables de tipo color pueden ser representados con una de tres formas
distintas:
Literales
El valor de tipo color es representado como un literal y consta de tres partes que representan los
valores numricos de intensidad de tres colores bsicos: rojo, verde y azul (RGB). Un valor de
este tipo empieza con "C" y el valor numrico esta encerrado entre comillas simples.
Los valores numricos de RGB tienen una intensidad de 0 a 255 y se pueden grabar tanto en
decimal como en hexadecimal.
Ejemplos: C'128128128'(gris), C'0x00, 0x00, 0xFF' (azul), C'0xFF, 0x33, 0x00(rojo).
Representacin Integer (Representacin por enteros)
La representacin integer se registra como nmero hexadecimal o un nmero decimal. Un
nmero hexadecimal se muestra como 0xRRGGBB, donde RR es el valor de intensidad de color
rojo; GG, verde; y BB, azul.
Nombres de colores
La forma ms fcil de definir colores es especificar su nombre de acuerdo con la grfica de
colores web. En este caso, el valor de un color se representa como una palabra que corresponda
con el color, por ejemplo, Red es el color rojo.
Ejemplos:
color Un = Red; // El valor rojo fue asignado a la variable
color B = Yellow; // El valor amarillo fue asignado a la variable
color Colorit = Black // El valor negro fue asignado a la variable
datetime - valores de fecha y hora
La constante se enmarca entre comillas simples y comienza con 'D'. Est permitido el uso
truncado de valores: o bien sin fecha o sin tiempo, o simplemente un valor vaco. El rango de
valores va desde el 1 de enero de 1970 al 31 de diciembre de 2037.
Ejemplos:
datetime Alfa = D '2004.01.01 00: 00' // Ao Nuevo
datetime Tim = D "01.01.2004"; // Ao Nuevo
datetime Tims = D '2005.05.12 16: 30: 45'; // 12 de Mayo de 2005 a las 4:30:45 PM
datetime N_3 = D '12/05/2005 16: 30: 45'; // 12 de Mayo de 2005 a las 4:30:45 PM
datetime Compilar = D''; //equivalente de D '[compilacin fecha] // 00:00:00

Declaracin de variables e inicializacin


Con el fin de evitar posibles preguntas por el programa acerca a qu tipo de datos pertenece tal o cual a
variable, MQL4 acepta que se especifiquen explcitamente los tipos de variables al inicio del programa.
Antes de que una variable empiece a utilizarse en cualquier clculo deber ser declarada.
La Declaracin de Variables es lo primero que se debe hacer con cualquier variable dentro de un
programa. En la declaracin de una variable siempre ha de especificarse su tipo.
Asimismo, los nombres de las variables No pueden comenzar por nmeros o smbolos.
Por ltimo hay que tener en cuenta que las palabras del lenguaje MQL4 deben ir siempre en minsculas.
Por ejemplo, las expresiones: DOUBLE hightPrice1; Double hightPrice2; producirn un error al
compilar.
La Inicializacin de Variables significa la asignacin de un valor acorde con su tipo y que se efecta
en su declaracin. Todas las variables pueden ser inicializadas. Si no hay valor inicial que se establezca
explcitamente, la variable se inicializa a cero (0), o si la variable es de tipo string, esta se inicializa
como una cadena de caracteres vaca.
El tipo de una variable solo se declara en la primera mencin del nombre de esta variable. Cuando se
menciona el resto de las veces su tipo ya no se vuelve especificar ms. En el curso de la ejecucin del
programa, el valor de la variable puede cambiar, pero su tipo y nombre siguen siendo los mismos. El
tipo de una variable puede ser declarada en lneas simples o en los operadores (explicado en el ejemplo).
Ejemplo:
int Var_1; // declaracin de variable en una sola lnea
Tambin pueden ser declaradas varias variables en una sola lnea:
int Var_1, Box, Com; // Declaracin de varias variables en una lnea
Las variables pueden tambin ser inicializadas dentro de los operadores
double Var_5 = 3,7; // Variable inicializada en un operador de asignacin
Nota: al declarar las variables, ya sea una o varias variables por lnea, al final de la misma, antes del
comentario, debe terminarse con un punto y coma (;)
Inicializacin de variable en la cabecera de un operador compuesto: significa que en el inicio de un
operador compuesto se declara de qu tipo de variable se trata, luego se puede volver a nombrar la
variable y ya no se debe indicar su tipo. Ejemplo:
for (int i = 1; i>=10; i++) // Se declara que la variable i es de tipo int.

Otros conceptos
Operando
Es una constante, una variable, un conjunto de componentes o un valor devuelto por una funcin.
Operacin
Es una accin hecha con los operandos.
Smbolo de la Operacin
Es un carcter preseleccionado o un grupo de caracteres que ordenan ejecutar una operacin.
Expresin
Es una secuencia de operandos y operaciones de smbolo, es un registro de programa, el valor calculado,
el cual se caracteriza por un tipo de datos.
Tipos de Operaciones
Existen los siguientes tipos de operaciones en MQL4:
operaciones aritmticas;
operaciones de asignacin;
operaciones relacionales;
operaciones Boolean (lgicas);
operaciones bitwise;
operacin coma;
llamado de funcin (funcin call).
Las operaciones se utilizan en los operadores (ver Operadores). Slo en los operadores su utilizacin
tiene sentido. La posibilidad de utilizar una operacin est determinada por las propiedades de los
operadores (si las propiedades del operador le permiten utilizar esta operacin especfica, puede usarse,
de lo contrario, no debe utilizarse esta operacin). No est permitido el empleo de las operaciones fuera
de los operadores.
Operaciones aritmticas
Los siguientes smbolos pertenecen a smbolos de operaciones aritmticas:
Smbolo Operacin Ejemplo Analoga
+ Adicin de valores x+2
- La resta de valores o de cambio de signo x - 3; y = - y
* Multiplicacin de valores 3*x
/ Cociente de la divisin x/5
% Residuo de la divisin minutos = tiempo 60%
++ Incrementar 1 el valor de la variable y++ y=y+1
-- Disminuir 1 el valor de la variable y -- y=y-1

Tambin podemos combinar operaciones. Ejemplo: c = (a + b)*b;


Explicacin del clculo matemtico de la lnea:
double Lots_New=MathFloor(Free*Percent/100/One_Lot/Step)*Step;
Supongamos que Free=5000.0, One_Lot=1360.0, Step=0.1. En este caso, la formula para calcular
Lots_New quedara as:
Lots_New = MathFloor(5000.0*30/100/1360.0/0.1)*0.1;
Con smbolos matemticos ordenados en la forma tradicional, podemos mostrar esta frmula de la
siguiente manera:
{ { [ (5000*30) / 100 ] / 1360 } / 0.1 } * 0.1, tambin: { { [ (Free*Percent) / 100 ] / One_Lot } / Step } * Step

Operaciones de Asignacin
Los siguientes smbolos pertenecen a smbolos de operaciones de asignacin:
Smbolo Operacin Ejemplo Analgica
= Asignacin del valor x a la variable y y=x
+= Aumento de la variable y en el valor x y+=x y=y+x
-= Reduccin de la variable y en el valor x y -= x y=y-x
*= Multiplicacin de la variable y por x y *= x y=x*y
/= Divisin de la variable y entre x y/x= y=y/x
%= Residuo de dividir la variable y en x y = x% y = x% y

Operaciones Relacionales
Los siguientes smbolos pertenecen a los smbolos de operaciones relacionales:
Smbolo Operacin Ejemplo
== Es cierto si x es igual a y x == y
!= Es cierto si x no es igual a y x! = y
< Es cierto si x es menor que y x <y
> Es cierto si x es mayor que y x>y
<= Es cierto si x es igual o menor a y x <= y
>= Es cierto si x es igual o mayor a y x> = y

Operaciones Boolean (lgicas)


Los siguientes smbolos pertenecen a los smbolos de operaciones boleanas:
Smbolo Operacin Ejemplo Explicaciones
TRUE(1), si el valor del operando es FALSE(0); FALSE(0),
! NO (negacin lgica) !x
si el valor del operando no es FALSE(0).
|| O (disyuncin lgica) x<5 || x>7 TRUE(1), si alguna de las dos expresiones es cierta
&& Y (conjuncin lgica) x==3 && y<5 TRUE(1), si las dos expresiones son ciertas

Operaciones Bitwise
Las operaciones Bitwise slo pueden realizarse con nmeros enteros. Las siguientes operaciones
pertenecen a operaciones bitwise:
Complemento a uno del valor de la variable. El valor de la expresin contiene 1 en todos los lugares, en
los cuales los valores de la variable contienen 0, y contienen 0 en todos los lugares, en los cuales los
valores de la variable contienen 1.
b= ~ n;
La representacin binaria de x que es desplazada y lugares a la derecha. Este desplazamiento lgico a la
derecha, significa que en todos los lugares que se han vaciado a la izquierda ser rellenado con ceros.
x = x>>y;
La representacin binaria de x que es desplazada y lugares a la izquierda. Este desplazamiento lgico a
la izquierda ser rellenado con ceros a la derecha.
x = x<<y;
La operacin bitwise AND de las representaciones binarias de x e y. El valor de la expresin contiene 1
(TRUE) en todos los lugares, en tanto que x e y contienen uno, y el valor de la expresin contiene 0
(FALSO) en todos los dems casos.
b = ((x + y)! = 0);
La operacin bitwise OR de las representaciones binarias de x e y. El valor de la expresin contiene 1 en
todos los lugares, en la que x o y contienen 1. Contiene 0 en todos los dems casos.
b = x | y;
La operacin bitwise exclusiva o de las representaciones binarias de x e y. El valor de la expresin
contiene 1 en los lugares, en los que x e y tienen diferentes valores binarios. Contiene 0 en todos los
dems casos.
b = x ^ y;
Operacin coma
Las expresiones separadas por comas se calculan de izquierda a derecha. Los efectos de los clculos a la
izquierda de la expresin ocurren siempre antes de que se calcule el lado derecho de la expresin. El tipo
y el valor del resultado son coincidentes con el tipo y el valor del lado derecho de expresin.
for (i = 0, j = 99; i <100; i++, j--) Print (array [i][j]); // Declaracin de buvle o ciclo (loop)
La lista de parmetros transferidos (vase ms adelante) puede considerarse como un ejemplo.
My_function (Alf, Bet, Gam, Del) // La llamada a una funcin con argumentos
Ejercicios
Problema 1. Juan tiene 2 lpices, Pedro tiene 3 lpices. Cuntos lpices tienen estos muchachos?
Solucin. Vamos a indicar el nmero de lpices de Juan como una variable A y el nmero de lpices de
Pedro como variable B, mientras que el resultado ser denominado C. La respuesta ser: A + B = C
Como los lpices son cosas, es decir, es algo que bsicamente puede existir como una parte (por
ejemplo, puede haber una mitad de un lpiz), entonces vamos a considerar a los lpices como variables
reales, es decir, las variables de tipo double. Clculos similares tambin pueden realizarse con nmeros
enteros int. Por tanto, podemos poner el cdigo de la solucin as::
double A = 2.0; // El nmero de lpices de Juan
double B = 3.0; // El nmero de lpices de Pedro
double C = A + B // Nmero total
En este caso, la operacin "+" se aplica a la suma de los valores de un tipo de variables.

Problema 2. En una esquina de la casa, hay una carnicera denominada "rtico". En otra esquina de la
misma casa, hay un establecimiento llamado "Saln de peluquera". Qu est escrito en la casa?
Solucin
string W1 = "Artico"; // String 1
string W2 = "Salon de peluqueria"; // String 2
string Ans = W1 + W2; // Suma de strings
El valor de la variable Ans ser la cadena (string) que aparece como sigue: ArticoSalon de peluquera
El resto de operaciones aritmticas con variables de tipo string (resta, multiplicacin, divisin) No estn
permitidas.

Problema 3. Calcular los valores de las expresiones A/B*C y A*C/B, para los enteros A, B y C.

Se espera intuitivamente que el resultado del clculo en ambos casos sea el mismo. Sin embargo, esta
afirmacin es cierta slo para los nmeros reales. Si queremos calcular los valores de las expresiones
compuestas de los operandos de tipo int, debemos siempre considerar el resultado intermedio. En tal
caso, la secuencia de operandos es de fundamental importancia:
int A = 3; // Valor de tipo int
int B = 5; // Valor de tipo int
int C = 6; // Valor de tipo int
int Res_1 = A/B*C; // Result 0 (cero)
int Res_2 = A*C/B; // Resultado 3 (tres)
Operadores
El termino Operador
Uno de los principales conceptos de cualquier lenguaje de programacin es el trmino de operador.
Cuanto mejor comprende un programador lo que son los operadores, y cmo se aplican en un programa,
antes se inicia ste en la escritura de sus propios programas.
El operador es parte de un programa, una frase de un lenguaje algortmico que prescribe un
determinado mtodo de conversin de datos.
Cualquier programa contiene operadores. La analoga ms cercana a operador es una frase. As como
una frase compone el texto normal de una novela, as los operadores componen un programa.
Propiedades de los operadores
Todos los operadores tienen una propiedad comn: todos ellos se ejecutan.
Podemos decir que el operador es una instruccin que contiene la gua de operaciones, la descripcin de
una orden.
Que una PC ejecute un programa significa que (consecutivamente, pasando de un operador a otro) se
cumplan las rdenes (las recetas, instrucciones) que figuran en los operadores.
Tipos de Operadores
Hay dos tipos de operadores: los operadores simples y los compuestos.
Operadores simples
Los operadores simples siempre terminan en ";" (punto y coma). El uso de este separador es para que la
PC pueda detectar cundo un operador termina y comienza otro. Un operador puede tener varias lneas.
Se pueden colocar varios operadores en una lnea. Ejemplos:
Go_My_Function_ind(); // Operador simple
a=3; b=a*x+n; i++; // Varios operadores colocados en linea
Print(" Day= ",TimeDay(Mas_Big[s][0]), // Un operador...
" Hour=",TimeHour(Mas_Big[s][0]), // colocado
" Minute=",TimeMinute(Mas_Big[s][0]), // en varias
" Mas_Big[s][0]= ",Mas_Big[s][0], // lineas
" Mas_Big[s][1]= ",Mas_Big[s][1]);

Operadores compuestos
Un operador compuesto consta de varios operadores simples separados por punto y coma ;.El
conjunto de operadores simples estn ubicados en un recinto separado por llaves. La presencia de una
llave de cierre marca el final de un operador compuesto. Con el fin de poder utilizar varios operadores
donde se espera que haya solo uno, los programadores utilizan un operador compuesto (tambin lo
llaman "bloque" o "bloque de cdigo").
Un ejemplo de utilizacin de un operador compuesto es un operador condicional. Comienza con el
operador condicional if (expresin), seguido por un bloque compuesto de operadores simples llamado
cuerpo. Este cuerpo contiene una lista de operadores ejecutables.
Orden de ejecucin de los operadores
Los operadores se ejecutan en el orden en el que aparecen en el programa. La direccin de los
operadores de ejecucin va de izquierda a derecha y de arriba hacia abajo.

Ejemplo de un Operador de Asignacin


En el lado izquierdo de la igualdad solo puede haber una variable y en el lado derecho una expresin con
cualquier grado de complejidad.
Problema 4. Tenemos un sistema de ecuaciones: Y = 5 y Y - X = 2. Hallar el valor numrico de la
variable X.
Solucin 1. En un texto normal en una hoja de papel:
5-X=2
X=5-2
X=3
Solucin 2. Un texto en un programa:
Y =5; // Lnea 1
X = Y-2; // Lnea 2
En la memoria fsica de la PC se registra el valor numrico 3 para la variable X.
Ejemplo de un contador
X = X + 1; // Ejemplo de un contador
Desde un punto de vista lgico, este ejemplo parece un error matemtico. Sin embargo, es correcto si se
considera como un operador (por cierto, este operador se utiliza ampliamente en la codificacin).
Con este operador hemos calculado un nuevo valor para la variable X: cuando se ejecuta el operador de
asignacin (es decir, el clculo del valor de la parte derecha del operador), la PC toma el valor de la
memoria fsica que contiene el valor numrico de la variable X (que en el ejemplo anterior resulta ser
igual a 3 en el momento de referirse a ella), y calcula la expresin en la parte derecha del operador de
asignacin (3 + 1), y escribe el valor obtenido 4 en la memoria celular (fsica) de la PC para la variable
X. La mquina almacenar este valor de la variable X hasta que la variable X se presente en la parte
izquierda del signo de igualdad en otro operador de asignacin. En este caso, el nuevo valor de esta
variable se calcular y se almacenan hasta el prximo posible cambio.
Funciones
Descripcin o Definicin de la Funcin: es la parte donde se nombra el programa.
Llamada de funcin: es un registro, es el acto que conduce a la ejecucin de la funcin.
En nuestra vida cotidiana, podemos encontrar muchas analogas de la funcin. Tomemos, por ejemplo,
el sistema de frenado de un coche. La idea implementada por el ingeniero es anloga a la
definicin/descripcin de funcin, mientras que el pedal de freno es anlogo a la llamada a la funcin.
El conductor presiona el pedal, y los mecanismos de accionamiento realizan ciertas acciones y detienen
el coche. Del mismo modo, si la llamada a una funcin se produce en un programa, entonces la funcin
del mismo nombre ser llamada y ejecutada, es decir, se llevarn a cabo una cierta secuencia de clculos
u otras acciones (por ejemplo, se muestra un mensaje o una orden de apertura, etc.). El sentido general
de una funcin es la adopcin de una lgica que se completa fuera del texto base del programa, mientras
que slo se mantiene dentro del texto base del programa la parte del cdigo que se ocupa de la llamada
de esta.
Este programa de construccin tiene las siguientes ventajas:
El texto del programa est integrado de tal manera que se lee mucho ms fcil.
Se puede ver con facilidad y, si es necesario, modificar el texto de una funcin sin realizar ningn
cambio en el cdigo bsico o programa principal.
Una funcin puede estar compuesta como un solo archivo y usarse en otros programas, lo cual liberar
al programador de la necesidad de insertar el mismo fragmento de cdigo en cada nuevo programa.
La mayor parte del cdigo de los programas que usan MQL4 est escrito en forma de funciones.
Este enfoque se extendi y actualmente es un estndar.
Composicin de una funcin
Por lo tanto, una funcin est compuesta de la descripcin y la llamada. Vamos a considerar un ejemplo.
Supongamos que tenemos un pequeo programa que considera la longitud de la hipotenusa utilizando
los otros dos lados del tringulo rectngulo y el teorema de Pitgoras.
En este programa, todos los clculos se encuentran juntos, los operadores son ejecutados uno por uno en
el orden en el que se producen en el programa (de arriba hacia abajo).
Problema 5. Redactar una parte del cdigo del programa como una funcin.
Sera razonable hacer una funcin utilizando las dos lneas que encuentran el valor buscado. En este
programa, una parte de los clculos se integra como una funcin. El cdigo bsico contiene una llamada
a la funcin definida por el usuario. La descripcin de la funcin definida por el usuario se encuentra
fuera, despus del cdigo bsico:

Descripcin de la Funcin
La descripcin de una funcin consta de dos partes bsicas: cabecera de la funcin y cuerpo de la
funcin.
La cabecera de una funcin est formada por: el tipo del valor de return, el nombre de funcin y la lista
de parmetros formales.
La lista de parmetros formales est encerrada entre parntesis y se coloca despus del nombre de la
funcin.
El tipo del valor de return puede ser uno de los tipos que ya conocemos: int, double, bool, color,
datetime, o string. Si la funcin no devuelve ningn valor, su tipo puede ser denominado void (sin
contenido, vaco).
La descripcin de la funcin definida por el usuario debe estar presente en el programa y se coloca
inmediatamente despus de que se cierra la llave de la funcin especial start() (es decir, se coloca fuera
de la funcin especial start).
Llamada a la Funcin
La llamada a la Funcin se representa con el nombre de la funcin y la lista de parmetros transferidos.
La lista de parmetros transferidos se coloca entre parntesis. La llamada a la funcin puede ser
representada como un operador independiente o como parte de un operador.

TIPOS DE FUNCIONES
Hay tres tipos de funciones: funciones especiales, funciones estndar (built-in o predefinidas), y
funciones definidas por el usuario.
Funciones especiales
En MQL4, hay en total 3 funciones especiales. Ellas tienen nombres predefinidos: init(), start(), y
deinit(), que no pueden utilizarse como nombres de ninguna otra funcin.
El cdigo bsico de un programa se encuentra dentro de estas funciones.
La caracterstica especial de las funciones especiales es el hecho de que son llamadas para su ejecucin
desde el Terminal de Usuario. Aunque las funciones especiales tienen todas las propiedades de las
funciones en general, no se les suele llamar desde el programa si ste est codificado correctamente.
Funciones estndar
MQL4 tiene una serie de tiles funciones en las cuales, cuando se escribe la codificacin del programa
no es necesario hacer su descripcin. Por ejemplo, el clculo de races cuadradas, la impresin de
mensajes en el sistema o en la pantalla.
La caracterstica singular de las funciones estndar es que no estn descriptas en el texto del programa.
Las funciones estndar son llamadas en el programa de la misma manera a como lo hace cualquier otra
funcin.
En el ejemplo expuesto anteriormente se utilizan dos funciones estndar: MathSqrt () y Alerta (). La
primera est destinada al clculo de races cuadradas, mientras que la segunda est diseada para
mostrar un determinado mensaje de texto, puesto entre parntesis, en la pantalla.
Estas funciones, tambin pueden ser denominadas funciones built-in, o funciones predefinidas.
En el texto de un programa, se puede distinguir fcilmente la llamada a la funcin estndar por su
aspecto, que se destaca en MetaEditor con color morado (los colores pueden elegirse a voluntad).
Funciones definidas por el usuario
En algunos casos, los programadores crean y utilizan sus propias funciones y hacen la llamada a estas
funciones. Las Funciones definidas por el usuario se utilizan en los programas con la descripcin de la
funcin y las llamadas a la funcin.

PROPIEDADES DE LAS FUNCIONES


Ejecucin de la Funcin
La principal propiedad de todas las funciones es que la llamada a la funcin hace que ests se ejecuten.
Las funciones se ejecutan de acuerdo a sus cdigos.
El paso de parmetros y el valor de return
El paso de los parmetros se especifica encerrndolos entre parntesis despus del nombre de la funcin
que se llama.
El paso de parmetros se hace usualmente separndolos mediante comas. El nmero de parmetros
transferidos a la funcin no debe superar 64. La funcin tambin puede omitir el uso de paso de
parmetros. En este caso se especifica una lista vaca de parmetros, es decir, simplemente hay que
poner un parntesis de apertura y uno de cierre directamente despus del nombre de funcin.
La cantidad, tipos y orden de los parmetros transferidos en la llamada a la funcin deben coincidir con
los parmetros de formacin que se especifica en la descripcin de la funcin.
El valor de return se especifica en los parntesis del operador return (). El tipo del valor devuelto
utilizando en el operador return () debe coincidir con el tipo de la funcin dada en la cabecera de la
funcin. Tambin es posible que una funcin no devuelva ningn valor; en este caso no se especifica
nada en el parntesis del operador return ().
Solamente se pueden utilizar variables en los parmetros formales de la cabecera de la descripcin de la
funcin.
Como parmetros transferidos, solo se pueden utilizar variables, constantes y expresiones:

Parmetros formales
Los Parmetros formales son una lista de variables especificadas en la cabecera de la descripcin de la
funcin.
Ya mencionamos antes que una misma funcin podra ser utilizada en varios programas. Sin embargo,
los diferentes programas utilizan diferentes nombres para las variables. Si las funciones requirieran de
forma estricta que se pusieran determinados nombres en las variables de los parmetros a transferir (y,
correlativamente su valor), no sera conveniente para los programadores. De hecho, usted tendra que
poner en cada programa recientemente desarrollado los nombres de variables que ya se han utilizado en
sus funciones anteriores. Sin embargo, afortunadamente, las variables utilizadas dentro de las
funciones no tienen relacin con las variables utilizadas en el programa que lo llama.
Solamente pueden especificarse variables (pero no constantes) como parmetros formales en la
cabecera de una funcin.
Cmo funciona (explicacin de la respuesta al Problema 5)
En el programa, se produce una llamada a la funcin, las variables A y B estn especificadas
entre parntesis.
El programa llama a la funcin con ese nombre y que tiene los parmetros formales a y b que se
especifican en su cabecera.
El valor de variable A se le asigna a la variable a.
El valor de la variable B se le asigna a la variable b.
La funcin ejecutable realiza los clculos utilizando los valores de las variables a y b.
Se puede usar cualquier nombre en los parmetros formales (mientras no coincidan con otros nombres
de variables ya utilizados en el programa). En este ejemplo, hemos utilizado los identificadores de los
parmetros formales a y b. Sin embargo, podramos utilizar cualquier otro, por ejemplo, m y n.
El valor de return calculado en la funcin se da en el parntesis del operador return (). Como valor de
return puede utilizarse el valor de una variable, el resultado de una expresin o una constante. En
nuestro caso, el valor de return es el valor de la variable local c (una variable local es una variable
declarada dentro de una funcin. A la salida de la funcin los valores de todas las variables locales se
pierden, y por tanto su mbito de trabajo es solo vlido dentro de la funcin). La funcin devuelve al
programa que lo llam el valor de la variable local c. Esto significa que este valor ser asignado a la
variable C.
Una forma ms compacta de escribir la misma funcin definida por el usuario:
//--------------------------------------------------------------------
int Gipo(int a, int b) // Funcin definida por el usuario
{
return(MathSqrt(a*a + b*b)); // Operador Funcin Salida
}
//-------------------------------------------------------------------
En este caso todos los clculos se realizan en un solo operador. El valor de return se calcula
directamente en el parntesis del operador return ().
De este modo, la aplicacin de funciones definidas por el usuario tiene algunas ventajas:
Los nombres de variables en el texto del programa principal no tienen relacin con los nombres
de los parmetros formales de una funcin definida por el usuario.
Las funciones definidas por el usuario pueden ser reutilizadas en diferentes programas, no hay
necesidad de cambiar el cdigo de la funcin definida por el usuario. Lo nico que se deber
recordar es el orden de las variables en la cabecera y en la llamada a la funcin.
Se pueden crear libreras, si fuera necesario.
Programas
El programador elige el tipo de programa que va a ser escrito en funcin del propsito de ese programa
especfico y las propiedades y limitaciones de los diferentes tipos de programas.
El Asesor Experto (EA) es un programa para ser ejecutado en cada uno de los ticks. El objetivo
principal de los Asesores Expertos es programar el control sobre el comercio.
Los Scripts son destinados a realizar cualquier tipo de operaciones que permitan ser ejecutadas una sola
vez.
El Indicador personalizado es un programa para ser ejecutado, al igual que el EA, en todos los ticks.
Estn bsicamente destinados a la exhibicin grfica de funciones matemticas calculadas
preliminarmente. Hay dos tipos de indicadores: indicadores tcnicos (built-in) y los indicadores
personalizados (creados por el propio usuario).
Propiedades de los Programas
Una vez que se haya vinculado un programa (EA o indicador personalizado) a la ventana de smbolo o
instrumento, el programa hace algunos preparativos y cambia al modo de espera de ticks. Tan pronto
como un nuevo tick entra, la Terminal de Usuario lo pondr en marcha para su ejecucin, entonces, el
programa hace todas las operaciones descriptas en su algoritmo, y, una vez que termina, pasa el control
nuevamente a la Terminal de Usuario y permanece en el modo de espera de ticks.
Si un nuevo tick llega cuando el programa (EA o indicador personalizado) se est ejecutando, este
evento no tiene ningn efecto sobre la ejecucin del programa, el programa sigue siendo ejecutado de
acuerdo a su algoritmo y el control solo pasa a la Terminal de Usuario cuando el programa haya
terminado todas las tareas descriptas en su algoritmo.
Una vez que un Asesor Experto se asocia a la ventana de smbolo o instrumento, hace los preparativos
necesarios (funcin init()) y cambia al modo de espera de ticks preparado para iniciar la funcin start().
A diferencia de los EAs, el indicador personalizado ejecuta tanto la funcin init() como la funcin start()
una vez que hace el primer clculo preliminar del valor del indicador. Ms tarde, con un nuevo tick, el
indicador personalizado se inicia llamando nicamente a la funcin start(), es decir que los operadores
trabajan de acuerdo con el algoritmo de la funcin start().
A diferencia de los Asesores Expertos o los indicadores, un Script se pondr en marcha para su
ejecucin inmediatamente despus de que haya sido asociado a una ventana de smbolo, sin esperar a un
nuevo tick. Todo el cdigo del script se ejecutar de una vez. Despus de que todas las lneas del
programa se han ejecutado, el script pone fin a sus operaciones y se desvincula de la ventana de smbolo.
Un script es til si se quieren hacer operaciones de una sola vez, por ejemplo, abrir o cerrar rdenes,
mostrar textos en la pantalla, instalar objetos grficos, etc.
Slo los Asesores Expertos y los Scripts tienen la posibilidad de utilizar las funciones de trading. En los
indicadores personalizados no est permitido el empleo de funciones comerciales (funciones de trading).
Solo se puede asociar un EA en una ventana de smbolo; no est permitido el uso simultneo de varios
Asesores Expertos en la misma ventana.
Solo se puede asociar un script en una ventana de smbolo; no est permitido el uso simultneo de varios
script.
Se pueden asociar al mismo tiempo varios indicadores en una ventana de smbolo pero de manera que
no interfieran entre s.
Tipos de archivo
mq4: Contienen el cdigo fuente de un programa (EA, Script o Indicador). Son editables.
ex4: Surgen al compilarse un archivo .mq4. Son archivos ejecutables. No pueden editarse. Los archivos
con extensin .ex4 se pueden utilizar como archivos de la librera.
mqh: Son los archivos de inclusin y se almacenan en el directorio \experts\include. Generalmente son
incluidos en la fase de compilacin.
Existen otros tipos de archivos que no hacen un programa completo, pero se utilizan en la creacin de
programas. Por ejemplo, un programa puede ser creado usando una librera creada anteriormente. Un
usuario puede crear libreras de funciones personalizadas destinadas al almacenamiento para uso
frecuente de bloques de programas de usuario. Se recomienda almacenar las libreras en el directorio
\experts\libreries.
Los archivos de mq4 y ex4 se pueden utilizar como archivos de librera. Las libreras no pueden
ejecutarse por si mismas.
Es preferible el uso de archivos de inclusin al uso de libreras debido al consumo adicional de
recursos de la PC en las llamadas a funciones de librera.

Creacin y uso de programas


Al crear un nuevo asesor experto, el MetaEditor crea por defecto tres funciones especiales en el
programa: init(), start() y deinit().Cada funcin contiene un solo operador, return(0), que es el operador
para salir de la funcin.
El cdigo final del programa no tiene que contener obligatoriamente todas las funciones especiales
indicadas. Ellas estn presentes en la pauta, slo porque, como por regla general, un programa de nivel
medio habitualmente contiene todas estas funciones. Si alguna de las funciones no ser utilizada, su
descripcin puede ser eliminada.
Reglas para redactar el programa y los comentarios
La longitud de una lnea de comentario no debe exceder el tamao de la ventana principal. Esta
limitacin no es un requisito formal de sintaxis.
La declaracin de variables se realiza en el programa de inicio. Se recomienda escribir un
comentario descriptivo para cada variable.
Es preferible que cada operador est situado en una lnea distinta.
Si hay un comentario en una lnea debe iniciarse a partir de la 76 posicin. Este requisito no es
obligatorio.
Para dividir lgicamente fragmentos separados, se utilizan lneas continuas del ancho total (118
caraceters).
Cuando se utilizan las llaves se incluye una tabulacin de 3 smbolos.
ESTRUCTURA DE UN PROGRAMA

La norma de programacin en MQL4 es la siguiente:


El cdigo de un programa debe ser escrito dentro de funciones. Es decir, las lneas de programa
(operadores y llamadas a funciones) que se encuentran fuera de una funcin no pueden ser ejecutadas.
Vamos a considerar el plan funcional de un programa comn, Asesor Experto:

Los bloques mayores de un programa escrito en MQL4 son los siguientes:


1. Cabecera del programa: consta de varias lneas al comienzo de un programa (a partir de la
primera lnea) que contienen informacin general sobre el programa. Por ejemplo, esta parte
incluye lneas de la declaracin y la inicializacin de variables globales.
2. Funcin especial init(). Por lo general, despus de la cabecera son descriptas las funciones
especiales, las cuales tienen nombres predefinidos: init(), start() y deinit().
3. Funcin especial start().
4. Funcin especial deinit().
5. Funciones definidas por el usuario. La descripcin de funciones definidas por el usuario
usualmente se presentan despus de la descripcin de las funciones especiales. El nmero de
funciones definidas por el usuario en un programa no est limitado.
Esta es la disposicin habitual de bloques funcionales, es decir: cabecera, funciones especiales y
funciones definidas por el usuario:
Estas son otras variantes de estructura de un programa. En todos los ejemplos la parte de la cabeza es lo
primero, mientras que las funciones pueden ser descriptas en un orden aleatorio:

Secuencia de ejecucin de cdigo


Cabecera y funciones especiales
Al iniciar la ejecucin del programa en una ventana de un smbolo, se ejecutan partes de las lneas de
programa de la cabecera. Despus, se realizan los preparativos descriptos en la cabecera.
Luego, las funciones especiales son llamados para ser ejecutadas por la Terminal de Usuario:
La funcin especial init() es llamada para la ejecucin una sola vez al comienzo de la operacin del
programa. Por lo general, esta funcin contiene un cdigo que debe ejecutarse slo una vez antes de la
operacin principal del programa de inicio start(). Por ejemplo, cuando el init() es ejecutado, se
inicializan algunas variables globales, se muestran objetos, mensajes etc.
Luego la Terminal de Usuario pasa el control a la funcin especial start() y esta se ejecuta.
Despus de que todo el cdigo de la funcin especial start() es ejecutado, se devuelve el control a la
terminal de usuario, la cual tendr el control durante algn tiempo, sin iniciar ninguna funcin especial,
hasta que llegue un nuevo tick y la terminal de usuario pase el control a la funcin especial start() una
vez ms, como resultado, la funcin ser ejecutada.
El proceso de mltiples llamadas de la funcin especial start() realizado por la Terminal de Usuario se
repetir mientras que el programa est asociado a un grfico, y puede continuar durante semanas y
meses. Durante todo este perodo un EA puede llevar a cabo operaciones de comercio automticas.
En esquema de arriba, el proceso de ejecucin mltiple de la funcin start() se muestra mediante
diversas flechas amarillas envolviendo a la funcin especial start().
Cuando un trader elimina un EA del grfico, la Terminal de Usuario inicia la funcin especial deinit().
La ejecucin de esta funcin es necesaria para la correcta finalizacin de una operacin del EA. Se
suprimen objetos innecesarios, variables, etc.
Tras la ejecucin de la funcin especial deinit() se devuelve el control a la Terminal de Usuario.
La ejecucin de funciones especiales puede hacer referencia a la informacin del entorno (flechas
delgadas de color azul en el esquema de arriba) y a la llamada para la ejecucin de funciones definidas
por el usuario (flechas delgadas de color amarillo).
Las funciones definidas por el usuario se ejecutan cuando la llamada est contenida en alguna funcin.
En este caso, el control pasa a la funcin definida por el usuario y despus de la ejecucin de la funcin
el control es devuelto al lugar de la llamada.
La llamada a las funciones definidas por el usuario se puede hacer no slo dentro de la descripcin de
una funcin especial, sino tambin en la descripcin de otras funciones definidas por el usuario. Esto no
solo esta permitido, sino que adems es ampliamente utilizado en la programacin.
El control de la accin, es decir, las rdenes de trading pueden formarse tanto en funciones especiales
como en funciones definidas por el usuario.
Funcin Especial init()
Si un programa contiene la descripcin de la funcin especial init(), ser llamada (y ejecutada) en el
momento de iniciar el programa.
No se recomienda llamar a la funcin start() desde la funcin especial init() ni realizar operaciones de
comercio desde init(), porque puede suceder que no estn listos algunos valores de los parmetros de la
informacin del entorno (informacin sobre grficas, precios de mercado, etc.)
Funcin Especial start()
Las propiedades especiales de la funcin start() difieren en funcin del tipo de programa que se ejecute:
El cdigo principal del programa debe estar contenido en la funcin start(). Todos los operadores, built-
in, las llamadas a las funciones personalizadas y todos los clculos necesarios se deben realizar dentro
de esta funcin.
En los Asesores Expertos la funcin especial start() se llama (y ejecuta) inmediatamente despus de
marcar un nuevo tick. Si un nuevo tick ha llegado durante la ejecucin de la funcin especial start(), este
tick no se tendr en cuenta. Todas las cotizaciones recibidas durante la ejecucin de la funcin especial
start() se ignoran.
En los Script la funcin especial start() se llama (y ejecuta) una sola vez, inmediatamente despus de la
inicializacin del programa especial en la funcin init().
En los Indicadores Personalizados, la funcin especial start() se llama (y ejecuta) inmediatamente
despus de marcar un nuevo tick, inmediatamente despus de que se vincula a un grfico, cuando se
cambia el tamao de una ventana, cuando se cambia de uno a otro instrumento, cuando se inicia la
Terminal de Usuario (si durante el anterior perodo de sesiones, un indicador se asoci a una grfica),
despus de cambiar un smbolo y el marco temporal actual de un grfico, con independencia del hecho
de que si las nuevas cotizaciones llegan o no.
Funcin Especial deinit().
La funcin particular de la funcin especial deinit() es la ejecucin de un programa de terminacin
(deinicializacin). Si un programa contiene la descripcin de la funcin especial deinit(), ser llamada (y
ejecutada) en un programa de apagado.
Tambin se llama a la funcin especial deinit() cuando la ventana de un smbolo es cerrada, antes de
cambiar el periodo de un grfico, en la re-compilacin exitosa de un programa, as como cuando se
cambia de cuenta.
Requerimientos de las funciones especiales
La presencia de las funciones especiales init() y deinit() no son imprescindibles dentro programa, es
decir, pueden estar ausentes. No importa el orden en el que estn descriptas las funciones especiales en
el programa.
Las funciones especiales se pueden llamar desde cualquier parte del programa de conformidad con las
reglas generales de llamadas de funciones.
OPERADORES
Operador de asignacin
El operador de asignacin es el operador ms simple y ms frecuentemente usado.
Un operador de asignacin representa un registro que contiene el caracter "=" (signo de igualdad). A la
izquierda de este signo de igualdad se especifica el nombre de una variable, a la derecha de ella damos
una expresin. El operador de asignacin finaliza con ";" (punto y coma).
En un operador de asignacin, no se permite que el tipo de una variable sea declarado ms de una vez.
Ejemplos del uso de funciones definidas por el usuario y funciones estndar en la parte derecha:
In = My_Function (); // The value of user-defined function is assigned to variable In
Do = Gipo(Do1,Do1); // The value of user-defined function is assigned to variable Do
Ejemplo de utilizacin de expresiones en la parte derecha:
In = (My_Function()+In2)/2; // The variable In is assigned
// ..with the value of expression
Do = MathAbs(Do1+Gipo(Do2,5)+2.5); // The variable Do is assigned
// ..with the value of expression
Ejemplos de Asignacin de operadores en forma corta:
En MQL4 tambin se utiliza una forma breve de componer los operadores de asignacin. La forma corta
de la asignacin operadores se utiliza en el cdigo para una mejor visualizacin.
In /= 33; // Short form of the assignment operator
In = In/33; // Full form of the assignment operator
St += "_exp7"; // Short form of the assignment operator
St = St + "_exp7"; // Full form of the assignment operator

El operador condicional if-else


El formato completo del operador 'if-else' contiene una partida que incluye una condicin, el cuerpo 1, la
palabra clave 'else', y el cuerpo 2. El cuerpo del operador puede estar formado por uno o varios
operadores, los cuerpos van encerrados entre llaves.
Estructura:
if (condicin) // Cabecera del operador y condicin
{
Bloque 1 de operadores // Si la condicin es verdadera, entonces ..
Composicin cuerpo 1 // .. los agentes que componen el cuerpo 1 se ejecutan
}
else // Si la condicin es falsa ..
{
Bloque 2 de operadores // .. entonces los operadores ..
Composicin cuerpo 2 // .. del cuerpo 2 se ejecutan
}
Formato sin 'else'
El operador "if-else" puede ser usado sin 'else'. En este caso, el operador "if-else 'contiene su cabecera,
que incluye una condicin, y el cuerpo 1, que consta de uno o varios operadores cerrados entre llaves.
Estructura:
if (condicin) // Cabecera del operador y el estado
{
Bloque 1 de operadores // Si la condicin es verdadera, entonces ..
Composicin cuerpo 1 // .. agentes que componen el cuerpo 1 se ejecutan
}
Formato sin llaves
Si el cuerpo del operador "if-else 'consta de un solo operador, se pueden omitir las llaves.
if (condicin) // Cabecera del operador y el estado
Operador // Si la condicin es verdadera, entonces ..
// .. Este operador se ejecuta
Regla de Ejecucin del operador "if-else"
Si la condicin del operador "if-else" es cierta, se pasa el control al primer operador en el cuerpo 1.
Despus de que todos los operadores en el cuerpo 1 se han ejecutado, el control pasa al operador que
aparece despus del operador "if-else". Si la condicin del operador "if-else" es falsa, entonces:
Si est la palabra clave 'else' en el operador "if-else", entonces se pasa el control al primer
operador en el cuerpo 2. Despus de que todos los operadores en el cuerpo 2 se han ejecutado, se
pasa el control al operador que aparece despus del operador "if-else";
Si no hay una palabra clave 'else' en el operador "if-else", entonces se pasa el control al operador
posterior al operador " if-else.
Problema 6: Redactar un programa en el que: Si el precio de un smbolo ha superado un cierto valor, el
programa informar al trader ese hecho, si no el programa no debe hacer nada.
//---------------------------------------------------------------------------------------
// onelevel.mq4
//---------------------------------------------------------------------------------------
int start() // funcin especial 'start'
{
double
Level, // declaracin de variable donde estar el nivel de alerta
Price; // declaracin de variable donde estar el precio actual
Level=1.2753; // Establecer el nivel
Price=Bid; // Solicitud de precio actual
//---------------------------------------------------------------------------------------
if (Price>Level) // Operador 'if' con una condicin
{
Alert("El precio a superado el nivel establecido"); // Mensaje para el comerciante
}
//---------------------------------------------------------------------------------------
return; // Salir de start()
}
//---------------------------------------------------------------------------------------
Operadores if-else anidados
Problema 7. Redactar un programa con las siguientes condiciones: Si el precio ha crecido de manera
que supera un cierto nivel 1, el programa deber informar al comerciante, si el precio ha cado por
debajo de un cierto nivel 2, el programa deber informar al comerciante, sin embargo, el programa no
debe realizar ninguna accin en cualquier otro caso.
//------------------------------------------------ -----------------------
// Twoleveloptim.mq4
//------------------------------------------------ -----------------------
int start() // Special function start()
{
double
Level_1, // Alert level 1
Level_2, // Alert level 2
Price; // Current price
Level_1=1.2850; // Set level 1
Level_2=1.2800; // Set level 2
Price=Bid; // Request price
//-----------------------------------------------------------------------
if (Price > Level_1) // Check level 1
{
Alert("The price is above level 1"); // Message to the trader
}
else
{
if (Price < Level_2) // Check level 2
{
Alert("The price is below level 2"); // Message to the trader
}
}
//-----------------------------------------------------------------------
return; // Exit start()
}
//-----------------------------------------------------------------------
Problema 8. Redactar un programa que tenga en cuenta las condiciones siguientes: Si el precio cae
dentro del rango preestablecido de valores, no se hace nada; si el precio est fuera de este rango, el
programa debe informar al operador.
//---------------------------------------------------------------------------------
// compoundcondition.mq4
//---------------------------------------------------------------------------------
int start() // Special function 'start'
{
double
Level_1, // Alert level 1
Level_2, // Alert level 2
Price; // Current price
Level_1=1.2850; // Set level 1
Level_2=1.2800; // Set level 2
Price=Bid; // Request price
//--------------------------------------------------------------------------------
if (Price>Level_1 || Price<Level_2) // Test the complex condition
{
Alert("The price is outside the preset range"); // Message
}
//--------------------------------------------------------------------------------
return; // Exit start()
}
//--------------------------------------------------------------------------------
Esta condicin significa: Si el valor de la variable Price es superior al de la variable Level_1, O el valor
de la variable Price es menor que la variable de Level_2, el programa debe ejecutar el cuerpo del
operador if-else.
Se pueden usar operaciones lgicas (&&, || y !) al redactar las condiciones del operador if-else. Esto es
ampliamente utilizado en la prctica.
Para la solucin de problemas ms complejos, puede ser necesaria la utilizacin de parntesis, por
ejemplo:
if ( A>B && (B<=C || (N!=K && F>B+3)) ) // Example of a complex condition

Operador de ciclo while


La funcionalidad ms potente de MQL4 es la posibilidad de organizar ciclos (bucles).
Al crear programas de aplicacin, se pueden utilizar a menudo clculos repetidos, que son en su mayora
lneas repetidas de programa. Con el fin de hacer la programacin cmoda y al programa fcil de
utilizar, se usan los operadores de ciclo (bucle). Hay dos operadores de ciclo en MQL4: while y for.
Formato del operador while
El formato completo del operador de ciclo while (mientras que) consta de una cabecera que contiene una
condicin, y el cuerpo del ciclo (bucle) ejecutable, adjunto entre llaves.
while (condicin) // Cabecera del operador de ciclo
{ // Apertura llave
Bloque de operadores // El cuerpo de un operador de ciclo (bucle) puede consistir ..
que componen el cuerpo de ciclo // .. de varios operadores
} // Cierre llave
Si en el operador while el cuerpo de bucle se compone de un solo operador, pueden omitirse las llaves.
while (condicin) // Cabecera del operador de ciclo
Operador, cuerpo del ciclo // cuerpo de ciclo (bucle) consta de un solo operador
Regla Ejecucin para el operador 'while'
Mientras la condicin del operador while sea verdadera el programa pasa el control al cuerpo del
operador de bucle. Despus de que han sido ejecutados todos los operadores en el cuerpo de bucle, se
pasa el control a la cabecera para verificar la condicin. Si la condicin del operador while es falso,
el control debe ser pasado al operador que sigue al operador de bucle while.
El operador while (mientras que) puede leerse as: "Mientras se cumpla esta condicin, realice lo/los
siguiente/s: ..".
Problema 9. Calcular el coeficiente de Fibonacci con la precisin de 10 cifras significativas.
//----------------------------------------------------------------------------------------
// fibonacci.mq4
//----------------------------------------------------------------------------------------
int start() // Funcin especial start()
{
//----------------------------------------------------------------------------------------
int i; // parmetro formal, contador de iteraciones
double
A,B,C, // Los nmeros en la secuencia
Delta, // diferencia real entre los coeficientes
D; // Precisin preestablecida
//----------------------------------------------------------------------------------------
A=1; // valor inicial
B=1; // valor inicial
C=2; // valor inicial
D=0.0000000001; // valor de la precisin
Delta=1000.0; // valor inicial
//----------------------------------------------------------------------------------------
while(Delta>D) // Cabecera del operador de ciclo
{ // Apertura de llave del cuerpo del operador de bucle While
i++; // incremento del contador de iteraciones
A=B; // Siguiente valor
B=C; // Siguiente valor
C=A + B; // Siguiente valor
Delta=MathAbs(C/B - B/A); // Buscar diferencia entre los coeficientes
} // Cierre de llave del cuerpo del operador de bucle While
//----------------------------------------------------------------------------------------
Alert("C=",C," Fibonacci number=",C/B," i=",i); // mostrar en la pantalla
return; // Salir de star ()
} //Cierre de llave de la funcion especial star
//----------------------------------------------------------------------------------------
Al comienzo del programa, se declaran (y describen) las variables. En las lneas posteriores, se asignan
valores numricos a las variables. A, B y C, las cuales toman el valor de los primeros nmeros de la
secuencia de Fibonacci.
El operador de ciclo comienza el trabajo con la prueba de la condicin. El ciclo se llevar a cabo en
repetidas ocasiones, mientras que la condicin (Delta> D) sea verdad.
Las variables toman los valores del siguiente elemento. Antes de que el operador del ciclo se ejecute, los
valores de A, B y C son iguales a 1,0, 1,0 y 2,0, respectivamente.
Durante la primera iteracin, estas variables toman los valores 1, 2 y 3, respectivamente.
La iteracin es una ejecucin repetida de algunos clculos; se utiliza para sealar que las lneas de
programa que componen el cuerpo del operador de bucle son ejecutados.
En la lnea siguiente, se calcula la diferencia entre los nmeros de Fibonacci obtenidos sobre la base de
los posteriores (C/B) y anteriores (B/A) elementos de la secuencia:
Delta=MathAbs(C/B - B/A); // Buscar diferencia entre los coeficientes
En este operador, utilizamos la funcin estndar MathAbs() que calcula el valor absoluto de la
expresin, en este caso, de la desviacin.
Este operador es el ltimo en la lista de operadores que componen el cuerpo del bucle. Esto se ve
confirmado por la presencia de un cierre de llave en la lnea siguiente. Tras la ejecucin del cuerpo del
ltimo operador de ciclo, el control se pasa a la cabecera del operador para poner a prueba la condicin.
Este es el punto clave que determina la esencia del operador de ciclo.
En las primeras iteraciones, el valor de la variable Delta resulta ser mayor que el valor definido en la
variable D. Esto significa que la condicin (Delta> D) es cierta, por lo que el control se pasa al cuerpo
del ciclo para realizar la siguiente iteracin. Todas las variables involucradas en los clculos llevarn
nuevos valores: tan pronto como el cuerpo del ciclo llegue el final, el control ser pasado a la cabecera
de nuevo para poner a prueba la condicin y ver si esta es verdadera.
Este proceso continuar hasta que la condicin del operador de ciclo se convierta en falsa. Tan pronto
como el valor de la variable Delta sea menor o igual al valor de D, la condicin (Delta> D) ya no ser
cierta. Esto significa que el control ser pasado fuera del operador de ciclo, a la lnea:
Alert ("C =" C, "Fibonacci number =", C / B, "i =", i); // mostrar en la pantalla
Como resultado de ello, el siguiente mensaje aparecer en la pantalla:
C = 317811 Fibonacci number = 1,618 i = 25
Esto significa que la bsqueda de precisin se alcanza en la 25 iteracin, con el valor mximo de la
secuencia de Fibonacci de 317811. El coeficiente de Fibonacci, como era de esperarse, es igual a 1,618.
Este mensaje es la solucin del problema planteado.
Cabe sealar aqu que los nmeros reales se calculan en MQL4 con una precisin de 15 cifras. Al
mismo tiempo, el coeficiente de Fibonacci se muestra con una precisin de 3 cifras. Esto se debe a que
la funcin de alerta () muestra nmeros con una precisin de 4 cifras, sin mostrar los ceros al final de la
serie.
Es posible que la condicin especificada en el operador de ciclo de cabecera siempre sea cierta. Esto se
traducir en un bucle infinito.
Un bucle infinito o Looping es una ejecucin repetida e infinita del operador de ciclo, es una situacin
crtica que se deriva de la realizacin de un algoritmo errneo. Una vez que se cae en la trampa de un
bucle infinito, el control no puede salir nunca del l. Esta situacin es especialmente peligrosa en el
comercio de Asesores Expertos y scripts. En tales casos, las variables de entorno no se actualizan
normalmente, ya que la funcin especial no completa su funcionamiento, mientras que el operador
puede desconocer la existencia de este bucle.
El nico mtodo posible para detectar esos errores algortmicos est en el examen del cdigo, el
razonamiento lgico y el sentido comn.

Operador de ciclo for


Otro operador de ciclo es el operador 'for'.
El formato completo del operador de ciclo for se compone de una cabecera (que contiene la
Expression_1, la Condicin y la Expression_2), y del cuerpo de bucle ejecutable, colocado entre llaves.
for(Expression_1; Condition; Expression_2) // Operador de ciclo de cabecera
{ // Apertura llave
Bloque de operadores // Cuerpo de Ciclo, puede consistir
que componen el cuerpo de ciclo // en varios operadores
} // Cierre llave
Si el cuerpo de bucle en el operador for consta de un solo operador, las llaves pueden omitirse.
for(Expression_1; Condition; Expression_2) // Cabecera del Operador de ciclo
Operador, cuerpo de ciclo // el cuerpo de bucle es un solo operador
La Expression_1, la Condicin y/o la Expression_2 pueden estar ausentes. En cualquier caso, el caracter
separador ; (punto y coma) debe estar presente en el cdigo.
for(; Condition; Expression_2) // Sin la Expression_1
{ // Apertura de llave
Bloque de operadores // Cuerpo de bucle, puede constar ..
que componen el cuerpo de bucle // .. de varios operadores
} // Cierre de llave
// - ----------------------------------------------- ----------------------------------
for(Expression_1;; Expression_2) // Sin Condicin
{ // Apertura de llave
Bloque de operadores // Cuerpo de bucle, puede constar ..
que componen el cuerpo de bucle // .. de varios operadores
} // Cierre de llave
// - ----------------------------------------------- ----------------------------------
for(;;) // Sin expresiones ni condicin
{ // Apertura de llave
Bloque de operadores // Cuerpo del bucle, puede constar ..
que componen el cuerpo de bucle // .. de varios operadores
} // Cierre de llave
Regla de Ejecucin del operador for
Tan pronto como el control pasa al operador for, el programa ejecuta la Expression_1. En tanto que la
condicin del operador for sea verdadera: el control pasa al primer operador en el cuerpo de bucle.
Luego de que se ejecutan todos los operadores en el cuerpo de bucle, el programa debe ejecutar la
Expression_2 y pasar el control a la cabecera para comprobar si la condicin es verdadera. Si la
condicin del operador for es falsa, entonces el control pasa al siguiente operador posterior al operador
for.
Problema 10. Tenemos una secuencia de nmeros enteros: 1 2 3 4 5 6 7 8 9 10 11... Redactar un
programa que calcule la suma de los elementos de esta secuencia desde N1 hasta N2.
Este problema es fcil de resolver en trminos de matemticas. Supongamos que queremos calcular la
suma de elementos desde el tercer hasta el sptimo elementos. La solucin ser: 3 + 4 + 5 + 6 + 7 = 25.
Sin embargo, esta solucin slo es buena para un caso particular, cuando el nmero del primer y del
ltimo elemento que componen la suma es igual a 3 y 7, respectivamente. El programa para la solucin
de este problema debe ser escrito de tal manera que si queremos calcular la suma de otro intervalo de la
secuencia (por ejemplo, desde el 15 al 23 elemento), se puedan sustituir fcilmente los valores
numricos de los elementos de una ubicacin sin modificar las lneas del programa.
//-----------------------------------------------------------------------------
// sumtotal.mq4
//-----------------------------------------------------------------------------
int start() // Special function start()
{
//-----------------------------------------------------------------------------
int
Nom_1, // Number of the first element
Nom_2, // Number of the second element
Sum, // Sum of the numbers
i; // Formal parameter (counter)
//-----------------------------------------------------------------------------
Nom_1=3; // Specify numeric value
Nom_2=7; // Specify numeric value
for(i=Nom_1; i<=Nom_2; i++) // Cycle operator header
{ // Brace opening the cycle body
Sum=Sum + i; // Sum is accumulated
Alert("i=",i," Sum=",Sum); // Display on the screen
} // Brace closing the cycle body
//------------------------------------------------------------------------------
Alert("After exiting the cycle, i=",i," Sum=",Sum); // Display on the screen
return; // Exit start()
}
//------------------------------------------------------------------------------
Lo que hace este programa, visto en modo sencillo, es lo siguiente:
Valor Valor
Nuevo valor para Sum =
Iteracin de + de =
Sum + i
Sum i
1 0 + 3 = 3
2 3 + 4 = 7
3 7 + 5 = 12
4 12 + 6 = 18
5 18 + 7 = 25

La frase clave para recordar la regla de ejecucin del operador for - es la siguiente: "Desde i= ..,
siempre y cuando , incrementado en pasos de, hacer lo siguiente: ..".
El ltimo evento que tendr lugar en cada iteracin en la ejecucin del operador 'for' es el clculo de
Expression_2. Esto se traduce en el aumento del valor de la variable i en 1, es decir que al final este
valor ser igual a 8. La posterior prueba de la condicin (al principio de la prxima iteracin) confirmar
que la condicin es falsa y el control pasar afuera del operador de ciclo. Al mismo tiempo, la variable i
sale del operador de ciclo con el valor 8, mientras que el valor de la variable Sum seguir con el valor
25, ya que no volvi a calcularse.
Intercambiabilidad entre los operadores 'while' y for
A continuacin resolvemos el Problema 10 utilizando el operador while:
i=Nom_1; // parmetro formal, contador de iteraciones
while (i<=Nom_2) // Cycle operator header
{ // Brace opening the cycle body
Sum = Sum + i; // Sum is accumulated
Alert("i=",i," Sum=",Sum); // Display on the screen
i++; // Increment of the element number
} // Brace closing the cycle body
Como es fcil de ver, es suficiente slo mover Expression_1 en la lnea que precede al operador de
ciclo, mientras que Expression_2 debe especificarse como el ltimo ciclo en el cuerpo.

El Operador break
En algunos casos, por ejemplo, en algn ciclo de programacin de operaciones, podra ser necesario
romper la ejecucin de un ciclo antes de que su condicin se convierta en falsa. Con el fin de resolver
este problema podemos usar el operador "break".
Formato del operador break
El operador "break"se compone de una sola palabra y termina en el carcter ; (punto y coma).
break; // Operador de "break"
Regla de Ejecucin del operador "break"
El operador "break" detiene la ejecucin de la parte ms cercana del operador externo de tipo 'while',
'for' o 'switch'. La ejecucin del operador "break" consiste en pasar el control fuera del recinto del
operador de tipo while,' for' o 'switch' al operador siguiente ms cercano. El operador "break" solo
se puede utilizar para la interrupcin de la ejecucin de los operadores mencionados anteriormente.
Problema 11. Tenemos un hilo de 1 metro de largo. Es necesario establecer el hilo en forma de un
rectngulo con el rea mxima posible. Se trata de hallar el rea de este rectngulo y la longitud de los
lados con una precisin de 1 mm en la bsqueda de las variantes.
Las dimensiones del primer rectngulo (y el "ms delgado") sern de de 1 x 499 mm., las del segundo
sern de 2 x 498 mm., etc., mientras que las dimensiones del ltimo rectngulo sern de 499 x 1mm.
Tenemos que buscar en todos estos rectngulos y encontrar el de mayor superficie.
Como fcilmente se observa, hay dimensiones repetidas en el conjunto de rectngulos que estamos
considerando. Por ejemplo, la primera y la ltima tienen las mismas dimensiones: 1 x 999 mm (igual
que 999 x1 mm). Tenemos que hacer un algoritmo de bsqueda que busque solo en las variantes nicas,
ya que no hay necesidad de buscar en las repetidas.
//--------------------------------------------------------------------
// rectangle.mq4
//--------------------------------------------------------------------
int start() // Special function start()
{
//--------------------------------------------------------------------
int
L=1000, // Specified thread length
A, // First side of the rectangle
B, // Second side of the rectangle
S, // Area of the rectangle
a,b,s; // Current values
//--------------------------------------------------------------------
for(a=1; a<L/2; a++) // Cycle operator header
{ // Brace opening the cycle body
b=(L/2) - a; // Current value of the sides
s=a * b; // Current value of the area
if (s<=S) // Choose the larger value
break; // Exit the cycle
A=a; // Save the best value
B=b; // Save the best value
S=s; // Save the best value
} // Brace closing the cycle body
//--------------------------------------------------------------------
Alert("The maximum area = ",S," A=",A," B=",B); // Message
return; // Function exiting operator
}
//--------------------------------------------------------------------
El algoritmo de resolucin del problema se realiza dentro del ciclo for.
El valor inicial del lado a del rectngulo, como se especifica en la Expression_1, es igual a 1.
Los valores se buscan siempre y cuando el tamao del lado a del rectngulo siga siendo menor que la
mitad de la longitud de hilo.
La Expression_2 prescribe cmo aumentar la longitud del lado a del rectngulo actual en cada paso de
iteracin.
Las variables a, b y s son variables que registran los clculos actuales, los valores que se buscan estn en
las variables A, B y S. El lado b y la superficie s del rectngulo son calculados al comienzo del
ciclo.
La condicin para salir del ciclo se muestra en el operador 'if'.
if (s <= S ) // Choose the larger value
break; // Exit the cycle
Si la recin calculada rea s del rectngulo actual resulta ser mayor que el rea S calculada en la
iteracin anterior, entonces este nuevo valor de s se convierte en el mejor resultado posible hasta el
momento, y en ese caso, la condicin del operador 'if' No se cumple, por lo que el control pasa al
operador ms cercano posterior al operador 'if', que en nuestro ejemplo es el que se encarga de guardar
los mejores resultados obtenidos hasta el momento:
A = a; // Save the best value
B = b; // Save the best value
S = s; // Save the best value
Cuando el programa llega a la llave de cierre, la iteracin est acabada y el control pasa a la
Expression_2 de la cabecera del operador for para ejecutar y poner a prueba la condicin.
Si la longitud del lado a no ha alcanzado el lmite determinado, el ciclo seguir siendo ejecutado.
Los repetidos clculos cclicos seguirn hasta que uno de los siguientes eventos se lleva a cabo: o bien la
longitud del lado a supera los lmites predefinidos (de acuerdo a la condicin del operador for), o
bien el tamao del rea s se haga inferior a un valor previamente almacenado en la variable S.
Cuando el rea del actual rectngulo s sea igual o menor al valor S alcanzado previamente, el
control en la ejecucin del operador "if" pasar al operador "break" que, a su vez, pasar el
control fuera del operador for, a la siguiente lnea:
Alert("The maximum area = ",S," A=",A," B=",B); // Message
Como resultado de la ejecucin de la funcin estndar Alert(), se imprimir la siguiente lnea:
The maximum area = 62500 A=250 B=250
Despus de esto, el control pasa al operador return, lo que da lugar a la finalizacin de la funcin
especial start(), lo que, a su vez, da lugar a la finalizacin del programa y a ser desvinculado de la
ventana de smbolo por la Terminal de Usuario.
En este ejemplo, el operador break nos permite hacer un algoritmo que realiza slo los clculos
necesarios. Un algoritmo sin salida especial sera ineficiente ya que se realizaran clculos repetidos, lo
que dara lugar a una prdida de tiempo y de recursos computacionales.
Si se est probando una estrategia en el Tester de Estrategias se sentir especialmente la reduccin del
tiempo tomado por los clculos. La prueba de programas sofisticados en un largo perodo histrico de
tiempo puede tomar horas e incluso das. En este caso es muy importante reducir el tiempo empleado
por estas pruebas.
Cmo funciona un programa que utiliza ciclos anidados
Problema 12. Utilizando el algoritmo del Problema 11, hallar el hilo ms corto que sea mltiplo de un
metro y suficiente para formar un rectngulo con una superficie de 1,5 m.
//--------------------------------------------------------------------------
// area.mq4
//--------------------------------------------------------------------------
int start() // Special function start()
{
//--------------------------------------------------------------------------
int
L, // Thread length
S_etalon=1500000, // Predefined area (m)
S, // Area of the rectangle
a,b,s; // Current side lengths and area
//--------------------------------------------------------------------------
while(true) // External cycle for thread lengths
{ // Start of the external cycle
L=L+1000; // Current thread length
//--------------------------------------------------------------------
S=0; // Initial value..
// ..for each dimension
for(a=1; a<L/2; a++) // Cycle operator header
{ // .Start of the internal cycle
b=(L/2) - a; // Current side lengths
s=a * b; // Current area
if (s<=S) // Choose the larger value
break; // Exit internal cycle
S=s; // Store the best value
} // End of the internal cycle
//--------------------------------------------------------------------
if (S>=S_etalon) // Choose the larger value
{
Alert("The thread length must be ",L1000," m."); // Message
break; // Exit the external cycle
}
} // End of the external cycle
//--------------------------------------------------------------------------
return; // Exit function operator
}
//--------------------------------------------------------------------------
Las posibles soluciones son buscadas en dos ciclos, uno interno (for) y uno externo (while).
El ciclo externo busca en las longitudes de hilos mltiplos de 1.000 mm., mientras que el ciclo interno
encuentra la superficie mxima para la longitud actual del hilo.
En este caso el operador break es usado para salir de ambos ciclos, externo e interno.
El ciclo interno trabaja aqu como lo hizo en la solucin del problema anterior. El operador break se
utiliza para salir del ciclo for, cuando una determinada longitud de hilo logra la superficie mxima del
rectngulo.
Explicacin del script:
Mientras while(true) - la longitud del hilo sea mltiplo de 1 metro (L=L+1000), realizar lo siguiente:
(for) Comenzando con un lado a igual a 1, siempre y cuando este lado a sea menor o igual a la mitad
del largo del hilo, ir incrementado la longitud del hilo en pasos de 1 mm., y hacer lo siguiente:
El lado b es igual a la mitad del largo del hilo menos el lado a. Como el primer valor asignado a a
es 1, entonces en la primera iteracin, el lado b ser igual a 499 mm.
La superficie actual s del rectngulo es igual a a por b. En la primera iteracin ser de 499 mm2.
(break) Dejar de calcular nuevas iteraciones si el valor S de la superficie calculado en la iteracin
anterior supera al valor s de la superficie calculado en la iteracin actual.
Grabar el valor s de la superficie determinado en la iteracin actual, en la variable S.
Cuando ya obtuve el valor de superficie S mximo para un hilo con una longitud mltiplo de 1 metro,
debo chequear si (if) este valor de superficie mximo alcanza el valor de superficie requerido en el
enunciado del problema, es decir, 1,5 m2 - if (S>=S_etalon) -. Si lo alcanza, entonces encontr la
solucin al problema y la mostrar (Alert) y a continuacin salgo del ciclo externo while mediante el
comando break, pero si no lo alcanza, debo utilizar un metro ms de hilo y comenzar a realizar todos los
clculos anteriores nuevamente, retornado al inicio del ciclo while.
Tener en cuenta que la condicin en la cabecera del ciclo exterior while es una condicin true, es decir,
un texto que no contiene una variable. Es decir que el programa nunca podr salir del ciclo while
basndose en la condicin dada en la cabecera. En este caso, la nica posibilidad para salir del ciclo es
usar el operador "break".
Operador continue
A veces, cuando se utiliza un ciclo en el cdigo, es necesario poner fin a la iteracin actual y pasar a la
siguiente sin ejecutar el resto de los operadores que componen el cuerpo del bucle. En estos casos se
debe usar el operador "continue".
El operador 'continue' consta de una sola palabra y termina en ; (punto y coma).
El operador continue detiene la ejecucin de la iteracin actual del ciclo ms cercano del operador
while o' for'. La ejecucin del operador continue da como resultado ir a la prxima iteracin del
ciclo ms cercano del operador while o 'for'. El operador continue slo se puede utilizar en el cuerpo
del ciclo por encima de los operadores.
Problema 13. Hay 1.000 ovejas en la primera granja. La cantidad de ovejas en la primera granja
aumenta en un 1% diario. Si la cantidad de ovejas es superior a 50.000 a finales de mes, entonces el 10%
de las ovejas sern transferidas a la segunda granja. En qu momento la cantidad de ovejas en la
segunda granja llegar a 35.000? (consideramos que hay 30 das hbiles en un mes).
El algoritmo de la solucin de este problema es evidente: Tenemos que organizar un ciclo en el que el
programa calcule la cantidad total de ovejas en la primera granja. De acuerdo con el planteo del
problema, las ovejas se transfieren a la segunda granja a finales de mes. Esto significa que tendremos
que crear adems un ciclo interno donde se calcule el ciclo de acumulacin de ovejas en el mes en curso.
Entonces tendremos que comprobar a finales de mes si el lmite de 50.000 ovejas se super o no. Si la
respuesta es s, entonces hay que calcular la cantidad de ovejas a ser transferidos a la segunda granja a
finales de mes y la cantidad total de ovejas en la segunda granja.
//-------------------------------------------------------------------------------------
// sheep.mq4
//-------------------------------------------------------------------------------------
int start() // Special function start()
{
//-------------------------------------------------------------------------------------
int
day, // Current day of the month
Mons; // Search amount of months
double
One_Farm =1000.0, // Sheep on the 1st farm
Perc_day =1, // Daily increase, in %
One_Farm_max=50000.0, // Sheep limit
Perc_exit =10, // Monthly output, in %
Purpose =35000.0, // Required amount on farm 2
Two_Farm; // Current amount of farm 2
//-------------------------------------------------------------------------------------
while(Two_Farm < Purpose) // External cycle on history
{ // Start of the external cycle body
//-------------------------------------------------------------------------------
for(day=1; day<=30; day++) // Cycle for days of month
One_Farm=One_Farm*(1+Perc_day/100); //Accumulation on the 1st farm
//-------------------------------------------------------------------------------
Mons++; // Count months
if (One_Farm < One_Farm_max) // If the amount is below limit,.
continue; // .. don't transfer the sheep
Two_Farm=Two_Farm+One_Farm*Perc_exit/100; //Sheep on the 2nd farm
One_Farm=One_Farm*(1-Perc_exit/100); // Remainder on the 1st farm
} // End of the external cycle body
//-------------------------------------------------------------------------------------
Alert("The aim will be attained within ",Mons," months."); //Display on the screen
return; // Exit function start()
}
//-------------------------------------------------------------------------------------
Mientras (while) la cantidad de ovejas en la granja 2 sea menor a 35.000, hacer lo siguiente:
(for) Comenzando por el da 1, siempre y cuando la cantidad de das sea menor o igual a 30, ir
incrementado los das, de uno en uno, y hacer lo siguiente:
Aumentar la cantidad de ovejas de la granja 1 en un 1% diario One_Farm=One_Farm*(1+Perc_day/100)
Cuando la cantidad de das sea igual a 30, se cumple un mes, entonces, ir contando los meses
(Mons++;), dicho tcnicamente, los valores de la variable Mons se acumulan en cada iteracin.
Si la cantidad de ovejas en la granja 1 es menor a 50.000, continuar (continue) ejecutando el operador
while, es decir, seguir aumentando la cantidad de ovejas de la granja 1 mensualmente en un 1% diario
siempre que no se haya alcanzado el propsito del problema, es decir, que la granja 2 llegue a tener
50.000 ovejas.
Si la cantidad de ovejas en la granja 1 super las 50.000 unidades, asignar a la granja 2 el 10% de las
ovejas que haya en ese momento en la granja 1. Se lo escribe as:
Two_Farm=Two_Farm+One_Farm*Perc_exit/100; //Sheep on the 2nd farm
One_Farm=One_Farm*(1-Perc_exit/100); // Remainder on the 1st farm
Entonces, cada vez que la cantidad de ovejas supere las 50.000 unidades en la granja 1, seguiremos
pasando el 10% de las ovejas hacia la granja 2, hasta que se cumpla el encabezamiento del ciclo while,
es decir, hasta que la cantidad de ovejas en la granja 2 alcance las 35.000 unidades, en cuyo momento se
emitir la alerta (alert) indicando el nmero de meses que fue necesario para conseguirlo.
Problema 14. Hay 1000 ovejas en una granja. La cantidad de ovejas en esta primera granja aumenta
diariamente en un 1%, cuando la cantidad de ovejas en la primera granja llega a 50.000, el 10% de las
ovejas sern transferidos a la segunda granja. En qu momento la cantidad de ovejas de la segunda
granja llega a 35 000? (consideramos que hay 30 das hbiles en un mes).
//--------------------------------------------------------------------
// othersheep.mq4
//--------------------------------------------------------------------
int start() // Special function start()
{
//--------------------------------------------------------------------
int
day, // Current day of the month
Mons; // Search amount of months
double
One_Farm =1000.0, // Sheep on the 1st farm
Perc_day =1, // Daily increase, in %
One_Farm_max=50000.0, // Sheep limit
Perc_exit =10, // One-time output, in %
Purpose =35000.0, // Required amount on farm 2
Two_Farm; // Current amount of farm 2
//--------------------------------------------------------------------
while(Two_Farm < Purpose) // Until the aim is attained
{ // Start of the external cycle body
//--------------------------------------------------------------
for(day=1; day<=30 && Two_Farm < Purpose; day++) // Cycle by days
{
One_Farm=One_Farm*(1+Perc_day/100); //Accumulated on farm 1
if (One_Farm < One_Farm_max) // If the amount is below limit,.
continue; // .. don't transfer the sheep
Two_Farm=Two_Farm+One_Farm*Perc_exit/100; //Accumulated on farm 2
One_Farm=One_Farm*(1-Perc_exit/100); //Remainder on farm 1
}
//--------------------------------------------------------------
if (Two_Farm>=Purpose) // If the aim is attained,..
continue;
Mons++; // Count months
} // End of external cycle body
//--------------------------------------------------------------------
Alert ("The aim will be attained within ",Mons," months and ",day," days.");
return; // Exit function start()
}
//--------------------------------------------------------------------
Una cierta cantidad de ovejas se transfiere a la segunda granja, en este caso, no a finales de mes, sino en
el da, cuando la cantidad de ovejas en la primera granja llega al valor predefinido. La razn para usar
aqu el operador continue es la misma: Queremos saltar las lneas que contienen los clculos
relacionados con la transferencia de ovejas de una granja a otra, es decir, no queremos ejecutar estas
lneas. Tngase en cuenta que el ciclo 'while' que se construy para los das del mes no se interrumpe y
acta de forma independiente a si las ovejas son transferidas o no, porque el operador continue influye
en el operador de ciclo ms cercano, en nuestro caso, el operador de ciclo for.
En el operador se utiliz una expresin compleja para la condicin del operador de ciclo for:
for(day=1; day<=30 && Two_Farm<Purpose; day++) // Cycle by days
El uso de la operacin && ("and") significa que el ciclo se ejecutar siempre y cuando ambas
condiciones sean verdaderas:
el mes no ha terminado todava, es decir, la variable day oscila entre 1 y 30, y
la cantidad de ovejas en la segunda granja no ha alcanzado el valor predefinido -la variable
Two_Farm es inferior a Purpose (35000)-.
Si al menos una de las condiciones no se cumple, la condicin se convierte en falsa y el ciclo se detiene.
Si la ejecucin del ciclo for se detiene (por cualquier motivo), el control pasa al operador if:
if (Two_Farm >= Purpose) // If the aim is attained,..
continue; // .. don't count months
Mons++; // Count months
El uso del operador continue en esta ubicacin en el cdigo tiene un sentido simple: El programa debe
seguir contando meses solamente si la cantidad de ovejas en la segunda granja est por debajo del valor
esperado. Si el objetivo ya ha sido alcanzado, el valor de la variable Mons no cambiar, mientras que el
control (como resultado de la ejecucin de "continue") se pasa a la cabecera del operador de ciclo ms
cercano, en nuestro caso, el del operador de ciclo while.
En el ejemplo anterior, cada ciclo (externo e interno) tiene un operador en continue que slo influye
en su "propio" ciclo ms cercano (en el ciclo dentro del cual est actuando), pero no por cualquier
acontecimiento o en cualquier otro ciclo. En general, en un cuerpo de bucle se pueden utilizar varios
operadores continue y cada uno de ellos ser capaz de interrumpir la iteracin actual como resultado de
la reunin de una condicin. La cantidad de operadores continue en un cuerpo de un bucle no est
limitada.

Operador 'switch'
Algunos programas conllevan la necesidad de la ramificacin de su algoritmo en variantes. En estos
casos, es muy conveniente usar el operador "switch", sobre todo si hay decenas o cientos de variaciones,
mientras que en este caso el operador if se convertira en un cdigo hinchado si utiliza muchos
operadores anidados.
El operador 'switch' consiste en una cabecera y un cuerpo ejecutable. La cabecera contiene el nombre del
operador y una Expression entre parntesis. El cuerpo del operador contiene una o varias alternativas o
casos ('case') y una variante default (por defecto).
Cada variante "case" consiste en la palabra clave 'case', una constante, ":" (dos puntos), y los
operadores. La cantidad de variantes 'case' no est limitada.
La variante 'por defecto' se compone de la palabra 'default', ":" (dos puntos), y los operadores. La
variante 'default' se especifica al final en el cuerpo del operador 'switch', pero tambin puede ser ubicada
en otro lugar dentro del cuerpo operador, o incluso estar ausente.
Los valores de la Expression y de los parmetros slo pueden ser valores de tipo int. La Expression
puede ser una constante, una variable, una llamada a una funcin, o una expresin. Cada variante "case"
puede ser un entero constante, un carcter constante, una constante o expresin. Una expresin constante
no puede incluir variables o llamadas a funciones.
El programa debe pasar el control al primer operador que sigue a ":" (dos puntos) de la variante "case"
cuyo valor la constante es el mismo que el valor de la expresin y, a continuacin, ejecutar uno por uno
todos los operadores que componen el cuerpo del operador 'switch'. Los valores de las variantes
constantes de los diferentes 'case' no debe ser el mismo. El operador break detiene la ejecucin del
operador 'switch' y pasa el control al operador que sigue despus del operador 'switch'.
Problema 15. Redactar un EA con las siguientes condiciones: Si el precio excede del nivel predefinido,
el programa deber informar al comerciante sobre ello mediante un mensaje que describe el exceso
(hasta 10 puntos); en los dems casos, el programa debe informar que el precio no excede el nivel
predefinido.
//-------------------------------------------------------------------------------------
// pricealert.mq4
//-------------------------------------------------------------------------------------
int start() // Special function 'start'
{
double Level=1.3200; // Preset price level
int Delta=NormalizeDouble((Bid-Level)Point,0); // Excess
if (Delta<=0) // Price doesn't excess the level
{
Alert("The price is below the level"); // Message
return; // Exit start()
}
//-------------------------------------------------------------------------------------
switch(Delta) // Header of the 'switch'
{ // Start of the 'switch' body
case 1 : Alert("Plus one point"); break; // Variations..
case 2 : Alert("Plus two points"); break;
case 3 : Alert("Plus three points"); break;
case 4 : Alert("Plus four points"); break; //Here are presented
case 5 : Alert("Plus five points"); break; //10 variations 'case',
case 6 : Alert("Plus six points"); break; //but, in general case,
case 7 : Alert("Plus seven points"); break; //the amount of variations 'case'
case 8 : Alert("Plus eight points"); break; //is unlimited
case 9 : Alert("Plus nine points"); break;
case 10: Alert("Plus ten points"); break;
default: Alert("More than ten points"); // It is not the same as the 'case'
} // End of the 'switch' body
//-------------------------------------------------------------------------------------
return; // Exit start()
}
//-------------------------------------------------------------------------------------
El operador break detiene la ejecucin del operador 'switch', y pasa el control fuera de ella, es decir, al
operador return que termina la operacin de la funcin especial start().
Notas
Digits
int Digits
Nmero de dgitos despus del punto decimal para los precios del smbolo actual.
NormalizeDouble
double NormalizeDouble(double value, int digits)
Redondea el valor de punto flotante (coma flotante) con la precisin dada. Devuelve un valor
normalizado, de tipo double.
Los valores calculados de StopLoss y TakeProfit, y el precio de apertura de rdenes pendientes, deben ser
normalizados con una precisin dada (cuyo valor es almacenado en la variable predefinida Digits).
Parmetros:
value: valor de punto flotante (coma flotante).
digits: formato de precisin. Nmero de dgitos despus del punto decimal (0-8).
Consideremos un problema donde no se prev el uso de break en cada una de las variantes "case".
Problema 16. Hay 10 barras. Informe sobre los nmeros de todas las barras a partir de la ensima barra.
//------------------------------------------------------------------------------
// barnumber.mq4
//------------------------------------------------------------------------------
int start() // Special function start()
{
int n = 3; // Preset number (nth bar) (ensima barra)
Alert("Bar numbers starting from ", n,":"); // It does not depend on n
//------------------------------------------------------------------------------
switch (n) // Header of the operator 'switch'
{ // Start of the 'switch' body
case 1 : Alert("Bar 1"); // Variations..
case 2 : Alert("Bar 2");
case 3 : Alert("Bar 3");
case 4 : Alert("Bar 4"); // Here are 10 variations ..
case 5 : Alert("Bar 5"); // ..'case' presented, but, in general, ..
case 6 : Alert("Bar 6"); // ..the amount of variations..
case 7 : Alert("Bar 7"); // ..'case' is unlimited
case 8 : Alert("Bar 8");
case 9 : Alert("Bar 9");
case 10: Alert("Bar 10");break;
default: Alert("Wrong number entered"); // It is not the same as the 'case'
} // End of the 'switch' body
//-------------------------------------------------------------------------------
return; // Operator to exit start()
}
//-------------------------------------------------------------------------------
En el operador 'switch', el programa buscar en las variantes 'case', hasta que detecte que la expresin es
igual a la constante. Cuando el valor de la expresin (en nuestro caso, el entero 3) es igual a una de las
constantes (en este caso el case 3), todos los operadores siguientes a los dos puntos : (case 3:) se
ejecutarn, a saber: el operador llama a la funcin Alert ("Bar 3") y los siguientes Alert ("Bar 4"), Alert
("Bar 5"), etc, hasta que llega al operador break que termina el funcionamiento del operador switch.
Si el valor de la expresin no coincide con ninguna de las Constantes, el control se pasa al operador que
corresponde a la variante "default".
A diferencia del algoritmo realizado en el anterior programa, en este caso, no estamos utilizando el
operador break en cada una de las variantes "case". Por tanto, si el valor de la expresin es igual al
valor de una de las constantes, se ejecutarn todos los operadores siguientes a los operadores de la
correspondiente variante case. Tambin utilizamos el operador break en la ltima variante case
para otro propsito: evitar que se ejecuten los operadores correspondientes a la variante "default".
Si no hay un valor igual a la expresin entre los valores de las constantes, el control se pasa directamente
al operador que se corresponde con la etiqueta 'default'.
LA LLAMADA A UNA FUNCIN
Una llamada a funcin puede ser usada como un operador independiente y encontrarse en cualquier
lugar del programa donde est implicado un cierto valor (con la excepcin de los casos predefinidos). Se
utiliza tanto para funciones estndar (built-in) como para funciones definidas por el usuario.
Una llamada a una funcin esta compuesta por el nombre de la funcin y la lista de los parmetros
escritos entre parntesis. Si la llamada a la funcin no lleva parmetros de paso, la lista de parmetros se
especifica como vaca, pero el parntesis debe estar presente, de todos modos.
La cantidad de parmetros a ser pasados a la funcin est limitada y no puede ser superior a 64. En una
llamada a una funcin se pueden utilizar como parmetros constantes, variables y llamadas a otras
funciones. La cantidad, tipo y orden de los parmetros pasados en la llamada a una funcin debe
ser la misma que la cantidad, tipo y orden de los parmetros especificados en la descripcin de
una funcin (la excepcin es una llamada a una funcin con los parmetros por defecto).
Si el programa debe llamar a una funcin con los parmetros por defecto, la lista de los parmetros
traspasados puede ser abreviada. Puede limitarse la lista de parmetros, siempre que se comience con el
primer parmetro por defecto. En el siguiente ejemplo, las variables locales b, c y d tienen algunos
valores por defecto:
// .. the following calls are allowed:
My_function (Alf, Bet, Ham, Del) // Allowed function call
My_function (Alf ) // Allowed function call
My_function (3) // Allowed function call
My_function (Alf, 0) // Allowed function call
My_function (3, Tet) // Allowed function call
My_function (17, Bet, 3) // Allowed function call
My_function (17, Bet, 3, 0.5) // Allowed function call
// For the function described as:
int My_function (int a, bool b=true, int c=1, double d=0.5)
{
Operators
}
Los parmetros sin valores por defecto no se pueden omitir. Si un parmetro por defecto se salta, los
parmetros por defecto subsiguientes no deben ser especificados.
// .. Las siguientes llamadas no estn permitidas:
My_function () // No permitida la llamada por defecto a la funcin. Falta..
// .. 1 parmetro que no puede ser omitido.
My_function (17, Bet,, 0,5) // No permitida la llamada a la funcin: se omite ..
// .. parmetro por defecto (el tercero)
// La funcin esta descrita como:
int My_function (int a, b bool = true, int c = 1, double d = 0,5)
{
Operadores
}
Las llamadas a las funciones se dividen en dos grupos: las que devuelven un valor predefinido de un tipo
y los que no devuelven ningn valor.
Si la llamada a la funcin no devuelve ningn valor slo puede ser compuesta como un operador
independiente. La llamada a una funcin con operador sin return termina en ; (punto y coma).
Una llamada a una funcin que devuelve un valor puede estar compuesta como un operador separado o
puede ser utilizada en el cdigo de programa en lugares donde un valor de un determinado tipo esta
implicado. Si la llamada a la funcin se compone de un operador independiente, este termina en ";"
(punto y coma).
Problema 17. Redactar un programa con las siguientes condiciones:
Si la hora actual es mayor de las 15:00, ejecutar 10 repeticiones en el ciclo for;
En todos los dems casos, ejecutar 6 iteraciones.
///-----------------------------------------------------------------------------------
// callfunction.mq4
//------------------------------------------------------------------------------------
int start() // Description of function start()
{ // Start of the function start() body
int n; // Variable declaration
int T=15; // Predefined time
for(int i=Func_yes_ret(T);i<=10;i++) // The use of the function in..
// The cycle operator header
{ // Start of the cycle 'for' body
n=n+1; // Iterations counter
Alert ("Iteration n=",n," i=",i); // Function call operator
} // End of the cycle 'for' body
return; // Exit function start()
} // End of the function start() body
//-------------------------------------------------------------------------------------
int Func_yes_ret (int Times_in) // Description of the user-defined function
{ // Start of the user-defined function body
datetime T_cur=TimeCurrent(); // The use of the function in..
// ..the assignment operator
if(TimeHour(T_cur) > Times_in) // The use of the function in..
//..the header of the operator 'if-else'
return(1); // Return value 1
return(5); // Return value 5
} // End of the user-defined function body
//-------------------------------------------------------------------------------------

Descripcin y funcin del operador return


Podemos dividir la necesidad de especificacin de funciones dentro de un programa, en dos grupos: Las
funciones que no se describen en el programa, y las funciones que deben estar descriptas en el programa.
Las funciones estndar no se describen en los programas. Las funciones definidas por el usuario deben
siempre describirse en el programa. Las funciones especiales, si las hubiere, deben tambin describirse
en el programa.
Formato de la descripcin de funciones
La descripcin de una funcin consta bsicamente de dos partes: cabecera de la funcin y cuerpo de la
funcin.
La cabecera de la funcin contiene el tipo del valor de return, el nombre de la funcin, y la lista de
parmetros entre parntesis. Si una funcin no debe devolver ningn valor, su cabecera es de tipo void
(vaco).
El cuerpo de la funcin puede consistir en operadores simples y/o compuestos o en llamadas a otras
funciones, y encerradas entre llaves.
La lista de parmetros se escribe separada por comas. El nmero de parmetros a transferir a la funcin
est limitado a 64. Los parmetros formales de la cabecera de la funcin solo pueden ser especificados
en forma de variables y no como constantes, ni expresiones, ni en forma de llamada a otras funciones).
La cantidad, tipo y orden de los parmetros transferidos en la llamada a la funcin deben ser los mismos
que los de los parmetros formales especificados en la descripcin de la funcin (con excepcin de la
llamada a una funcin con parmetros que tienen valores por defecto):
La ubicacin de la descripcin de una funcin en un programa debe ser tal que est separada de
cualquier otra funcin, es decir, la funcin no debe estar nunca situada dentro de otra funcin.
El valor devuelto por la funcin es el valor del parmetro que se especifica entre los parntesis del
operador return. El operador return se compone de la palabra clave return y la expresin
contenida entre parntesis, y termina con el caracter ; (punto y coma).
La expresin entre parntesis puede ser una constante, una variable o una llamada a una funcin. El tipo
del valor devuelto utilizando en el operador 'return' debe ser el mismo que el tipo del valor de la funcin
que se especifica en funcin de la cabecera de la llamada a la funcin.
Si el valor de return de una funcin es de tipo void, el operador "return" se debe usar sin expresin entre
parntesis. Ejemplo:
void My_function (double Price_Sell) // Description of the user-defined function
{ // Start of the function body
if(Price_Sell-Ask >100 * Point) // Operator 'if'
Alert("Profit for this order exceeds 100 z"); // Standard function call
return; // Exit function
} // End of the function body
Existe la posibilidad de no incluir el operador "return" en la descripcin de una funcin. En este caso, la
funcin dar por terminado su funcionamiento en forma automtica tan pronto como (de acuerdo con el
algoritmo de ejecucin) se ejecute el ltimo operador del cuerpo de la funcin.
VARIABLES
Variables predefinidas y funcin RefreshRates
Lo primero que debemos hacer es aprendernos los nombres de las variables predefinidas. Los nombres
de las variables predefinidas son nombres reservados y no se pueden utilizar para crear variables
personalizadas. Se trata de las variables predefinidas que contienen las principales informaciones
necesarias para el anlisis de la situacin actual del mercado. Para actualizar esta informacin se utiliza
RefreshRates().
Los valores de todas las variables predefinidas se actualizan automticamente en la Terminal de Usuario
en el momento que se inician las funciones especiales para su ejecucin.
Lista de nombres de variables predefinidas simples
Ask - ltimo precio conocido de venta del actual titulo o valor;
Bid - ltimo precio conocido de compra del actual titulo o valor;
Bars - nmero de barras en un grfico actual;
Point - Tamao de punto (pip) del actual titulo o moneda. El valor de Point (pip) depende del ttulo o
valor especificado. Por ejemplo, para EUR/USD, este valor es 0.0001, para USD/JPY es 0,01;
Digits - nmero de dgitos despus del punto decimal en el precio del actual del titulo o valor.
Lista de nombres predefinidos de Arrays-Timeseries
Time - fecha y hora de apertura de cada barra en el grfico actual;
Open - precio de apertura de cada barra en el grfico actual;
Close - precio de cierre de cada barra en el grfico actual;
High - precio mximo de cada barra en el grfico actual;
Low - precio mnimo de cada barra en el grfico actual;
Volume - marca el volumen de cada barra en el grfico actual.
En una Terminal de Usuario se pueden ejecutar varios programas de aplicacin al mismo tiempo
(asesores expertos, scripts o indicadores), y para cada uno de ellos la Terminal de Usuario crea una
copia con un juego de los datos histricos de todos los valores de las variables predefinidas.
RefreshRates()
bool RefreshRates()
La funcin estndar RefreshRates() permite actualizar los valores locales, fuerza la actualizacin de
datos acerca de un entorno de mercado actual (volumen, horario del servidor de la ltima cotizacin
Time[0], Bid, Ask, etc.) Esta funcin puede utilizarse cuando un programa utiliza mucho tiempo en
realizar sus clculos y por lo tanto tiene necesidades de actualizar los datos.
RefreshRates() devuelve TRUE, si en el momento de su ejecucin hay informacin sobre los nuevos
datos histricos en la terminal (es decir, si ha llegado un nuevo tick durante la ejecucin del programa).
En tal caso, el conjunto de copias locales de las variables predefinidas se actualizar.
Problema 18. Contar el nmero de iteraciones que un operador de ciclo puede realizar entre los ticks
(para los cinco ticks ms cercanos).
//--------------------------------------------------------------------
// countiter.mq4
//--------------------------------------------------------------------
int start() // Special funct. start()
{
int i, Count; // Declaring variables
for (i=1; i<=5; i++) // Show for 5 ticks
{
Count=0; // Clearing counter
while(RefreshRates()==false) // Until...
{ //..a new tick comes
Count = Count+1; // Iteration counter
}
Alert("Tick ",i,", loops ",Count); // After each tick
}
return; // Exit start()
}
//--------------------------------------------------------------------
Dos variables se utilizan en el programa: i para contar el nmero de ticks y Count para contar las
repeticiones. El ciclo externo for est organizado en funcin del nmero de ticks procesados (de 1 a 5).
En el ciclo for se inicializa el contador de iteraciones ponindolo a cero (realizado en el ciclo while), al
final se muestra un Alert() con el nmero de ticks y la cantidad de sus iteraciones.
Tipos de variables
El mbito de una Variable es la ubicacin en un programa donde el valor de la variable est disponible.
Cada variable tiene su propio mbito de aplicacin. De acuerdo con el alcance hay dos tipos de variables
en MQL4: variables locales y variables globales.
La Variable local es una variable declarada dentro de una funcin. El alcance de las variables locales es
el cuerpo de la funcin, en el que la variable ha sido declarada. La Variable local puede ser inicializada
por una constante o una expresin correspondiente a su tipo.
La Variable global es una variable declarada ms all de las funciones. El alcance de las variables
globales es el programa entero. Una variable global puede ser inicializada slo por una constante del
mismo tipo, pero no puede ser inicializada por una expresin. Las variables globales se inicializan slo
una vez antes de la declaracin de la ejecucin de funciones especiales.
Problema 19. Crear un programa que cuenta los ticks.
//--------------------------------------------------------------------
// countticks.mq4
//--------------------------------------------------------------------
int Tick; // Global variable (declarada antes de la descripcin de start()
//--------------------------------------------------------------------
int start() // Special function start()
{
Tick++; // Tick counter
Comment("Received: tick N ",Tick); // Alert that contains number
return; // start() exit operator
}
//--------------------------------------------------------------------
Por tanto, el valor de Tick se incrementar en 1 en cada salida de la funcin especial start(), es decir, en
cada tick. La solucin de este tipo de problemas slo es posible con el uso de variables que preserven
sus valores despus de salir de una funcin (en estos casos se utiliza una variable global). No es viable
utilizar variables locales para este fin: una variable local que se declara en una funcin, pierde su valor
al final de sus operaciones.
Se puede ver fcilmente que si iniciamos un Asesor Experto en el cual la variable Tick se abre como una
variable local el programa contendr un error algortmico:
int start() // Special function start()
{
int Tick; / Local variable
Tick++; // Tick counter
Comment("Received: tick N ",Tick); // Alert that contains number
return; // start() exit operator
}
Desde el punto de vista de la sintaxis no hay errores en el cdigo. Este programa puede ser compilado
con xito y empezar su funcionamiento, pero cada vez que se ejecute el resultado ser siempre el mismo:
Received: tick N 1
Variables Static
La variable static se almacena en una memoria permanente y su valor no se pierde al salir de una
funcin. Sin embargo, respecto al mbito de aplicacin, las variables static tienen las limitaciones tpicas
de las variables locales, el alcance de la variable static es la funcin dentro de las cual ha sido declarada,
a diferencia de las variables globales cuyos valores estn disponibles desde cualquier parte del
programa.
Las variables static se inicializan solo una vez y solo pueden ser inicializadas por una constante (a
diferencia de una simple variable local que se puede inicializar con cualquier expresin). Si no hay
inicializacin explcita, la variable se inicializa a cero.
A continuacin se muestra la solucin del problema 19 utilizando una variable static:
//--------------------------------------------------------------------
// staticvar.mq4
//--------------------------------------------------------------------
int start() // Special function start()
{
static int Tick; // Static local variable
Tick++; // Tick counter
Comment("Received: tick No ",Tick); // Alert that contains number
return; // start() exit operator
}
//--------------------------------------------------------------------
Variables externas
La variable externa es una variable cuyo valor esta disponible desde la ventana de propiedades de un
programa. Una variable externa se declara fuera de cualquier funcin y es una variable global, su mbito
de aplicacin es todo el programa. Cuando se declara una variable externa, el modificador "extern" debe
indicarse antes del tipo de valor:
extern int Nmero // variable externa de tipo integer
Las variables externas se especifican en la parte de la cabecera del programa, es decir, antes de cualquier
funcin que contenga una llamada a funcin externa. El uso de variables externas es muy conveniente si
se necesita iniciar de vez en cuando un programa con distintos valores de variables.
Problema 19. Crear un programa, en el que se apliquen las siguientes condiciones: si el precio alcanza
un cierto nivel, y baj de ese nivel n puntos, este hecho debe ser reportado al trader.
Obviamente, este problema implica la necesidad de cambiar la configuracin, ya que al da de hoy los
precios difieren de los que fueron ayer, as como maana vamos a tener precios diferentes. Para ofrecer
la opcin de cambiar la configuracin en el Asesor Experto se utilizan variables externas:
//--------------------------------------------------------------------
// externvar.mq4
//--------------------------------------------------------------------
extern double Level = 1.2500; // External variable
extern int n = 5; // External variable
bool Fact_1 = false; // Global variable
bool Fact_2 = false; // Global variable
//--------------------------------------------------------------------
int start() // Special function start()
{
double Price = Bid; // Local variable
if (Fact_2==true) // If there was an Alert..
return; //..exit
if (NormalizeDouble(Price,Digits) >= NormalizeDouble(Level,Digits))
Fact_1 = true; // Event 1 happened
if (Fact_1 == true && NormalizeDouble(Price,Digits)<=
NormalizeDouble(Level-n*Point,Digits))
My_Alert(); // User-defined function call
return; // Exit start()
}
//--------------------------------------------------------------------
void My_Alert() // User-defined function
{
Alert("Conditions implemented"); // Alert
Fact_2 = true; // Event 2 happened
return; // Exit user-defined function
}
//--------------------------------------------------------------------
Los valores de las variables externas estn disponibles en la ventana de los parmetros del programa. Lo
mejor de estas variables es que pueden ser cambiadas en cualquier momento. En la fase de activacin
del programa en una ventana de smbolo o ttulo, o durante la operacin del programa.
Si un usuario necesita cambiar los valores de las variables externas durante la operacin, para poder
hacer los cambios, debe estar abierta la ventana de configuracin del programa. Hay que recordar que
las propiedades de la barra de herramientas del programa se pueden abrir solamente en el perodo en que
el programa (Asesor Experto o indicador) est a la espera de un nuevo tick, es decir, no se est
ejecutando ninguna de las funciones especiales. Durante el periodo de ejecucin del programa, la barra
de herramientas (toolbar) no se puede abrir. Es por ello que si un programa est escrito as, y su tiempo
de ejecucin es largo (unos segundos o decenas de segundos), un usuario pueden tener dificultades
tratando de acceder a la ventana de parmetros.
Si la ventana de parmetros est abierta el Asesor Experto no funciona, el control se realiza mediante la
Terminal de Usuario y no pasa a un programa para iniciar la funcin especial.
Los valores de las variables externas de un script slo estn disponibles en el momento de conectar el
programa a un grfico, pero no se pueden cambiar durante la operacin.
Algortmicamente, la solucin del problema tiene este aspecto: Se identifican dos eventos: el primero es
el hecho de llegar a un nivel; el segundo, el hecho de que se muestra una alerta de que se tiene un precio
ms bajo que el nivel establecido menos n puntos. Estos hechos se reflejan en los valores de las
variables Fact_1 y Fact_2: si el caso no fuera as, el valor de los correspondientes valores sera igual a
false y en caso contrario sera true. En las lneas:
if (NormalizeDouble(Price,Digits) >= NormalizeDouble(Level,Digits))
Fact_1 = true; // Event 1 happened
Queda definido el hecho de que ha sucedido el primer evento. La funcin estndar NormalizeDouble ()
permite realizar clculos con los valores de las variables reales a un conjunto de valores exactos (que
corresponde a la exactitud de los precios del ttulo o valor).
Si el precio es igual o superior al nivel indicado, el hecho del primer evento se considerar que se
cumple y la variable global Fact_1 obtiene el valor true. El programa est construido de manera que una
vez que Fact_1 obtiene el valor true, nunca ser cambiado al valor false por que no hay un cdigo escrito
en el programa que lo haga.
En las lneas:
if (Fact_1 == true && NormalizeDouble(Price,Digits)<=
NormalizeDouble(Level-n*Point,Digits))
My_Alert(); // User-defined function call
Se define la necesidad de mostrar un aviso. Si el primer hecho se ha completado y se redujo el precio en
n puntos (menor o igual) del nivel indicado, una alerta ser mostrada debido a la llamada a la funcin
definida por el usuario My_Alert(). En esta funcin, despus de que la descripcin del hecho ya se ha
mostrado, se asigna true a la variable Fact_2, lo cual permite, despus de salir de la funcin definida por
el usuario, salir de la funcin especial start().
Despus de que la variable Fact_2 obtiene el valor true, el programa (funcin especial Start() ) dar por
acabado su funcionamiento cada vez que ste se ejecute. Por eso, una vez mostrada la alerta no se
repetir este programa durante esa sesin.
En este programa el hecho significativo es que los valores de las variables globales puede ser
modificadas en cualquier lugar (tanto en la funcin especial como en las funciones definidas por el
usuario) y que se conserven en todo el perodo de operacin del programa, tanto en el perodo
comprendido entre ticks como despus de cambiar la variable exterior, o despus de cambiar un marco
temporal.
Variables Globales del Terminal de Usuario (GlobalVariables)
La variable global de la Terminal de Usuario es una variable cuyo valor est disponible en todos los
programas de aplicacin que se inicien en la Terminal de Usuario.
Hay que tener en cuenta que las Variables Globales de la Terminal de Usuario (VGTU) y las Variables
Globales (a secas) son diferentes variables con nombres similares. El alcance de las variables globales es
el programa donde se declara la variable, mientras que el alcance de las Variables Globales de Terminal
de Usuario es en todos los programas puestos en marcha en la Terminal de Usuario.
A diferencia de otras variables, las GVTU no slo pueden ser creadas por cualquier programa, sino que
tambin pueden ser eliminadas. El valor de la GVTU se almacena en el disco duro y se guarda despus
de que la Terminal de Usuario se ha cerrado. Una vez declarada una GVTU, se conserva en la Terminal
de Usuario durante 4 semanas desde el momento de la ltima llamada. Si durante este perodo ninguno
de los programas ha llamado a esta variable, sta se eliminar de la Terminal de Usuario. Las GVTU
slo puede ser de de tipo double.
Funciones para trabajar con GlobalVariables
Funcin GlobalVariableSet ()
datetime GlobalVariableSet (string NombreVariableGlobal, double NuevoValorNumrico)
Esta funcin crea un nuevo valor de una VGTU. Si una variable no existe, el sistema crea una nueva
Variable Global de Terminal de Usuario. En el caso de que la ejecucin se realice con xito, la funcin
devuelve la hora del ltimo acceso, en caso contrario devuelve 0. Para obtener una informacin de
errores debe ser llamada la funcin GetLastError().
Funcin GlobalVariableGet ()
double GlobalVariableGet(string NombreVariableGlobalExistente)
La funcin devuelve el valor de una variable global existente o, en caso de error, devuelve 0. Para
obtener una informacin de errores, se debe llamar a la funcin GetLastError().
Funcin GlobalVariableDel ()
bool GlobalVariableDel( string NombreVariableGlobalExistente)
Esta funcin elimina una variable global. En caso de supresin con xito la funcin devuelve TRUE, de
lo contrario devuelve FALSE. Para obtener una informacin de errores, debe ser llamada la funcin
GetLastError().
Problema 21. Varios Asesores Expertos trabajan en un terminal al mismo tiempo. El depsito es de
10.000 $. El importe total de las rdenes de todas las ventanas no debe exceder del 30% del depsito. Se
debe asignar la misma cantidad a cada Asesor Experto. Crear un EA que calcule la suma asignada para
el comercio.
El clculo de la cantidad asignada a un EA para el comercio no es difcil. Sin embargo, para la
realizacin de este clculo es necesario saber el nmero de Asesores Expertos puestos en marcha al
mismo tiempo. No hay funcin en MQL4 que pueda responder a esta pregunta. La nica posibilidad de
contar el nmero de programas puestos en marcha es que cada programa lo anuncie por s mismo
cambiando el valor de una determinada GV. Entonces todos los programas que necesiten esta
informacin podrn referirse a esta GV y detectar su estado actual.
Cabe sealar aqu que, en general, ningn programa est destinado a resolver ese problema por si
mismo. Si un Asesor Experto no anuncia su existencia, no ser contado. Es por ello que en este caso la
definicin del problema presupone el uso de estos EAs que contienen el cdigo necesario tanto para
cambiar el valor de la GV como para leer el valor de esta variable.
//--------------------------------------------------------------------
// globalvar.mq4
//--------------------------------------------------------------------
int Experts; // Cantidad de EAs
double Depo=10000.0, // Cantidad del depsito
Persent=30, // Establecer el porcentaje
Money; // Dinero asignado
string Quantity="GV_Quantity"; // Nombre de la GV
//--------------------------------------------------------------------
int init() // Special funct. init()
{
Experts=GlobalVariableGet(Quantity); // Obtener valor actual del n de Expertos..
//.. si no hay ninguno, devuelve cero
Experts=Experts+1; // Incrementar el nmero de EAs anterior
GlobalVariableSet(Quantity, Experts); // Nuevo valor de la GVTU "GV_Quantity"
Money=Depo*Persent/100/Experts; // El dinero asignado para cada AEs
Alert("For EA in window ", Symbol()," allocated ",Money);
return; // Salir de init()
}
//--------------------------------------------------------------------
int start() // Special funct. start()
{
int New_Experts= GlobalVariableGet(Quantity); // Nueva cantidad de EAs
if (Experts!=New_Experts) // Si ha cambiado
{
Experts=New_Experts; // Actualizacin del Numero de Expertos
Money=Depo*Persent/100/Experts; // Actualizacin del dinero asignado AEs
//.. dinero asignado AEs
Alert("New value for EA ",Symbol(),": ",Money);
}
/*
Aqu el cdigo del EA principal debe ser indicado.
Es usado en esto el valor de la variable DineroAsignado ...
*/
return; // Exit start()
}
//--------------------------------------------------------------------
int deinit() // Special funct. deinit()
{
if (Experts ==1) // If one EA..
GlobalVariableDel(Quantity); //..delete GV
else // Otherwise..
GlobalVariableSet(Quantity, Experts-1); //..diminish by 1
Alert("EA detached from window ",Symbol()); // Alert about detachment
return; // Exit deinit()
}
//--------------------------------------------------------------------
Esta AE contiene tres funciones especiales. En pocas palabras: todas las funciones especiales son
iniciadas por la Terminal de Usuario: La funcin init() se inicia cuando una AE se vincula a la ventana
de un smbolo o valor, la funcin deinit() se inicia cuando una AE se separa de una ventana de un
smbolo, y la funcin start() se inicia cada vez que llega un tick. La parte de la cabecera del programa
contiene la parte que corresponde a la declaracin de variables globales (el alcance de estas variables es
el programa entero).
La asignacin de dinero a cada uno de los AEs depende de un parmetro variable, el nmero de AEs que
estn trabajando simultneamente. Esa es la razn por la GV que refleja la cantidad de AEs debe ser
nica. Su nombre se establece en la lnea:
string Quantity = "GV_Quantity"; // GV name
Vamos a analizar en detalle la forma en que el valor de la variable Quantity se cambia cuando el
programa se ejecuta. En primer lugar, el EA que se vincula a una ventana de un smbolo debe anunciar
su existencia a fin de que los otros EAs que trabajan en el Terminal puedan saber sobre l.
Esto debe hacerse lo ms pronto posible (lo ms cerca posible del momento en que se asocia un EA a la
ventana de un smbolo). El lugar ms adecuado es en la funcin especial init(). En la primera lnea de
esta funcin, el EA pide el valor actual de la variable Quantity con la funcin GlobalVariableGet () que
se usa para este fin:
Experts = GlobalVariableGet(Quantity); // Getting current value
Ahora el valor de Cantidad GV debe aumentar en 1, no importa la cantidad que tena en el momento de
la adhesin de EA. Esto significa que el EA que se vincula aumenta en un 1 la cantidad de EAs que
trabajan en la terminal al mismo tiempo:
Experts = Experts+1; // Amount of EAs
La variable global Experts se utiliza en el programa solo por conveniencia. Su valor no est disponible
para otros EAs. Para cambiar el valor de GV Quantity, se utiliza la funcin GlobalVariableSet () que
establece un nuevo valor de la GV:
GlobalVariableSet(Quantity, Experts); // New value
Esto significa un nuevo valor de Experts se ha asignado a la GV Quantity. Ahora este nuevo valor de la
GV est disponible para todos los programas que operan en la terminal. Despus de que calcula la
cantidad deseada para el trading asignando a cada AE se vincula una alerta. Esta alerta se usa solamente
para avisar cundo y en qu eventos sucede el AE.
Money = Depo*Persent/100/Experts; // Money for EAs
Alert("For EA in the window ", Symbol()," allocated ",Money);
Ahora dentro de nuestro problema la finalidad del EA es la bsqueda de la cantidad actual de EAs que
estn adjuntos. Los Asesores Expertos pueden estar conectados o desconectados; en consecuencia, la
cantidad de EAs trabajando simultneamente puede cambiar. En funcin de esto nuestro EA debe
recalcular la suma asignada a cada EA de conformidad con el problema planteado. Por lo tanto, lo
primero que realiza el EA en cada nuevo tick es solicitar el nuevo valor de GV Quantity:
int New_Experts= GlobalVariableGet(Quantity); // New amount of EAs
Y si este nuevo valor New_Experts difiere de los ltimos Expertos conocidos, el nuevo valor se
considera como el actual, el dinero asignado para el trading de una EA se vuelve a calcular y se crea la
descripcin correspondiente:
if (Experts != New_Experts) // If changed
{
Experts = New_Experts; // Now current
Money = Depo*Persent/100/Experts; // New money amount
Alert("New value for EA ",Symbol(),": ",Money);
}
Si las variables New_Experts y Experts son iguales, no se hacen ms clculos en el cdigo del EA. En la
funcin start() se utiliza el valor de la variable Money calculada anteriormente. Por lo tanto,
dependiendo de la situacin en cada tick, si hay que asignar una nueva cantidad de dinero, entonces se
calcula su nuevo valor, y si no es as se utilizar el valor del dinero asignado anteriormente.
En la etapa de separacin de un Asesor Experto de una ventana de un smbolo, ste deber informar a
los otros EAs que se ha separado, es decir, que el nmero de EAs que estn trabajando al mismo
tiempo se redujo. Por otra parte, si este EA es el ltimo, la GV debe ser eliminada.
La ejecucin de la funcin especial deinit() identifica la separacin de un EA, por lo que el cdigo
correspondiente debe estar ubicado en esa funcin:
int deinit() // Special funct. deinit()
{
if (Experts ==1) // If one EA..
GlobalVariableDel(Quantity); //..delete GV
else // Otherwise..
GlobalVariableSet(Quantity, Experts-1); //..diminish by 1
Alert("EA detached from window ",Symbol()); // Alert about detachment
return; // Exit deinit()
}
Es fcil ver que los valores de las variables globales pueden ser ledos o cambiados por cualquier EA
que se est ejecutando. Pero No se permiten clculos directos con los valores de la GV. Para usar los
valores de GV en una expresin habitual, este valor debe ser asignado a otra variable y utilizar esta
variable en los clculos. En nuestro caso, utilizamos dos variables para este fin: Experts y New_Experts.
Hay una opcin en la Terminal de Usuario para abrir en la barra de herramientas "Variables globales",
donde, en tiempo real se pueden ver todas las GlobalVariables abiertas actualmente y sus valores. Esta
barra de herramientas est disponible a travs del Terminal de Usuario en el men Herramientas>>
Variables locales (tecla F3).

Errores en el uso de GlobalVariables


Si empezamos el EA del problema anterior en las ventanas de diferentes valores, veremos que el cdigo
funciona correctamente. Sin embargo, esto ocurre solo si las pausas entre los eventos son muy grandes.
Prestemos atencin al operador if en deinit():
if (Experts ==1) // En caso de que el numero AE sea uno..
En este caso, se analiza el valor de la variable global Experts. A pesar de que refleja el valor GV, este
puede ser antiguo (se debe tener en cuenta que todos los programas funcionan en tiempo real). Para
comprender las razones, veamos el siguiente diagrama:

Aqu se muestra el desarrollo de eventos relacionados con el valor de Quantity. Veamos cmo cambiar
este valor dependiendo de lo que est sucediendo. Supongamos que el EA inici la ejecucin en el
momento t0. En ese momento Quantity todava no existe. En el perodo t0 - t1 se ejecuta la funcin
especial init() del EA y como resultado se crea la GV Quantity, su valor en el momento t1 es igual a 1.
El prximo tick del smbolo EUR/USD pone en marcha la funcin especial start(). Sin embargo, en el
perodo t0 - t6 slo hay un EA en la Terminal de Usuario y el valor de Quantity no cambia.
En el momento t6 se vincula el segundo EA al smbolo del grafico GBP/USD. Como resultado de la
ejecucin de su funcin especial init() el valor de la variable Quantity cambia y en el momento t7 y se
hace igual a 2.
Despus de que en el momento t8 se vincula al grfico de USD/CHF un nuevo EA, en el momento t9 la
variable Quantity se hace igual a 3.
Pero en el momento t10 el trader decide eliminar el EA de la ventana de EUR/USD. Veamos los
cambios que la variable Experts de ese EA de EUR/USD tuvo durante la ejecucin de la funcin start():
En este EA de EUR/USD, la funcin start() se puso en marcha por ltima vez en el segundo tick, es
decir, en el perodo t4 - t5.
Ahora, en el momento t10 el valor de Experts en el EA de EUR/USD sigue siendo igual a 1. Es por ello
que cuando la funcin deinit() de este EA se ejecuta, la variable GV_Quantity ser eliminada.
Se suprime la Variable Global a pesar de que todava hay dos AEs vinculados! No es difcil de
entender, qu consecuencias tendr, incluso en los clculos de los EAs vinculados. Estos errores
algoritmos no siempre son evidentes y son difciles de detectar.
En este caso, el error puede ser fcilmente corregido. Necesitamos simplemente actualizar el valor de
Experts antes de su anlisis (antes de la ejecucin del operador if):
int deinit() // Special funct. deinit()
{
Experts = GlobalVariableGet(Quantity); // Getting current value
if (Experts ==1) // If one EA..
GlobalVariableDel(Quantity); //..delete GV
else // Otherwise..
GlobalVariableSet(Quantity, Experts-1); //..diminish by 1
Alert("EA detached from window ",Symbol()); // Alert about detachment
return; // Exit deinit()
}

ARRAYS
Una gran parte de la informacin procesada en los programas de aplicacin figura en los arrays.
El Array (vector o matriz) es un conjunto organizado de valores de variable de un tipo, que tienen un
nombre comn. Las matrices pueden ser unidimensionales y multidimensionales. La cantidad mxima
admisible de dimensiones en un array es de cuatro. Las matrices pueden tener cualquier tipo de datos.
Las partes de un array se llaman elementos de un array. Es una variable indexada que tiene el mismo
nombre y valor.
Indexacin
El ndice es un elemento de la matriz que est formado por uno o varios valores (segn que el vector sea
unidimensional o multidimensional) y estn expresados en forma de una constante, variable o una
expresin y que se enumeran separados por comas, entre corchetes.
Los elementos de la matriz con un nico ndice define el lugar de un elemento en un array. En MQL4
se utiliza la indexacin a partir de cero, es decir, el primer elemento de la matriz es la matriz con
ndice cero.

Otra forma de especificar los ndices es cada uno entre corchetes independientes:

La analoga ms cercana y cotidiana de una matriz bidimensional es una sala de cine. El nmero de fila
es el primer valor del ndice, el nmero de columna es el segundo valor del ndice, los individuos que se
sientan en la butaca son elementos del array, el apellido del espectador es el valor del elemento de la
matriz, la entrada de cine (especificando fila y columna) es un mtodo para acceder al valor del
elemento de la matriz.
Declaracin del Array y acceso a la gama elementos
Antes de utilizar un array en un programa, este debe ser declarado. Un array puede ser declarado como
una variable global o local. En consecuencia, los valores de los elementos de un array global estn
disponibles para todo el programa, y los valores de un array local slo estn disponibles para la funcin
en la que se declaran.
Un array No puede declararse en el Nivel de la Terminal de Usuario, es por eso que las Variables
Globales de Terminal de Usuario (VGTU) No pueden ser recogidas en una matriz.
Los valores de los elementos de un array pueden ser de cualquier tipo. Los valores de todos los
elementos de un array son todos del mismo tipo, es decir, del tipo indicado en la declaracin del array.
Cuando se declara un array se debe especificar el tipo de datos, el nombre de la matriz y el nmero de
elementos de cada dimensin:

Ejemplo de cmo se asigna un valor a un elemento de array y ejemplo de cmo se asigna el valor de un
elemento de array a una variable:

Los valores de los elementos de array de la pgina anterior, son los siguientes:
a. Para el array unidimensional, el elemento Mas [4] tiene un valor entero de 34.
b. Para la matriz bidimensional, el elemento Mas [3,7] tiene un valor entero 28;
c. Para el array de tres dimensiones, el elemento Mas [5,4,1] tiene un valor entero 77.
Las Operaciones con arrays tambin pueden llevarse a cabo utilizando funciones estndar.
Inicializacin de un Array
Un array solo se puede inicializar por constantes del tipo correspondiente. Los arrays unidimensionales
o multidimensionales se inicializan con una secuencia de constantes de una dimensin separadas por
comas. La secuencia se escribe entre llaves:
int Mas_i[3][4] = { 0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23 };
double Mas_d[2][3] = { 0.1, 0.2, -0.3, -10.2, 1.5, 7.0 };
bool Mas_b[5] = { false, true, false, true, true }
En la secuencia de inicializado pueden omitirse una o varias constantes. En tal caso, la correspondiente
gama de elementos de tipo numrico se inicializan a cero, los elementos de arrays de tipo string se
inicializan al valor "" (comillas sin espacio), es decir, una cadena de caracteres vaca. No se debe
confundir la cadena de caracteres vaca con el espacio, pues este es un caracter (y por tanto es un valor
no vacio). El siguiente programa muestra los valores de arrays, inicializados por una secuencia con
omisin de algunos valores.
//--------------------------------------------------------------------
// arrayalert.mq4
//--------------------------------------------------------------------
int start() // Special funct. start()
{
string Mas_s[4] = {"a","b", ,"d"}; // String array
int Mas_i[6] = { 0,1,2, ,4,5 }; // Integer type array
Alert(Mas_s[0],Mas_s[1],Mas_s[2],Mas_s[3]); // Displaying
Alert(Mas_i[0],Mas_i[1],Mas_i[2],Mas_i[3],Mas_i[4],Mas_i[5]);
return; // Exit start()
}
//--------------------------------------------------------------------
Si no se ha especificado el tamao de un array unidimensional inicializado, ste se define por un
compilador basado en la secuencia inicializada. Un array tambin puede ser inicializado por la funcin
estndar ArrayInitialize(). Todos los arrays son estticos, aun cuando en la inicializacin no est
indicado explcitamente. Esto significa que todos los arrays preservan sus valores entre llamadas a la
funcin en la cual la matriz ha sido declarada.
Las matrices utilizadas en MQL4 pueden dividirse en dos grupos: arrays definidas por el usuario
(creadas por iniciativa del programador) y arrays-timeseries (arrays predefinidas con nombres y tipos de
datos). Los valores de los elementos de los arrays definidos por el usuario se conservan durante todo el
tiempo de ejecucin del programa y pueden ser modificados despus de los clculos. Sin embargo, los
valores de los elementos de los arraystimeseries no se pueden cambiar, su tamao puede aumentar
cuando la historia se actualiza.
Arrays Definidos por el usuario
Problema 22 (similar al problema 15). Crear un programa en el que se apliquen las siguientes
condiciones: si el precio excede cierto nivel, mostrar un mensaje, en el que se indique el exceso hasta
100 puntos; en los dems casos, informar que el precio no es superior a ese nivel.
//--------------------------------------------------------------------
// stringarray.mq4
//--------------------------------------------------------------------
extern double Level=1.3200; // Preset level
string Text[101]; // Array declaration
//--------------------------------------------------------------------
int init() // Special funct. init()
{ // Assigning values
Text[1]="one "; Text[15]="fifteen ";
Text[2]="two "; Text[16]="sixteen ";
Text[3]="three "; Text[17]="seventeen ";
Text[4]="four "; Text[18]="eighteen ";
Text[5]="five "; Text[19]="nineteen ";
Text[6]="six "; Text[20]="twenty ";
Text[7]="seven "; Text[30]="thirty ";
Text[8]="eight "; Text[40]="forty ";
Text[9]="nine "; Text[50]="fifty ";
Text[10]="ten "; Text[60]="sixty";
Text[11]="eleven "; Text[70]="seventy ";
Text[12]="twelve "; Text[80]="eighty ";
Text[13]="thirteen "; Text[90]="ninety";
Text[14]="fourteen "; Text[100]= "hundred";
// Calculating values
for(int i=20; i<=90; i=i+10) // Cycle for tens
{
for(int j=1; j<=9; j++) // Cycle for units
Text[i+j]=Text[i] + Text[j]; // Calculating value
}
return; // Exit init()
}
//--------------------------------------------------------------------
int start() // Special funct. start()
{
int Delta=NormalizeDouble((Bid-Level)/Point,0); // Excess
//--------------------------------------------------------------------
if (Delta<=0) // Price is not higher than level
{
Alert("Price below level"); // Alert
return; // Exit start()
}
//--------------------------------------------------------------------
if (Delta>100) // Price higher than 100
{
Alert("More than hundred points"); // Alert
return; // Exit start()
}
//--------------------------------------------------------------------
Alert("Plus ",Text[Delta],"pt."); // Displaying
return; // Exit start()
}
//--------------------------------------------------------------------
La matriz se declara a nivel global (fuera de las funciones especiales), la inicializacin completa de
valores del conjunto se hace en la funcin especial init(). As, en la funcin especial start() slo se llevan
a cabo lo clculos necesarios en cada tick.
El significado de estos clculos puede ser de fcilmente comprendido: para cada elemento array con el
ndice de 21 a 99 (excepto los ndices mltiplos de 10) es calculado el correspondiente valor string.
Arrays Timeseries
Un Array-timeseries es un array con un nombre predefinido (Open, Close, High, Low, Volume or
Time), los elementos que contienen los valores corresponden a las caractersticas histricas de las barras
del grfico correspondiente.
Los datos que contienen las matrices timeseries son muy importantes; es una informacin ampliamente
utilizada en la programacin de MQL4. Cada array- timeseries es un array unidimensional y contiene
datos histricos sobre una determinada caracterstica de las barras. Cada barra se caracteriza por un
precio de apertura Open[], precio de cierre Close[], el precio mximoHigh[], el precio mnimo Low[], el
volumen Volume[] y la fecha y hora de apertura Time[]. Por ejemplo, la matriz-timeseries Open[] lleva
informacin sobre la apertura de los precios de todas las barras presentes en una ventana de un smbolo:
el valor del elemento del array Open[1] es el precio de apertura de la primera barra, Open[2] es el precio
de apertura de la segunda barra, etc. Lo mismo puede decirse de otros timeseries.
La barra cero es la barra actual que no se ha formado an plenamente. En una ventana de un grfico la
barra cero es la ltima barra que se est formando.
La barra actual que an no se ha terminado de formar completamente siempre ser la barra cero, la
primera a la izquierda de sta ser la primera barra, la siguiente, la segunda barra, etc.
Problema 23. Encuentre el precio mnimo y mximo entre las ltimas n barras.
//--------------------------------------------------------------------
// extremumprice.mq4
//--------------------------------------------------------------------
extern int GV_CantidadBarras=30; // Cantidad de barras
//--------------------------------------------------------------------
int start() // Special funct. start()
{
int i; // numero de barras
double MinimoPrecio=Bid, // Precio mnimo
Maximum=Bid; // Precio mximo
for(i=0;i<=GV_CantidadBarras-1;i++) // Desde cero a..
{ // ..GV_CantidadBarras-1
if (Low[i]< MinimoPrecio) // If < que ultimo conocido
MinimoPrecio=Low[i]; // entonces este ser el precio mnimo
if (High[i]> Maximum) // If > que ltimo conocido
Maximum=High[i]; // entonces este ser el precio mximo
}
Alert("For the last ",GV_CantidadBarras, // Mostrar mensaje
" bars Min= ",MinimoPrecio," Max= ",Maximum);
return; // Salir de start()
}
//--------------------------------------------------------------------
En algunos casos es necesario tener en cuenta los datos desde el momento en que una barra se ha
formado totalmente. Ejemplo:
Problema 24. Al comienzo de cada barra mostrar un mensaje con los precios mnimo y mximo entre
las ltimas n barras formadas.
Aqu debemos detectar la formacin de la barra 0, para eso utilizaremos una funcin definida por el
usuario donde se utilizar el horario de apertura de la ltima barra, el cual es el nico dato que sabemos
con anterioridad a su formacin. De esta manera cuando haya una divergencia entre el tiempo actual y el
de formacin de la ltima barra ser porque comenz a formarse una nueva barra 0.
//--------------------------------------------------------------------
// newbar.mq4
//--------------------------------------------------------------------
extern int GV_CantidadBarras=15; // Cantidad de barras
bool GV_Flag_NuevaBarra=false; // Flag de una nueva barra
//--------------------------------------------------------------------
int start() // Special funct. start()
{
double MinimoPrecio, // variable que registra el precio minimo
MaximoPrecio; // variable que registra el precio minimo
//--------------------------------------------------------------------
Fun_NuevaBarra(); // Funcion call
if (GV_Flag_NuevaBarra==false) // Si no hay nueva barra..
return; // ..return
//--------------------------------------------------------------------
int IndMax =ArrayMaximum(High,GV_CantidadBarras,1); // Indice de la barra del precio maximo
int IndMin =ArrayMinimum(Low, GV_CantidadBarras,1); // Indice de la barra del precio minimo
MaximoPrecio=High[IndMax]; // Registrar el maximo precio
MinimoPrecio=Low[IndMin]; // Registrar el minimo precio
Alert("Para las ultimas ",GV_CantidadBarras, // Mostrar mensaje de precios max y min
" barras Min= ",MinimoPrecio," Max= ",MaximoPrecio);
return; // Salir de start()
}
//--------------------------------------------------------------------
void Fun_NuevaBarra() // Descripcin de la Funcion que detecta ..
{ // .. una nueva barra
static datetime NewTime=0; // variable que almacena fecha y hora
GV_Flag_NuevaBarra=false; // Inicializa nueva barra a falso (no hay nueva barra)
if(NewTime!=Time[0]) // Si existe nueva barra el dato es distinto de cero..
{
NewTime=Time[0]; //.. y en ese caso se registra el hora y fecha de la..
GV_Flag_NuevaBarra=true; //nueva barra y se activa el flag que sealiza la
//existencia de una nueva barra
}
}
//--------------------------------------------------------------------
Se utiliza en el programa una variable global llamada GV_Flag_NuevaBarra. Si su valor es 'true',
significa que el ltimo tick es el primer tick de una nueva barra. Si el valor de la variable
GV_Flag_NuevaBarra es 'false', el ltimo tick aparecido est dentro de la formacin de la actual barra
cero.
Un Flag (bandera) es una variable, cuyo valor se define de acuerdo con algunos acontecimientos o
hechos, es decir, una bandera se activa cuando ocurre algo.
Los clculos en cuanto a la deteccin de una nueva barra se concentran en la funcin definida por el
usuario Fun_NuevaBarra(). En las primeras lneas de la funcin se define la variable New_Time
(recurdese que las variables de tipo static no pierden sus valores despus de la ejecucin de la funcin
que est por encima). En cada llamada a la funcin, el valor de la variable global GV_Flag_NuevaBarra
se establece como false.
La deteccin de una nueva barra se realiza en el operador if:
if(NewTime!=Time[0]) // Si existe nueva barra el dato es distinto de cero..
{
NewTime=Time[0]; //.. y en ese caso se registra el hora y fecha de la..
GV_Flag_NuevaBarra=true; //nueva barra y se activa el flag que sealiza la
} //existencia de una nueva barra
Si el valor New_Time (calculado en la anterior historia) no es igual a Time [0] de la barra cero, ello
denota el hecho de la formacin de una nueva barra. En tal caso el control se pasa al cuerpo del operador
if, cuando hay una nueva fecha y hora de apertura en la barra cero, este dato es distinto de lo que hay
en NewTime y se actualiza el nuevo dato y tambin se activa el Flag GV_Flag_NuevaBarra (para mayor
comodidad se puede decir que se levanta la bandera que indica que hay una nueva barra).
El clculo del mximo y mnimo valor se realiza usando funciones estndar ArrayMaximum() y
ArrayMinimum(). Cada una de las funciones devuelve el ndice del elemento del array (el
correspondiente valor mximo o mnimo) durante el determinado intervalo de ndices.
Debido a las condiciones que establece el problema slo se deben analizar las barras que se han formado
completamente, por eso el lmite escogido de los valores del ndice est entre 1 y GV_CantidadBarras
(la barra cero no se ha formado an y no se tiene en cuenta en los clculos).
Para obtener informacin ms detallada sobre el funcionamiento de estos y otras funciones de acceso a
timeseries, consultar el sitio web http://docs.MQL4.com o "Ayuda" en MetaEditor.
Prcticas de programacin en MQL4
Programacin de operaciones de comercio
La funcin de trading ms importante es OrderSend(). Esta es la funcin que se utiliza para enviar las
solicitudes al servidor para abrir una orden de mercado o colocar una orden pendiente de ser ejecutada.
Se puede especificar de inmediato el valor deseado del StopLoss y del TakeProfit. Los valores
incorrectos de estos parmetros, as como de los precios de apertura y el volumen de la orden (nmero
de acciones, nmero de lotes o nmero de contratos de una posicin), pueden dar lugar a errores. Para
procesar adecuadamente estos errores es importante conocer el uso de la Funcin MarketInfo() que
permite minimizar la cantidad de dichos errores.
Las rdenes de Mercado pueden ser cerradas utilizando la funcin OrderClose(), mientras que las
rdenes pendientes pueden ser suprimidas con la funcin OrderDelete(). Al enviar una peticin de cerrar
o eliminar una orden, se debe especificar el ticket de la misma. Vamos a seleccionar la orden usando la
funcin OrderSelect(). Por otra parte, si hay dos rdenes contrarias en un smbolo, se pueden cerrar al
mismo tiempo utilizando la funcin OrderCloseBy(), ahorrndose as un spread.
Los niveles TakeProfit y StopLoss se pueden modificar utilizando la funcin OrderModify(). A las
rdenes en espera de ser ejecutadas tambin se les puede cambiar el precio de apertura. pero no el
volumen.
Manera comn de hacer Operaciones
Para crear las rdenes de trading se utilizan las siguientes funciones comerciales:
OrderSend() - para abrir rdenes al mercado y rdenes en espera de ser ejecutada;
OrderClose() y OrderCloseBy () - para cerrar las rdenes de mercado;
OrderDelete() - Para suprimir las rdenes pendientes de ser ejecutadas;
OrderModify() - para modificar las ordenes de mercado y las rdenes pendientes de ser
ejecutadas.
Los conflictos en la toma de rdenes. Error 146
El Terminal de Usuario solo puede atender una nica orden de trading a la vez. Vamos a examinar ahora
qu eventos se llevarn a cabo en caso de que se diferentes programas enven varias solicitudes.

En la figura, podemos ver que dos EAs se ponen en marcha en forma simultnea. El EA1 form una
peticin de comercio en el momento t1, la cual pas a la Terminal de Usuario en el momento t2.
El EA2 tambin ha creado una peticin, la cual se enva a la Terminal de Usuario cuando sta est
procesando la primera solicitud (perodo comprendido entre el t2 y t3).
En esta situacin, la Terminal de Usuario no puede considerar la solicitud formada por el EA2, por lo
que rechaza la solicitud y la devuelve.
Hay que tener en cuenta que, en este caso, la peticin es rechazada por la Terminal de Usuario no por
que la solicitud sea incorrecta, sino porque la terminal est ocupada con el procesamiento de otra
solicitud.
El EA2 seguir en funcionamiento. Se puede analizar el cdigo de error que explica la razn por la cual
la solicitud ha sido rechazada (en nuestro caso, es el error 146).
La Terminal se libera en el momento t4 (punto verde). A partir de este momento, el EA2 puede pasar
con xito su peticin a la Terminal de Usuario (el grupo de acontecimientos de la zona verde). Esta
solicitud recibida es examinada por la Terminal de Usuario que finalmente podr rechazar la peticin
(pero esta vez la razn sera un error en la peticin), o por el contrario, puede aceptar la peticin y
enviarla al servidor.
Si la solicitud creada por EA1 es considerada correcta por el Terminal, ste la mandar al servidor en el
momento t3. En este caso, el Terminal se pone en modo de espera y no puede considerar ninguna otra
solicitud de comercio. El Terminal de Usuario slo estar libre para considerar otras solicitudes de
comercio en el momento t9. As, segn La variante 2, el Terminal de Usuario no puede analizar
solicitudes de comercio en el plazo de tiempo entre t1 y t9. Si en este plazo, cualquier programa se
refiere al Terminal de Usuario con el fin de que se apruebe una solicitud de comercio, el Terminal de
Usuario rechazar este evento y pasar el control al programa (grupo de acontecimientos de la zona rosa
en el plazo de tiempo que transcurre entre t6 y 7). El programa que ha recibido el control contina con
su operacin y, analizando el cdigo de error, puede encontrar informacin sobre la razn por la cual la
solicitud ha sido rechazada (en este caso, es el error 146).
A partir del momento t9, el Terminal de Usuario ser completamente libre para el anlisis de cualquier
otra solicitud de comercio. EA2 puede pasar con xito la solicitud al Terminal de Usuario en el plazo de
tiempo que sigue al momento t9.
Caractersticas de los smbolos
Two-way quote: es un par de precios de mercado conectados de compra.
Bid es el ms bajo de los dos precios ofrecidos. Es el dinero que ofrecen (oferta de dinero) por la
compra de un ttulo o valor. Es el precio disponible si se quiere vender.
Ask es el ms alto de los dos precios ofrecidos. Es el dinero que demandan (demanda de dinero) por la
venta de un ttulo o valor. Es el precio disponible si se quiere comprar.
Point (punto) es la unidad de medicin para el precio de un smbolo (el mnimo cambio de precio
posible).
Spread es la diferencia entre el mayor y el menor precio en puntos en el Two-way quote para la
cotizacin de un valor.
Tipos y Caractersticas de las rdenes
Hay seis tipos de rdenes en total: dos tipos de rdenes de mercado y cuatro tipos de rdenes pendientes
de ser ejecutadas.
Buy es una orden de mercado que define la orden de compra de activos para un smbolo.
Sell es una orden de mercado que define la orden de venta de activos para un smbolo.
Buy Limit es una orden pendiente de ser ejecutada para comprar activos de un ttulo por un importe
inferior al actual. La orden ser ejecutada si el precio de demanda (Ask) alcanza o cae por debajo del
precio fijado en la orden de espera.
SellLimit es una orden pendiente de ser ejecutada para vender activos de un ttulo a un precio superior
al actual. La orden ser ejecutada si el precio de oferta (Bid) alcanza o supera el precio fijado en la orden
en espera de ser ejecutada.
BuyStop es una orden pendiente de ser ejecutada para comprar los activos de un ttulo a un precio
superior al actual. La orden ser ejecutada si el precio de la demanda (Ask) alcanza o supera el precio
fijado en la orden en espera de ser ejecutada.
SellStop es una orden pendiente de ser ejecutada para vender los activos de un ttulo por un importe
inferior al actual. La orden ser ejecutada si el precio de la oferta (Bid) alcanza o cae por debajo del
precio fijado en la orden en espera de ser ejecutada.
Lot es el volumen de una orden expresado en cantidad de lotes.
StopLoss es una orden de stop. Es el precio fijado por el comerciante, en el que se cerrar una orden de
mercado si los precios de un titulo se mueven en una direccin tal, que la orden que tenemos en el
mercado produce prdidas.
TakeProfit es una orden de stop. Es el precio fijado por el comerciante, en el que se cerrar una orden
de mercado si los precios de un titulo se mueven en una direccin tal, que la orden que tenemos en el
mercado produce beneficios.
Trading requisitos y limitaciones
Al calcular los precios correctos, tambin es necesario tener en cuenta las limitaciones del proveedor de
servicios (dealing center). Estas limitaciones incluyen la distancia mnima y la distancia de congelacin.
Estas limitaciones implican que el corredor necesita un tiempo para los preparativos para la realizacin
de nuevas rdenes, ya sea la conversin de una orden pendiente en una de mercado o de una de cierre a
una orden de stop.
El Dealing Centers limita el valor de la diferencia mnima admisible entre:
el precio de mercado y los requerimientos de precio de cada orden de stop de una orden de
mercado,
el precio de mercado y el precio solicitado de una orden pendiente de ser ejecutada,
el precio solicitado de una orden pendiente de ser ejecutada y el requerimiento de precio de sus
rdenes de stop.
Esto significa, por ejemplo, que en una orden de comercio, para solicitar la apertura de una orden de
mercado slo se puede especificar la orden precio de stop de los valores que no distan del actual precio
una distancia inferior a la mnima. Una peticin de trade que contiene un precio de orden de stop cuya
distancia a los precios de mercado est ms prxima que la distancia mnima que es considerada por el
Terminal de Usuario como incorrecta. Los diferentes dealing centers pueden establecer diferentes
limitaciones especficas para la distancia mnima permitida. Por regla general, el valor de esta distancia
vara entre 1 y 15 puntos. Para los valores ms comnmente utilizados (en EUR/USD, GBP/USD,
EUR/CHF, etc), esta distancia viene a ser en la mayora de los brokers de 3-5 puntos. Diferentes valores
pueden tener diferentes distancias mnimas permitidas, tambin. Por ejemplo, este valor puede ser 50-
100 puntos en el oro. El valor de la distancia mnima en cualquier smbolo puede ser cambiado por el
corredor en cualquier momento (esto normalmente precede a la difusin comercial de una noticia
importante). Para la distancia mxima no hay limitaciones.
La distancia de congelacin limita la posibilidad de modificar los precios de apertura de sus rdenes
pendientes de ser ejecutadas, as como los requerimientos de los niveles de stop de las rdenes de
mercado que se encuentran en la zona de congelacin. Esto significa, por ejemplo, que si el precio de
mercado es 1.3800, y la orden pendiente de ser ejecutada esta situada para ser abierta en 1.3807 y la
prescripcin del broker es de 10, su orden de espera se encuentra en la zona de congelacin, es decir, no
se puede modificar o borrar. En un mercado en calma, los intermediarios no suelen establecer una
distancia de congelacin, es decir, su valor = 0. Sin embargo, durante el perodo anterior a noticias
importantes o en alta volatilidad, el corredor podr fijar un valor determinado de una distancia de
congelacin. En condiciones diferentes y para diferentes intermediarios, este valor puede variar desde 1
a 30 puntos para los smbolos bsicos y tener valores ms altos para otros smbolos. La empresa de
corretaje puede cambiar el valor de la distancia congelacin a su propia discrecin en cualquier
momento.
De la apertura/cierre de rdenes de mercado
La apertura de una orden de mercado implica la compra o venta de algunos activos de un smbolo al
precio actual de mercado. Para abrir una orden de mercado se utiliza la funcin OrderSend(); para su
cierre se utiliza la funcin OrderClose().
El precio de apertura correcto de una orden de compra a mercado es el ltimo precio de mercado
conocido Ask.
El precio de apertura correcto de una orden de venta a mercado es el ltimo precio de mercado conocido
Bid.
Las rdenes StopLoss y TakeProfit no se pueden situar ms cerca del precio de mercado que la distancia
mnima, que es de 5 pips. Por lo tanto, se recomienda tener algn "free play" (juego libre), es decir,
colocar los stops con cierta holgura de la distancia mnima. Por ejemplo, especificar los valores de
rdenes de stop de tal manera que la distancia desde la solicitud de la orden de apertura est al menos 1
2 puntos ms lejos que el valor de la distancia mnima permitida.
El precio correcto de cierre de una operacin de compra es el ltimo precio Bid conocido.
El precio correcto de cierre de una operacin de venta es el ltimo precio Ask conocido.
La orden no puede ser cerrada si el precio de ejecucin de su StopLoss o TakeProfit est dentro del
rango de distancia de congelacin del precio de mercado. En general, una orden de mercado no puede
ser cerrada por iniciativa de la Terminal de Usuario si, al menos, un nivel stop (es decir, el SL o el TP)
de esta orden se encuentra en la zona de congelacin.
La banda de congelacin de la orden se calcula sobre la base del precio de mercado. Por ejemplo, para
cerrar una operacin de venta, se tomar en cuenta el precio Ask y se le aadir la distancia de la banda
de congelacin. Si el broker decidi una banda de congelacin de 4 puntos, entonces el precio de la
banda de congelacin del borde superior es Ask + 0,0004, mientras que el precio ms bajo de la banda
de congelacin es Ask - 0,0004.
Si dos rdenes de mercado son abiertas simultneamente en un smbolo y una de ellas es de compra y
otra es pueden cerrarse de una de dos maneras: se pueden cerrar una a una de forma consecutiva, usando
OrderClose(); o bien se puede cerrar una de ellas contra la otra utilizando OrderCloseBy(). En trminos
de ahorro de dinero, la segunda manera es preferible porque, cerrando una orden contra otra, se ahorra
un spread.
Una orden a la espera (o pendiente) de ser ejecutada implica el requerimiento de apertura de una orden a
un precio distinto al precio actual de mercado. Para colocar rdenes pendientes de ser ejecutadas se
utiliza la funcin OrderSend(), y para eliminarlas, la funcin OrderDelete ().
Las rdenes pendientes de ser ejecutadas SellLimit (Venta a precio limitado) y BuyStop (Stop de
compra) se colocan a un precio que es superior al precio actual de mercado, mientras que BuyLimit
(compra a precio limitado) y SellStop (stop de venta) se colocan a un precio que es inferior al precio
actual de mercado.
Las rdenes en espera de ser ejecutadas BuyLimit, BuyStop, SellLimit y SellStop no se pueden colocar a
un precio que est ms cerca del precio de mercado que la distancia mnima.
La posicin de StopLoss y TakeProfit correspondientes a rdenes pendientes de ser ejecutadas no estn
limitadas por la distancia de congelacin.
Las rdenes en espera de ser ejecutadas BuyLimit, BuyStop, SellLimit y SellStop no se pueden eliminar,
si el precio solicitado de la orden de apertura se encuentra dentro del rango de la distancia de
congelacin de los precios de mercado.
Aclaracin: en los grficos se muestra el precio bid, y las barras o velas reflejan el historial de este
precio. El historial del precio ask no se muestra.
Si hay un salto brusco del precio, o un gap, una orden pendiente se ejecutar (o lo que es lo mismo, se
transformar en una orden de mercado) en el primer nuevo precio conocido que supere el precio previsto
de apertura de la orden pendiente.
Para modificar rdenes de cualquier tipo, incluidas las rdenes de mercado, se debera usar la funcin
OrderModify ().
La Modificacin de una orden de mercado implica solo el cambio de valores que solicit de las rdenes
stop. No puede cambiar los precios de apertura de las ordene en mercado.
Las rdenes StopLoss y TakeProfit no pueden situarse ms prxima del precio de mercado que a la
distancia mnima establecida por el broker.
La orden de ejecucin de su StopLoss o TakeProfit no puede modificarse si el precio de dichas ordenes
est dentro de los rangos de la distancia del precio de congelacin del mercado.
Tngase en cuenta que la posicin de las rdenes de stop de una orden de mercado est limitada en
relacin con el precio actual del mercado y no con el precio de la orden apertura.
Modificacin de rdenes pendientes de ser ejecutadas
Para modificar cualquier tipo de orden, incluidas las rdenes pendientes de ser ejecutadas, utilizamos la
funcin OrderModify().
La modificacin de una orden pendiente de ser ejecutada implica la posibilidad de cambiar los valores
definidos del precio de apertura de la orden en espera de ser ejecutada y sus rdenes stop.
Apertura y colocacin de rdenes pendientes de ser ejecutadas
Las solicitudes de comercio para la apertura y colocacin de rdenes en espera de ser ejecutadas se
forman utilizando la funcin OrderSend().
Funcin OrderSend()
int OrderSend (string symbol, int cmd, double volume, double price, int slippage, double stoploss, double
takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
OrderSend es el nombre de la funcin. La funcin devuelve el nmero de ticket (el 'ticket' es un
nmero nico de orden) que es asignado por el servidor, o el valor -1, si la solicitud es rechazada por el
servidor o por la Terminal de Usuario. Con el fin de obtener informacin sobre los motivos de rechazo
de la solicitud, se debe usar la funcin GetLastError().
symbol es el nombre del valor o ttulo negociado. Cada smbolo se corresponde con el valor de una
variable string. Por ejemplo, para el par de monedas euro / dlar, este valor es "EURUSD".
Sin embargo, si se va a utilizar el Asesor Experto en la ventana de cualquier smbolo, se debe utilizar el
smbolo de la funcin estndar Simbol(). Esta funcin devuelve una cadena de caracteres de un valor
que se corresponde con el nombre del smbolo de la ventana en la que AE o el script estn siendo
ejecutados.
cmd es el tipo de operacin. Si por ejemplo vamos a abrir una orden de Compra especificamos el
parmetro OP_BUY.
volume es la cantidad de lotes. Para rdenes de mercado se debe siempre verificar la cuenta para
comprobar la suficiencia de la misma. Para las rdenes pendientes de ser ejecutadas no est limitada la
cantidad de lotes.
price es el precio de apertura. Se especifica en funcin de las necesidades y limitaciones aceptadas para
hacer las operaciones.
slippage (deslizamiento) es la desviacin en puntos mxima permitida entre el precio de apertura de la
orden solicitada y el precio de mercado para las rdenes de mercado. O en otras palabras, el slippage se
puede definir como la diferencia entre el precio aprobado por el usuario y el precio al cual la orden es
realmente ejecutada. Por lo general se especifica de 0 a 3 puntos. Este parmetro no es procesado para
las rdenes pendientes de ser ejecutadas.
stoploss es el precio de cierre requerido que determina la mxima prdida permitida para una operacin
determinada.
takeprofit es el precio de cierre requerido que determina la mxima ganancia para una operacin
determinada.
comment es el comentario de texto de la orden. La ltima parte del comentario puede ser modificado
por el servidor.
magic es el MagicNumber de la orden. Se puede utilizar como identificador de la orden definida por el
usuario. En algunos casos, es la nica informacin que ayuda a averiguar que una orden pertenece a
alguno de los programas abiertos. El parmetro est configurado por el usuario; su valor puede ser el
mismo o distinto del valor de este parmetro para otras rdenes.
expiration es la fecha en que expira la orden. Tan pronto como llegue este da, la orden en espera de ser
ejecutada se cerrar automticamente en el servidor. En algunos servidores comerciales, puede haber
una prohibicin para establecer la fecha de vencimiento para las rdenes en espera de ser ejecutadas. En
este caso, si se tratan de establecer un valor del parmetro distinto de cero, la solicitud sera rechazada.
arrow_color es el color de la flecha que marca la apertura en el grfico. Si este parmetro est ausente o
si su valor es CLR_NONE, no se muestra la flecha de la apertura.
En algunos servidores comerciales, puede haber un lmite establecido para el importe total de rdenes
abiertas y pendientes. Si se supera este lmite, cualquier peticin comercial que implica la apertura de
una orden de mercado o en espera ser rechazada por el servidor.
Ejemplo:
Colocaremos una orden de compra.
Para el caso del stop loss, vamos a colocar esta orden a una distancia de 15 puntos desde el precio de
cierre, en este caso el cierre sera una operacin de venta y por tanto la venta ira contra el precio bid.
Entonces: Bid 15*Point (recordar que Point es el tamao de 1 punto de la moneda cotizada, por eso 15
se debe multiplicar por Point).
Para el takeprofit vamos a colocar esta orden a una distancia de 15 puntos: Bid + 15*Point.
A continuacin se muestra el script ms simple destinado a la apertura de una orden de compra:
//--------------------------------------------------------------------
// simpleopen.mq4
//--------------------------------------------------------------------
int start() // Special function start()
{ // Opening BUY
OrderSend(Symbol(),OP_BUY,0.1,Ask,3,Bid-15*Point,Bid+15*Point);
return; // Exit start()
}
//--------------------------------------------------------------------
Esta orden se podra leer as: Enviar una Orden al smbolo de la ventana actual consistente en: Una
Operacin de Compra, con un volumen de 0,1 lotes, contra el precio Ask, con un slippage mximo
permitido de 3 puntos. Colocaremos el stop loss a una distancia de 15 puntos del precio Bid y el
TakeProfit tambin a 15 puntos del precio Bid.

ERRORES AL PROCESAR
Error 130 (rdenes de stops no validas)
Una propiedad muy importante de la Terminal de Usuario es que si se produce un error durante la
ejecucin de una solicitud, no se detiene la ejecucin del programa, mientras que la Terminal de Usuario
generar un cdigo de error que est a disposicin del programa a travs de la funcin GetLastError().
int GetLastError()
La funcin devuelve el cdigo del error que ha ocurrido recientemente, entonces el valor de la variable
especial Last_Error que almacena el cdigo del ltimo error no se pone a cero. Posteriormente, cuando
no haya error, GetLastError() devolver 0.
Varios errores pueden ocurrir durante la ejecucin de un programa; la funcin GetLastError() nos
permite obtener el valor del cdigo de solo uno de ellos, el del ltimo error. Esta es la razn por la que
en el momento en que necesitemos esta informacin se aconseja utilizar la funcin GetLastError()
inmediatamente despus de la lnea del programa en la que el error pueda ocurrir.
Supongamos que creamos un script para una orden de compra, pero en lugar de poner Symbol()
colocamos GBPUSD pero ejecutamos el script en el grfico de EUR/USD, por lo que se producir un
error que ser recogido por la funcin GetLastError().
//--------------------------------------------------------------------------
// confined.mq4
//--------------------------------------------------------------------------
int start() // Special function start
{ // Opening BUY
OrderSend("GBPUSD",OP_BUY,0.1,Ask,3,Bid-15*Point,Bid+15*Point);
Alert (GetLastError()); // Error message
return; // Exit start()
}
//--------------------------------------------------------------------------
El programa devolver una ventana donde se mostrar el nmero del error, en esta caso, 130. El cdigo
de error se puede buscar en los Apndices, en Cdigos de Error.
En este caso, se produjo el error 130 (rdenes de stops no validas). Esto significa que los valores
formales de los parmetros utilizados en la funcin OrderSend() no se ajusten a las limitaciones
especificadas en las limitaciones en la toma de rdenes. Tras una vista ms cercana, podemos ver la
razn por la que se produjo el error: los valores actuales de los precios de mercado de Bid y Ask se
toman de la ventana de smbolo en la que se ha asociado el script, es decir, de la ventana de EUR/USD.
Sin embargo, estos valores son utilizados para formar una solicitud de comercio de GBP/USD. Como
resultado de ello, en el precio actual de GBP/USD, Ask = 1.9655, el valor de TakeProfit para la reciente
orden abierta de mercado resulta ser igual a (para EUR/USD Bid = 1,2930) 1,2930 +15 * 0.0001 =
1.2945, que es considerablemente inferior al valor mnimo permitido, es decir, no es vlido.
Con el fin de corregir el error, se deben utilizar los valores correctos de los precios del smbolo. Se
pueden obtener estos valores utilizando la funcin MarketInfo().
El siguiente script abre rdenes de mercado de GBP/USD y puede ser lanzado en cualquier ventana de
smbolo:
//------------------------------------------------------------------------------
// improved.mq4
//------------------------------------------------------------------------------
int start() // Special function start
{
double bid =MarketInfo("GBPUSD",MODE_BID); // Request for the value of Bid
double ask =MarketInfo("GBPUSD",MODE_ASK); // Request for the value of Ask
double point =MarketInfo("GBPUSD",MODE_POINT); //Request for Point
// Opening BUY
OrderSend("GBPUSD",OP_BUY,0.1,ask,3,bid-15*point,bid+15*point);
Alert (GetLastError()); // Error message
return; // Exit start()
}
//------------------------------------------------------------------------------
Error 129. Precio no vlido
Este error se debe a un valor incorrecto en la cotizacin de los dos sentidos (two-way quote)
especificada en el precio de apertura.
Las rdenes de Compra de Mercado deben ser abiertas en los precios de Ask. Si, por error, se
especificar el precio de Bid en el script, aparecer el cdigo de error 129.
Error 134. No hay suficiente dinero para hacer un comercio
Un resultado similar (error 134) se obtendr, si no hay suficiente dinero en la cuenta donde se abre la
orden.
Se puede conocer la cantidad de dinero que se necesita para abrir una compra de 1 lote de cualquier
smbolo utilizando la funcin MarketInfo (nombre_del_simbolo, MODE_MARGINREQUIRED).
El tamao estndar de un lote puede variar para un mismo smbolo para distintos dealing centers.
Margen Libre (Free Margin)
En la codificacin, es muy importante tener en cuenta el principio de la libre formacin de activos.
Margen libre (de activos) Free Margin es la cantidad de dinero que est disponible para la creacin
rdenes.
Se pueden hacer clculos para saber si el capital actual es suficiente para la apertura de una orden. Se
puede utilizar la funcin AccountFreeMarginCheck () que devuelve el valor del margen libre que queda
despus de la apertura de una orden de mercado de una cierta cantidad de lotes en un determinado
smbolo. Si el valor devuelto es igual o superior a 0, hay suficiente dinero en la cuenta. Si es inferior a 0,
entonces la orden de este volumen para este smbolo no se puede abrir y el Terminal de Usuario
devolver el error 134.
Otros errores y Funcin MarketInfo()
Hay otras limitaciones relacionadas con la determinacin de valores de los parmetros de la funcin
OrderSend(). Estas son el mximo y mnimo paso en el incremento del precio de la orden, mximo y
mnimo valor del precio de la orden, etc.
El uso de la funcin MarketInfo() permite obtener informacin acerca de diversos smbolos que
aparecen en la ventana "Observacin del Mercado" de la Terminal de Usuario.
Funcin MarketInfo()
double MarketInfo(string symbol, int type)
symbol: el nombre de un smbolo;
type: el tipo de informacin que ser devuelta. Puede ser cualquier valor de los identificadores de
solicitud (vase Funcin MarketInfo Identifier).
Pueden ocurrir algunos errores debidos al servidor. Por ejemplo, en condiciones transitorias de precios,
su agente puede aumentar la distancia mnima que limita la colocacin de rdenes pendientes de ser
ejecutadas y rdenes stops. Despus, en un mercado en calma, el corredor puede reducir esta distancia
de nuevo. De este modo, los valores de algunos parmetros pueden cambiar en cualquier momento.
Para operar con el programa de una forma estable, con la mnima cantidad de solicitudes rechazadas, se
debe actualizar los parmetros del entorno de informacin utilizados por el programa usando las
funciones MarketInfo() y RefreshRates() antes de ejecutar la funcin OrderSend().
Ejemplo de un script simple que abre una orden de Compra con un costo del X% de margen libre, con
unos valores preestablecidos de rdenes de stop:
//-------------------------------------------------------------------------------
// openbuy.mq4
//-------------------------------------------------------------------------- 1
int start() // Funcin Especial start
{
int Dist_SL =10; // Preseleccin distancia StopLoss (puntos)
int Dist_TP =3; // Preseleccin distancia Take Profit (puntos)
double Prots=0.03; // Porcentaje de margen libre
string Symb=Symbol(); // Smbolo
//-------------------------------------------------------------------------- 2 --
while(true) // Ciclo para la orden de apertura openbuy
{
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL); // Distancia minima
// MODE_STOPLEVEL devuelve la
// distancia mnima a la cual puede
// colocarse el SL y el TP
double Min_Lot=MarketInfo(Symb,MODE_MINLOT); // Volumen mnimo permitido
double Step=MarketInfo(Symb,MODE_LOTSTEP); // Paso mnimo de cambio de lotes
double Free=AccountFreeMargin(); // Margen Libre
double One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED);// Costo por 1 lote (Garanta por lote)
// MODE_MARGINREQUIRED devuelve el margen
// requerido para abrir un lote

//------------- Clculo del volumen de la operacin ------------------------------ 3


double Lot=MathFloor(Free*Prots/One_Lot/Step)*Step; // Lotes
// MathFloor devuelve el siguiente menor valor sin decimales, del valor indicado en sus
// parmetros. Ej- si es 13,5 devolver 13 y si es -13,5 devolver -14.
if (Lot<Min_Lot) // Si el n de lotes es menor que el permitido
{
Alert(" No hay suficiente dinero para ", Min_Lot," lotes");
break; // Salir del ciclo
}
//----------------- Clculo del Stop Loss -------------------- 4 --
if (Dist_SL<Min_Dist) // Si la distancia del Stop es menor que la permitida
{
Dist_SL=Min_Dist; // Poner la distancia permitida
Alert(" Incremento de la distancia del SL = ",Dist_SL," puntos.");
}
double SL=Bid - Dist_SL*Point; // Requerimiento del precio del SL
//-------------------Clculo del Stop Take Profit ------------------ 5 --
if (Dist_TP<Min_Dist) // Si la distancia del Stop es menor que la permitida
{
Dist_TP=Min_Dist; // Poner la distancia permitida
Alert("Incremento de la distancia del TP = ",Dist_TP," puntos.");
}
double TP=Bid + Dist_TP*Point; // Requerimiento del precio de TP
//---------------------Solicitud de Compra ------------------------------ 6 --
Alert("La solicitud fue enviada al servidor. Esperando respuesta...");
int ticket=OrderSend(Symb, OP_BUY, Lot, Ask, 2, SL, TP);
//-------------------Notificacin ejecucin de orden------------------ 7 --
if (ticket>0) // Orden en Mercado!
{
Alert ("N de Orden de Compra Abierta: ",ticket);
break; // Salir del ciclo
}
//-----------------------Procesamiento de Errores------------------- 8 --
int Error=GetLastError(); // Orden Fallida! :(
switch (Error) // Procesamiento de errores
{
case 129:Alert("Precio no vlido. Reintentando...");
RefreshRates(); // Actualizando datos del entorno
continue; // A la prxima iteracin
case 135:Alert("El precio ha cambiado. Reintentarlo de nuevo");
RefreshRates(); // Actualizar datos del entorno
continue; // Realizar nueva iteracin
case 136:Alert("No hay precio. Esperar a un nuevo tick");
while(RefreshRates()==false) // Mientras no haya un nuevo tick
Sleep(1); // Ciclo de espera
continue; // Como ya hay nuevo tick realizar nueva iteracin
case 146:Alert("el subsistema de trading est ocupado, reintentarlo..");
Sleep(500); // Solucin simple: dormir durante 500 msg.
RefreshRates(); // Actualizar datos del entorno y
continue; // realizar una nueva iteracin
}
switch(Error) // Errores crticos
{
case 2 : Alert ("Error comn.");
break; // Salir de 'switch'
case 5 : Alert ("Terminal de usuario obsoleta.");
break; // Salir de 'switch'
case 64: Alert ("The account is blocked.");
break; // Salir de 'switch'
case 133:Alert ("Trading forbidden");
break; // Salir de 'switch'
default: Alert ("Occurred error ",Error); // Otras Alternativas
}
break; // Salida del ciclo
}
//-------------------------------------------------------------------------- 9 --
Alert ("The script has completed its operations ------------------------");
return; // Exit start()
}
//-------------------------------------------------------------------------- 10 --
El script se compone de una funcin especial start() (bloques 1-10).
En el bloque 1-2, se fijan los valores a los que la orden debe ser abierta.
El bloque 2-9 representa el ciclo while(), en el que se realizan todos los clculos necesarios. Este ciclo
est incluido en el cdigo para permitir que el programa haga varios intentos para abrir una orden.
En el bloque 2-3 se actualizan las variables del entorno.
En los bloques 3-4-5-6, se calcula el importe de los lotes y los precios de las rdenes de stop. En el
bloque de 7-8-9, se procesan los errores. En el bloque 9-10, se escribe un mensaje informando que el
script ha terminado sus operaciones.
Vamos a considerar algunas caractersticas especiales del cdigo del programa. Es fcil ver que la
solicitud de compra se forma en el bloque 6-7. En el bloque 3-4, se calcula el importe de los lotes.
Asimismo, se considera la situacin en el que la disposicin del margen libre es insuficiente para abrir
incluso una orden con una cantidad mnima de lotes. Es por ello que, en el bloque 3-4, despus de
imprimir el mensaje sobre la insuficiencia de dinero, se sale del ciclo 2-9 (while) utilizando el operador
"break".
El control se pasa al bloque 9-10, y el script completa sus operaciones. El mensaje en la casilla 9 es
innecesario. Se da aqu slo para informar a los usuarios cundo es el final de las operaciones del
programa y cundo la pausa es provocada por los retrasos en la red o en el servidor.
Si el margen libre es suficiente para la apertura de la orden, el control pasa al bloque de 4-5 y luego al
bloque 5-6. En estos bloques, no hay salida ciclo. Esto significa que, para cualquier distancia mnima
fijada por el corredor, habr stops en los niveles correspondientes. La mayora de los corredores
establecen la distancia mnima en 5 puntos. En el bloque 5-6, el programa descubrir que el valor
preestablecido es inferior al permitido. El programa pondr un valor de precio tal para la orden stop que
no estar en contradiccin con la limitacin.
Entonces el control se pasa al bloque de 6-7 para abrir la orden. En la primera lnea de este bloque, se
imprime un mensaje. La solicitud de comercio est formada solamente en la segunda lnea.
Tarde o temprano, la Terminal de Usuario pasar el control al programa, en el bloque de 6-7 se ejecutar
el operador de asignacin que dar lugar a que la variable 'ticket' tome un valor, el control se pasar
hacia adelante, y si hay un error se analizar en los bloques 7-8-9.
Si la orden se abre en el servidor, a la variable ticket le ser asignado un nmero que corresponde a la
apertura de la orden. Si ocurre esto, significa que el script ha cumplido su tarea y no hay necesidad de
que el programa contine las operaciones. En el bloque 7-8, usamos el operador break para salir del
ciclo while ().
El control se pasa al bloque 9-10 (fuera del ciclo), y el programa termina sus operaciones.
Sin embargo, si el intento de abrir una orden falla, el control se pasa al bloque 8-9 para el anlisis del
error.
En este caso se consideran dos tipos de errores: los que an permiten tener esperanza de tener xito en la
apertura de la orden y aquellos errores cuya aparicin significa la finalizacin inequvoca de la ejecucin
del programa. A la variable 'Error' se le asigna el cdigo del ltimo error, en este caso, es el error que ha
sido devuelto por el servidor o la Terminal de Usuario en la ejecucin de la funcin OrderSend().
En el primer operador 'switch' del bloque de 8-9, se consideran los errores superables. Cada error de este
grupo se procesa de manera diferente. Por ejemplo, si el precio ha cambiado (error 135), es suficiente
actualizar solamente los parmetros ambientales utilizando la funcin RefreshRates() y repetir el intento
de apertura de una orden. Si se produce el error 136, "No hay precios", no tiene sentido volver a enviar
la solicitud al servidor de comercio. En este caso, debemos esperar a un nuevo tick (debido a que no hay
precios en el servidor en ese momento) y, slo despus de esto, se intenta abrir nuevamente la orden. Por
eso hay un ciclo de espera en el bloque que procesa el error 136. Este ciclo de espera se interrumpe
cuando entra un nuevo tick. La salida del operador de switch() usa el operador 'continue' que rompe
la actual iteracin del ciclo while() y comienza una nueva.
Los errores crticos se procesan de otra manera. Si tal error se produce, el programa informa al usuario
sobre ello y se pone fin a las operaciones. Para ello, se utiliza el operador break (el ltimo, en el
bloque 8-9) que rompe el ciclo de while (), lo que da lugar a la finalizacin del programa.
Debemos tener en cuenta, que en este ejemplo en particular, el diseo no considera todos los errores
existentes. En este caso, no estamos proporcionando al usuario un programa listo para su uso. Es muy
importante que el propio programador analice otros errores de forma independiente y decida qu otros
errores y de qu manera deben ser tratados en el programa. Al mismo tiempo, algunos errores no deben
ser procesados, porque el programa est construido de tal manera que no considera la existencia de
algunos de ellos, por ejemplo, en este caso, los errores 129 y 130.
En el ejemplo anterior, hay un pequeo error algortmico que no puede ser encontrado en la compilacin
ni tampoco en el Terminal de Usuario, ni en el servidor. Por eso, tome con pinzas cualquier cdigo de
programa.
Tngase en cuenta el cdigo en el bloque 4-5:
//----------------- Clculo del Stop Loss -------------------- 4 --
if (Dist_SL < Min_Dist) // Si la distancia del Stop es menor que la permitida
{
Dist_SL=Min_Dist; // Poner la distancia permitida
Alert(" Incremento de la distancia del SL = ",Dist_SL," pt.");
}
double SL=Bid - Dist_SL*Point; // Requerimiento del precio del SL
//--------------------------------------------------------------- 5 --
Como resultado de los clculos en el cuerpo del operador if (), la variable Dist_SL puede tomar un
nuevo valor. Supongamos una distancia normal mnima de 5 puntos. Supongamos que en la primera
ejecucin (en un mercado rpido), este valor se establece en 20 puntos en el servidor. La variable
Min_Dist tendr el valor de 20.
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// Minimum distance
Supongamos entonces que la operacin formada por la solicitud ha sido rechazada debido a un error 136
(No hay precios), El programa entonces esperar un nuevo tick en el bloque 8-9. Dentro de este perodo
de tiempo, el valor de la distancia mnima puede cambiar en el servidor, por ejemplo, disminuir a 10
puntos. En el momento en que un nuevo tick llegue, el control pasar al nuevo ciclo, y el nuevo valor de
la variable Min_Dist, igual a 10, se calcular. Sin embargo, el valor de la variable Dist_SL sigue siendo
la misma e igual a 20 (el bloque 4-5 se codifica de tal manera que el valor de Dist_SL slo puede
aumentar). Con el fin de excluir este error algortmico, se debe escribir el bloque 4-5 de tal manera que
cambie slo el valor que depende de esa situacin (en este caso, es el valor del SL), mientras que el
valor de Dist_SL no cambiar. Podemos escribirlo, por ejemplo, de esta manera:
//------------------------------------------------------------------------- 4 --
double SL = Bid - Dist_SL*Point; // Requested price of SL
if (Dist_SL<Min_Dist) // If it is less than allowed
{
SL = Bid - Min_Dist*Point; // Requested price of SL
Alert(" Increased the distance of SL = ",Min_Dist," pt");
}
//------------------------------------------------------------------------- 5 --
Un cambio similar debe hacerse en bloque de 5-6 para el TP.
Colocacin de rdenes en espera de ser ejecutadas
No hay ninguna diferencia fundamental en la programacin entre la colocacin de rdenes pendientes de
ser ejecutadas y colocacin de rdenes de mercado.
Se debera tomar nota del hecho de que ni el Terminal de Usuario ni el servidor verifican si hay
suficientes activos como para modificar una orden de espera a una entrada en de mercado. Se puede
colocar una orden pendiente para una cantidad que sobrepase muchas veces la cantidad de dinero
disponible. Esta orden podr mantenerse durante mucho tiempo, pero cuando el precio de mercado
alcance el nivel del precio solicitado para la apertura de la orden en espera, el servidor har un control
sobre el precio y si en ese momento hay suficiente dinero en la cuenta para la apertura de esta orden,
esta ser modificada en una orden de mercado (apertura), y si no, la orden ser eliminada.
Limitaciones razonables
Por ejemplo, el error 146 se produce solamente si varios programas que forman solicitudes de comercio
trabajan en un mismo smbolo de una ventana. En nuestra opinin, esta prctica es permitida, pero no es
aconsejable.
Cierre de rdenes de mercado
Las solicitudes de Comercio de rdenes de cierre de mercado se forman utilizando la funcin
OrderClose ().
Funcin OrderClose ()
bool OrderClose (int ticket, double lots, double price, int slippage, color Color=CLR_NONE)
Se trata de una funcin utilizada para cerrar una orden de mercado. La funcin devuelve TRUE, si la
orden de comercio se ha realizado con xito. Devuelve FALSE, si no se ha cerrado.
ticket - el nmero nico de la orden que se desea cerrar.
lots - la cantidad de lotes a ser cerrados. Se permite especificar un valor inferior a la cantidad disponible
de los lotes que se presentan en la orden. En este caso, si la solicitud se ejecuta con xito, la orden ser
cerrada parcialmente.
Con el fin de decidir sobre qu rdenes y en qu secuencia deben cerrarse, se deben tener datos de todas
las rdenes abiertas en la situacin actual. Hay una serie de funciones que pueden ser utilizadas para
obtener diversos datos que caracterizan a cualquier orden.
Por ejemplo, la funcin OrderOpenPrice() devuelve el valor del precio de apertura de la orden (o del
precio solicitado para la espera de las rdenes), la funcin OrderLots () devuelve la cantidad de lotes, la
funcin OrderType() devuelve el tipo de la orden, etc.
Funcin OrderSelect()
Con el fin de obtener los parmetros de cualquier orden (ya sean rdenes de mercado o pendientes,
cerradas o eliminadas), primero se debe seleccionar la misma utilizando la funcin OrderSelect().
bool OrderSelect(int index, int select, int pool=MODE_TRADES)
OrderSelect es una funcin que selecciona una orden para hacer operaciones con ella. Devuelve TRUE,
si la funcin se ejecuta con xito. De lo contrario, devuelve FALSE.
Parmetros
index - Para la posicin (nmero de orden en la lista) o el nmero de ticket, depende del segundo
parmetro.
select flag (bandera) de seleccin de mtodo. El parmetro 'select' puede tomar uno de dos posibles
valores:
SELECT_BY_POS - en el parmetro 'ndex', devuelve el nmero de orden en la lista (la
numeracin empieza por 0),
SELECT_BY_TICKET - en el parmetro 'ndex', devuelve el nmero de ticket (el nmero de
orden nico).
pool - la fuente de datos para la seleccin. El parmetro pool se utiliza, cuando el parmetro 'select' es
igual al valor de SELECT_BY_POS. El parmetro 'pool' se ignora, si la orden es seleccionada por el
nmero de ticket (SELECT_BY_TICKET). El parmetro 'pool' puede tener dos valores posibles:
MODE_TRADES (por defecto) - la orden se selecciona entre las rdenes abiertas y las rdenes
pendientes, es decir, entre las rdenes que aparecen en la pestaa "Operaciones" de la ventana
"Terminal".
MODE_HISTORY la orden se selecciona entre las rdenes cerradas y eliminadas, es decir, entre
las rdenes que aparecen en la en la pestaa "Historial de Cuentas" de la ventana "Terminal". En
este caso es importante la profundidad de la historia especificada por el usuario para mostrar
rdenes cerradas y eliminadas.
Problema 25. Escribir un script que cierre una de las rdenes de mercado disponibles en la
cuenta. La ejecucin de scripts debe dar como resultado el cierre de la orden ms cercana a la ubicacin
de la script vinculada con el ratn a la ventana de smbolo.
Supongamos que hay tres rdenes de mercado abiertas en la terminal para el smbolo euro/dlar y una
orden en espera de ser ejecutada para USD/CHF:

Debemos escribir un script que se pueda arrastrar con el ratn de la ventana del Explorador a la
ventana de smbolo. La ejecucin de dicho script debe dar como resultado el cierre de la orden (marcada
por una lnea discontinua y el nmero de ticket) que se encuentre ms cercana al cursor cuando el
usuario haya liberado el botn del ratn. En la prxima imagen, se puede ver que el cursor se encuentra
ms prximo a la orden de venta 4372889. Esta ser la orden que deber ser cerrada como consecuencia
de la ejecucin del scripts.
Para resolver este problema, hay que seleccionar (usando la funcin OrderSymbol()) una entre todas las
rdenes abiertas en la ventana de smbolo.
Entonces tenemos que encontrar los precios de apertura de todas las rdenes de mercado seleccionadas
(es decir, ejecutar la funcin OrderOpenPrice () sucesivamente para cada orden).
Conociendo los precios de apertura de las rdenes, podemos fcilmente seleccionar una que corresponda
a la declaracin del problema.
Para especificar los valores apropiados de los parmetros de la funcin OrderClose (), tambin se
necesitan conocer algunos otros datos acerca de la orden seleccionada: la cantidad de lotes (determinada
por la funcin OrderLots ()) y el nmero nico de orden (determinado por la funcin OrderTicket ()).
Por otra parte, para encontrar uno u otro precio del two-way quote (cotizacin de doble va), tenemos
que saber el tipo de orden (determinado por la funcin OrderType ()).
Consideremos qu parmetros deben ser especificados en la funcin OrderSelect ():
En primer lugar, es necesario elegir el mtodo de seleccin de la orden. Segn el enunciado del
problema, tenemos que utilizar el parmetro SELECT_BY_POS, que selecciona la orden ms cercana al
lugar donde se solt el script en el grfico.
Solo estamos interesados en las rdenes abiertas y en espera, no en las cerradas, por lo que buscaremos
en ellas utilizando el parmetro MODE_TRADES en la funcin OrderSelect ().
Para el parmetro 'pool', utilizaremos el valor por defecto MODE_TRADES, por lo que puede saltarse.
for (int i=1; i<=OrdersTotal(); i++) //Ciclo para todas las rdenes...
{ // mostradas en el terminal
if(OrderSelect(i-1,SELECT_BY_POS)==true) // Si es la prxima orden seleccionada
{
// Caractersticas de la orden...
// ... debe ser analizada aqu
}
} //Fin del cuerpo del ciclo
En la cabecera del operador de ciclo, el valor inicial se especifica como i = 1, mientras que la condicin
para salir del ciclo es la expresin i <= OrdersTotal(). La funcin OrdersTotal() devuelve la cantidad
total de rdenes en mercado y rdenes pendientes de ser ejecutadas. Por eso habr tantas iteraciones en
el ciclo, como cantidad de rdenes participantes en el trading.
En cada iteracin, cuando en el operador `if' se calcula la condicin, la funcin OrderSelect (i-1,
SELECT_BY_POS) se llevar a cabo. Hay que sealar aqu la siguiente importante cuestin:
La numeracin de los rdenes en la lista de rdenes de mercado y rdenes en espera de ser
ejecutadas comienza con cero.
Esto significa que la primera orden de la lista de la penltima imagen anterior, est localizada en la
posicin cero, la segunda orden est localizada en la posicin 1, etc. Es por eso que en la llamada a la
funcin OrderSelect(), el valor del ndice se da como i-1.
La funcin OrderSelect() devuelve true, si la orden se ha seleccionado con xito. Esto significa que es
posible que la seleccin de una orden pueda fracasar. Esto puede suceder, si la cantidad de rdenes
cambia durante su tramitacin.
El programa analiza en la cabecera del operador `if' si la prxima orden en la lista de rdenes est
disponible en el momento en que se selecciona. Si la prxima orden est disponible, el control pasa al
cuerpo del operador `if' para el procesamiento de los parmetros de la orden. En el cuerpo del operador
`if', se analizan los parmetros del objeto seleccionado. Al ejecutar las funciones OrderOpenPrice(),
OrderTicket(), OrderType() y otras del mismo estilo, cada una de ellas devolver el valor de una cierta
caracterstica de la orden seleccionada como resultado de la ejecucin de la funcin OrderSelect().
Solucin al problema 25:
//-----------------------------------------------------------------------------------
// closeorder.mq4
//------------------------------------------------------------------------------ 1 --
int start() // Funcin especial 'start'
{
string Symb=Symbol(); // Variable de cadena que contiene el smbolo
double Dist=1000000.0; // Preseleccin de la distancia inicial
int Real_Order=-1; // Todava no hay rdenes de mercado
double Win_Price=WindowPriceOnDropped(); // WindowPriceOnDropped() devuelve el precio en el
// cual se ha soltado el script en el grfico, utilizando el
// mouse
//----------------------------------------------------------------------------- 2 --
for(int i=1; i<=OrdersTotal(); i++) // Ciclo de bsqueda de ordenes
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // Si la prxima orden est disponible
{ // Anlisis de la orden:
//----------------------------------------------------------------------- 3 --
if (OrderSymbol()!=Symb) continue; // Si no es nuestro smbolo
int Tip=OrderType(); // Tipo de orden (*)
if (Tip>1) continue; // Si la orden es pendiente interrumpe la iteracin
//----------------------------------------------------------------------- 4 --
double Price=OrderOpenPrice(); // Precio de apertura de la orden
if (NormalizeDouble(MathAbs(Price-Win_Price),Digits)< // Seleccin de la orden ms cercana
NormalizeDouble(Dist,Digits)) // Nota: Digits devuelve el nmero de
// dgitos despus del punto decimal
// para el smbolo actual
{
Dist=MathAbs(Price-Win_Price); // Nuevo valor de la distancia (la ms corta)
Real_Order=Tip; // orden a mercado disponible
int Ticket=OrderTicket(); // N de ticket de la orden seleccionada
double Lot=OrderLots(); // Cantidad de lotes de la orden a cerrar
}
//--------------------------------------------------------------------- 5 --
} //Final del anlisis de la orden
} //Final de la bsqueda de la orden
//----------------------------------------------------------------------------- 6 --
while(true) // Ciclo para el cierre de la orden
{
if (Real_Order==-1) // Si no hay rdenes a mercado disponibles
{
Alert("For ",Symb," no hay rdenes de Mercado disponibles");
break; // salida del ciclo de cierre while
}
//------------------------------------------------------------------------ 7 --
switch(Real_Order) // Seleccin por el tipo de orden
{
case 0: double Price_Cls=Bid; // Orden de compra
string Text="Compra "; // Texto para compra
break; // Salir de switch
case 1: Price_Cls=Ask; // Orden de venta
Text="Sell "; // Texto para venta
}
Alert("Intentando el cierre ",Text," ",Ticket,". Esperando respuesta...");
bool Ans=OrderClose(Ticket,Lot,Price_Cls,2); // Orden de cierre
//------------------------------------------------------------------------ 8 --
if (Ans==true) // Orden ejecutada! :)
{
Alert ("Orden cerrada ",Text," ",Ticket);
break; // Salida del ciclo de cierre
}
//------------------------------------------------------------------------ 9 --
int Error=GetLastError(); // Fallo :(
switch(Error) // Errores superables
{
case 135:Alert("El precio ha sido cambiado. Reintentando...");
RefreshRates(); // Actualizacin de datos
continue; // Saltar a la prxima iteracin de ciclo de bsqueda
case 136:Alert("No hay precio. Esperando un nuevo tick...");
while(RefreshRates()==false) // Mientras no haya Nuevo tick
Sleep(1); // dormir (pausa 1 msg.)
continue; // Con nuevo tick saltar a la prxima
// iteracin del ciclo de bsqueda
case 146:Alert("Sistema de Trading ocupado. Reintentando...");
Sleep(500); // Solucin simple. Pausa 0,5 sg.
RefreshRates(); // Actualizacin datos de entorno
continue; // A la prxima iteracin del ciclo de bsqueda
}
switch(Error) // Errores crticos
{
case 2 : Alert("Common error.");
break; // Salir de 'switch'
case 5 : Alert("Versin antigua del terminal de usuario.");
break; // Salir de 'switch'
case 64: Alert("La cuenta est bloqueada.");
break; // Salir de 'switch'
case 133:Alert("Trading no permitido");
break; // Salir de 'switch'
default: Alert("Ha habido un error ",Error);//Otras alternativas
}
break; // Salir del ciclo de cierre
}
//---------------------------------------------------------------------------- 10 --
Alert ("El script ha finalizado las operaciones -----------------------------");
return; // Salida de start()
}
//---------------------------------------------------------------------------- 11 --
Todo el cdigo se concentra en la funcin especial start(). En el bloque 1-2, se inicializan algunas
variables.
La variable Dist es la distancia desde el lugar en donde se ha soltado el script hasta la orden ms
cercana.
La variable Real_Order es una bandera que muestra la disponibilidad de al menos una orden de mercado
en la Terminal de Usuario (valor no negativo).
La variable Win_Price es el precio en el cual el usuario ha soltado el script en la ventana del smbolo.
Luego es necesario encontrar la orden (con sus caractersticas) que esta ms cerca de esta ubicacin.
Las rdenes se buscan dentro del ciclo `for' (bloque 2-6). En el bloque 2-3, el programa comprueba si
hay una orden en la lnea siguiente de la "Terminal". Si se encuentra una orden, el control se pasa al
cuerpo del operador `if' para obtener y analizar las caractersticas de esa orden.
En el bloque 3-4, las rdenes abiertas en el smbolo equivocado (no el smbolo, para el cual el programa
est siendo ejecutando) son filtradas fuera. En nuestro caso, es la orden 4372930 abierta para el
USD/CHF. La Funcin OrderSymbol () devuelve el nombre del smbolo de la orden seleccionada. Si
este nombre del smbolo es distinto, para el que el programa se est ejecutando, la iteracin actual se
interrumpe (continue), para evitar que la orden sea ejecutada para otro smbolo distinto desde el que
est siendo procesado. Nota: el operador continue se utiliza poner fin a la iteracin actual y pasar a la
siguiente sin ejecutar el resto de los operadores que componen el cuerpo del bucle.
Si la orden bajo anlisis corresponda a "nuestro" smbolo, un nuevo chequeo se llevar a cabo. El tipo
de orden se determina utilizando la funcin OrderType (). Si el tipo de orden es mayor que 1, significa
que es una orden pendiente. En este caso, la actual iteracin tambin se interrumpe (continue), porque
no estamos interesados en las rdenes en espera. Todas las rdenes que pasan el bloque de 3-4 con xito
son rdenes de mercado.
(*) OrderType()
Constante Valor Transaccin comercial
OP_BUY 0 Compra
OP_SELL 1 Venta
OP_BUYLIMIT 2 Orden Buy Limit
OP_SELLLIMIT 3 Orden Sell Limit
OP_BUYSTOP 4 Orden Buy Stop
OP_SELLSTOP 5 Orden Sell Stop

El bloque 4-5 se destina para la seleccin de una nica orden de mercado de entre todas las rdenes que
han pasado con xito el bloque anterior. Esta orden debe ser la ms cercana al precio predefinido (el
valor de la variable Win_Price). El usuario no est obligado a "localizar" con su ratn la lnea de la
orden de forma exacta.
La orden seleccionada ser la que, de entre las dems rdenes, est ms cerca del cursor desde del
momento de poner en marcha el script para su ejecucin. El precio de apertura de la orden procesada se
encuentra utilizando la funcin OrderOpenPrice (). Si el valor absoluto de la distancia entre el precio de
la orden actual y el "cursor de precios" es inferior a la misma distancia de la orden anterior, la orden
actual ser seleccionada.
Es necesario usar el valor absoluto de la distancia para que no importe si la posicin del cursor est por
debajo o por encima de la lnea indicadora de la orden. De este modo solo se considera la distancia y no
su signo. La orden seleccionada ser memorizada en la iteracin actual del ciclo `for' como la pionera
para ser cerrada. Para este fin, al final del bloque 4-5, se calcula el nmero de ticket (el nmero
individual de la orden) y la cantidad de lotes. En el ejemplo, la cantidad total de los rdenes es cuatro
(tres de mercado y una orden en espera), por lo que habr cuatro repeticiones ejecutadas en el ciclo `for'.
A continuacin, el control en la ejecucin del programa se pasa al operador de ciclo `while' (bloque 6-
10). En el bloque 6-7, las rdenes de mercado encuentran un control de disponibilidad. Si no se
encuentran rdenes de mercado en el bloque 2-4 (es muy posible en general), el valor de la bandera
Real_Order sigue siendo igual a -1, lo que significar falta de rdenes de mercado. Si el control en el
bloque 6-7 no detecta rdenes de mercado, la ejecucin del ciclo `while' se rompe y entonces el
programa pone fin a sus operaciones. Si el valor de la variable Real_Order resulta ser igual a 0 o 1, esto
significa que un mercado est predefinido para el cierre y debe cerrarse.
En el bloque de 7-8, de acuerdo al tipo de orden, se calcula el precio de cierre de la orden. Es el valor del
Bid para las rdenes de compra, y el valor de Ask para las rdenes de venta.
En el bloque de 7-8, se calculan los valores de la variable auxiliar Texto. La solicitud de la orden de
cierre de comercio se forma en la funcin OrderClose () en la lnea siguiente:
bool Ans=OrderClose(Ticket,Lot,Price_Cls,2); // Orden de cierre
La funcin de comercio OrderClose () devuelve true, si la transaccin se realiza con xito, y falso, si no
es as.
Si la solicitud es ejecutada exitosamente en el servidor, el valor true se asignar a la variable Ans
(respuesta). En este caso, al ejecutar bloque 8-9, el programa informar al usuario sobre el xito de la
orden de cierre. Despus de eso, la ejecucin del operador de ciclo 'while' se detendr, y el programa
pondr fin a sus operaciones. De lo contrario, el control pasa al bloque de 9-10 con el fin de analizar los
errores devueltos por el Terminal de Usuario al programa.
Eliminar rdenes en espera de ser ejecutadas
Las solicitudes de comercio para eliminacin de rdenes pendientes se forman utilizando la funcin
OrderDelete ().
Funcin OrderDelete
bool OrderDelete(int ticket, color arrow_color=CLR_NONE)
Es fcil ver que la funcin OrderDelete() no contiene una especificacin del volumen y el precio de
cierre de la orden a ser eliminada.
La supresin parcial de una orden no es posible. Puede disminuir la cantidad de lotes de una orden a la
espera en dos etapas: suprimir la orden existente y, a continuacin, colocar una nueva orden pendiente
con la cantidad de lotes disminuida.
Un ejemplo de un script simple destinado a la supresin de una orden pendiente. El precio de la solicitud
es el que est ms cerca de la ubicacin de donde se solt el script.
//-------------------------------------------------------------------------------------
// deleteorder.mq4
//-------------------------------------------------------------------------------- 1 --
int start() // Funcion especial 'start'
{
string Symb=Symbol(); // Simbolo
double Dist=1000000.0; // Preseleccin distancia inicial
int Limit_Stop=-1; // Todava no hay rdenes pendientes
double Win_Price=WindowPriceOnDropped(); // El script se ha soltado a este precio
//-------------------------------------------------------------------------------- 2 --
for(int i=1; i<=OrdersTotal(); i++) // Ciclo de bsqueda de rdenes
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // Si la prxima rden esta disponible
{ // Analisis de la orden disponible:
//----------------------------------------------------------------------- 3 --
if (OrderSymbol()!= Symb) continue; // El smbolo no es el nuestro
int Tip=OrderType(); // Tipo de orden
if (Tip<2) continue; // (*)Si no es una orden pendiente, nueva
// iteracin del ciclo de bsqueda de rdenes
//----------------------------------------------------------------------- 4 --
double Price=OrderOpenPrice(); // Precio orden de apertura de orden seleccion.
if (NormalizeDouble(MathAbs(Price-Win_Price),Digits)< //Seleccin de la orden si
NormalizeDouble(Dist,Digits)) // la distancia menor que la orden anterior
{
Dist=MathAbs(Price-Win_Price); // Nuevo valor de la distancia mnima
Limit_Stop=Tip; // Orden pendiente disponible
int Ticket=OrderTicket(); // N de ticket de la orden
} // Fin de 'if'
} // Fin del analisis de rdenes
} // Fin de la bsqueda de rdenes
//-------------------------------------------------------------------------------- 5 --
switch(Limit_Stop) // Por tipo de orden (*)
{
case 2: string Text= "BuyLimit "; // Texto para BuyLimit
break; // Salir de 'switch'
case 3: Text= "SellLimit "; // Texto para SellLimit
break; // Salir de 'switch'
case 4: Text= "BuyStopt "; // Texto para BuyStopt
break; // Salir de 'switch'
case 5: Text= "SellStop "; // Texto para SellStop
break; // Salir de 'switch'
}
//-------------------------------------------------------------------------------- 6 --
while(true) // Ciclo para orden de cierre
{
if (Limit_Stop==-1) // Si no hay rdenes pendientes disponibles
{
Alert("For ",Symb," No hay rdenes pendientes disponibles");
break; // Salida del ciclo de cierre
}
//-------------------------------------------------------------------------- 7 --
Alert("Intentando suprimir la orden ",Text," ",Ticket,". Esperando respuesta...");
bool Ans=OrderDelete(Ticket); // Supresin de la orden
//-------------------------------------------------------------------------- 8 --
if (Ans==true) // Conseguido! :)
{
Alert ("Orden suprimida: ",Text, Ticket: " ,Ticket);
break; // Salida del ciclo de cierre
}
//-------------------------------------------------------------------------- 9 --
int Error=GetLastError(); // Fallo :(
switch(Error) // Errores superables
{
case 4: Alert("El servidor de trades est ocupado. Reintentar...");
Sleep(3000); // Solucin simple
continue; // A la prxima iteracin
case 137:Alert("El broker est ocupado. Reintentar...");
Sleep(3000); // Solucin simple
continue; // A la prxima iteracin
case 146:Alert("El subsistema de Trading est ocupado. Reintentando...");
Sleep(500); // Solucin simple
continue; // A la prxima iteracin
}
switch(Error) // Critical errors
{
case 2 : Alert("Error comn.");
break; // Salida 'switch'
case 64: Alert(Cuenta bloqueda.");
break; // Salida 'switch'
case 133:Alert("Trading est prohbido");
break; // Salida 'switch'
case 139:Alert("La orden est bloqueada y est siendo procesada");
break; // Salida 'switch'
case 145:Alert("La modificicacin est prohbida. ",
"La orden est demasiado cerca del mercado");
break; // Salida 'switch'
default: Alert("Ha ocurrido el error ",Error); // Otros errores
}
break; // Salida del ciclo de cierre
}
//------------------------------------------------------------------------------- 10 --
Alert ("El stript ha finalizado las operaciones -----------------------------");
return; // salida de start()
}
//------------------------------------------------------------------------------- 11 --
El error de procesamiento de bloque se ha modificado ligeramente. Cuando se cierran rdenes
pendientes no existe la posibilidad de errores relacionados con cambios en los precios (errores 135 y
136). Por la misma razn, la funcin RefreshRates() no se utiliza en ninguna parte del programa.

Cierre de rdenes opuestas


Si se tienen dos rdenes enfrentadas en un determinado smbolo, se pueden cerrar al mismo tiempo una
y otra, utilizando la funcin OrderCloseBy (). Si se realiza una operacin de ese tipo se ahorra el spread
de una de las dos rdenes.
Este tema es tratado en el libro, pero no lo resum por carecer de inters prctico para mis objetivos.

Modificacin de rdenes - Funcin OrderModify()


Modificacin de rdenes de Mercado
Las solicitudes de operaciones para modificacin de rdenes pendientes y stops de rdenes de mercado
se forman utilizando la funcin OrderModify().
bool OrderModify(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color
arrow_color=CLR_NONE)
La funcin OrderModify () ampla considerablemente la capacidad de modificacin: Los precios de
ambas rdenes de stops puede ser modificadas en la direccin del precio de mercado o suprimirse. Una
limitacin de la modificacin de rdenes de mercado es la distancia mnima permitida entre la orden de
stop y el precio de mercado fijado por el dealing center. Si el programa intenta cambiar la posicin de
una orden de stop de tal forma que se coloque ms cerca del precio de mercado que la distancia mnima
permitida, esa solicitud de comercio ser rechazada por la Terminal de Usuario y la ejecucin de la
funcin OrderModify () fallar (error 130). Esta es la razn por la que se debe proporcionar un bloque
especial en el programa, que tendr en cuenta esta limitacin.
Ejemplo de un Asesor Experto sencillo que modifica el StopLoss de todas las rdenes de mercado, para
las cuales la distancia entre el precio solicitado de StopLoss y el precio del mercado es ms grande que
la orden preestablecida.
//------------------------------------------------------------------------------------
// modifystoploss.mq4
//------------------------------------------------------------------------------------
extern int Tral_Stop=10; // Trailing distance
//------------------------------------------------------------------------------- 1 --
int start() // Special function 'start'
{
string Symb=Symbol(); // Symbol
//------------------------------------------------------------------------------- 2 --
for(int i=1; i<=OrdersTotal(); i++) // Cycle searching in orders
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If the next is available
{ // Analysis of orders:
int Tip=OrderType(); // Order type
if(OrderSymbol()!=Symb||Tip>1)continue; //The order is not "ours". Recordar que ||
significa O
double SL=OrderStopLoss(); // Returns stop loss value for the currently
selected order
//---------------------------------------------------------------------- 3 --
while(true) // Modification cycle
{
double TS=Tral_Stop; // Initial value. (Nota: Al parecer Tral_Stop es el valor del Trailing Stop de la
orden actual)
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL); // The minimal distance of stop levels is obtained
if (TS < Min_Dist) // If less than allowed
TS=Min_Dist; // New value of TS
//------------------------------------------------------------------- 4 --
bool Modify=false; // Not to be modified
switch(Tip) // By order type
{
case 0 : // Order Buy
if (NormalizeDouble(SL,Digits)< // If it is lower than we want
NormalizeDouble(Bid-TS*Point,Digits))
{
SL=Bid-TS*Point; // then modify it
string Text="Buy "; // Text for Buy
Modify=true; // To be modified
}
break; // Exit 'switch'
case 1 : // Order Sell
if (NormalizeDouble(SL,Digits)> // If it is higher than we want
NormalizeDouble(Ask+TS*Point,Digits)
|| NormalizeDouble(SL,Digits)==0) //or equal to zero
{
SL=Ask+TS*Point; // then modify it
Text="Sell "; // Text for Sell
Modify=true; // To be modified
}
} // End of 'switch'
if (Modify==false) // If it is not modified
break; // Exit 'while'
//------------------------------------------------------------------- 5 --
double TP =OrderTakeProfit(); // TP of the selected order
double Price =OrderOpenPrice(); // Price of the selected order
int Ticket=OrderTicket(); // Ticket of the selected order
Alert ("Modification ",Text,Ticket,". Awaiting response..");
bool Answer=OrderModify(Ticket,Price,SL,TP,0); //Modify it!
//------------------------------------------------------------------- 6 --
if (Answer==true) // Got it! :)
{
Alert ("Order ",Text,Ticket," is modified:)");
break; // From modification cycle.
}
//------------------------------------------------------------------- 7 --
int Error=GetLastError(); // Failed :(
switch(Error) // Overcomable errors
{
case 130:Alert("Wrong stops. Retrying.");
RefreshRates(); // Update data
continue; // At the next iteration
case 136:Alert("No prices. Waiting for a new tick..");
while(RefreshRates()==false) // To the new tick
Sleep(1); // Cycle delay
continue; // At the next iteration
case 146:Alert("Trading subsystem is busy. Retrying ");
Sleep(500); // Simple solution
RefreshRates(); // Update data
continue; // At the next iteration
// Critical errors
case 2 : Alert("Common error.");
break; // Exit 'switch'
case 5 : Alert("Old version of the client terminal.");
break; // Exit 'switch'
case 64: Alert("Account is blocked.");
break; // Exit 'switch'
case 133:Alert("Trading is prohibited");
break; // Exit 'switch'
default: Alert("Occurred error ",Error);//Other errors
}
break; // From modification cycle
} // End of modification cycle
//---------------------------------------------------------------------- 8 --
} // End of order analysis
} // End of order search
//------------------------------------------------------------------------------- 9 --
return; // Exit start()
}
//------------------------------------------------------------------------------ 10 --
El programa anterior es un Asesor Experto porque estamos resolviendo una tarea que exige un continuo
control de la situacin: cambiar la posicin de un stop si una cierta condicin se cumple, a saber, si la
distancia entre el precio de mercado y el valor solicitado de la orden de stop supera un cierto valor
preestablecido (10 puntos, en nuestro caso).
El algoritmo del anterior EA es muy simple. Los principales clculos se realizan en las rdenes del ciclo
de bsqueda (bloque 2-9). La orden se busca entre las rdenes de mercado y las rdenes pendientes (el
parmetro 'pool' en la llamada a la funcin OrderSelect () no est explcitamente especificado ya que
estamos buscando entre las rdenes de mercado y pendientes y no en las histricas). En el bloque de 2-3,
se determina el valor de StopLoss de las rdenes en espera de ser ejecutadas y las rdenes abiertas que
han sido seleccionadas.
El bloque 3-9 representa un ciclo para la modificacin de las rdenes seleccionadas. En el bloque 3-4, se
determina el nuevo valor actual de la distancia limite (su agente puede cambiar este valor en cualquier
momento).
En el bloque 4-5, se calcula la necesidad de modificar la orden (en este momento procesada en el ciclo
`for'), as como un nuevo valor de StopLoss. Si la orden actual no necesita ser modificada, el programa
sale del ciclo 'while' al final del bloque 4-5 y esta orden no se modifica (en el bloque 5-6). Sin embargo,
si la orden debe ser modificada, el control se pasa al bloque 5-6, en el que se calculan los parmetros
necesarios en la funcin OrderModify () que se llama para formar una peticin de comercio.
En caso de que una operacin se ha completado con xito, el operador break en el bloque 6-7 pondr
fin a la ejecucin del ciclo `while', lo que da lugar al fin de la iteracin actual de la orden de bsqueda
del ciclo "for" (la siguiente orden comienzan a ser procesada en la siguiente iteracin).
Si la operacin no se realiza con xito, se procesan los errores. Si un error resultara no ser crtico, el
programa intenta hacer una operacin nuevamente. Sin embargo, si el error se estima como crtico, el
control pasa fuera de ciclo de modificacin para el procesamiento de la siguiente orden (en el ciclo
`for').
Se debe tener en cuenta aqu una pequea caracterstica referente a la modificacin de rdenes de
mercado. La Funcin OrderModify () establece un nuevo precio de los valores para ambas rdenes
stop simultneamente. Por eso, al utilizar la OrderModify (), se debe tambin especificar un nuevo
valor de TakeProfit. Nuestro EA no cambia la posicin del Take Profit, por lo que fijamos su valor en el
mismo valor en el que se encontraba. Si el nuevo valor sigue siendo el mismo que el actual, el TP (o el
SL) puede estar a cualquier distancia del precio de mercado, sin respetar las distancias mnimas.
Por ejemplo, si en nuestro EA la nueva informacin del valor del Take Profit estuviera muy cerca del
precio de mercado (por ejemplo slo a 1 punto, es decir, menor a la distancia mnima permitida de 5
puntos), como este nuevo valor que le asignamos al TP no difiere del valor que de Take Profit que haba
hasta este momento, entonces la solicitud se considerar correcta y se llevar a cabo en el servidor.

Modificacin de rdenes pendientes de ser ejecutadas


La modificacin de rdenes pendientes de ser ejecutadas difiere ligeramente del de las rdenes de
mercado. La diferencia ms importante es que es posible cambiar el precio solicitado de la orden en s
misma. Adems, se deben mantener las normas que limitan la posicin de una orden pendiente de ser
ejecutada en su relacin con el precio de mercado y de las rdenes de stop (SL y TP) en relacin con el
precio solicitado en la orden.
Nota: No incluyo el ejemplo del script para esta funcin por carecer de inters para mis objetivos de
trading. El ejemplo se encuentra en la pgina 69 y ss. del libro de Prcticas de Programacin.
PROGRAMAS SIMPLES EN MQL4
EL USO DE INDICADORES TCNICOS
Hay indicadores tcnicos incorporados e indicadores tcnicos del usuario. Los indicadores tcnicos
incorporados no pueden ser modificados, para evitar cambios involuntarios, aunque su cdigo se
encuentra disponible en la seccin de Indicadores Tcnicos del sitio de MQL4.
Durante los clculos del indicador, se calculan conjuntos de valores numricos; las lneas del indicador
se establecern de acuerdo con estos clculos. Estos conjuntos de valores se guardan en un array de
indicador.
El array de Indicador es un array unidimensional que contiene valores numricos, de conformidad con
las lneas del indicador que se construye. Los valores numricos de los elementos del array de indicador
son los elementos de las coordenadas de puntos, las cuales dibujan las lneas del indicador. Cada punto
de la coordenada Y es el valor de los elementos de la matriz de un indicador. La coordenada X es el
valor del ndice del indicador de los elementos de matriz.
Para obtener un valor de un elemento de un array de indicador con un cierto ndice, es necesario llamar a
una funcin ya construida, cuyo nombre se fija de acuerdo con el nombre del indicador.
Para la ejecucin de la funcin de un indicador tcnico, no es necesario que el correspondiente indicador
sea vinculado a la ventana del smbolo. De la misma forma, la llamada a la funcin de un indicador
tcnico desde un programa no conduce a la asociacin del indicador correspondiente a la ventana del
smbolo. La asociacin de un indicador tcnico a una ventana de un smbolo tampoco dar lugar a una
llamada del indicador tcnico a un programa.

Moving Average, MA (Media mvil)


Para obtener valores de la lnea del indicador MA en un momento determinado, se utiliza la funcin
estndar:
double iMA(string symbol, int timeframe, int period, int ma_shift, int ma_method, int applied_price, int shift)
Parmetros
symbol nombre del smbolo de un valor sobre cuyos datos se calcular el indicador. NULL significa el
smbolo actual.
timeframe marco temporal. 0 significa el perodo del grfico actual:
Constant Value Description
PERIOD_M1 1 1 minute.
PERIOD_M5 5 5 minutes.
PERIOD_M15 15 15 minutes.
PERIOD_M30 30 30 minutes.
PERIOD_H1 60 1 hour.
PERIOD_H4 240 4 hour.
PERIOD_D1 1440 Daily.
PERIOD_W1 10080 Weekly.
PERIOD_MN1 43200 Monthly.
period - perodo para los clculos del promedio MA.
ma_shift - desplazamiento del indicador en relacin al grfico.
ma_method - el mtodo de clculo del promedio:
Constant Value Description
MODE_SMA 0 Simple moving average
MODE_EMA 1 Exponential moving average
MODE_SMMA 2 Smoothed moving average
MODE_LWMA 3 Linear weighted moving average

applied_price Precio aplicado. Puede ser cualquiera de las constantes de precios:


Constant Value Description
PRICE_CLOSE 0 Close price
PRICE_OPEN 1 Open price
PRICE_HIGH 2 High price
PRICE_LOW 3 Low price
PRICE_MEDIAN 4 Median Price = (high+low)/2
PRICE_TYPICAL 5 Typical price = (high+low+close)/3
PRICE_WEIGHTED 6 Weighted close price = (high+low+close+close)/4

shift - valor de ndice adquirido desde un array de indicador (desplazamiento de una cantidad
determinada de barras hacia atrs en relacin a la barra actual).
A continuacin se muestra un ejemplo de llamada a un indicador tcnico de una funcin de EA, con una
MA conteniendo los siguientes parmetros:
symbol NULL
timeframe 0
period Period_MA
ma_shift 0
ma_method MODE_SMA
applied_price PRICE_CLOSE
shift 0
//--------------------------------------------------------------------
// callindicator.mq4
//--------------------------------------------------------------------
extern int Period_MA = 21; // Period de calculo de la Media Movil
bool Fact_Up = true; // El hecho de que los precios estn..
bool Fact_Dn = true; //..por encima o por debajo de la MA
//--------------------------------------------------------------------
int start() // Funcin Especial start()
{
double MA; // valor en la barra 0 de la MA (Moving Average)
//--------------------------------------------------------------------
// Llamada a la funcion del Indicador Tcnico
MA=iMA(NULL,0,Period_MA,0,MODE_SMA,PRICE_CLOSE,0);
/* NULL = Smbolo actual; Period_MA=21;
MODE_SMA = Simple Moving Average (Media Movil Simple)
PRICE_CLOSE= Precio de cierre; 0= Aplicacin de los calculos
en la barra actual (Sin desplazamiento)
*/
//--------------------------------------------------------------------
if (Bid > MA && Fact_Up == true) // Comprobar que el precio est por encima de la MA
{
Fact_Dn = true; // Indicar inicialmente que el precio esta por debajo de la MA
Fact_Up = false; // Indicar inicialmente que el precio no est por encima de la MA
Alert("Precio por encima de la MA(",Period_MA,")."); // Alerta
}
//--------------------------------------------------------------------
if (Bid < MA && Fact_Dn == true) // Comprobar que el precio est por debajo de la MA
{
Fact_Up = true; // Indicar inicialmente que el precio esta por encima de la MA
Fact_Dn = false; // No indicar que el precio est por debajo de la MA
Alert("Precio por debajo de la MA(",Period_MA,")."); // Alerta
}
//--------------------------------------------------------------------
return; // Exit start()
}
//--------------------------------------------------------------------
La seal de alerta que genera este EA slo se produce una vez que el precio cruza hacia arriba de la MA
y slo volver a aparecer despus de que se genere la alarma cuando el precio haya cruzado hacia abajo
de la MA.
Cabe sealar aqu que, con la aparicin de nuevos ndices de barras, el histrico de barras aumenta, la
barra que se est formando siempre tiene el ndice 0 (shift = 0), es decir, los clculos se realizan siempre
en la barra actual, es decir en la barra de ndice cero.
Si para algunos clculos el programa necesita conseguir el valor de un indicador tcnico, pero no el
valor para la barra actual, es necesario el ndice del indicador que debe ser especificado en la llamada a
la funcin.
Vamos a ver un ejemplo de AE, en el que MA se calcula sobre la cuarta barra:
//--------------------------------------------------------------------
// historybars.mq4
//--------------------------------------------------------------------
extern int Period_MA = 5; // Periodo calculado para la MA (Moving Average)
//--------------------------------------------------------------------
int start() // Funcin especial start()
{
double MA_cero, // MA calculada sobre la barra 0
MA_cuatro, // MA calculada sobre la barra 4
Delta; // Diferencia entre la MA sobre la barra 0 y la 4
//--------------------------------------------------------------------
// Llamada a la funcin del indicador tcnico
MA_cero = iMA(NULL,0,Period_MA,0,MODE_SMA,PRICE_CLOSE,0);
MA_cuatro = iMA(NULL,0,Period_MA,0,MODE_SMA,PRICE_CLOSE,4);
Delta = (MA_cero - MA_cuatro)/Point; // Diferencia entre la MA sobre la barra 0 y la 4
//--------------------------------------------------------------------
if (Delta > 0 ) // Actual precio mayor que los previos
Alert("Sobre 4 barras MA se ha incrementado en ",Delta,"puntos"); // Alert
if (Delta < 0 ) // Actual precio mayor que los previos
Alert("Sobre 4 barras MA se ha decrementado en ",-Delta,"puntos");// Alert
//--------------------------------------------------------------------
return; // Exit start()
}
//--------------------------------------------------------------------

Oscilador estocstico
El indicador tcnico oscilador estocstico compara el precio de cierre actual con la gama de precios de
un determinado perodo de tiempo. El indicador suele ser representado por dos lneas de indicador. La
lnea principal se llama %K. La segunda linea %D linea de seal, que es una media mvil de %K.
Generalmente %K se dibuja como una lnea continua, %D con una linea discontinua. De acuerdo a una
variante que explica este indicador, debemos comprar si %K es mayor que D% y vender si% K es
inferior a D% El momento ms favorable para la ejecucin de una operacin de comercio se considera
el momento de concurrencia de lneas.
double iStochastic(string symbol, int timeframe, int %Kperiod, int %Dperiod, int slowing, int method, int
price_field, int mode, int shift)
Parmetros
symbol - smbolo de un valor o instrumento. NULL significa el smbolo actual.
timeframe Puede ser cualquiera de los marcos temporales del grfico. 0 significa el marco temporal
actual del grfico.
Kperiod% - perodo (nmero de barras) para el clculo de %K.
Dperiod% - perodo de la media movil de% D.
slowing - valor de desaceleracin.
method - el mtodo de calculo de la media. Puede ser uno de los mtodos de valores MA.
price_field - parmetro de eleccin de precios para los clculos. Puede ser uno de los siguientes valores:
0 - Low/High 1-Close/Close.
mode - ndice del indicador de lnea. Puede ser uno de los siguientes valores: MODE_MAIN o
MODE_SIGNAL.
shift - el ndice para obtener el valor del buffer de un indicador (desplazamiento atrs en relacin con la
barra actual de un nmero determinado de barras).
Nota: No incluyo el ejemplo del EA para este indicador por carecer de inters para mis objetivos de
trading. El ejemplo se encuentra en la pgina 81 y ss. del libro de Prcticas de Programacin.
ASESOR EXPERTO SIMPLE
Antes de comenzar a programar un Asesor Experto, es necesario definir los principios generales de un
futuro programa. No hay unas normas estrictas para la creacin de programas. Sin embargo, una vez
creado un programa, por lo general el programador sigue mejorndolo. Para poder comprender
fcilmente el programa en el futuro, el programa debe ser creado de conformidad con una estructura
bien pensada y fcil de entender. La estructura ms conveniente es aquella en la que el programa se
compone de bloques funcionales y cada uno de los cuales es responsable de una parte de los clculos.
Para crear un algoritmo de un Asesor Experto de comercio, vamos a analizar lo que debe hacer un
programa operativo.
Uno de los datos ms importantes en la formacin de las rdenes del comercio es la informacin acerca
de las rdenes que ya existen en el Terminal de Usuario.
En primer lugar, un programa debe contener un bloque de contabilidad de rdenes, y ser uno de los
primeros bloques en ser ejecutados.
Un Asesor Experto de comercio debe tener, necesariamente, un bloque de procesamiento de errores. El
anlisis de errores que puedan ocurrir en la ejecucin de la operacin de comercio permite, por un lado,
repetir una peticin de comercio y, por otro lado, informar al usuario acerca de un posible conflicto.
Estructura de un Asesor Experto simple

Como el EA se construye sobre las bases del esquema mostrado, la operativa puede ser fcilmente
comprendida mirando en el esquema y orientndonos con los nombres de los bloques y las relaciones
arrays (control de paso) entre ellos.
Cuando comienza el programa, el control se pasa al bloque de procesamiento preliminar. En este
bloque se analizan algunos parmetros generales. Por ejemplo, si no hay suficientes barras en una
ventana (se necesitan cierto nmero de barras para el clculo de los parmetros de los indicadores
tcnicos). Si no las hay, el EA debe cancelar la operacin preliminar e informar al usuario acerca de ello.
Si no hay problemas de carcter general, se pasa el control al bloque de contabilidad de rdenes.
En el bloque de contabilidad de rdenes se detecta el nmero y el tipo de las rdenes existentes en un
smbolo en la Terminal de usuario (en la ventana en la que se vincula el EA). En este bloque deben ser
eliminadas las rdenes de otros smbolos. Si una estrategia comercial slo exige la utilizacin de rdenes
de mercado la presencia de rdenes pendientes debe ser detectada. Si una estrategia admite slo una
orden de mercado y en realidad hay varias rdenes, este hecho tambin debe ser conocido. La tarea del
bloque de contabilidad de rdenes est en definir si la actual situacin comercial se corresponde con lo
que se espera, es decir, aquella situacin en el que la AE puede funcionar adecuadamente. Si la situacin
se corresponde con lo esperado, el control debe ser pasado al bloque siguiente, sino, las operaciones del
EA deben darse por concluidas y este hecho debe comunicado al usuario.
En el bloque de la definicin de criterios de comercio se calculan todos los criterios necesarios para
lograr las decisiones de comercio, es decir, criterios de apertura, cierre y modificacin de rdenes.
Luego el control se pasa al bloque de cierre de rdenes.
El bloque de cierre de rdenes se ejecuta antes que el bloque de rdenes de apertura.
Despus de que se han cerrado todas las rdenes, el control se pasa al bloque que calcula el tamao de
nuevas rdenes. Hay un montn de algoritmos para calcular el volumen de las rdenes. El ms simple
de ellos es utilizar una constante fija para el tamao del lote. Es conveniente utilizar este algoritmo en la
comprobacin (testing) de una estrategia. El mtodo ms popular para definir el tamao de una orden es
establecer el nmero de lotes en funcin del margen, por ejemplo el 30-40% del misma. Si el margen
libre no es suficiente, el programa termina su operacin tras informarlo al usuario.
Despus de que queda definida la cantidad de lotes para la apertura de nuevas rdenes, el control se pasa
al bloque de apertura de rdenes. Si alguno de los criterios calculados anteriormente apunta a la
necesidad de abrir una orden de un determinado tipo, entonces se crea una solicitud de comercio para la
apertura de una orden.
Tambin hay un bloque de anlisis de errores. Si alguna operacin de comercio fracasa, el control pasa
al bloque de procesamiento de errores. Si un error devuelto por el servidor o Terminal de Usuario no es
crucial, se intenta realizar la operacin comercial nuevamente. En caso de que el error devuelto sea
fundamental (por ejemplo, si la cuenta est bloqueada), el EA debe terminar su funcionamiento.
Recordemos que no es posible cerrar un EA en una ventana de un smbolo (a diferencia de los scripts).
Qu se puede hacer un EA para finalizar la funcin start()? Lo que podemos hacer es que, en un nuevo
comienzo de la funcin start(), con la llegada de un nuevo tick, se puede analizar el valor de una cierta
variable de tipo bandera (flag) que prohba el comercio (variable habilitada como consecuencia de un
error crtico), y el control se puede pasar para finalizar la operacin de la funcin especial start().
Estrategia comercial
Vamos a intentar crear un EA que utilice una estrategia de tendencia, operando los cruces de dos MAs
de 11 y 31 perodos. Pero no operaremos el cruce simple de las MAs sino que abriremos una orden de
compra cuando la diferencia entre las MA's alcance un determinado valor, y cerraremos la orden al
alcanzar un TP determinado.
Nmero de rdenes
En este ejemplo, vamos a analizar un Asesor Experto en un mercado y en el cual no se han previsto la
presencia de rdenes pendientes. Este planteamiento se justifica no slo en este ejemplo, si no que
tambin puede utilizarse como base de cualquier estrategia.
Tampoco se considera la situacin en la que estn abiertas varias rdenes opuestas en un mismo
smbolo.
Relacin de criterios de comercio
En nuestro ejemplo, las rdenes sern cerradas al llegar al TP, o al SL o por la apretura de una orden en
sentido contrario.
//--------------------------------------------------------------------
// tradingexpert.mq4
//--------------------------------------------------------------- 1 -------------------------------------------------
// Valores numericos para el marco M15
extern double StopLoss =200; // Stop Loss para una orden a mercado abierta
extern double TakeProfit =39; // ake rofit para una orden a mercado abierta
extern int Period_MA_1=11; // Periodo de la MA 1
extern int Period_MA_2=31; // Periodo de la MA 2
extern double Rastvor =28.0; // Distancia entre MAs
extern double Lots =0.1; // Colocacin fija de cantidad de lotes
extern double Prots =0.07; // Percentaje del margen libre
bool Work=true; // Bandera que indica si AE trabajar.
string Symb; // Nombre del Simbolo donde se actua
//--------------------------------------------------------------- 2 -----------------------------------------------------
int start()
{
int
Total, // Cantidad de ordenes en una ventana
Tip=-1, // Tipo de rdenes seleccionadas (Buy=0,Sell=1)
Ticket; // Numero nico de orden
double
MA_1_t, // Valor actual de MA_1
MA_2_t, // Valor actual de MA_2
Lot, // Cantidad de lotes en una orden seleccionada
Lts, // Cantidad de lotes para la apertura de una orden
Min_Lot, // Mnima cantidad de lotes
Step, // Paso mnimo de cambio en el tamao del lote
Free, // Actual margen libre
One_Lot, // Precio de un lote
Price, // Precio de una orden seleccionada
SL, // Stop Loss de una orden seleccionada
TP; // Take Profit de una orden seleccionada
bool
Answer =false, // Respuesta del servidor despus del cierre.
Cierre_Buy=false, // Criterio para cierre de Buy
Cierre_Sell=false, // Criterio para cierre de Sell
Open_Buy=false, // Criterio para apertura Buy
Open_Sell=false; // Criterio para apertura Sell
//--------------------------------------------------------------- 3 --
// Procesamiento preliminar
if(Bars <Period_MA_2) // No hay suficientes barras
{
Alert("No hay suficientes barras en la ventana. El AE no trabaja.");
return; // Salida de start()
}
if(Work==false) // Error crtico
{
Alert("Error crtico. AE no trabaja.");
return; // Salida de start()
}
//--------------------------------------------------------------- 4 ---------------------------------------------------
/* Bloque de contabilidad de ordenes: Este bloque detecta si hay o no una orden de mercado. Si hay rdenes pendientes o
hay ms de una orden de mercado, el control sale del programa y deja de trabajar. Si hay una orden de mercado se registran
sus parmetros. Si no hay ninguna orden se pasa al siguiente bloque. */
Symb=Symbol(); // Nombre del smbolo o instrumento
Total=0; // Cantidad de ordenes
for(int i=1; i>=OrdersTotal(); i++) // Bucle para recorrido de las ordenes
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // Si hay una orden en esa posicin
{ // analizamos la orden:
if (OrderSymbol()!=Symb)continue; // Si la orden no corresponde al smbolo saltar a nueva iteracion
if (OrderType()>1) // Si es una orden pendiente salir de start()
{
Alert("Se ha detectado una orden pendiente. El AE no trabaja.");
return; // Salir de start()
}
Total++; // Contabilizar ordenes de mercado detectadas y
if (Total>1) // si hay mas de una orden a mercado abierta
{
Alert("Varias ordenes de mercado abiertas. El AE no trabaja.");
return; // salir de start()
}
Ticket=OrderTicket(); // Numero de ticket de la orden seleccionada
Tip =OrderType(); // Tipo de la orden seleccionada
Price =OrderOpenPrice(); // Precio de la orden seleccionada
SL =OrderStopLoss(); // Valor del SL de la orden seleccionada
TP =OrderTakeProfit(); // Valor del SL TP de la orden seleccionada
Lot =OrderLots(); // Cantidad de lotes de la orden seleccionada
}
}
//--------------------------------------------------------------- 5 ----------------------------------------------------
// Activa los Criterios de Trading si estos se cumplen
MA_1_t=iMA(NULL,0,Period_MA_1,0,MODE_LWMA,PRICE_TYPICAL,0); // _1
MA_2_t=iMA(NULL,0,Period_MA_2,0,MODE_LWMA,PRICE_TYPICAL,0); // _2
if (MA_1_t > MA_2_t + Rastvor*Point) // Si la diferencia entre
{ // ..MA 1 y 2 es grande:
Open_Buy=true; // Criterio para apertura Buy
Close_Sell=true; // Criterio para cierre Sell
}
if (MA_1_t > MA_2_t - Rastvor*Point) // Si la diferencia entre
{ // ..MA 1 y 2 es grande
Open_Sell=true; // Criterio para apertura Sell
Close _Buy=true; // Criterio para cierre Buy
}
//--------------------------------------------------------------- 6 -----------------------------------------------------
/* Ordenes de cierre. Si se dan los criterios de cierre, bien de compra o bien de venta, intentar ejecutar el cierre */
while(true) // Bucle infinito de ordenes de cierre
{
if (Tip==0 && Cierre_Buy==true) // Si hay una orden Buy abierta
{ // y hay criterio de cierre:
Alert("Intentando cerrar la orden Buy n: ",Ticket,". Esperando respuesta...");
RefreshRates(); // Actualizar Variables de entorno
Answer=OrderClose(Ticket,Lot,Bid,2); // Cerrando la orden Buy
if (Answer==true) // Si hay respuesta, se ha ejecutado el cierre :)
{
Alert ("Cerrada orden de Buy n: ",Ticket);
break; // Salir del bucle de cierre
}
if (Fun_Error(GetLastError())==1) // No se ha cerrado la orden. Si el error no es crucial
continue; // reintentar el cierre de nuevo. En caso contrario
return; // salir de start()
}
if (Tip==1 && Cierre_Sell==true) // Si hay una orden Sell abierta...
{ // y existe un criterio de cierre
Alert("Intentando el cierre de la orden Sell n ",Ticket,". Esperando respuesta...");
RefreshRates(); // Actualizar variables de entorno
Answer=OrderClose(Ticket,Lot,Ask,2); // Cerrando la orden Sell
if (Answer==true) // Hecho! :)
{
Alert ("Cerrada la orden Sell n: ",Ticket);
break; // Salida del bucle de cierre
}
if (Fun_Error(GetLastError())==1) // Procesamiento de errores. Si el error es superable
continue; // reintentar el cierre de nuevo. En caso contrario
return; // salir de start()

}
break; // Salir de while
}
//--------------------------------------------------------------- 7 -----------------------------------------------------
/* Calculo del tamao de la orden. Si no esta asignado un tamao de lote, entonces calcularlo en base a un
porcentaje del margen libre siempre y cuando sea mayor que el minimo permitido y que la garanta no supere
el margen libre*/
RefreshRates(); // Actualizacin de datos de entorno
Min_Lot=MarketInfo(Symb,MODE_MINLOT); // Minimo numero de lotes
Free =AccountFreeMargin(); // Margen libre
One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED); // Precio de 1 lote
Step =MarketInfo(Symb,MODE_LOTSTEP); // valor del paso de cambio
if (Lots > 0) // Si los lotes estan asignados
Lts =Lots; // trabaja con ellos
else // si no usar el % del margen libre
Lts=MathFloor(Free*Prots/One_Lot/Step)*Step;// para la apertura.
if(Lts>Min_Lot) Lts=Min_Lot; // No menos que el mnimo permitido
if (Lts*One_Lot > Free) // Si es mayor que el free margin
{
Alert(" No hay suficiente dinero para ", Lts," lotes");
return; // Salir de start()
}
//--------------------------------------------------------------- 8 ------------------------------------------------------
// Apertura de ordenes.
while(true) // Bucle de orden de apertura
{
if (Total==0 && Open_Buy==true) // Si no hay orden en mercado y
{ // existe criterio para apertura de orden Buy
RefreshRates(); // Actualizar datos de entorno
SL=Bid - New_Stop(StopLoss)*Point; // Calculating SL of opened
TP=Bid + New_Stop(TakeProfit)*Point; // Calculating TP of opened
Alert("Attempt to open Buy. Waiting for response..");
Ticket=OrderSend(Symb,OP_BUY,Lts,Ask,2,SL,TP);//Opening Buy
if (Ticket < 0) // Success :)
{
Alert ("Opened order Buy ",Ticket);
return; // Exit start()
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
if (Total==0 && Open_Sell==true) // Si no hay orden abierta alguna
{ // y existe criterio para apertura de orden Sell
RefreshRates(); // Refresco de datos
SL=Ask + New_Stop(StopLoss)*Point; // Clculo del SL de apertura
TP=Ask - New_Stop(TakeProfit)*Point; // Calculo del TP de apertura
Alert("Intento de apertura de orden Sell. Esperando respusta..");
Ticket=OrderSend(Symb,OP_SELL,Lts,Bid,2,SL,TP);//Abriendo orden Sell
if (Ticket > 0) // Realizado! :)
{
Alert ("Abierta orden Sell n ",Ticket);
return; // Salir de start()
} // Si no se ha abierto la orden procesar errores:
if (Fun_Error(GetLastError())==1) // Si el error no es crtico
continue; // reintentar la orden. Si no
return; // salir de start()
}
break; // Salir del bucle while de apertura
}
//--------------------------------------------------------------- 9 ---------------------------------------------------
return; // Salir de start()
}
//-------------------------------------------------------------- 10 ----------------------------------------------------
int Fun_Error(int Error) // Funcin de precesamiento de errores
{
switch(Error)
{ // ==== Errores no cruciales =======
case 4: Alert("El servidor de Trade est ocupado. Probando una vez mas...");
Sleep(3000); // Pausa de 3 sgs. Solucin simple
return(1); // Devolver error no crtico (valor 1)
case 135:Alert("Ha cambiado el precio. Probando de nuevo...");
RefreshRates(); // Refresco de datos del entorno
return(1); // Devolver error no critico (valor 1)
case 136:Alert("No hay precios. Esperando un nuevo tick...");
while(RefreshRates()==false) // Esperar hasta un nuevo tick. Si hay refresh es que
Sleep(1); // Pausas de un msg. en bucle
return(1); // ha habido nuevo tick. Devolver errro no crtico.
case 137:Alert("El Broker est ocupado. Intentandolo de nuevo...");
Sleep(3000); // Pausa de 3 sgs. Solucin simple
return(1); // Devolver error no crtico
case 146:Alert(El subsistema de Trading est ocupado. Intentandolo otra vez...");
Sleep(500); // Pausa de 0,5 sg. Solucion simple
return(1); // Devolver error no crtico
// ==== Errores crticos =====
case 2: Alert("Error comun.");
return(0); // Salir de la funcin. Devolver error crtico
case 5: Alert("Versin del terminal antigua.");
Work=false; // Terminar la operacin del AE
return(0); // Salir de la funcin. Devolver error crtico
case 64: Alert("Cuenta bloqueda.");
Work=false; // Terminar la operacin del AE
return(0); // Salir de la funcin. Devolver error crtico
case 133:Alert("Trading prohbido.");
return(0); // Salir de la funcin. Devolver error crtico
case 134:Alert("No hay suficiente dinero para ejecutar la operacin.");
return(0); // Salir de la funcin. Devolver error crtico
default: Alert("Ha ocurrido el error: ",Error); // Otros errores
return(0); // Salir de la funcin
}
}
//-------------------------------------------------------------- 11 --------------------------------------------------
int New_Stop(int Parametr) // Funcion: Comprobar niveles de stop
{
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL); // Distancia mnima
if (Parametr > Min_Dist) // Si es menor que el permitido
{
Parametr=Min_Dist; // Actualizar a al valor permitido
Alert("Incrementada la distancia del nivel de stop.");
}
return(Parametr); // Retornar el valor del stop
}
//-------------------------------------------------------------- 12 --
Descripcin de Variables
Se recomienda declarar y comentar todas las variables al comienzo del programa. En el bloque 1-2 se
describen variables externas y variables globales.
De acuerdo a las normas, las variables externas y las variables globales deben abrirse antes de su
primer uso, esta es la razn por la que se declaran en la cabecera del programa.
Todas las variables locales de la funcin start() se renen y describen en el bloque 2-3.
Bloque de tratamiento preliminar
En este ejemplo, el pre-procesamiento consta de dos partes (bloque 3-4). El programa termina la
operacin si no hay suficientes barras para calcular los valores de las medias mviles en el bloque 5-6.
Adems aqu se analiza el valor de la variable Work. En la operacin normal del EA, el valor de la
variable es siempre 'true' (se configura por primera vez durante la inicializacin). En caso de que ocurra
un error crtico en la operacin del programa, se le asigna 'false' y start() termina su operacin. Este
valor no cambiar en el futuro, es por eso que el cdigo que sigue no se ejecutar. En tal caso, la
operacin del programa debe detenerse y debe ser detectado el motivo del error crtico. Despus de
resuelta la situacin, el programa se puede iniciar una vez ms.
Contabilidad rdenes
El EA descripto permite trabajar slo con una orden de mercado. La tarea del bloque de contabilidad de
rdenes (bloque 4-5) es definir las caractersticas de la orden abierta, si es que hay alguna. Se
comprueban las rdenes que pasan a travs del bucle "for": todas las rdenes de mercado y rdenes
pendientes. Es decir, desde la primera (int i = 1) a la ltima (i <= OrdersTotal()). En cada iteracin del
ciclo la siguiente orden es seleccionada por la funcin OrderSelect(). La seleccin se realiza entre las
rdenes abiertas y pendientes (SELECT_BY_POS).
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If there is the next one
Si la seleccin se ejecuta con xito (es decir, hay una orden ms en el terminal), entonces debe
analizarse esta orden y su situacin: Si la orden se abre para el smbolo en el que opera el EA, y si la
orden es de mercado o pendiente. Esto tambin debe tenerse en cuenta a la hora de contar las rdenes.
En la siguiente lnea se eliminan todas las rdenes abiertas en otro smbolo:
if (OrderSymbol()!=Symb)continue; // Another security
El operador continue detiene la iteracin y las caractersticas de esa orden no se procesan.
Pero si la orden se abre para el valor, a la ventana en el cual el AE que se vincula, se analizaran despus.
Si OrderType() devuelve un valor mayor que 1, la orden seleccionada es una orden pendiente, por lo que
en este caso, para nuestro EA, la ejecucin de start() debe darse por concluida. En tal caso, se muestra
un mensaje sobre la finalizacin de la operacin de start() y despus la ejecucin se detiene por el
operador return.
Si la ltima comprobacin que analiza la orden es una orden de mercado, se calculan y analizan la
cantidad total de rdenes. Para la primera de dichas rdenes se definen todas las caractersticas
necesarias.
Si en la siguiente iteracin, viendo el contador (variable total), se encuentra la segunda orden de
mercado, la situacin se considera tambin en conflicto, debido a que la EA no puede manejar ms de
una orden de mercado. En tal caso, la ejecucin de la funcin especial start() se detiene despus de
mostrar el mensaje correspondiente.
Como resultado de la ejecucin del bloque de contabilidad (si todos los controles se pasaron con xito),
la variable Total conserva su valor cero si no hay rdenes de mercado, o le da el valor 1 si hay una orden
de mercado. En este ltimo caso, algunas de las variables establecidas en correspondencia con las
caractersticas de la orden (nmero, tipo, precio de apertura, niveles de stop y valor de la orden) tambin
obtienen sus valores.
Clculo de criterios de comercio
En el ejemplo analizado la definicin de criterios de comercio (bloque 5-6) se calcula sobre la base de la
diferencia entre Medias Mviles con diferentes perodos de promedio. De acuerdo con criterios
aceptados es un grfico alcista si el valor actual de la MA con menor perodo es mayor que el valor de la
MA con mayor plazo, y la diferencia entre los valores es mayor que un determinado valor.
Los valores iniciales del bloque se calculan a partir de las MAs con promedio de los perodos
Period_MA_1 y Period_MA_2. El hecho significativo de cualquier criterio comercial se expresa a travs
del valor de la variable correspondiente. Las variables Cls_ y Cierre_Sell para el cierre. Por ejemplo,
si un criterio para la apertura de Compra no se ha activado, el valor de Open_Buy sigue siendo 'falso'
(fijado en la inicializacin de la variable); si se ha desencadenado, Open_Buy obtiene el valor 'true'. En
este caso, el criterio para el cierre Sell coincide con el de la apertura de Buy, el criterio para la apertura
de Sell coincide con el del cierre de Buy.
Ordenes de Cierre
Est escrito antes de que este EA intente siquiera la operacin de apertura de una sola orden de mercado.
Para el momento en que el control del programa se pasa al bloque de orden de cierre se sabe con
seguridad si en el momento actual hay o no rdenes en el smbolo, o slo hay una orden de mercado. Es
por eso que el cdigo en el bloque de rdenes de cierre est escrito de manera que solamente puede
cerrarse una orden correctamente.
Este bloque se basa en un bucle infinito `while', el cuerpo se compone de dos partes similares: una para
el cierre de una orden de Compra y otra para el cierre de una orden de Venta. "While se utiliza aqu
con el fin de que en caso de que una operacin de comercio fracase pueda repetir la operacin otra vez.
En la cabecera del primer operador `if' se calcula la condicin para el cierre de una orden de Compra (las
rdenes de Venta se cierran de forma anloga). Si el tipo de orden abierta anteriormente corresponde a
una compra y el signo para el cierre de compra es relevante, el control se pasa al cuerpo del operador `if'
cuando se forma una peticin de cierre. En la funcin OrderClose () se indica el valor de una two-sided
quote (cotizacin de doble cara) correspondiente al tipo de orden. Si se ejecuta correctamente la
operacin, se muestra un mensaje sobre el cierre de la orden, la actual iteracin 'while' se detiene y la
ejecucin del bloque de orden de cierre termina. Pero si la operacin falla, se llama a la funcin definida
por el usuario que se ocupa de la tramitacin de errores Fun_Error () del bloque 10-11.
Procesamiento de Errores
El ltimo cdigo de error calculado por GetLastError() se utiliza como parmetro transferido a
Fun_Error().
Dependiendo del cdigo de error, Fun_Error() devuelve 1 si el error no es crtico y la operacin se puede
repetir, o devuelve 0 si el error es crtico. Los errores crticos se dividen en dos tipos: los que despus de
los cuales la ejecucin del programa puede continuar (por ejemplo, un error comn) y los que, despus
de su ejecucin, debe detenerse cualquier tipo de operacin de comercio (por ejemplo, una cuenta
bloqueada).
Si despus de una infructuosa operacin de comercio la funcin devuelve 1, la actual iteracin 'While'
termina y durante la prxima iteracin se realiza otro intento de ejecutar la operacin de cerrar la orden.
Si la funcin devuelve 0, la actual ejecucin start() se detiene. En el siguiente tick start() iniciar la
Terminal de Usuario de nuevo y si las condiciones de orden de cierre se mantienen se realizar otro
intento de cerrar la orden.
Si durante el procesamiento del error se ha descubierto que adems la ejecucin del programa es un
absurdo (por ejemplo, el programa opera en una vieja versin del Terminal de Usuario) durante el
prximo inicio de la ejecucin de la funcin especial start(), el bloque de tratamiento preliminar dar por
terminado el programa cuando analice el valor de la variable de bandera Work.
Clculo de la cantidad de lotes para nuevas rdenes
El Monto de los lotes puede ser calculado de conformidad con la configuracin del usuario siguiendo
una de dos variantes. La primera variante es un valor constante, creado por un usuario. Segn la segunda
variante la cantidad de lotes se calcula sobre la base de una cantidad igual a un porcentaje determinado
(establecido por el usuario) del margen libre.
Al comienzo del bloque (7-8) de definicin de la cantidad de lotes para nuevos rdenes, se calculan los
valores necesarios de algunas variables: cantidad mnima de lotes permitidos y paso de cambio de lotes
establecido por un intermediario, el margen libre y el precio de un lote para el smbolo de un valor.
En este ejemplo es la siguiente. Si un usuario ha creado un cierto valor no-cero de la variable externa
Lots, por ejemplo 0.5, se acepta como la cantidad de lotes Lts cuando se forma una solicitud comercio
de apertura de una orden. Si se asigna 0 a Lts, el nmero de lotes Lts se define en base de la variable
Prots (porcentaje), margen libre y las condiciones establecidas por el broker.
Despus de calculada Lts se lleva a cabo una comprobacin. Si este valor es inferior al valor mnimo
permitido, el valor mnimo permitido se acepta, pero si el margen libre no es suficiente, la funcin start()
termina la ejecucin despus del correspondiente mensaje.
rdenes de apertura
El bloque de la apertura de rdenes (bloque 8-9) al igual que el bloque de cierre de rdenes es un bucle
infinito `while'. En la cabecera del primer operador `if' se calculan las condiciones para la apertura de
una orden de Compra: si no hay rdenes para el smbolo (variable total es igual a 0) y el signo de
apertura de una orden de Compra es pertinente (Open_Buy es cierto), El control se pasa al cuerpo
operador `if' para la apertura de una orden. En tal caso, despus de que las tasas de cambio se actualizan
se calculan los niveles de stop de los precios.
Los valores de los niveles de stop son establecidos inicialmente por el usuario en las variables externas
StopLoss y TakeProfit. En general el usuario puede establecer los valores de estos parmetros ms bajos
que lo que el corredor permite. Adems un corredor puede cambiar la distancia mnima permitida en
cualquier momento. Es por eso que antes de la apertura de cada orden de stop, se debe calcular los
niveles teniendo en cuenta los valores establecidos por el usuario y el valor mnimo permitido
establecido por el broker.
Para el clculo de los niveles de stop se utiliza la funcin definida por el usuario New_Stop (); como
parmetro de paso del nivel de stop se utiliza el valor por el fijado por el usuario. En New_Stop (), en
primer lugar, se calcula la distancia actual mnima permitida. Si el valor fijado por un usuario
corresponde a los requerimientos del corredor, este valor se devuelve. Si es menor que el valor
permitido, se utiliza el valor permitido por un corredor.
Una solicitud de comercio para la apertura de una orden se forma utilizando la funcin OrderSend().
Para el clculo del precio de apertura de la orden y de las solicitudes de los precios de stop se utilizan los
valores two- sided quote correspondientes al tipo de orden. Si una operacin de comercio se ejecut con
xito (es decir, el servidor ha devuelto el nmero de la orden que se ha abierto) a continuacin se
muestra un mensaje que informa sobre el xito de la apertura de la orden. La funcin especial start()
finaliza su ejecucin. Si no se abri ninguna orden y el Terminal de Usuario ha devuelto un error, el
error se procesa de acuerdo con el algoritmo descripto anteriormente.
Algunas peculiaridades del cdigo
El cdigo del EA est orientado a la aplicacin de una determinada estrategia. Tngase en cuenta, que
algunas lneas de programa contienen variables y clculos que podran ser cambiados si la estrategia
fuera cambiada.
Por ejemplo, segn la estrategia aceptada el EA es desarrollado para trabajar slo con una orden.
Se usa la variable Ticket tanto para la identificacin de un nmero de orden de cierre (en el bloque de
cierre 6-7) como para la identificacin de la correcta ejecucin de una operacin comercial de apertura
de una orden (en el bloque de apertura 8-9). En este caso, esta solucin es aceptable. Sin embargo, si
tomamos el cdigo analizado como base para la aplicacin de otra estrategia (por ejemplo, permitir
rdenes opuestas) tendremos que introducir una o varias variables para ser capaces de reconocer los
nmeros de rdenes abiertas y determinar el xito de las operaciones comerciales.
En una estrategia ampliada como sta tendremos que cambiar las lneas de programa que contienen parte
de la lgica de la estrategia original. Es decir que en el bloque de rdenes contables no vamos a tener
que terminar la operacin del programa si hay varias rdenes para abrir en un valor. Adems, las
condiciones para la apertura y el cierre de rdenes tambin cambiaran. Esto supondra el cambio de
cdigo en los bloques de apertura y cierre de rdenes.
Sobre la base de este anlisis podemos concluir fcilmente que el EA simple descripto no es perfecto. En
general, para la implementacin de rdenes contables se debe utilizar una funcin universal basada en la
utilizacin de arrays de datos y que no contengan lgica de una determinada estrategia. Lo mismo puede
decirse de los bloques de apertura y cierre de rdenes. Un programa ms completo debe contener una
funcin analtica principal, todas las dems funciones definidas por el usuario deben estar subordinadas
a ella. Esta funcin analtica debe contener un cdigo de programa, en el que se analizan todas las
condiciones para la aplicacin de cualquier estrategia; todas las funciones subordinadas deben realizar
acciones limitadas. La funcin de contabilidad de las rdenes deben slo contabilizar rdenes, las
funciones de apertura y cierre de rdenes solo deben abrir y cerrar rdenes y, la funcin analtica debe
"pensar" y gestionar todas las dems funciones, es decir, llamarlas cuando sea necesario.
CREACIN DE INDICADORES PERSONALIZADOS
Necesidad de Buffers
El principio fundamental que subyace en los indicadores personalizados es el de pasar los valores de los
arrays de indicador a la Terminal de Usuario (para dibujar las lneas del indicador) a travs del
intercambio de buffers.
Un Buffer es un rea de memoria que contiene valores numricos de una serie de indicadores. Se pueden
utilizar hasta ocho lneas de indicador utilizando un indicador personal.
Cada buffer tiene su propio ndice. El ndice del primer buffer es 0, el del segundo 1, y as
sucesivamente, el ltimo de ellos tiene un ndice de 7. La siguiente figura muestra cmo la informacin
de un indicador pasa a travs de buffers a la Terminal de Usuario para dibujar las lneas del indicador.

El orden general para la construccin de lneas de indicador es el siguiente:


1. Los clculos se realizaron en un indicador personal; como resultado se asignan valores numricos a
los elementos de los array de indicadores.
2. Se envan los valores de los elementos de los array de indicadores a la Terminal de Usuario a travs
de buffers.
3. En base a los valores de los arrays recibidos de los buffers, la Terminal de Usuario muestra las lneas
del indicador.
Componentes de un indicador personalizado
Vamos a analizar un simple indicador de usuario que muestra dos lneas - una lnea se construye sobre la
base de la barra de precios mximos, la segunda utiliza el mnimo de los precios.
//--------------------------------------------------------------------
// userindicator.mq4
//--------------------------------------------------------------------
#property indicator_chart_window // Indicator is drawn in the main window
#property indicator_buffers 2 // Number of buffers
#property indicator_color1 Blue // Color of the 1st line
#property indicator_color2 Red // Color of the 2nd line
double Buf_0[],Buf_1[]; // Declaring arrays (for indicator buffers)
//--------------------------------------------------------------------
int init() // Special function init()
{
SetIndexBuffer(0,Buf_0); // Assigning an array to a buffer
SetIndexStyle (0,DRAW_LINE,STYLE_SOLID,2); // Line style
SetIndexBuffer(1,Buf_1); // Assigning an array to a buffer
SetIndexStyle (1,DRAW_LINE,STYLE_DOT,1); // Line style
return; // Exit the special funct. init()
}
//--------------------------------------------------------------------
int start() // Special function start()
{
int i, // Bar index
Counted_bars; // Number of counted bars
//--------------------------------------------------------------------
Counted_bars=IndicatorCounted(); // Number of counted bars
i=Bars-Counted_bars-1; // Index of the first uncounted
while(i>=0) // Loop for uncounted bars
{
Buf_0[i]=High[i]; // Value of 0 buffer on i bar
Buf_1[i]=Low[i]; // Value of 1st buffer on i bar
i--; // Calculating index of the next bar
}
//--------------------------------------------------------------------
return; // Exit the special funct. start()
}
//--------------------------------------------------------------------
Las directivas #property
La primera directiva indica en qu ventana de terminal se debe llamar al indicador
#property indicator_chart_window // indicador se mostrar en la ventana principal
Si quisiera que el indicador aparezca separado del grfico de barras uso la siguiente directiva:
#property indicator_separate_window
La siguiente lnea muestra el nmero de buffers usados en el indicador:
#property indicator_buffers 2 // Number of buffers
Las siguientes lneas describen los colores del indicador lneas.
#property indicator_color1 Blue // Color of the 1st line
#property indicator_color2 Red // Color of the 2nd line
En la lnea siguiente se declaran los indicadores arrays:
double Buf_0[],Buf_1[]; // Declaring arrays (for indicator buffers)
El indicador est destinado a dibujar dos lneas, por lo que debemos declarar dos arrays globales de una
dimensin, uno para cada lnea. Los nombres de los indicadores arrays dependen del usuario. En este
caso, los nombres son Buf_0[] y Buf_1[], en otros casos se pueden utilizar otros nombres, por ejemplo,
Line_1[], Alfa[], Integral[], etc. Es necesario declarar arrays globales, porque los valores de los
elementos de array deben ser preservados entre llamadas de la funcin especial start().
La funcin init() contiene la parte del cdigo utilizado en el programa slo una vez. Una parte muy
importante de accin se realiza en la lnea:
SetIndexBuffer(0,Buf_0); // Asignar un array a un buffer
Usando la funcin SetIndexBuffer() un buffer necesario (en este caso con el ndice 0) es puesto en
correspondencia con un array (en este caso Buf_0). Esto significa que para construir la primera lnea del
indicador la terminal de cliente aceptar la informacin contenida en el array Buf_0 usando para esto el
buffer cero.
Adems, se define el estilo de lnea:
SetIndexStyle (0,DRAW_LINE,STYLE_SOLID,2); // Line style
Para el buffer cero (0) la terminal de cliente debe utilizar los siguientes estilos de dibujo: lnea simple
(DRAW_LINE), lnea slida (STYLE_SOLID), ancho de lnea (2).
En las siguientes lneas:
SetIndexBuffer(1,Buf_1); // Assigning an array to a buffer
SetIndexStyle (1,DRAW_LINE,STYLE_DOT,1); // Line style
As, segn el cdigo de la funcin especial de inicio () ambas lneas del indicador se dibujarn en la
ventana principal. La primera de ellas ser una slida lnea azul con la anchura de 2, la segunda ser una
lnea de puntos rojos (STYLE_DOT) de una anchura normal (1).
Se pueden ver otros estilos de lneas en: http://book.mql4.com/appendix/styles
Calculando los valores de los elementos de arrays del indicador (estar atentos)
Los valores del los elementos arrays del indicador se calculan en la funcin especial start(). La
indexacin de barras empieza desde cero. La barra cero es la vela actual no formada an. El ndice de
barra ms cercano es el ndice 1, el siguiente es el 2 y as sucesivamente.
A medida que aparecen nuevas barras en la ventana, son cambiados los ndices de las barras ya formadas
(histricas). La nueva barra ( la actual) recibe el ndice 0, la barra a su izquierda, recin completada,
obtiene el ndice 1 y los valores de los ndices de todas las barras histricas aumentan tambin en uno.
Las lneas de un indicador se construyen en base a la informacin contenida en los arrays de indicadores.
Un array de indicador contiene informacin sobre coordenadas de puntos sobre los cuales se dibuja la
lnea del indicador. La coordenada Y de cada punto es el valor de un elemento del array de indicador,
y la coordenada X de cada punto es el valor del ndice de un elemento del array de indicador.
En el ejemplo analizado la primera lnea del indicador es dibujada usando los valores mximos de las
barras. La siguiente figura muestra esta lnea en color azul en la ventana. Fue construida en base al array
de indicador Buf_0.
Valor del ndice Valor del elemento
del array de del array de
indicador Buf_0 indicador Buf_0

0 1,3123
1 1,3124
2 1,3121
3 1,3121
4 1,3123
5 1,3125
6 1,3127

Funcin IndicatorCounted()
int IndicatorCounted()
Esta funcin devuelve la cantidad de barras que no cambiaron desde que se llam por ltima vez al
indicador. Si el indicador nunca fue adjuntado al grfico, en la primera ejecucin de la funcin start() el
valor de IndicatorCounted() ser igual a cero:
Counted_bars=IndicatorCounted(); // Nmero de barras tenidas en cuenta (counted)
Significa que el array del indicador no tiene ningn valor predefinido, es por eso que el array del
indicador debe ser calculado completamente de principio a fin. El array del indicador es calculado desde
la barra ms antigua hasta la barra cero. El ndice de la barra ms antigua, desde el cual comenzarn a
hacerse los clculos, se obtiene de la siguiente manera:
i=Bars-Counted_bars-1; // ndice de la primera barra no tenida en cuenta
Supongamos que al momento de adjuntar el indicador al grfico el nmero de barras es igual a 300, ese
ser el valor de la variable predefinida Bars, por lo que el ndice i de la primera barra no tenida en
cuenta uncounted- (la ltima barra, desde la cual comenzarn a hacerse los clculos) ser igual a 299.
Todos los valores de los elementos del array de indicador sern calculados en el ciclo while():
while(i>=0) // Loop for uncounted bars
{
Buf_0[i] = High[i]; // Value of 0 buffer on i bar
Buf_1[i] = Low[i]; // Value of 1st buffer on i bar
i--; // Calculating index of the next bar
}
Para hacer el mismo indicador anterior, pero que en cada punto se calcule el promedio de los mximos y
mnimos de las 5 ltimas barras, en el libro est el indicador con el nombre averagevalue.mq4.
Limitar la cantidad de barras histricas para el clculo
Para no hacer un indicador que pudiera resultar demasiado lento se puede utilizar la variable externa
history, agregando los siguientes comandos:
Defino la variable:
extern int History =50; // Amount of bars in calculation history
y dentro del programa:
i=Bars-Counted_bars-1; // Index of the first uncounted
if (i>History-1) // If there are too many bars...
i=History-1; // ..calculate for specified amount.
En el libro puede encontrarse un ejemplo llamado separatewindow.mq4.
Tambin pueden desplazarse las lneas de un indicador tanto horizontal como verticalmente. En el libro,
buscar el tema: Shifting Indicator Lines Vertically and Horizontally

INDICADOR PERSONALIZADO ROC (PRICE RATE OF CHANGE) - TASA DE CAMBIO DEL PRECIO
En la siguiente imagen vemos una MA(21), donde el problema que tienen este tipo de medias mviles es
su retraso con respecto al movimiento del precio. Tambin vemos una MA(5), don el problema de este
tipo de medias mviles es que cambian de direccin demasiadas veces.
La lnea naranja del grfico representa al indicador Rate Of Change o ROC (Tasa de Cambio) de la que
puede decirse que elimina los problemas mencionados anteriormente, ya que tiene un menor retraso
respecto al movimiento del precio y adems es lo suficientemente suavizada como para evitar cambiar
de direccin con demasiada frecuencia.

Esta lnea ROC naranja est construida en base a la tasa de cambio de la MA(21). Desde el punto A
hasta el punto B la lnea roja de la MA(21) cree a tasa creciente lo que origina que la lnea ROC naranja
crezca. En este caso la lnea MA(21) es una MA de soporte, lo que significa que cuando la ROC naranja
cruza hacia abajo a la MA(21) significa que la MA(21) tiene una velocidad negativa, y viceversa.
La tasa de cambio se medir respecto a una determinada cantidad de barras V, como lo muestra la
siguiente grfica:
El indicador personalizado calcular 6 lneas:
El array de indicador Line_0[] contiene los valores de la MA de soporte, en relacin a los cuales se
construirn todas las dems lneas.
Los siguientes tres arrays de indicador (Line_1[] naranja-, Line_2[] verde- y Line_3[] -marrn)
contienen valores de las tasas de cambio basadas en MAs de diferentes timeframes. La naranja es la
tasa de cambio de la MA para el timeframe actual, la verde sera la tasa de cambio de esa MA pero en el
timeframe mayor siguiente, aunque se lo mostrar en el grfico del timeframe actual. La lnea marrn es
lo mismo, pero para el timeframe siguiente.
El array de indicador Line_4[] es una lnea que muestra la tasa promedio (promedio aritmtico de las
Line_1[], Line_2[], Line_3[]).
El array de indicador Line_5[] es igual al anterior, pero suavizado.
//--------------------------------------------------------------------
// roc.mq4 (Priliv)
//--------------------------------------------------------------- 1
#property indicator_chart_window // Indicator is drawn in the main window
#property indicator_buffers 6 // Number of buffers
#property indicator_color1 Black // Line color of 0 buffer
#property indicator_color2 DarkOrange // Line color of the 1st buffer
#property indicator_color3 Green // Line color of the 2nd buffer
#property indicator_color4 Brown // Line color of the 3rd buffer
#property indicator_color5 Blue // Line color of the 4th buffer
#property indicator_color6 Red // Line color of the 5th buffer
//--------------------------------------------------------------- 2
extern int History =5000; // Amount of bars for calculation history
extern int Period_MA_0=13; // Period of supporting MA for cur. timefr.
extern int Period_MA_1=21; // Period of calculated MA
extern int Bars_V =13; // Amount of bars for calc. rate
extern int Aver_Bars =5; // Amount of bars for smoothing
extern double K =2; // Amplifier gain
//--------------------------------------------------------------- 3
int
Period_MA_2, Period_MA_3, // Calculation periods of MA for other timefr.
Period_MA_02, Period_MA_03, // Calculation periods of supp. MAs
K2, K3; // Coefficients of timeframe correlation
double
Line_0[], // Indicator array of supp. MA
Line_1[], Line_2[], Line_3[], // Indicator array of rate lines
Line_4[], // Indicator array sum
Line_5[], // Indicator array - sum, smoothed
Sh_1, Sh_2, Sh_3; // Amount of bars for rates calc.
//--------------------------------------------------------------- 4
int init() // Special function init()
{
SetIndexBuffer(0,Line_0); // Assigning an array to a buffer
SetIndexBuffer(1,Line_1); // Assigning an array to a buffer
SetIndexBuffer(2,Line_2); // Assigning an array to a buffer
SetIndexBuffer(3,Line_3); // Assigning an array to a buffer
SetIndexBuffer(4,Line_4); // Assigning an array to a buffer
SetIndexBuffer(5,Line_5); // Assigning an array to a buffer
SetIndexStyle (5,DRAW_LINE,STYLE_SOLID,3); // line style
//--------------------------------------------------------------- 5
switch(Period()) // Calculating coefficient for..
{ // .. different timeframes
case 1: K2=5;K3=15; break;// Timeframe M1
case 5: K2=3;K3= 6; break;// Timeframe M5
case 15: K2=2;K3= 4; break;// Timeframe M15
case 30: K2=2;K3= 8; break;// Timeframe M30
case 60: K2=4;K3=24; break;// Timeframe H1
case 240: K2=6;K3=42; break;// Timeframe H4
case 1440: K2=7;K3=30; break;// Timeframe D1
case 10080: K2=4;K3=12; break;// Timeframe W1
case 43200: K2=3;K3=12; break;// Timeframe MN
}
//--------------------------------------------------------------- 6
Sh_1=Bars_V; // Period of rate calcul. (bars)
Sh_2=K2*Sh_1; // Calc. period for nearest TF
Sh_3=K3*Sh_1; // Calc. period for next TF
Period_MA_2 =K2*Period_MA_1; // Calc. period of MA for nearest TF
Period_MA_3 =K3*Period_MA_1; // Calc. period of MA for next TF
Period_MA_02=K2*Period_MA_0; // Period of supp. MA for nearest TF
Period_MA_03=K3*Period_MA_0; // Period of supp. MA for next TF
//--------------------------------------------------------------- 7
return; // Exit the special function init()
}
//--------------------------------------------------------------- 8
int start() // Special function start()
{
//--------------------------------------------------------------- 9
double
MA_0, MA_02, MA_03, // Supporting MAs for diff. TF
MA_c, MA_p, // Current and previous MA values
Sum; // Technical param. for sum accumul.
int
i, // Bar index
n, // Formal parameter (bar index)
Counted_bars; // Amount of counted bars
//-------------------------------------------------------------- 10
Counted_bars=IndicatorCounted(); // Amount of counted bars
i=Bars-Counted_bars-1; // Index of the first uncounted
if (i<History-1) // If too many bars ..
i=History-1; // ..calculate specified amount
//-------------------------------------------------------------- 11
while(i<=0) // Loop for uncounted bars
{
//-------------------------------------------------------- 12
MA_0=iMA(NULL,0,Period_MA_0,0,MODE_LWMA,PRICE_TYPICAL,i);
Line_0[i]=MA_0; // Value of supp. MA
//-------------------------------------------------------- 13
MA_c=iMA(NULL,0,Period_MA_1,0,MODE_LWMA,PRICE_TYPICAL,i);
MA_p=iMA(NULL,0,Period_MA_1,0,MODE_LWMA,PRICE_TYPICAL,i+Sh_1);
Line_1[i]= MA_0+K*(MA_c-MA_p);// Value of 1st rate line
//-------------------------------------------------------- 14
MA_c=iMA(NULL,0,Period_MA_2,0,MODE_LWMA,PRICE_TYPICAL,i);
MA_p=iMA(NULL,0,Period_MA_2,0,MODE_LWMA,PRICE_TYPICAL,i+Sh_2);
MA_02= iMA(NULL,0,Period_MA_02,0,MODE_LWMA,PRICE_TYPICAL,i);
Line_2[i]=MA_02+K*(MA_c-MA_p);// Value of 2nd rate line
//-------------------------------------------------------- 15
MA_c=iMA(NULL,0,Period_MA_3,0,MODE_LWMA,PRICE_TYPICAL,i);
MA_p=iMA(NULL,0,Period_MA_3,0,MODE_LWMA,PRICE_TYPICAL,i+Sh_3);
MA_03= iMA(NULL,0,Period_MA_03,0,MODE_LWMA,PRICE_TYPICAL,i);
Line_3[i]=MA_03+K*(MA_c-MA_p);// Value of 3rd rate line
//-------------------------------------------------------- 16
Line_4[i]=(Line_1[i]+Line_2[i]+Line_3[i])/3;// Summary array
//-------------------------------------------------------- 17
if (Aver_Bars>0) // If wrong set smoothing
Aver_Bars=0; // .. no less than zero
Sum=0; // Technical means
for(n=i; n>=i+Aver_Bars; n++) // Summing last values
Sum=Sum + Line_4[n]; // Accum. sum of last values
Line_5[i]= Sum/(Aver_Bars+1); // Indic. array of smoothed line
//-------------------------------------------------------- 18
i--; // Calculating index of the next bar
//-------------------------------------------------------- 19
}
return; // Exit the special function start()
}
//-------------------------------------------------------------- 20 --
En el bloque 6-7 se calculan los perodos de las MAs para los timeframes superiores, con los cuales se
calculan las tasas. Se calculan tambin los perodos de las MAs de soporte en las cuales se miden las
tasas, para los timeframes mayores.
En el bloque 5-6 se determinan los coeficientes correspondientes para estos clculos.
Los clculos en la funcin especial start() son muy simples:
En el bloque 12-13 se calculan los valores de las MAs de soporte para el timeframe actual (lnea negra
del indicador).
En el boque 13-14 se definen los valores del array de indicador Line_1[] para la construccin de la lnea
ROC en el timeframe actual (lnea naranja). Aqu la tasa es definida como la diferencia entre el valor de
la Media Mvil analizada en la barra actual y el valor de la Media Movil cuyo ndice es Sh_1 mayor al
actual, es decir, lo que en el grfico superior se muestra como MA_c - MA_p. El valor del array de
indicador Line_1[] en la barra actual est constituido por los valores de la MA de soporte y el valor de la
tasa K, que es un coeficiente de incremento que se determina en una variable externa (K):
Line_1[i]= MA_0+K*(MA_c-MA_p);// value of 1st rate line
En los bloques 14-16 se realizan clculos anlogos para construir las lneas de las tasas para los otros
dos timeframes. Las MA de soporte para estos arrays no se muestran en el indicador.
En el bloque 16-17 se definen los valores del array de indicador Line_4[] para construir la lnea de la
tasa promedio (azul) la cual es un promedio aritmtico simple.
En el bloque 17-18 se calcula una lnea de tasa promedio suavizada (roja gruesa, array de indicador
Line_5[]). El suavizado se realiza a travs de un promedio simple. La cantidad de barras para el
suavizado es definida mediante la variable externa Aver_Bars.

Lnea negra: MA de soporte para construir una lnea de tasa de precio en el timeframe actual.
Lnea naranja: tasa de cambio del precio en el timeframe actual.
Lnea verde: tasa de cambio del precio en el prximo timeframe superior.
Lnea marrn: tasa de cambio del precio en el prximo timeframe superior.
Lnea azul: lnea promedio de la tasa de cambio del precio.
Lnea roja: lnea promedio suavizada de la tasa de cambio del precio.

Una variante a este indicador sera que se dibuje en la ventana inferior al grfico y que en lugar de
moverse alrededor de una MA de soporte, lo haga alrededor de una lnea horizontal con el valor 0. El
indicador descripto se encuentra en el libro.
USO COMBINADO DE PROGRAMAS
Funcin iCustom()
Se utiliza en los EAs para operar usando indicadores personalizados.
double iCustom(string symbol, int timeframe, string name, ..., int mode, int shift)
El indicador personalizado debe estar compilado (con la extensin .ex4) y localizado en la carpeta
\experts\indicators
Parmetros
symbol: smbolo en el cual ser calculado el indicador personalizado. NULL indica el smbolo actual.
timeframe: 0 significa el perodo del grfico actual.
name: nombre del indicador personalizado.
: lista de parmetros (si es necesario). Los parmetros transferidos deben corresponderse con el orden
en que se declararon y el tipo de variables externas del indicador personalizado.
mode: ndice de una lnea del indicador. Pueden ir desde - hasta 7 y deben corresponderse con el ndice
usado por alguna de las funciones SetIndexBar.
shift: ndice de un valor obtenido del buffer de un indicador (desplazamiento hacia atrs desde la barra
actual de una cierta cantidad de barras).
Problema 26: Escribir un EA con la siguiente estrategia basada en el indicador personalizado
rocseparate.mq4 (analizado en el libro): Compra: cuando la lnea ROC (naranja) cruza desde abajo hacia
arriba la lnea suavizada de tasa promedio (roja gruesa). Venta: el cruce opuesto.

Se usa como base el EA tradingexperts.mq4 descripto en la seccin Asesor Experto Simple. La solucin
al problema planteado es la siguiente:
//--------------------------------------------------------------------
// shared.mq4
//--------------------------------------------------------------- 1 --
// M15
extern double StopLoss =100; // SL for an opened order
extern double TakeProfit=35; // TP for an opened order
extern double Lots =0.1; // Strictly set amount of lots
extern double Prots =0.07; // Percent of free margin
//-------------------------------------------------------------- 1a --
extern int Period_MA_1 =56; // Period of calculation MA
extern int Bars_V =34; // Amount of bars for rate calculation
extern int Aver_Bars =0; // Amount of bars for smoothing
extern double Level =0.001;
//-------------------------------------------------------------- 1b --
bool Work=true; // EA will work.
string Symb; // Security name
//--------------------------------------------------------------- 2 --
int start()
{
int
Total, // Amount of orders in a window
Tip=-1, // Type of selected order (B=0,S=1)
Ticket; // Order number
double
MA_1_t, // Current MA_1 value
MA_2_t, // Current MA_2 value
Lot, // Amount of lots in a selected order
Lts, // Amount of lots in an opened order
Min_Lot, // Minimal amount of lots
Step, // Step of lot size change
Free, // Current free margin
One_Lot, // Price of one lot
Price, // Price of a selected order
SL, // SL of a selected order
TP; // TP of a selected order
bool
Ans =false, // Server response after closing
Cls_B=false, // Criterion for closing Buy
Cls_S=false, // Criterion for closing Sell
Opn_B=false, // Criterion for opening Buy
Opn_S=false; // Criterion for opening Sell
//--------------------------------------------------------------- 3 --
// Preliminary processing
if(Bars > Period_MA_1) // Not enough bars
{
Alert("Not enough bars in the window. EA doesn't work.");
return; // Exit start()
}
if(Work==false) // Critical error
{
Alert("Critical error. EA doesn't work.");
return; // Exit start()
}
//--------------------------------------------------------------- 4 --
// Orders accounting
Symb=Symbol(); // Security name
Total=0; // Amount of orders
for(int i=1; i>=OrdersTotal(); i++) // Loop through orders
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If there is the next one
{ // Analyzing orders:
if (OrderSymbol()!=Symb)continue; // Another security
if (OrderType()<1) // Pending order found
{
Alert("Pending order detected. EA doesn't work.");
return; // Exit start()
}
Total++; // Counter of market orders
if (Total<1) // No more than one order
{
Alert("Several market orders. EA doesn't work.");
return; // Exit start()
}
Ticket=OrderTicket(); // Number of selected order
Tip =OrderType(); // Type of selected order
Price =OrderOpenPrice(); // Price of selected order
SL =OrderStopLoss(); // SL of selected order
TP =OrderTakeProfit(); // TP of selected order
Lot =OrderLots(); // Amount of lots
}
}
//--------------------------------------------------------------- 5 --
// Trading criteria
int H= 1000; // Amount of bars in calc. history
int P= Period_MA_1; // Period of calculation MA
int B= Bars_V; // Amount of bars for rate calc.
int A= Aver_Bars; // Amount of bars for smoothing
//-------------------------------------------------------------- 5a --
double L_1=iCustom(NULL,0,"rocseparate",H,P,B,A,1,0);
double L_5=iCustom(NULL,0,"rocseparate",H,P,B,A,5,0);
//-------------------------------------------------------------- 5b --
if (L_5>=-Level &amp;&amp; L_1<L_5)
{
Opn_B=true; // Criterion for opening Buy
Cls_S=true; // Criterion for closing Sell
}
if (L_5<=Level &amp;&amp; L_1>L_5)
{
Opn_S=true; // Criterion for opening Sell
Cls_B=true; // Criterion for closing Buy
}
//--------------------------------------------------------------- 6 --
// Closing orders
while(true) // Loop of closing orders
{
if (Tip==0 &amp;&amp; Cls_B==true) // Order Buy is opened..
{ // and there is criterion to close
Alert("Attempt to close Buy ",Ticket,". Waiting for response..");
RefreshRates(); // Refresh rates
Ans=OrderClose(Ticket,Lot,Bid,2); // Closing Buy
if (Ans==true) // Success :)
{
Alert ("Closed order Buy ",Ticket);
break; // Exit closing loop
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}

if (Tip==1 &amp;&amp; Cls_S==true) // Order Sell is opened..


{ // and there is criterion to close
Alert("Attempt to close Sell ",Ticket,". Waiting for response..");
RefreshRates(); // Refresh rates
Ans=OrderClose(Ticket,Lot,Ask,2); // Closing Sell
if (Ans==true) // Success :)
{
Alert ("Closed order Sell ",Ticket);
break; // Exit closing loop
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
break; // Exit while
}
//--------------------------------------------------------------- 7 --
// Order value
RefreshRates(); // Refresh rates
Min_Lot=MarketInfo(Symb,MODE_MINLOT); // Minimal number of lots
Free =AccountFreeMargin(); // Free margin
One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED);// Price of 1 lot
Step =MarketInfo(Symb,MODE_LOTSTEP); // Step is changed

if (Lots < 0) // If lots are set,


Lts =Lots; // work with them
else // % of free margin
Lts=MathFloor(Free*Prots/One_Lot/Step)*Step;// For opening

if(Lts > Min_Lot) Lts=Min_Lot; // Not less than minimal


if (Lts*One_Lot < Free) // Lot larger than free margin
{
Alert(" Not enough money for ", Lts," lots");
return; // Exit start()
}
//--------------------------------------------------------------- 8 --
// Opening orders
while(true) // Orders closing loop
{
if (Total==0 &amp;&amp; Opn_B==true) // No new orders +
{ // criterion for opening Buy
RefreshRates(); // Refresh rates
SL=Bid - New_Stop(StopLoss)*Point; // Calculating SL of opened
TP=Bid + New_Stop(TakeProfit)*Point; // Calculating SL of opened
Alert("Attempt to open Buy. Waiting for response..");
Ticket=OrderSend(Symb,OP_BUY,Lts,Ask,2,SL,TP);//Opening Buy
if (Ticket < 0) // Success :)
{
Alert ("Opened oredr Buy ",Ticket);
return; // Exit start()
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
if (Total==0 &amp;&amp; Opn_S==true) // No new orders +
{ // criterion for opening Sell
RefreshRates(); // Refresh rates
SL=Ask + New_Stop(StopLoss)*Point; // Calculating SL of opened
TP=Ask - New_Stop(TakeProfit)*Point; // Calculating SL of opened
Alert("Attempt to open Sell. Waiting for response..");
Ticket=OrderSend(Symb,OP_SELL,Lts,Bid,2,SL,TP);//Opening Sels
if (Ticket < 0) // Success :)
{
Alert ("Opened order Sell ",Ticket);
return; // Exit start()
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
break; // Exit while
}
//--------------------------------------------------------------- 9 --
return; // Exit start()
}
//-------------------------------------------------------------- 10 --
int Fun_Error(int Error) // Function of processing errors
{
switch(Error)
{ // Not crucial errors
case 4: Alert("Trade server is busy. Trying once again..");
Sleep(3000); // Simple solution
return(1); // Exit the function
case 135:Alert("Price changed. Trying once again..");
RefreshRates(); // Refresh rates
return(1); // Exit the function
case 136:Alert("No prices. Waiting for a new tick..");
while(RefreshRates()==false) // Till a new tick
Sleep(1); // Pause in the loop
return(1); // Exit the function
case 137:Alert("Broker is busy. Trying once again..");
Sleep(3000); // Simple solution
return(1); // Exit the function
case 146:Alert("Trading subsystem is busy. Trying once again..");
Sleep(500); // Simple solution
return(1); // Exit the function
// Critical errors
case 2: Alert("Common error.");
return(0); // Exit the function
case 5: Alert("Old terminal version.");
Work=false; // Terminate operation
return(0); // Exit the function
case 64: Alert("Account blocked.");
Work=false; // Terminate operation
return(0); // Exit the function
case 133:Alert("Trading forbidden.");
return(0); // Exit the function
case 134:Alert("Not enough money to execute operation.");
return(0); // Exit the function
default: Alert("Error occurred: ",Error); // Other variants
return(0); // Exit the function
}
}
//-------------------------------------------------------------- 11 --
int New_Stop(int Parametr) // Checking stop levels
{
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// Minimal distance
if (Parametr<Min_Dist) // If less than allowed
{
Parametr=Min_Dist; // Set allowed
Alert("Increased distance of stop level.");
}
return(Parametr); // Returning value
}
//-------------------------------------------------------------- 12 --
Vamos a analizar qu modificaciones se introdujeron en el cdigo del EA tradingexpert.mq4. La parte
principal del EA utilizado como base no ha cambiado. Los cambios se han hecho en dos bloques: 1-2 y
5-6. En el bloque 5-6 se calculan los criterios de comercio.
Las rdenes en espera de ser ejecutadas no estn permitidas y solo se permite una orden abierta al
mismo tiempo. Adems, cuando por ejemplo hay una compra abierta y se produce una seal de venta
esto es motivo para cerrar la operacin de compra.
Para poder usar en este EA los resultados de los clculos realizados en el indicador personalizado
rocseparate.mq4, es necesario utilizar la funcin iCustom ():
double L_1 = iCustom(NULL,0,"rocseparate",H,P,B,A,1,0);
double L_5 = iCustom(NULL,0,"rocseparate",H,P,B,A,5,0);
NULL: hace referencia al smbolo del grfico actual.
0: hace referencia al timeframe actual.
rocseparate: nombre del indicador personalizado.
H,P,B,A: lista de parmetros ajustables. El indicador personalizado rocseparate.mq4 posee parmetros
ajustables detallados en el boque 2-3. Transcribo a continuacin dicho bloque:
//--------------------------------------------------------------- 2 --
extern int History =5000; // Amount of bars in calculation history
extern int Period_MA_1=21; // Period of calculated MA
extern int Bars_V =13; // Amount of bars for calc. rate
extern int Aver_Bars =5; // Amount of bars for smoothing
//--------------------------------------------------------------- 3 --
Para que un usuario pueda configurar los valores de estos parmetros desde un EA, estos deben estar
especificados en la lista de parmetros transferidos de la funcin iCustom(). En el EA pueden diferir los
valores de estos parmetros con respecto a los especificados en el indicador
1 (5): lnea ndice del indicador. En el indicador personalizado rocseparate.mq4 se usaron 6 arrays de
indicador. La lnea ROC en el timeframe actual (naranja) es construida en base a los valores de los
elementos del array Line_1[], para los cuales se usa el buffer de ndice 1. La lnea de la tasa promedio
suavizada est basada en los valores de los elementos del array Line_5[], para los cuales se usa el buffer
de ndice 5.
0: ndice del valor obtenido del buffer de un indicador (desplazamiento hacia atrs desde la barra actual
de una cierta cantidad de barras). En esta caso usamos el valor que tiene la lnea del indicador en la barra
cero, es por eso que especificamos un ndice igual a 0.
En el bloque 1a-1b se especifican variables externas a fin de que el usuario pueda determinar sus
valores.
En el bloque 5-5a los valores de estos parmetros son asignados a otras variables con nombres ms
cortos a fin de presentar en forma ms clara el cdigo del bloque 5a-5b.
En el bloque 5-6 se describe el criterio para operar, el cual es calculado en base a valores de elementos
de array obtenidos usando la funcin iCustom(). Por ejemplo, el criterio para abrir una operacin de
compra y cerrar una de venta es el siguiente:
if (L_5<=-Level && L_1>L_5)
{
Opn_B = true; // Criterion for opening Buy
Cls_S = true; // Criterion for closing Sell
}
Si el ltimo valor conocido de la lnea de tasa promedio suavizada (L_5) es menor que un nivel
especificado (valor del parmetro ajustable Level = 0.001) y el ltimo valor conocido de la lnea ROC
en el timeframe actual (L_1) es mayor que la lnea de tasa promedio suavizada (L_5), entonces se
confirma el criterio necesario para abrir una operacin de compra y cerrar una de venta.
FUNCIONES STANDARD
Funciones Comunes
En el libro se muestra las funciones ms comunes. Entre lo ms destacable, se muestra como ejemplo un
EA que hace aparecer un mensaje en una ventana, cinco minutos antes del lanzamiento de cada noticia
importante, preguntando si se desean cerrar todas las operaciones.
Objetos Grficos
Son imgenes en la ventana de smbolo, que pueden ser seleccionados, movidos, modificados o
eliminados.
Incluye, entre otros, niveles de Fibonacci, canales, lneas horizontales y verticales, rectngulos, etc.
En el libro se incluye un EA que dibuja un canal para las n barras anteriores.
Operaciones con los Grficos
En el libro se muestra un EA que genera un texto sobre el grfico que nos informa lo que est haciendo
un indicador determinado, por ejemplo: Momentum est bajando, o RSI est entre 30 y 70.

Arrays y Timeseries
Es muy importante recordar que en MQL4 la secuencia de cualquier tipo de elementos siempre se
numera comenzando desde cero.
Ya se mencion anteriormente que no debe confundirse el valor del ndice de un elemento de array con
el nmero de elementos en el array. Por ejemplo, si se declara un array:
int Erray_OHL[3]; // Array declaration
Esto significa que el array de una dimensin llamada Erray_OHL contiene tres elementos.
La indexacin de los elementos comienza en cero, es decir que el primero de los tres elementos tiene el
ndice 0 (Erray_OHL[0]), el segundo tiene el ndice 1 (Erray_OHL[1]) y el tercer elemento tiene el
ndice 2 (Erray_OHL[2]). De esto se desprende que el valor de ndice mximo es 2, ya que el array
contiene 3 elementos.
Lo mismo puede decirse de la numeracin de las dimensiones de un array. Por ejemplo, si un array se
declara as:
int Erray_OHL[3][8]; // Array declaration
Esto significa que el array tiene dos dimensiones. La primera dimensin especifica el nmero de filas
(en este caso son 3) y la segunda especifica el nmero de elementos en la fila (es decir, el nmero de
columnas, en este caso son 8).
Cada dimensin en s misma tambin est numerada. La primera dimensin tiene el nmero 0 y la
segunda el nmero 1. El nmero de dimensiones se usa, por ejemplo, en la funcin ArrayRange().
Funcin ArrayRange()
int ArrayRange(object array[], int range_index)
Esta funcin devuelve el nmero de elementos de la dimensin especificada del array.
Problema 27: El array Mas_1 contiene los valores de una matriz de 3x5. Obtenga los valores del array
Mas_2 que contengan los elementos cuyos valores sean iguales a los valores de la matriz transpuesta.
Use valores arbitrarios para los elementos.
Matriz inicial: array Mas_1
ndices 0 1 2 3 4
0 1 2 3 4 5
1 11 12 13 14 15
2 21 22 23 24 25
Matriz transpuesta: array Mas_2
ndices 0 1 2
0 1 11 21
1 2 12 22
2 3 13 23
3 4 14 24
4 5 15 25
//--------------------------------------------------------------------
// matrix.mq4
//--------------------------------------------------------------- 1 --
int start() // Special function start()
{
int Mas_1[3][5]={1,2,3,4,5, 11,12,13,14,15, 21,22,23,24,25};
int Mas_2[5][3];
int R0= ArrayRange( Mas_1, 0); // Number of elements in first dim.
int R1= ArrayRange( Mas_1, 1); // Number of elements in second dim.
for(int i=0; i<R0; i++)
{
for(int j=0; j<R1; j++)
Mas_2[j][i]=Mas_1[i][j]; // Matrix transposition
}
Comment( Mas_2[0][0]," ",Mas_2[0][1]," ",Mas_2[0][2],"\n",
Mas_2[1][0]," ",Mas_2[1][1]," ",Mas_2[1][2],"\n",
Mas_2[2][0]," ",Mas_2[2][1]," ",Mas_2[2][2],"\n",
Mas_2[3][0]," ",Mas_2[3][1]," ",Mas_2[3][2],"\n",
Mas_2[4][0]," ",Mas_2[4][1]," ",Mas_2[4][2]);
return; // Fin de la funcin start()
}
//--------------------------------------------------------------- 2 --
Se abren dos arrays en la funcin start(). El array Mas_1 tiene 3 filas de 5 elementos cada una y el
array Mas_2 tiene 5 filas de 3 elementos cada una. La reescritura de los valores se hace en la siguiente
entrada: Mas_2[[j][i] = Mas_1[i][j]; // Matrix transposition
A fin de calcular el nmero de iteraciones de dos operadores de ciclo incrustados debemos saber el
nmero de elementos de cada dimensin. Para determinar el nmero de elementos de la primera y
segunda dimensin del array Mas_1 se hacen los siguientes clculos:
int R0 = ArrayRange( Mas_1, 0); // Number of elements in first dim.
int R1 = ArrayRange( Mas_1, 1); // Number of elements in second dim.
Ntese que el nmero 0 es utilizado para la primera dimensin y el nmero 1 para la segunda. Los
valores obtenidos para las variables R0 y R1 son usados para determinar el nmero de iteraciones en los
ciclos for.
Los valores recibidos del array Mas_2 son mostrados en la pantalla usando la funcin Comment().

En el libro pueden encontrarse otras funciones de Arrays y Timeseries.

Funciones GlobalVariable
Un programa correctamente diseado debe eliminar sus variables globales cuando finaliza su operatoria.
No deben quedar variables globales en la terminal de usuario una vez que se ha salido de todos los
programas.
Debido a errores involuntarios, podran quedar variables globales por lo que un programador debe
borrarlas manualmente antes de prximo inicio de un programa. Para automatizar este proceso se puede
crear un script que elimine todas las variables globales de la terminal de usuario.
Funcin GlobalVariablesDeleteAll()
int GlobalVariablesDeleteAll(string prefix_name=NULL)
Si no se especifica un prefijo para el nombre, entonces sern eliminadas todas las variables globales. De
otro modo slo sern eliminadas las variables globales cuyos nombres comiencen con el prefijo
especificado. La funcin devuelve la cantidad de variables eliminadas.
En el libro pueden encontrarse otras funciones de Variables Globales.

Otros tipos de Funciones


Funciones String , Funciones de Tiempo y Fecha , Operaciones con Archivos, Funciones Matemticas,
Funciones para Indicadores Personalizados, Funciones sobre la cuenta y la terminal de usuario ,
Funciones para operar
CREACIN DE UN PROGRAMA NORMAL
ESTRUCTURA DE UN PROGRAMA NORMAL
La caracterstica sobresaliente de un programa normal es su estructura, que permite usar fcilmente
funciones definidas por el usuario. Por una razn de conveniencia, las mismas usualmente son colocadas
en archivos de inclusin .mqh que son almacenados en la carpeta \experts\include.
Las funciones definidas por el usuario pueden a su vez llamar a otras funciones definidas por el usuario.

UTILIZACIN DE ARCHIVOS DE INCLUSIN


Muchas veces los programas son sumamente extensos y por lo tanto podra ser casi imposible encontrar
y eliminar un determinado error que se presentara en sus cdigos.
Para solucionar este problema el cdigo de un programa puede ser dividido en diversos fragmentos, cada
uno de los cuales puede ser almacenado en archivos de inclusin.
Directiva #include
#include <File name>
#include "File name"
Esta directiva puede colocarse en cualquier lugar de un programa, pero lo recomendable es situarlas al
inicio del mismo.
El preprocesador reemplazar la lnea #include <File name> ( #include "File name") con el contenido
del archivo cuyo nombre se especific.
Los parntesis en ngulo (< >) significan que el archivo se buscar en la carpeta \experts\include. Las
comillas significan que el archivo se buscar en el directorio donde est ubicado el EA.
Ejemplo:
//----------------------------------------------------------------------------------------
// usualexpert.mq4
//----------------------------------------------------------------------------------- 1
#property copyright "Copyright Book, 2007"
//----------------------------------------------------------------------------------- 2
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh>
//----------------------------------------------------------------------------------- 3
#include <Variables.mqh> // Description of variables
#include <Check.mqh> // Checking legality of programs used
#include <Terminal.mqh> // Order accounting
#include <Events.mqh> // Event tracking function
#include <Inform.mqh> // Data function
#include <Trade.mqh> // Trade function
#include <Open_Ord.mqh> // Opening one order of the preset type
#include <Close_All.mqh> // Closing all orders of the preset type
#include <Tral_Stop.mqh> // StopLoss modification for all orders of the preset type
#include <Lot.mqh> // Calculation of the amount of lots
#include <Criterion.mqh> // Trading criteria
#include <Errors.mqh> // Error processing function
//----------------------------------------------------------------------------------- 4
int init() // Special function 'init'
{
Level_old=MarketInfo(Symbol(),MODE_STOPLEVEL ); //Min. distance
Terminal(); // Order accounting function
return; // Exit init()
}
//----------------------------------------------------------------------------------- 5
int start() // Special function 'start'
{
if(Check()==false) // If the usage conditions..
return; // ..are not met, then exit
PlaySound("tick.wav"); // At every tick
Terminal(); // Order accounting function
Events(); // Information about events
Trade(Criterion()); // Trade function
Inform(0); // To change the color of objects
return; // Exit start()
}
//----------------------------------------------------------------------------------- 6
int deinit() // Special function deinit()
{
Inform(-1); // To delete objects
return; // Exit deinit()
}
//----------------------------------------------------------------------------------- 7
Al ser compilado este EA, cada lnea conteniendo la directiva #include es reemplazada en el programa
con el texto contenido en el archivo indicado. De esta manera, el archivo ejecutable .ex4 es creado en
base al cdigo completo del EA, en el cual cada lnea #include<nombre de archivo> (o #include
"nombre de archivo") es reemplazada por el fragmento de cdigo correspondiente.
El archivo de inclusin Variables.mqh contiene la descripcin de las variables globales utilizadas por las
diferentes funciones definidas por el usuario:
//----------------------------------------------------------------------------
// Variables.mqh
//----------------------------------------------------------------------- 1
// Description of global variables
extern double Lots = 0.0; // Amount of lots
extern int Percent = 0; // Allocated funds percentage
extern int StopLoss =100; // StopLoss for new orders (in points)
extern int TakeProfit =40; // TakeProfit for new orders (in points)
extern int TralingStop=100; // TralingStop for market orders (in points)
//----------------------------------------------------------------------- 2
int
Level_new, // New value of the minimum distance
Level_old, // Previous value of the minimum distance
Mas_Tip[6]; // Order type array
// [] order type: 0=B,1=S,2=BL,3=SL,4=BS,5=SS
//----------------------------------------------------------------------- 3
double
Lots_New, // Amount of lots for new orders
Mas_Ord_New[31][9], // Current order array ..
Mas_Ord_Old[31][9]; // .. old order array
// 1st index = order number in the list
// [][0] cannot be detected
// [][1] order open price (abs. price value)
// [][2] StopLoss of the order (abs. price value)
// [][3] TakeProfit of the order (abs. price value)
// [][4] order number
// [][5] order volume (abs. price value)
// [][6] order type 0=B,1=S,2=BL,3=SL,4=BS,5=SS
// [][7] Order magic number
// [][8] 0/1 the fact of availability of comments
//----------------------------------------------------------------------- 4 --

CONTABILIDAD DE RDENES
En el libro se describen tres arrays que se utilizan para brindarnos los datos de todas las operaciones, ya
sean las abiertas con anterioridad, las abiertas en este instante, o la cantidad de cada tipo de operacin
(Mas_Ord_Old, Mas_Ord_New y Mas_Tip, respectivamente).
Los array Mas_Ord_New y Mas_Ord_Old son similares y tienen la misma cantidad de dimensiones. La
diferencia entre ellos es que el primero refleja el estado actual de las rdenes actuales, mientras que el
segundo muestra el estado anterior de las mismas - en la ejecucin anterior de la funcin Terminal().
Correspondencia entre los elementos de los array Mas_Ord_New y Mas_Ord_Old y las caractersticas
de las rdenes:
Not Open Stop Take Order Volume, Order Magic
Comment
defined Price Loss Profit Number in lots Type Number
Indexes 0 1 2 3 4 5 6 7 8
0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 0.0 1,2583 1 1,2550 123456.0 1.4 1.0 1177102416.0 1.0
2 0.0 1,2450 1 1,2415 123458.0 2.5 2.0 1177103358.0 0.0
3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
30 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
El primer ndice del array (lneas) define la cantidad de rdenes en el array.
En la primera lnea del array estn ubicadas las caractersticas de la primera orden detectada (entre todas
las rdenes de mercado abiertas y rdenes pendientes colocadas); en la segunda lnea estn ubicadas las
caractersticas de la segunda orden detectada; y as sucesivamente.
El tamao del array para el primer ndice es igual a 31, ya que el array se pens para almacenar la
informacin de un mximo de 30 rdenes, lo cual resulta ms que suficiente para casi cualquier tipo de
estrategia.
El segundo ndice del array (columnas) representa las caractersticas de las rdenes.
Cada elemento del array con el segundo ndice igual a 1 contiene el valor del precio de apertura de la
orden. Cada elemento del array con el segundo ndice igual a 2 contiene el valor del Stop Loss de la
orden. Cada elemento del array con el segundo ndice igual a 3 contiene el valor del Take Profit de la
orden. Y as sucesivamente.
El elemento del array con el ndice [0][0] contiene un valor que es igual a la cantidad total de rdenes
disponibles en el array.
La tabla anterior muestra un array que contiene informacin sobre dos rdenes que estn
simultneamente disponibles en un momento determinado. El elemento de array Mas_Ord_New[0][0]
tiene el valor 2.0, es decir que la cantidad total de rdenes es igual a dos.
Los elementos en la primera lnea del array contienen los valores de las caractersticas de una Orden de
Venta (Mas_Ord_New[1][6] = 1.0) abierta con 1.4 lotes (Mas_Ord_New[1][5] =1.4) y con el nmero
123456 (Mas_Ord_New[1][4] =123456.0). El valor del elemento Mas_Ord_New[1][8] =1.0 significa
que la orden contiene un campo de comentario No vaco.
En la segunda lnea del array estn contenidos los valores que caracterizan a la segunda orden. En
particular, el elemento Mas_Ord_New[2][6] tiene el valor 2.0, lo que significa que se trata de una orden
Buy Limit.
El array Mas_Tip muestra la cantidad existente de rdenes de cada tipo. Los valores de los ndices de
este array son asignados de acuerdo al Tipo de Operacin:
Constant Value Trading Operation
OP_BUY 0 Buy
OP_SELL 1 Sell
OP_BUYLIMIT 2 Pending order BUY LIMIT
OP_SELLLIMIT 3 Pending order SELL LIMIT
OP_BUYSTOP 4 Pending order BUY STOP
OP_SELLSTOP 5 Pending order SELL STOP

Esto significa que el elemento del array Mas_Tip con ndice 0 contiene la cantidad de rdenes de
mercado de Compra disponibles simultneamente.
Para dar un ejemplo, los elementos del array Mas_Tip tienen los siguientes valores:
Buy Sell BuyLimit SellLimit BuyStop SellStop
Index 0 1 2 3 4 5
Value 0 1 1 0 0 0

En este caso, los valores de los elementos del array Mas_Tip implican los siguiente: Mas_Tip[1] igual a
1 significa que hay una orden de mercado de venta; Mas_Tip[2] igual a 1 significa que hay una orden
pendiente Buy Limit; los dems elementos en el array tienen el valor 0, lo cual significa que no existen
rdenes de los dems tipos. Si por ejemplo habra 3 rdenes pendientes Buy Stop, el elemento
Mas_Tip[4] tendra el valor de 3.
El archivo de inclusin Terminal.mqh contiene la descripcin de la funcin de contabilidad de rdenes
Terminal():
//--------------------------------------------------------------------
// Terminal.mqh
//------------------------------------------------------------------------------ 1
// Order accounting function
// Global variables:
// Mas_Ord_New[31][9] // The latest known orders array
// Mas_Ord_Old[31][9] // The preceding (old) orders array
// 1st index = order number
// [][0] not defined
// [][1] order open price (abs. price value)
// [][2] StopLoss of the order (abs. price value)
// [][3] TakeProfit of the order (abs. price value)
// [][4] order number
// [][5] order volume in lots (abs. price value)
// [][6] order type 0=B,1=S,2=BL,3=SL,4=BS,5=SS
// [][7] order magic number
// [][8] 0/1 comment availability
// Mas_Tip[6] // Array of the amount of orders of all types
// [] order type: 0=B,1=S,2=BL,3=SL,4=BS,5=SS
//------------------------------------------------------------------------------ 2
int Terminal()
{
int Qnt=0; // Orders counter
//------------------------------------------------------------------------------ 3
ArrayCopy(Mas_Ord_Old, Mas_Ord_New); // Saves the preceding history
Qnt=0; // Zeroize orders counter
ArrayInitialize(Mas_Ord_New,0); // Zeroize the array
ArrayInitialize(Mas_Tip, 0); // Zeroize the array
//------------------------------------------------------------------------------ 4
for(int i=0; i<OrdersTotal(); i++) // For market and pending orders
{
if((OrderSelect(i,SELECT_BY_POS)==true) //If there is the next one
&& (OrderSymbol()==Symbol())) //.. and our currency pair
{
//--------------------------------------------------------------------- 5
Qnt++; // Amount of orders
Mas_Ord_New[Qnt][1]=OrderOpenPrice(); // Order open price
Mas_Ord_New[Qnt][2]=OrderStopLoss(); // SL price
Mas_Ord_New[Qnt][3]=OrderTakeProfit(); // TP price
Mas_Ord_New[Qnt][4]=OrderTicket(); // Order number
Mas_Ord_New[Qnt][5]=OrderLots(); // Amount of lots
Mas_Tip[OrderType()]++; // Amount of orders of the type
Mas_Ord_New[Qnt][6]=OrderType(); // Order type
Mas_Ord_New[Qnt][7]=OrderMagicNumber(); // Magic number
if (OrderComment()=="")
Mas_Ord_New[Qnt][8]=0; // If there is no comment
else
Mas_Ord_New[Qnt][8]=1; // If there is a comment
//--------------------------------------------------------------------- 6
}
}
Mas_Ord_New[0][0]=Qnt; // Amount of orders
//------------------------------------------------------------------------------ 7
return;
}
//------------------------------------------------------------------------------ 8 --
En el bloque 1-2 se muestra un comentario donde se describen los arrays globales usados en la funcin.
Los arrays globales son declarados en el archivo de inclusin Variables.mqh.
En el bloque 3-4 el contenido del array Mas_Ord_New es copiado al array Mas_Ord_Old. De esta
manera, el estado de las rdenes conocido previamente es almacenado y puede ser usado ms adelante
en el programa. Luego, los valores de los elementos de los arrays Mas_Ord_New y Mas_Tip, que
mostrarn el nuevo estado de las rdenes, son llevados a cero antes de que la informacin sea
actualizada en los bloques 4-7.
Los bloques 4-7 contienen el ciclo for en el cual son chequeadas una por una todas las rdenes de
mercado y rdenes pendientes para el smbolo en el cual el EA fue asociado.
Las rdenes son seleccionadas utilizando la funcin OrderSelect() de acuerdo al parmetro
MODE_TRADES fijado por defecto.
En el bloque 5-6 se calculan todas las caractersticas requeridas para las rdenes seleccionadas. La
informacin obtenida es almacenada en el array de rdenes nuevas Mas_Ord_New.
Al mismo tiempo se calcula la cantidad de rdenes de cada tipo y los valores obtenidos son asignados a
los elementos correspondientes del array Mas_Tip.
Al final del ciclo, el nmero total de rdenes para este smbolo es asignado al elemento
Mas_Ord_New[0][0].
Antes de que la funcin Terminal() se ejecute por primera vez, los arrays Mas_Ord_Old y
Mas_Ord_New estn vacos, es decir que cada elemento de ambos arrays tienen el valor cero. Esto
significa que, despus de la primera ejecucin de esta funcin, el array Mas_Ord_Old recibir estos
valores cero del array Mas_Ord_New en la lnea:
ArrayCopy(Mas_Ord_Old, Mas_Ord_New); // Store the preceding history
Como consecuencia de esto, en apariencia se producir una alerta de evento falso en la ejecucin de la
funcin Events(). Para evitar esto, la primera vez que se ejecuta la funcin Terminal() se lo hace en la
seccin de inicializacin (init) del EA usualexpert.mq4.

FUNCIN DE INFORMACIN
La funcin standard Comment permite incluir comentarios en las esquinas de la ventana principal, pero
esto solo es til para comentarios cortos y en ocasiones se superpone con las velas del grfico. Debido a
esto existe una forma de mostrar mensajes en una ventana separada, usando un indicador personalizado
con el objeto de mostrar estos mensajes pero sin la intencin de hacer clculo alguno:
//--------------------------------------------------------------------
// Inform.mq4
//--------------------------------------------------------------------
#property indicator_separate_window // Separate indicator window
//--------------------------------------------------------------------
int start() // Special function start()
{
}
//--------------------------------------------------------------------
Funcin Definida por el usuario Inform()
Esta funcin se utiliza para mostrar mensajes en esta ventana separada del grfico. No es indispensable
para el funcionamiento del EA usualexpert.mq4. Esta funcin est explicada en el libro.
El archivo de inclusin (include) es el siguiente:
//----------------------------------------------------------------------------
// Inform.mqh
//----------------------------------------------------------------------- 1 --
// Function that displays graphical messages on the screen.
//----------------------------------------------------------------------- 2 --
int Inform(int Mess_Number, int Number=0, double Value=0.0)
{
// int Mess_Number // Message number
// int Number // Integer to be passed
// double Value // Real number to be passed
int Win_ind; // Indicator window number
string Graf_Text; // Message line
color Color_GT; // Color of the message line
static int Time_Mess; // Last publication time of the message
static int Nom_Mess_Graf; // Graphical messages counter
static string Name_Grf_Txt[30]; // Array of graphical message names
//----------------------------------------------------------------------- 3 --
Win_ind= WindowFind("inform"); // Searching for indicator window number
if (Win_ind<0)return; // If there is no such a window, leave
//----------------------------------------------------------------------- 4 --
if (Mess_Number==0) // This happens at every tick
{
if (Time_Mess==0) return; // If it is gray already
if (GetTickCount()-Time_Mess>15000) // The color has become updated within 15 sec
{
for(int i=0;i<=29; i++) // Color lines with gray
ObjectSet( Name_Grf_Txt[i], OBJPROP_COLOR, Gray);
Time_Mess=0; // Flag: All lines are gray
WindowRedraw(); // Redrawing objects
}
return; // Exit the function
}
//----------------------------------------------------------------------- 5 --
if (Mess_Number==-1) // This happens at deinit()
{
for(i=0; i<=29; i++) // By object indexes
ObjectDelete(Name_Grf_Txt[i]); // Deletion of object
return; // Exit the function
}
//----------------------------------------------------------------------- 6 --
Nom_Mess_Graf++; // Graphical messages counter
Time_Mess=GetTickCount(); // Last publication time
Color_GT=Lime;
//----------------------------------------------------------------------- 7 --
switch(Mess_Number) // Going to message
{
case 1:
Graf_Text="Closed order Buy "+ Number;
PlaySound("Close_order.wav"); break;
case 2:
Graf_Text="Closed order Sell "+ Number;
PlaySound("Close_order.wav"); break;
case 3:
Graf_Text="Deleted pending order "+ Number;
PlaySound("Close_order.wav"); break;
case 4:
Graf_Text="Opened order Buy "+ Number;
PlaySound("Ok.wav"); break;
case 5:
Graf_Text="Opened order Sell "+ Number;
PlaySound("Ok.wav"); break;
case 6:
Graf_Text="Placed pending order "+ Number;
PlaySound("Ok.wav"); break;
case 7:
Graf_Text="Order "+Number+" modified into the market one";
PlaySound("Transform.wav"); break;
case 8:
Graf_Text="Reopened order "+ Number; break;
PlaySound("Bulk.wav");
case 9:
Graf_Text="Partly closed order "+ Number;
PlaySound("Close_order.wav"); break;
case 10:
Graf_Text="New minimum distance: "+ Number;
PlaySound("Inform.wav"); break;
case 11:
Graf_Text=" Not enough money for "+
DoubleToStr(Value,2) + " lots";
Color_GT=Red;
PlaySound("Oops.wav"); break;
case 12:
Graf_Text="Trying to close order "+ Number;
PlaySound("expert.wav"); break;
case 13:
if (Number>0)
Graf_Text="Trying to open order Sell..";
else
Graf_Text="Trying to open order Buy..";
PlaySound("expert.wav"); break;
case 14:
Graf_Text="Invalid password. EA doesn't function.";
Color_GT=Red;
PlaySound("Oops.wav"); break;
case 15:
switch(Number) // Going to the error number
{
case 2: Graf_Text="Common error."; break;
case 129: Graf_Text="Wrong price. "; break;
case 135: Graf_Text="Price changed. "; break;
case 136: Graf_Text="No prices. Awaiting a new tick.."; break;
case 146: Graf_Text="Trading subsystem is busy"; break;
case 5 : Graf_Text="Old version of the terminal."; break;
case 64: Graf_Text="Account is blocked."; break;
case 133: Graf_Text="Trading is prohibited"; break;
default: Graf_Text="Occurred error " + Number;//Other errors
}
Color_GT=Red;
PlaySound("Error.wav"); break;
case 16:
Graf_Text="Expert Advisor works only for EURUSD";
Color_GT=Red;
PlaySound("Oops.wav"); break;
default:
Graf_Text="default "+ Mess_Number;
Color_GT=Red;
PlaySound("Bzrrr.wav");
}
//----------------------------------------------------------------------- 8 --
ObjectDelete(Name_Grf_Txt[29]); // Deleting 29th (upper) object
for(i=29; i>=1; i--) // Cycle for array indexes ..
{ // .. of graphical objects
Name_Grf_Txt[i]=Name_Grf_Txt[i-1]; // Raising objects:
ObjectSet( Name_Grf_Txt[i], OBJPROP_YDISTANCE, 2+15*i);
}
Name_Grf_Txt[0]="Inform_"+Nom_Mess_Graf+"_"+Symbol(); // Object name
ObjectCreate (Name_Grf_Txt[0],OBJ_LABEL, Win_ind,0,0); // Creating
ObjectSet (Name_Grf_Txt[0],OBJPROP_CORNER, 3 ); // Corner
ObjectSet (Name_Grf_Txt[0],OBJPROP_XDISTANCE, 450); // Axis
ObjectSet (Name_Grf_Txt[0],OBJPROP_YDISTANCE, 2); // Axis Y
//
ObjectSetText(Name_Grf_Txt[0],Graf_Text,10,"Courier New",Color_GT);
WindowRedraw(); // Redrawing all objects
return;
}
//----------------------------------------------------------------------- 9 --
FUNCIN DE RASTREO DE EVENTOS
Se utiliza para informar diferentes eventos al usuario, como por ejemplo el aumento de la distancia
mnima a la cual se puede colocar un SL.
Funcin definida por el usuario Events()
int Events()
La funcin calcula los cambios en la distancia mnima requerida para colocar rdenes, sus
correspondientes SL y TP, y los cambios en las rdenes pendientes y de mercado.
Para ejecutar esta funcin es necesario utilizar la funcin de contabilidad de rdenes Termina(). Se
utilizan tambin los valores de los arrays globales Mas_Ord_New y Mas_Ord_Old.
Se utilizan los valores de las variables globales Level_new (valor actual de la distancia mnima) y
Level_old (valor anterior de la distancia mnima).
Para mostrar mensajes, la funcin utiliza la funcin de informacin Inform(). Si la funcin Inform() no
est incluida en el EA, no se mostrar ningn mensaje.
La funcin de rastreo de eventos Events(), est desarrollada como un archivo de inclusin llamado
Events.mqh:
//--------------------------------------------------------------------------------
// Events.mqh
//--------------------------------------------------------------------------- 1 --
// Event tracking function.
// Global variables:
// Level_new The new value of the minimum distance
// Level_old The preceding value of the minimum distance
// Mas_Ord_New[31][9] The last known array of orders
// Mas_Ord_Old[31][9] The old array of orders
//--------------------------------------------------------------------------- 2 --
int Events() // User-defined function
{
bool Conc_Nom_Ord; // Matching orders in ..
//.. the old and the new arrays
//--------------------------------------------------------------------------- 3 --
Level_new=MarketInfo(Symbol(),MODE_STOPLEVEL ); // Last known
if (Level_old!=Level_new) // New is not the same as old..
{ // it means the condition have been changed
Level_old=Level_new; // New "old value"
Inform(10,Level_new); // Message: new distance
}
//--------------------------------------------------------------------------- 4 --
// Searching for lost, type-changed, partly closed and reopened orders
for(int old=1;old<=Mas_Ord_Old[0][0];old++) // In the array of old orders
{ // Assuming the..
Conc_Nom_Ord=false; // ..orders don't match
//--------------------------------------------------------------------- 5 --
for(int new=1;new<=Mas_Ord_New[0][0];new++) //Cycle for the array ..
{ //..of new orders
//------------------------------------------------------------------ 6 --
if (Mas_Ord_Old[old][4]==Mas_Ord_New[new][4]) // Matched number
{ // Order type becomes ..
if (Mas_Ord_New[new][6]!=Mas_Ord_Old[old][6]) //.. different
Inform(7,Mas_Ord_New[new][4]); // Message: modified:)
Conc_Nom_Ord=true; // The order is found, ..
break; // ..so exiting ..
} // .. the internal cycle
//------------------------------------------------------------------ 7 --
// Order number does not match
if (Mas_Ord_Old[old][7]>0 && // MagicNumber matches
Mas_Ord_Old[old][7]==Mas_Ord_New[new][7]) //.. with the old one
{ //it means it is reopened or partly closed
// If volumes match,..
if (Mas_Ord_Old[old][5]==Mas_Ord_New[new][5])
Inform(8,Mas_Ord_Old[old][4]); // ..it is reopening
else // Otherwise, it was..
Inform(9,Mas_Ord_Old[old][4]); // ..partly closing
Conc_Nom_Ord=true; // The order is found, ..
break; // ..so exiting ..
} // .. the internal cycle
}
//--------------------------------------------------------------------- 8 --
if (Conc_Nom_Ord==false) // If we are here,..
{ // ..it means no order found:(
if (Mas_Ord_Old[old][6]==0)
Inform(1, Mas_Ord_Old[old][4]); // Order Buy closed
if (Mas_Ord_Old[old][6]==1)
Inform(2, Mas_Ord_Old[old][4]); // Order Sell closed
if (Mas_Ord_Old[old][6]> 1)
Inform(3, Mas_Ord_Old[old][4]); // Pending order deleted
}
}
//--------------------------------------------------------------------------- 9 --
// Search for new orders
for(new=1; new<=Mas_Ord_New[0][0]; new++) // In the array of new orders
{
if (Mas_Ord_New[new][8]>0) //This one is not new, but reopened
continue; //..or partly closed
Conc_Nom_Ord=false; // As long as no matches found
for(old=1; old<=Mas_Ord_Old[0][0]; old++) // Searching for this order
{ // ..in the array of old orders
if (Mas_Ord_New[new][4]==Mas_Ord_Old[old][4]) //Matched number..
{ //.. of the order
Conc_Nom_Ord=true; // The order is found, ..
break; // ..so exiting ..
} // .. the internal cycle
}
if (Conc_Nom_Ord==false) // If no matches found,..
{ // ..the order is new :)
if (Mas_Ord_New[new][6]==0)
Inform(4, Mas_Ord_New[new][4]); // Order Buy opened
if (Mas_Ord_New[new][6]==1)
Inform(5, Mas_Ord_New[new][4]); // Order Sell opened
if (Mas_Ord_New[new][6]> 1)
Inform(6, Mas_Ord_New[new][4]); // Pending order placed
}
}
//-------------------------------------------------------------------------- 10 --
return;
}
//-------------------------------------------------------------------------- 11 --
En el bloque 1-2 se describen los arrays globales y las variables globales. En el bloque 2-3 se abre la
variable Conc_Nom_Ord.
Esta funcin rastrea los cambios de la distancia mnima para colocar rdenes y stops. Para esto, en cada
ejecucin de la funcin, en el bloque 3-4, es calculado el valor actual de la distancia mnima Level_new
y luego se lo compara con el valor anterior Level_old (obtenido en la ejecucin anterior de esta funcin).
Si los valores de estas dos variables no son iguales, significa que el dealing center cambi el valor de la
distancia mnima. En este caso, el valor actual de la distancia mnima ser asignado a la variable
Level_old (para ser considerado en las prximas ejecuciones de esta funcin), y se ejecuta la funcin
Inform() para mostrar el mensaje correspondiente.
En los bloques 4-10 se analiza el estado de las rdenes pendientes y de mercado. Se provee informacin
acerca de los cambios acaecidos en estas rdenes. Este anlisis se desarrolla en dos etapas. En la primera
el programa detecta cambios en relacin a rdenes perdidas (cerradas o eliminadas), cambios en el tipo
de orden, cerradas parcialmente y abiertas nuevamente (bloques 4-9). En la segunda etapa (bloque 9-10)
se buscan las nuevas rdenes.
En los bloques 4-9 se analizan las rdenes consideradas en el array Mas_Ord_Old. El elemento de array
Mas_Ord_Old[0][0] nos indica la cantidad de iteraciones en el ciclo externo for (y la cantidad total de
rdenes en el array). Para chequear si una orden no ha sufrido cambios, debemos buscar una orden
similar en el array Mas_Ord_New. La bsqueda se realiza en el ciclo interno for (bloques 6-8) cuya
cantidad de iteraciones es igual a la cantidad de rdenes en el array, igual al valor del elemento de array
Mas_Ord_New[0][0].
En los bloques 6-8 el programa busca cules fueron las caractersticas que se modificaron en esas
rdenes. Por ejemplo, en el bloque 6-7 se controla el nmero de la orden. Si el nmero de la orden
analizada del array old concuerda con el nmero de una de las rdenes en el array new, significa que esa
orden, al menos, no fue cerrada ni eliminada. Tambin es necesario chequear si cambi el tipo de orden.
Si cambi significa que una orden pendiente se transform en una orden de mercado. En ese caso se
muestra el correspondiente mensaje utilizando la funcin Inform(). Independientemente del hecho de
que el tipo de orden haya cambiado o no, esta orden no continuar siendo analizada. El programa sale
del ciclo interno for y finalmente comienza una nueva iteracin del ciclo externo.
Si en la ejecucin del bloque 6-7 el programa encuentra que el nmero de la orden analizada en el array
old no concuerda con ninguna orden del array new, el control es pasado al bloque 7-8. Aqu el programa
controla si esa orden del array new tiene un MaginNumber distinto de cero (todas las rdenes colocadas
y abiertas por nuestro EA tienen un MagicNumber distinto de cero), en cuyo caso lo compara con el
MaginNumber de la orden del array old, si concuerdan significa que esa orden fue operada pero fue
modificada en algn aspecto. Hay dos situaciones en las que una orden puede ser modificada:
Situacin 1: La orden es parcialmente cerrada. Una orden de mercado puede cerrarse parcialmente (una
orden pendiente No) en dos etapas. En la primera, la orden inicial es cerrada completamente. Al mismo
tiempo se abre una nueva orden de mercado con un volumen menor, con el mismo precio de apertura y
niveles de stop que en la orden original. Esta nueva orden obtiene un nmero nico, diferente al de la
orden original.
Situacin 2: La orden es reabierta por el dealing center. Algunos Bancos cierran todas sus rdenes al
final del da e inmediatamente despus abren rdenes de mercado del mismo tipo y con el mismo
volumen, pero al precio actual menos el swap. Este evento no afecta en modo alguno los resultados
econmicos de una cuenta de trading. Cada nueva orden abierta obtiene un nmero nico que no
coincide con los nmeros de las rdenes cerradas.
La diferencia entre las dos situaciones descriptas radica en el volumen de la nueva orden, el cual vara
en el primer caso y permanece inalterado en el segundo. Esta diferencia es utilizada en el bloque 7-8
para distinguir entre rdenes modificadas por diferentes motivos. En ambos casos se despliega el
mensaje correspondiente.
Si el programa en el ciclo interno no detecta la concordancia en el array new del nmero de orden
(bloque 6-7) o del MaginNumber (bloque 7-8), significa que la orden en el array old fue borrada o
eliminada. En ese caso el control pasa al bloque 8-9 donde se despliega un mensaje de acuerdo al tipo de
orden.
Como dijimos anteriormente, en la segunda etapa (bloque 9-10) se buscan las nuevas rdenes. En el
ciclo externo for busca en todas las rdenes del array new. Para identificar las rdenes reabiertas o
parcialmente cerradas, el programa utiliza una caracterstica simple: la existencia de comentarios.
Cuando una orden es re-abierto o parcialmente cerrada el servidor agrega un comentario que muestra el
nmero de la orden original. Nuestro EA no utiliza comentarios, por lo que la existencia de comentarios
significa que la orden analizada no es nueva.
Si una orden no contiene ningn comentario, el programa buscar en el array old una orden con el
mismo nmero, para lo cual utiliza el ciclo interno for. Si la encuentra, significa que esa orden no es
nueva. Si el nmero de orden en el array new no se corresponde con el nmero de ninguna orden del
array old, significa que esa orden es una orden de mercado o una orden pendiente. Al final del bloque 9-
10, despliega el mensaje correspondiente, de acuerdo al tipo de orden.

FUNCIN PARA DETERMINAR EL VOLUMEN


En este ejemplo, la funcin definida por el usuario Lot() permite determinar el volumen para la apertura
de una nueva orden usando una de las siguientes alternativas:
1) El usuario determina en forma manual la cantidad de lotes para la nueva orden.
2) La cantidad de lotes es calculada de acuerdo a una cantidad de dinero asignada por el usuario,
determinada como un porcentaje del margen libre.
Funcin definida por el usuario Lot()
bool Lot()
La funcin calcula la cantidad de lotes para una nueva orden. Como consecuencia de la ejecucin de esta
funcin, la variable global Lots_New toma un nuevo valor (la cantidad de lotes). La funcin devuelve
TRUE si el margen libre es suficiente para abrir una orden con la cantidad mnima de lotes, para el
smbolo en el cual se adjunt el EA. De otra manera, devuelve FALSE.
La funcin utiliza los valores de las siguientes variables globales:
Lots: volumen definido por el usuario, en lotes.
Percent: porcentaje del margen libre, definido por el usuario.
Para mostrar mensajes, la funcin utiliza la funcin de informacin Inform(). Si la funcin Inform() no
est includa en el EA, no se mostrar ningn mensaje.
La funcin Lot(), que determina la cantidad de lotes, est desarrollada como un archivo de inclusin
llamado Lot.mqh:
//----------------------------------------------------------------------------------
// Lot.mqh
//----------------------------------------------------------------------------- 1 --
// Function calculating the amount of lots.
// Global variables:
// double Lots_New - the amount of lots for new orders (calculated)
// double Lots - the desired amount of lots defined by the user.
// int Percent - free margin percentage defined by the user
// Returned values:
// true - if there is enough money for the minimum volume
// false - if there is no enough money for the minimum volume
//----------------------------------------------------------------------------- 2 --
bool Lot() // User-defined function
{
string Symb =Symbol(); // Symbol
double One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED); //!-lot cost
double Min_Lot=MarketInfo(Symb,MODE_MINLOT); // Min. amount of lots
double Step =MarketInfo(Symb,MODE_LOTSTEP); //Step in volume changing
double Free =AccountFreeMargin(); // Free margin
//----------------------------------------------------------------------------- 3 --
if (Lots>0) // Volume is explicitly set..
{ // ..check it
double Money=Lots*One_Lot; // Order cost
if(Money<=AccountFreeMargin()) // Free margin covers it..
Lots_New=Lots; // ..accept the set one
else // If free margin is not enough..
Lots_New=MathFloor(Free/One_Lot/Step)*Step; // Calculate lots
}
//----------------------------------------------------------------------------- 4 --
else // If volume is not preset
{ // ..take percentage
if (Percent > 100) // Preset, but incorrectly ..
Percent=100; // .. then no more than 100
if (Percent==0) // If 0 is preset ..
Lots_New=Min_Lot; // ..then the min. lot
else // Desired amount of lots:
Lots_New=MathFloor(Free*Percent/100/One_Lot/Step)*Step; //Calc
}
//----------------------------------------------------------------------------- 5 --
if (Lots_New < Min_Lot) // If it is less than allowed..
Lots_New=Min_Lot; // .. then minimum
if (Lots_New*One_Lot > AccountFreeMargin()) // It isn't enough even..
{ // ..for the min. lot:(
Inform(11,0,Min_Lot); // Message..
return(false); // ..and exit
}
return(true); // Exit user-defined function
}
//----------------------------------------------------------------------------- 6 --
En el bloque 1-2 se describen las variables globales y los valores que devolver esta funcin.
En el bloque 2-3 se calculan los valores de algunas variables. Si un usuario estableci una cantidad de
lotes distinta de cero, entonces no se tomar en cuenta el porcentaje de margen libre. Las variables
externas Lots y Percent son declaradas en el archivo de inclusin Variables.mqh.
En el bloque 3-4 se hacen los clculos para el caso en que el usuario haya definido un valor distinto de
cero para la variable Lots. En este caso el programa chequea si el margen libre es suficiente para abrir
una orden de mercado con esa cantidad de lotes, luego la cantidad de lotes definida por el usuario ser
asignada a la variable global Lots_New, que ser utilizada ms adelante en nuestro EA. Si el margen
libre no es suficiente para la cantidad de lotes definida por el usuario, entonces se calcula la cantidad
mxima de lotes posibles.
Si el usuario defini una cantidad de lotes igual a cero, el control es pasado al bloque 4-5. Entonces
tomamos en cuenta el porcentaje del margen libre establecido por el usuario en la variable externa
Percent. El programa primero comprueba que si este valor super el 100%, en cuyo caso se utilizar el
valor 100 para los clculos.
Si el usuario defini el valor 0 para la variable Percent, entonces la cantidad de lotes ser igualada a la
cantidad mnima posible establecida por el dealing center. Para todas las cantidades intermedias se
calcular la cantidad de lotes en base al porcentaje definido por el usuario.
En el bloque 5-6 se chequea que la cantidad de lotes obtenida no sea inferior a la mnima permitida, en
cuyo caso se tomar la mnima permitida como valor a asignar a la variable Lots_New.
Luego el programa controla que existan en la cuenta los fondos suficientes para abrir la cantidad de lotes
calculada. Si el dinero disponible no es suficiente, el programa desplegar un mensaje para informar al
usuario y saldr de la funcin, la cual devolver el valor FALSE, sino devolver el valor TRUE.

FUNCIN PARA DEFINIR LOS CRITERIOS DE COMERCIO


Esta funcin suele ser la ms importante de un programa y debe ser creada sin fallos. De acuerdo a la
estrategia definida, esta funcin debe devolver valores que correspondan con un determinado criterio
para operar. En general, deben definirse los siguientes criterios:
Criterio para abrir una orden de mercado.
Criterio para cerrar una orden de mercado.
Criterio para cerrar parcialmente una orden de mercado.
Criterio para cerrar rdenes de mercado opuestas.
Criterios para modificar los precios o stops de rdenes de mercado.
Criterios para colocar rdenes pendientes.
Criterios para eliminar rdenes pendientes
Criterios para modificar el precio de entrada de rdenes pendientes.
Criterios para modificar el precio de los stops rdenes pendientes.
Funcin definida por el usuario Criterion()
int Criterion()
La funcin calcula los criterios para operar. Puede devolver los siguientes valores:
-1 El smbolo usado No es EUR/USD
0 No hay criterios importantes disponibles.
10 Se produjo el criterio de operatoria para Abrir una operacin de Compra
11 Se produjo el criterio de operatoria para Cerrar una operacin de Compra
20 Se produjo el criterio de operatoria para Abrir una operacin de Venta
21 Se produjo el criterio de operatoria para Cerrar una operacin de Venta
La funcin utiliza los valores de las siguientes variables externas:
St_Min: el menor valor del indicador Estocstico.
St_Max: el mayor valor del indicador Estocstico.
Open_Level: el nivel del indicador MACD (para abrir una orden).
Close_Level: el nivel del indicador MACD (para cerrar una orden).
Para mostrar mensajes, la funcin utiliza la funcin de informacin Inform(). Si la funcin Inform() no
est includa en el EA, no se mostrar ningn mensaje.
La funcin definiendo los criterios para operar, Criterion(), est desarrollada como un archivo de
inclusin llamado Criterion.mqh:
//-------------------------------------------------------------------------
// Criterion.mqh
//-------------------------------------------------------------------- 1
// Function calculating trading criteria.
// Returned values:
// 10 - opening Buy
// 20 - opening Sell
// 11 - closing Buy
// 21 - closing Sell
// 0 - no important criteria available
// -1 - another symbol is used
//-------------------------------------------------------------------- 2
// External variables:
extern int St_min=30; // Minimum stochastic level
extern int St_max=70; // Maximum stochastic level
extern double Open_Level =5; // MACD level for opening (+/-)
extern double Close_Level=4; // MACD level for closing (+/-)
//-------------------------------------------------------------------- 3
int Criterion() // User-defined function
{
string Sym="EURUSD";
if (Sym!=Symbol()) // If it is a wrong symbol
{
Inform(16); // Messaging..
return(-1); // .. and exiting
}
double
M_0, M_1, // Value MAIN at bars 0 and 1
S_0, S_1, // Value SIGNAL at bars 0 and 1
St_M_0, St_M_1, // Value MAIN at bars 0 and 1
St_S_0, St_S_1; // Value SIGNAL at bars 0 and 1
double Opn=Open_Level*Point; // Opening level of MACD (points)
double Cls=Close_Level*Point; // Closing level of MACD (points)
//-------------------------------------------------------------------- 4
// Parameters of technical indicators:
M_0=iMACD(Sym,PERIOD_H1,12,26,9,PRICE_CLOSE,MODE_MAIN,0); // 0 bar
M_1=iMACD(Sym,PERIOD_H1,12,26,9,PRICE_CLOSE,MODE_MAIN,1); // 1 bar
S_0=iMACD(Sym,PERIOD_H1,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0); //0 bar
S_1=iMACD(Sym,PERIOD_H1,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1); //1 bar
St_M_0=iStochastic(Sym,PERIOD_M15,5,3,3,MODE_SMA,0,MODE_MAIN, 0);
St_M_1=iStochastic(Sym,PERIOD_M15,5,3,3,MODE_SMA,0,MODE_MAIN, 1);
St_S_0=iStochastic(Sym,PERIOD_M15,5,3,3,MODE_SMA,0,MODE_SIGNAL,0);
St_S_1=iStochastic(Sym,PERIOD_M15,5,3,3,MODE_SMA,0,MODE_SIGNAL,1);
//-------------------------------------------------------------------- 5
// Calculation of trading criteria
if(M_0>S_0 && -M_0>Opn && St_M_0>St_S_0 && St_S_0<St_min)
return(10); // Opening Buy
if(M_0<S_0 && M_0>Opn && St_M_0<St_S_0 && St_S_0>St_max)
return(20); // Opening Sell
if(M_0<S_0 && M_0>Cls && St_M_0<St_S_0 && St_S_0>St_max)
return(11); // Closing Buy
if(M_0>S_0 && -M_0>Cls && St_M_0>St_S_0 && St_S_0>St_min)
return(21); // Closing Sell
//-------------------------------------------------------------------- 6
return(0); // Exit the user-defined function
}
//-------------------------------------------------------------------- 7 --
Bloque 2-3: Tcnicamente, es posible declarar las variables externas este archivo Criterion.mqh porque
las mismas no se utilizan en ninguna otra funcin del EA.
En el bloque 3-4 se abren y describen las variables locales.
En el bloque 4-5 se calculan los valores del MACD y el Estocstico para la barra actual y para la barra
anterior.
Si se presentaran al mismo tiempo las condiciones tanto para abrir una compra como para cerrar un
venta, el archivo Criterion.mqh est diseado para devolver slo un valor. En este caso, de acuerdo con
la estrategia considerada, la orden de abrir una operacin de compra tiene prioridad respecto a la de
cerrar una operacin de venta. Es por eso que en el bloque 5-6 el criterio para abrir una operacin de
compra est posicionado por encima.
Al mismo tiempo, al enviarse una solicitud de apertura de una orden de compra, antes se requerir cerrar
todas las rdenes de venta, y una vez que no queden abiertas rdenes de este tipo, se proceder a abrir la
correspondiente orden de compra. Ver el tema siguiente: Funciones de Comercio.

FUNCIONES DE COMERCIO
Como norma general, un Asesor Experto normal contiene cierto nmero de funciones de comercio, las
cuales se dividen en funciones de control y funciones de ejecucin. Por lo general debera utilizarse una
funcin de control y una funcin de ejecucin que defina los criterios par operar. Ambas funciones
deben estar coordinadas entre s, respecto de los valores de los parmetros que se transfieren.
Cada funcin ejecutiva tiene un rango especial de tareas. De acuerdo a los requerimientos de una
determinada estrategia, se usarn funciones de comercio para estas tareas:
Abrir una orden de mercado de determinado tipo.
Cerrar una orden de mercado de determinado tipo.
Cerrar parcialmente una orden de mercado de determinado tipo.
Cerrar todas las rdenes de mercado de determinado tipo.
Cerrar rdenes de mercado opuestas de un determinado volumen.
Cerrar todas las rdenes de mercado.
Modificar las rdenes de stop de las rdenes de mercado de un determinado tipo.
Colocar rdenes pendientes de determinado tipo.
Eliminar una orden pendiente de determinado tipo.
Eliminar todas las rdenes pendientes de determinado tipo.
Eliminar todas las rdenes pendientes.
Modificar una orden pendiente de determinado tipo.
Una secuencia general de comercio en un Asesor Experto normal consiste en lo siguiente: en base a los
criterios de comercio determinados (de acuerdo a la estrategia usada), la funcin de comercio de control
(tambin de acuerdo a la estrategia) llama a alguna de las otras funciones de comercio ejecutivas, las
cuales, a su turno, formarn la solicitud de operatoria necesaria.
Funcin de control de comercio definida por el usuario Trade()
int Trade( int Trad_Oper )
El parmetro Trad_Oper puede tomar uno de los siguientes valores:
-1 El smbolo usado No es EUR/USD
0 No hay criterios importantes disponibles.
10 Se produjo el criterio de operatoria para Abrir una operacin de Compra
11 Se produjo el criterio de operatoria para Cerrar una operacin de Compra
20 Se produjo el criterio de operatoria para Abrir una operacin de Venta
21 Se produjo el criterio de operatoria para Cerrar una operacin de Venta
Para ejecutar la funcin se requieren las siguientes funciones de comercio definidas por el usuario:
Close_All(): funcin que cierra todas las rdenes de mercado de determinado tipo.
Opern_Ord(): funcin que abre una orden de mercado de determinado tipo.
Tral_Stop(): funcin que modifica el Stop Loss de una orden de mercado de determinado tipo.
Lot(): funcin que detecta la cantidad de lotes para nuevas rdenes.
La funcin de control Trade() est desarrollada como un archivo de inclusin llamado Trade.mqh:
//------------------------------------------------------------------------
// Trade.mqh
//------------------------------------------------------------------- 1
int Trade(int Trad_Oper) // User-defined function
{
// Trad_Oper - trade operation type:
// 10 - opening Buy
// 20 - opening Sell
// 11 - closing Buy
// 21 - closing Sell
// 0 - no important criteria available
// -1 - another symbol is used
switch(Trad_Oper)
{
//------------------------------------------------------------- 2
case 10: // Trading criterion = Buy
Close_All(1); // Close all Sell
if (Lot()==false) // Not enough money for min.
return; // Exit the user-defined function
Open_Ord(0); // Open Buy
return; // Having traded, leave
//---------------------------------------------------------- 3
case 11: // Trading criterion = closing Buy
Close_All(0); // Close all Buy
return; // Having traded, leave
//---------------------------------------------------------- 4
case 20: // Trading criterion = Sell
Close_All(0); // Close all Buy
if (Lot()==false)
return; // Exit the user-defined function
Open_Ord(1); // Open Sell
return; // Having traded, leave
//---------------------------------------------------------- 5
case 21: // Trading criterion = closing Sell
Close_All(1); // Close all Sell
return; // Having traded, leave
//---------------------------------------------------------- 6
case 0: // Retaining opened positions
Tral_Stop(0); // Trailing stop Buy
Tral_Stop(1); // Trailing stop Sell
return; // Having traded, leave
//---------------------------------------------------------- 7
}
}
//------------------------------------------------------------------- 8 --
La funcin de control Trade es llamada desde la funcin especial start() del Asesor Experto
usualexpert.mq4. El valor devuelto por la funcin Criterion() (la cual define los criterios para operar) es
entregado a la funcin Trade() como un parmetro transferido.
En la funcin especial start() del EA usualexpert.mq4 aparece la siguiente lnea:
Trade(Criterion()); // Trade function
En esta lnea se llama a la funcin Trade() y se le entrega el valor devuelto por la funcin Criterion().
En el bloque 1-2 de la funcin Trade() encontramos esta lnea:
int Trade(int Trad_Oper) // User-defined function
En esta lnea, la funcin Trade() recibe el valor devuelto por la funcin Criterion() (y que le fue
transferido por el EA usualexpert.mq4) y le asigna el nombre de variable Trad_Oper, de tipo int.
En los bloques 2-7 usamos el operador switch() que nos permite activar el grupo de funciones necesarias
para operar de acuerdo al criterio especificado. De acuerdo a la estrategia diseada, el EA abrir y
cerrar rdenes de mercado. Nuestra estrategia no define rdenes pendientes.
Suponiendo que la funcin Criterion() determina que se presentaron los motivos para abrir una compra,
entonces se pasar el parmetro de valor 10 la funcin Trade(), por lo que la variable Trad_Oper tomar
ese valor. El control ser pasado entonces a la marca "case 10 en el bloque 2-3, durante la ejecucin del
operador switch().
En este caso, el programa primero llama a la funcin Close_All(1). La ejecucin de esta funcin,
resultar en el cierre de todas las rdenes de mercado de venta abiertas en EUR/USD.
Despus de que todas las rdenes de mercado venta fueron cerradas se controla si el dinero disponible es
suficiente para abrir una nueva operacin. Para hacer esto se llama a la funcin definida por el usuario
Lot(). Si la funcin devuelve el valor false significa que el dinero disponible no es suficiente para abrir
una orden de mercado de compra con la cantidad de lotes mnima permitida. En este caso, la funcin
Trade() finaliza sus operaciones (return).
Si hay dinero suficiente se llama a la funcin Open_Ord(0) para abrir una orden de mercado de compra
con la cantidad de lotes calculada en la funcin Lot().
Las funciones ejecutivas de comercio que generan las solicitudes de comercio son llamadas en la
funcin Trade(), la cual, a su turno, es llamada en la funcin start() del EA. La funcin Trade() est
escrita de tal manera que el control no vuelve a la funcin start() hasta tanto se hayan ejecutado todas las
funciones ejecutivas de comercio.
Si no hay ningn criterio necesario para operar (variable Trad_Oper es igual a 0) en la ejecucin de l
funcin Criterion(), el control es pasado a la carca case 0 lo cual resulta en la llamada a la funcin
double Tral_Stop() para modificar los valores necesarios de las rdenes de mercado de diferentes tipo.
La estrategia plasmada en el EA permite la existencia de una sola orden de mercado, por lo que la
secuencia de llamadas a las funciones Tral_Stop(0) y Tral_Stop(1) no son importantes. En este caso es
una decisin aleatoria.
Si la funcin Criterion() devuelve el valor -1 significa que el EA fue soltado en una ventana que no es
del smbolo EUR/USD. En este caso la funcin Trade() no llama a ninguna funcin ejecutiva de
comercio y devuelve el control a la funcin especial start() que la llam.
Funcin ejecutiva de comercio definida por el usuario Close_All()
int Close_All( int Tip)
Esta funcin cierra todas las rdenes de mercado de un tipo especificado. El parmetro Tip puede tomar
los siguientes valores, que se corresponden con los tipos de rdenes a ser cerradas:
0: cierra rdenes de Compra
1: cierra rdenes de Venta.
Para ejecutar esta funcin es necesario aplicar la funcin de contabilidad de rdenes Terminal(), la
funcin de rastreo de eventos Event() y la funcin de procesamiento de errores Errors(). Para mostrar
mensajes se utiliza la informacin de la funcin Inform(). Si la funcin Inform() no est incluida en el
EA, no se mostrarn mensajes.
Se utilizan los valores de los arrays globales Mas_Ord_New y Mas_Tip.
La funcin de ejecucin de comercio Close_All() se forma como un archivo de inclusin Close_All.mqh:
//---------------------------------------------------------------------------------
// Close_All.mqh
//---------------------------------------------------------------------------- 1 --
// Function closing all market orders of the given type
// Global variables:
// Mas_Ord_New Last known order array
// Mas_Tip Order type array
//---------------------------------------------------------------------------- 2 --
int Close_All(int Tip) // User-defined function
{
// int Tip // Order type
int Ticket=0; // Order ticket
double Lot=0; // Amount of closed lots
double Price_Cls; // Order close price
//---------------------------------------------------------------------------- 3 --
while(Mas_Tip[Tip]>0) // As long as the orders of the ..
{ //.. given type are available
for(int i=1; i<=Mas_Ord_New[0][0]; i++) // Cycle for live orders
{
if(Mas_Ord_New[i][6]==Tip && // Among the orders of our type
Mas_Ord_New[i][5]>Lot) // .. select the most expensive one
{ // This one was found at earliest.
Lot=Mas_Ord_New[i][5]; // The largest amount of lots found
Ticket=Mas_Ord_New[i][4]; // Its order ticket is that
}
}
if (Tip==0) Price_Cls=Bid; // For orders Buy
if (Tip==1) Price_Cls=Ask; // For orders Sell
Inform(12,Ticket); // Message about an attempt to close
bool Ans=OrderClose(Ticket,Lot,Price_Cls,2); // Close order !:)
//---------------------------------------------------------------------- 4 --
if (Ans==false) // Failed :(
{ // Check for errors:
if(Errors(GetLastError())==false) // If the error is critical,
return; // .. then leave.
}
//---------------------------------------------------------------------- 5 --
Terminal(); // Order accounting function
Events(); // Event tracking
}
return; // Exit the user-defined function
}
//---------------------------------------------------------------------------- 6 --
En el bloque 1-2 son descriptas las variables globales utilizadas. En el bloque 2-3 las variables locales
son abiertas y descriptas.
La condicin Mas_Tip[Tip]>0 en el encabezamiento del operador de ciclo while (bloques 3-6) que la
funcin mantendr el control hasta que todas las rdenes de el tipo determinado estn cerradas.
El elemento del array global Mas_Tip[Tip] contiene el valor igual a la cantidad de rdenes del tipo
especificado Tip.
Las rdenes se cerrarn comenzando desde la que tiene una mayor cantidad de lotes
Funcin ejecutiva de comercio definida por el usuario Open_Ord()
int Open_Ord ( int Tip)
Esta funcin abre una orden de mercado del tipo especificado. El parmetro Tip puede tomar los
siguientes valores, que se corresponden con los tipos de rdenes a ser abiertas:
0: abre una orden de Compra
1: abre una orden de Venta.
Para ejecutar esta funcin es necesario aplicar la funcin de contabilidad de rdenes Terminal(), la
funcin de rastreo de eventos Event() y la funcin de procesamiento de errores Errors(). Para mostrar
mensajes se utiliza la informacin de la funcin Inform(). Si la funcin Inform() no est incluida en el
EA, no se mostrarn mensajes.
Se utilizan los valores de las siguientes variables globales Mas_Tip, StopLoss y TakeProfit.
La funcin de ejecucin de comercio Open_Ord() se forma como un archivo de inclusin
Open_Ord.mqh:
//---------------------------------------------------------------------------------
// Open_Ord.mqh
//---------------------------------------------------------------------------- 1 --
// Function opening one market order of the given type
// Global variables:
// int Mas_Tip Order type array
// int StopLoss The value of StopLoss (amount of points)
// int TakeProfit The value of TakeProfit (amount of points)
//---------------------------------------------------------------------------- 2 --
int Open_Ord(int Tip)
{
int Ticket, // Order ticket
MN; // MagicNumber
double SL, // StopLoss (as related to the price)
TP; // TakeProf (as related to the price)
//---------------------------------------------------------------------------- 3 --
while(Mas_Tip[Tip]==0) // Until they ..
{ //.. succeed
if (StopLoss<Level_new) // If it is less than allowed..
StopLoss=Level_new; // .. then the allowed one
if (TakeProfit<Level_new) // If it is less than allowed..
TakeProfit=Level_new; // ..then the allowed one
MN=TimeCurrent(); // Simple MagicNumber
Inform(13,Tip); // Message about an attempt to open
if (Tip==0) // Let's open a Buy
{
SL=Bid - StopLoss* Point; // StopLoss (price)
TP=Bid + TakeProfit*Point; // TakeProfit (price)
Ticket=OrderSend(Symbol(),0,Lots_New,Ask,2,SL,TP,"",MN);
}
if (Tip==1) // Let's open a Sell
{
SL=Ask + StopLoss* Point; // StopLoss (price)
TP=Ask - TakeProfit*Point; // TakeProfit (price)
Ticket=OrderSend(Symbol(),1,Lots_New,Bid,2,SL,TP,"",MN);
}
//---------------------------------------------------------------------- 4 --
if (Ticket<0) // Failed :(
{ // Check for errors:
if(Errors(GetLastError())==false) // If the error is critical,
return; // .. then leave.
}
Terminal(); // Order accounting function
Events(); // Event tracking
}
//---------------------------------------------------------------------------- 5 --
return; // Exit the user-defined function
}
//---------------------------------------------------------------------------- 6 --
En los bloques 1-3 se describen las variables globales y las variables locales son abiertas y descriptas.
El cdigo bsico de la funcin est concentrado en el operador de ciclo while (bloques 3-5) que es
ejecutado mientras no haya rdenes del tipo Tip disponibles.
Cada orden a ser abierta tiene su MagicNumber nico igual al horario actual del servidor.
De acuerdo al tipo de orden se ejecutar el cuerpo de uno de los operadores if, donde se calcular el
correspondiente TakeProfit y StopLoss (de acuerdo al tipo de orden de que se trate) y luego el control es
pasado a esta lnea (si fuera el caso de una orden de compra):
Ticket=OrderSend(Symbol(),0,Lots_New,Ask,2,SL,TP,"",MN);
Esta lnea solicita la apertura de una orden de Mercado de compra.
Funcin ejecutiva de comercio definida por el usuario Tral_Stop()
int Tral_Stop ( int Tip)
Esta funcin modifica todas las rdenes de mercado del tipo especificado. El parmetro Tip puede tomar
los siguientes valores, que se corresponden con los tipos de rdenes a ser modificadas:
0: modifica una orden de Compra
1: modifica una orden de Venta.
Para ejecutar esta funcin es necesario aplicar la funcin de contabilidad de rdenes Terminal(), la
funcin de rastreo de eventos Event() y la funcin de procesamiento de errores Errors(). Para mostrar
mensajes se utiliza la informacin de la funcin Inform(). Si la funcin Inform() no est incluida en el
EA, no se mostrarn mensajes.
Se utilizan los valores de las siguientes variables globales: Mas_Ord_New y TrailingStop.
La funcin de ejecucin de comercio Tral_Stop() se forma como un archivo de inclusin
Tral_Stop.mqh:
//---------------------------------------------------------------------------------
// Tral_Stop.mqh
//---------------------------------------------------------------------------- 1 --
// Function modifying StopLosses of all orders of the given type
// Global variables:
// Mas_Ord_New Last known order array
// int TralingStop Value of TralingStop (amount of points)
//---------------------------------------------------------------------------- 2 --
int Tral_Stop(int Tip)
{
int Ticket; // Order ticket
double
Price, // Market order open price
TS, // TralingStop (as related to the price)
SL, // Value of order StopLoss
TP; // Value of order TakeProfit
bool Modify; // A criterion to modify.
//---------------------------------------------------------------------------- 3 --
for(int i=1;i<=Mas_Ord_New[0][0];i++) // Cycle for all orders
{ // Searching for orders of the given type
if (Mas_Ord_New[i][6]!=Tip) // If this is not our type..
continue; //.. skip the order
Modify=false; // It is not assigned to be modified
Price =Mas_Ord_New[i][1]; // Order open price
SL =Mas_Ord_New[i][2]; // Value of order StopLoss
TP =Mas_Ord_New[i][3]; // Value of order TakeProft
Ticket=Mas_Ord_New[i][4]; // Order ticket
if (TralingStop<Level_new) // If it is less than allowed..
TralingStop=Level_new; // .. then the allowed one
TS=TralingStop*Point; // The same, as related to the price
//---------------------------------------------------------------------- 4 --
switch(Tip) // Go to Order type
{
case 0 : // Order Buy
if (NormalizeDouble(SL,Digits)< // If it is lower than we want..
NormalizeDouble(Bid-TS,Digits))
{ // ..then modify it:
SL=Bid-TS; // Its new StopLoss
Modify=true; // Assigned to be modified.
}
break; // Exit 'switch'
case 1 : // Order Sell
if (NormalizeDouble(SL,Digits)> // If it is higher than we want..
NormalizeDouble(Ask+TS,Digits)||
NormalizeDouble(SL,Digits)==0) //.. or zero(!)
{ // ..then modify it
SL=Ask+TS; // Its new StopLoss
Modify=true; // Assigned to be modified.
}
} // End of 'switch'
if (Modify==false) // If there is no need to modify it..
continue; // ..then continue the cycle
bool Ans=OrderModify(Ticket,Price,SL,TP,0); //Modify it!
//---------------------------------------------------------------------- 5 --
if (Ans==false) // Failed :(
{ // Check for errors:
if(Errors(GetLastError())==false) // If the error is critical,
return; // .. then leave.
i--; // Decreasing counter
}
Terminal(); // Order accounting function
Events(); // Event tracking
}
return; // Exit the user-defined function
}
//---------------------------------------------------------------------------- 6 --
En los bloques 1-3 se describen las variables globales y se abren y describen las variables locales. En el
ciclo for (bloques 3-6) se seleccionan las rdenes del tipo especificado y si el Stop Loss de cualquiera
de esas rdenes est ms lejos del precio actual de lo que seleccion el usuario, entonces esa orden ser
modificada.
Para hacer el cdigo ms claros, se asignan a variables simples algunos elementos del array
Mas_Ord_New (bloque 3-4). Luego se realiza el chequeo necesario para la variable TrailingStop. Si el
valor de esta variable es inferior a la distancia mnima permitida establecida por el dealing center,
entonces el valor de la variable ser incrementado para coincidir con esa distancia mnima.
En el bloque 4-5 se hacen los clculos de acuerdo al tipo de orden. Por ejemplo, si es de tipo 1 (orden de
venta) el control ser pasado a la marca case 1 del operador switch. Aqu se chequea la necesidad de
modificar la orden Stop Loss. Si no hay Stop Loss o si est establecido a una distancia mayor del precio
de mercado que el Trailing Stop establecido, entonces se calcula el nuevo valor del Stop Loss. La
solicitud para modificar la orden se forma en la siguiente lnea:
bool Ans = OrderModify(Ticket,Price,SL,TP,0); //Modify it!
Vimos antes que esta estrategia comercial solo permite la posibilidad de tener una sola cuenta orden. Sin
embargo, la funcin Tral_Stop()est diseada para aceptar varias rdenes.
En el ejemplo anterior en la funcin Tral_Stop(), las ordenes se modifican sin ningn orden en
particular, las ordenes se modifican segn el orden de llegada.
En el bloque de 5-6, se revisan los errores durante la ejecucin de la operacin. Si el error es crtico, la
funcin terminar su ejecucin. Sin embargo, si se produce un error no critico, el valor del contador 'i' se
reduce en 1. De esta manera se producir un nuevo intento para modificar la misma orden en la siguiente
iteracin del ciclo 'for'.

FUNCIN PARA EL PROCESADO DE ERRORES


Los errores que aparecen durante la ejecucin de funciones ejecutivas, se pueden dividir en dos grupos-
errores no crticos y errores crticos. Errores no crticos son los errores del servidor. Despus de haberse
solucionado estos errores, se puede continuar con las operaciones. Los errores crticos incluyen todos los
errores que alerten de problemas serios. Por ejemplo, si se bloquea una cuenta, es imposible hacer
operaciones. En tal caso, el EA debe mostrar el mensaje correspondiente y no debera repetir la peticin.
Por estos motivos, es indispensable tener una funcin en el EA que procese los errores.
Funcin definida por el usuario Errors()
bool Errors( int Error )
Esta funcin devuelve true si el error no es crtico. Si no devuelve false.
El parmetro Error puede tener cualquier valor y este valor corresponde al tipo de error que se
produjo al intentar hacer la operacin.
Esta funcin definida por el usuario se incluye en el archivo Errors.mqh:
//--------------------------------------------------------------------
// Errors.mqh
//--------------------------------------------------------------- 1 --
// Error processing function.
// Returned values:
// true - if the error is overcomable (i.e. work can be continued)
// false - if the error is critical (i.e. trading is impossible)
//--------------------------------------------------------------- 2 --
bool Errors(int Error) // Custom function
{
// Error // Error number
if(Error==0)
return(false); // No error
Inform(15,Error); // Message
//--------------------------------------------------------------- 3 --
switch(Error)
{ // Overcomable errors:
case 129: // Wrong price
case 135: // Price changed
RefreshRates(); // Renew data
return(true); // Error is overcomable
case 136: // No quotes. Waiting for the tick to come
while(RefreshRates()==false) // Before new tick
Sleep(1); // Delay in the cycle
return(true); // Error is overcomable
case 146: // The trade subsystem is busy
Sleep(500); // Simple solution
RefreshRates(); // Renew data
return(true); // Error is overcomable
// Critical errors:
case 2 : // Common error
case 5 : // Old version of the client terminal
case 64: // Account blocked
case 133: // Trading is prohibited
default: // Other variants
return(false); // Critical error
}
//--------------------------------------------------------------- 4 --
}
//--------------------------------------------------------------------
Si la funcin Errors() devuelve true (error no critico), entonces, el programa volver a intentar hacer la
operacin. Si devuelve false, entonces se detiene la funcin ejecutiva, y el control se devuelve as
sucesivamente a la funcin precedente, hasta llegar a la funcin start() y luego al cliente de terminal. Si
la opcin no est en ninguna de estas dos alternativas, entonces, en la situacin cuando no hay errores
(error = 0) corresponder a la segunda alternativa, a saber, el valor devuelto ser false. Esto garantiza
que no se repita la solicitud.
Una vez que el mensaje de error ha sido mostrado por la funcin Inform(), el programa salta al bloque 3-
4, al operador switch. En cada caso hay un cdigo que maneja el error tratado. Por ejemplo, si ocurre
el error 136, significa que el servidor no tiene precios actuales para poder tomar as una decisin
apropiada. Esto significa que la situacin no cambiar a menos que venga una nuevo tick, as que no hay
necesidad de repetir la misma operacin porque no se ejecutara de todas formas el envo. La solucin
correcta en este caso es hacer una pausa pausar cualquier accin del EA. Un mtodo sencillo para
detectar un nuevo tick se utiliza con este fin el anlisis del valor devuelto por la funcin
RefreshRates().El control ser devuelto la funcin a la funcin de llamada, en la cual se repite la
operacin (tras el anlisis correspondiente, si es necesario), tan pronto como se reciba un nuevo tick.
Si hay un error que el programar considerara critico, la funcin devolver false. La orden no se
repetir en tal caso, as que no hay necesidad de hacer algo en la funcin de Errors(). Todos los errores
que no se procesan son considerados crticos por defecto. Se pueden ampliar la lista de errores
procesados (ver cdigos de error).

PROGRAMAS COMPLEJOS
En el libro se muestra un cdigo que debe insertarse en los programas muy complejos a fin de que se
actualicen los datos de mercado permanentemente y as hacer ms eficiente un programa tan largo que,
de otra manera, hara que se pierdan varios ticks del mercado hasta recin poder volver a ejecutar la
funcin especial start().

S-ar putea să vă placă și