Documente Academic
Documente Profesional
Documente Cultură
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
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
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 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.
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.
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.
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
//-------------------------------------------------------------------------------------
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
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.
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.
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 && L_1<L_5)
{
Opn_B=true; // Criterion for opening Buy
Cls_S=true; // Criterion for closing Sell
}
if (L_5<=Level && 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 && 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()
}
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().
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.
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.
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'.
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().