English Русский 中文 Deutsch 日本語 Português
Lenguaje MQL4 para principiantes. Problemas complicados en frases simples.

Lenguaje MQL4 para principiantes. Problemas complicados en frases simples.

MetaTrader 4Ejemplos | 30 marzo 2016, 12:14
3 851 0
Antoniuk Oleg
Antoniuk Oleg

Introducción

Este es el segundo artículo de la serie "Lenguaje MQL4 para principiantes". El primer artículo "Lenguaje MQL4 para principiantes. Introducción" describía lo que se puede hacer utilizando MQL4. Aprendimos a escribir scripts simples, estudiamos qué es una variable, aprendimos a trabajar con variables, analizamos funciones, gamas, gamas y variables integradas, ciclos "for" y condiciones simples y complejas. Esta vez examinaremos construcciones del lenguaje más avanzadas y complicadas, aprenderemos nuevas opciones, y veremos cómo pueden aplicarse en la práctica diaria. Se familiarizará con un nuevo tipo de ciclo, "while"; con un nuevo tipo de condición, "switch"; con los operadores "break" y "continue". Además, aprenderá a escribir sus propias funciones y a trabajar con gamas multidimensionales. Y de postre, una explicación sobre un pre procesador.


Consejo

No empiece a leer este artículo si no ha comprendido por completo el primero. Cometerá muchos errores y seguirá sin comprender nada. Este artículo está basado en el material anterior, ¡así que no tenga prisa! Las dificultades con las que se encontrará durante el aprendizaje del nuevo material son engañosas: quiero ponérselo fácil. Llegará el momento en el que no tendrá que pensar cómo se escriben los ciclos, qué condiciones poner, etc.: lo hará todo mecánicamente. Cuanto más trabaje con el lenguaje MQL4, más fácil le será usarlo.

Nuevo tipo de ciclos: while

Me gustaría mencionar que el ciclo "for", descrito en el artículo anterior, es un ciclo universal y que se puede sustituir por cualquier otro tipo de ciclo que aprendamos a partir de ahora. Pero no siempre es conveniente y apropiado. A veces es más eficiente utilizar while. Pronto se dará cuenta de que el uso de cada tipo de ciclo es más bien racional. Vamos a hacer una tarea de dos formas: vamos a encontrar el volumen total de barras, utilizando ambos ciclos y viendo las diferencias:

// using the cycle for
double sum = 0.0;
 
for(int a = 0; a < Bars; a++)
    sum += Volume[a];
 
// now using while, the result is the same
double sum = 0.0;
int a = 0;
 
while(a < Bars)
  {
    sum += Volume[a];
    a++;
  }

Verá que el contador se declara y se usa por separado. "While" muestra que, mientras la condición sea verdadera, el ciclo continúa. Aquí tiene una apariencia general:

while(condition of cycle fulfillment)
  {
    code;
  }

Aquí tiene un ejemplo más sencillo:

while(I havent eaten up the apple) // condition
  {
    // what to do, if the condition is not fulfilled
bite more;                 
  }
De hecho, el ciclo "while" se diferencia de "for" sólo en la ausencia de contador. Si no lo necesita, use while, aunque no es necesario. Por ejemplo, yo escribo a menudo con contador, es una cuestión de gustos. Como en el caso de for, si el cuerpo del ciclo incluye sólo una instrucción, puede omitir bracers. Para su evolución recuerde también el significado de la palabra iteración. Es uno de las múltiples operaciones (repeticiones) que realiza el ciclo. Por ejemplo, ejecutar el cuerpo de un ciclo una vez significa que se ejecuta una iteración.

Nuevo tipo de ciclos: cambio

Como en el caso de los ciclos, se debe tener en cuenta que switch se puede sustituir por una combinación de condiciones familiares a "if" y "else". La construcción "cambio" se usa cuando se necesita ejecutar algunas acciones dependiendo en el valor de una variable. Es como un interruptor normal en un microondas. Por ejemplo, imagine que escribe un Asesor experto y cambia su comportamiento dependiendo en la situación del mercado. Deje que una variable int marketState se responsabilice de él. Puede significar lo siguiente:

  • 1 - tendencia positiva
  • 2 - tendencia decreciente
  • 3 - plano

No importa cómo se defina su posición, nuestra tarea es darnos cuenta de algún tipo de mecanismo para que, dependiendo de la situación del mercado, el Asesor experto ejecute las acciones correspondientes. Ya sabe cómo hacerlo. La variante más evidente es la siguiente:

if(marketState == 1)
  {
    // trading strategy for an uptrend
  }
else 
    if(marketState == 2)
      {
        // strategy for a downtrend
      }
    else 
        if(marketState == 3)
          {
            // strategy for a flat
          }
        else
          {
            // error: this state is not supported!
          }

Aquí tiene algunas peculiaridades:

  • todas las condiciones están conducidas por la misma variable.
  • todas las condiciones comparan la variable con uno de los significados que ésta puede aceptar.

Todo esto hace referencia también a la estructura de switch. Aquí tiene un código, utilizando switch, el resultado es el mismo:

switch(marketState)
  {
    case 1:  // trading strategy for an uptrend
             break;
    case 2:  // strategy for a downtrend
             break;
    case 3:  // strategy for a flat
             break;
    default: // error: this state is not supported!
             break;
  }

Tenga en cuenta que primero definimos qué variable será comparada:

// switch - key word, marketState - 
// a variable for comparison
switch(marketState)

y luego indicamos qué debe hacerse en los casos específicos.

case 1:                        // case - key word; 
   // trading strategy         // if marketState is equal to 1, then 
   // for an uptrend           // perform this code
   break;                      // key word that indicates  
                               // the end of actions in this case
 
case 2:                        // if marketState is equal to 2, then
    // startegy for            // perform this
    // a downtrend          
    break;                     // end
 
case 3:                        // identical
    // strategy for flat
    break;
 
default:                       // otherwise, perform this
    // error: this   
    // state is not 
    // supported!
    break;

En una vista general, switch tiene la siguiente forma:

switch(a variable for comparison)
  {
    case [a variable value]:
    // a code for this case 
    break;
   
    case [another value of the variable]
    // a code for this case
    break;
   
    default:
    // a code for all other cases
    break;
  }

Utilice switch cuando compare una variable a varios valores, y un cierto bloque corresponda a un valor. En otros casos, utilice una combinación común de las condiciones "if" y "else" A veces tiene que ejecutar un código en varios valores de una variable. Por ejemplo, si marketState = 1 o 2, se ejecuta un cierto código. Así es cómo puede hacerse utilizando switch:

switch(marketState)
  {
    case 1:  // if marketState is equal to 1
    case 2:  // or if marketState is equal to 2, then
             // perform this
             break;
 
    default: // in any other case perform 
             // this code
             break;
  }


Operadores: continue y break

Acabamos de ver el operador break. Se usa para salir del cuerpo de switch. Además, se puede usar para salir de un ciclo. Por ejemplo, si no necesita ejecutar un ciclo en ciertas condiciones. Suponga que necesita encontrar la cantidad de primeras barras, necesitaría cerrar 1 000 puntos. Podemos escribir el siguiente código:

int a = 0;
double volume = 0.0;
 
while(volume < 1000.0)
  {
    volume += Volume[a]; // equivalent to volume = volume + Volume[a]; 
    a++;
  }
 
// now variable "a" includes the amount of bars, the volume of their sums 
// is no less than 1000 points

Ahora escribamos un código analógico utilizando el operador break.

int a = 0;
double volume = 0.0;
 
while(a < Bars)
  {
    // if the volume is exceeds 1000 points, then
    if(volume > 1000.0) // exit the cycle   
        break;            
 
    volume += Volume[a];
    a++;
  }

El operador break es fácil de utilizar y le permite evitar iteraciones no deseadas. El operador continue es más útil y está diseñado para "omitir" las iteraciones no deseadas. Suponga que necesita calcular un volumen total, pero no se deben tener en cuenta el volumen de barras en los momentos de noticias importantes. Como ya sabe, las noticias importantes requieren volúmenes grandes de puntos. Imaginemos que somos niños inocentes y supongamos que el volumen de la barra es 50 puntos y las noticias son más. Para resolver esta tarea, se usará el operador continue:

int a = -1;
double volume = 0.0;
 
while(a < Bars)
  {
    a++;
    // if the volume exceeds 50 points, then it must 
    // be news, omit it 
    if(Volume[a] > 50.0)          
        continue;          
    volume += Volume[a];
  }

Como ve, el uso del operador continue es bastante trivial, pero a veces puede ayudarle. Está claro que este script está diseñado para periodos de tiempo pequeños.


Escribir funciones propias

¿Por qué se necesitan? El hecho es que, muy a menudo, se puede encontrar duplicados de su código. Por ejemplo, usará el mismo set de instrucciones en diferentes casos. Para ahorrar tiempo y fuerza, puede escribir este código duplicado en una función separada. Y cuando lo necesite, simplemente puede escribir el nombre de la función y lo hará todo. Veamos cómo funciona. Imagine que necesita averiguar el color de una vela. Ya se sabe que una vela blanca es la que cierra más alto que en la apertura; la negra, viceversa. Escribamos un código para determinar el color de una vela:

bool color; // as there are only 2 variants 
            // (white or black candlestick), 
            // then suppose that the velue 
            // false corresponds to a black 
            // candlestick, and true - white
 
if(Close[0] > Open[0])
    color = true;      // white candlestick
    
if(Open[0] > Close[0])
    color = false;     // black candlestick

Eso es todo, ahora el color de la variable contiene el color de la última vela. Para determinar el color de otra vela, por ejemplo la penúltima, necesita cambiar el índice de 0 a 1. ¿Pero va a poner este código cada vez que necesite averiguar el color de una vela? ¿Y si hay docenas de casos así? Por eso se necesitan las funciones. Pensemos cómo debería funcionar. Una función así debería aceptar un argumento: el índice de una vela, qué color necesita determinar, y volver al color; una variable del tipo bool. Imaginemos que la función se escribe y la activamos:

bool color; // here will be the color of a wanted candlestick
 
color = GetColor(0);

Cómo habrá supuesto, la función se llama GetColor. En esta función de llamada, queríamos encontrar el color de la última vela. Por eso el único argumento es igual a cero. La función vuelve al color de la vela, por lo que hacemos los encargos uno a uno. ¡Es un momento muy importante! Se crea una variable dentro de la función, luego su valor se colocará en la llamada de la función. Finalmente, la llamada de la función y el código determinante de la función, descrito arriba, darán el mismo resultado: el color de la variable contendrá el color de la última vela, pero utilizando las funciones se necesita menos esfuerzo.

Y ahora volvamos al código de un script vacío. El hecho es que ya contiene una descripción completa de la función start(). ¡Lo más interesante es que todo este tiempo ha estado escribiendo scripts en esta función! Cuando inicie su script, la terminal activará la función start(). Examinemos el código de un script vacío:

int start()

¡Esto es muy importante! Incluye el nombre de la función, por ejemplo, una palabra clave que escribirá para activar esta función. En este caso es "start". También contiene el tipo del valor de retorno: int. Significa que cuando la función deje de ejecutarse, devolverá algunos valores del tipo int. Los grupos contienen una lista de argumentos, pero en este caso, la función no acepta ningún parámetro.

Luego, en los bracers se ve la descripción de la función, por ejemplo, un código que se ejecutará al llamar a la función.

{
    //----
    // a code that will be performed 
    // at the function call.
    //----
    return(0);
  }

Queda claro que se escribe un código en el cuerpo de la función start(). Al final de la función, veremos el retorno del operador, que devuelve los valores de la función. En este caso devuelve cero.

Ahora mire a la apariencia general de la función de escritura:

[type of return value] [function name] ([list of arguments])
  {
    // function code
    return([a value, which the function returns]);
  }

Ahora volvamos a las velas y a la función GetColor. Mire el código de esta función:

bool GetColor(int index)
  {
    bool color;
    if(Close[index] > Open[index])
        color = true;      // white candlestick
    if(Open[index] > Close[index])
        color = false;     // black candlestick
    return(color);
  }

Vamos a permanecer en la primera línea:

bool GetColor(int index)

Tenemos: bool: tipo de un valor de retorno; GetColor: nombre de la función; int: tipo de argumento; index: nombre del argumento. Dese cuenta de que usamos index dentro del cuerpo de la función, pero en la llamada de la función este nombre no se menciona nunca. Por ejemplo:

bool lastColor = GetColor(0);

Entonces:

{
   bool color;
   if(Close[index]>Open[index])
       color=true;      // white candlestick
   if(Open[index]>Close[index])
       color=false;     // black candlestick

El cuerpo de esta función es un código general, que se ejecutará en cada llamada de la función. Después:

return(color);
}

El operador retorno indica qué función debería volver. El valor de retorno debería corresponderse con el tipo determinado al principio. Si lo necesita, puede utilizar varios operadores retorno en una función, por ejemplo:

bool GetColor(int index)
  {
   if(Close[index] > Open[index])
       return(true);      // white candlestick
   if(Open[index] > Close[index])
       return(false);     // black candlestick
  }

Queda claro que el uso de varios operadores retorno permite evitar la variable color. Además, en el operador retorno puede utilizar incluso expresiones lógicas.

return(Close[index] > Open[index]);

Es posible, porque el operador de comparación también devuelve variables de tipo bool (verdaderas o falsas) como algunas de las otras funciones comunes. Parece complicado, pero se acostumbrará pronto.

Volvamos a la lista de argumentos. En nuestra función sólo se utiliza el argumento int index. Si necesita utilizar varios argumentos, enumérelos separados por una coma:

bool SomeСomplicatedFunction(int fistArgument, int secondArgument, 
                             sting stringArgument)

Para hacer referencia a los argumentos, utilice sus nombres como en la función anterior. Cuando una llamada de función tenga varios argumentos, preste atención al orden de la secuencia de argumentos: ¡no mezcle nada! En el caso de que la función no deba devolver ningún valor, utilice la palabra clave nulo para indicarlo. Tenga en cuenta que el operador retorno no se usa en este caso.

void function()
  {
    // code
  }

Un detalle más: muede establecer los valores para los argumentos de las funciones por defecto. ¿Qué quiere decir esto? Imagine que ha escrito una función compleja que incluye 5 argumentos que influyen en su comportamiento. Pero varios de los últimos argumentos casi siempre se usan con los mismos valores. Por sólo dos docenas de llamadas de función necesita utilizar diferentes valores. Para tener que indicar cada vez los valores de los últimos argumentos, que casi siempre son los mismos, se utilizan los valores por defecto. En tal caso, sólo tiene que omitir los últimos argumentos, como si no existieran, aunque en realidad se están utilizando, pero los valores se asignan por defecto. Cuando se encuentre con ese caso especial, indique todos los argumentos. Veamos cómo se puede declarar una función con argumentos por defecto:

void someFunction(int argument1, int argument2, 
                  int specialArgument = 1)
  {
    // code
  }

Como ve, todo es muy fácil: se asigna un valor necesario a un argumento necesario, y ya se puede omitir en la llamada de la función.

someFunction(10,20);   // we omitted the last argument, but 
                       // actually it is assigned a value by default
 
someFunction(10,20,1); // this activation is fully identical to the previous one
 
someFunction(10,20,2); // here we indicate another value,  
                       // it is a rare case

Puede indicar tantos valores por defecto de los argumentos como quiera. Pero recuerde una norma importante: todos deben colocarse al final. Por ejemplo:


void someFunction(int argument1, int argument2, 
                  int specialArgument = 1)   // all right
 
void someFunction(int argument1, int argument2 = 10, 
                  int specialArgument=1)     // all right
 
void someFunction(int argument1, int argument2 = 10, 
                  int specialArgument)     // wrong! default
                                           // values must stay
                                           // at the end of the 
                                           // list of arguments
                                                                           
void someFunction(int argument1 = 0, int argument2 = 10, 
                  int specialArgument = 1) // you can assign  
                                           // default values  
                                           // to all arguments

Gamas multidimensionales

Durante la programación utilizará gamas a menudo, y en la mayoría de los casos, las unidimensionales serán suficientes. Pero en algunos casos necesitará gamas bidimensionales o tridimensionales. Ahora aprenderá a utilizarlas.

Para empezar, vamos a mostrar las gamas unidimensionales actuales, a revisar la declaración, inicialización, índices y valor:


Cualquier gama unidimensional se puede presentar como una fila de valores de un tipo. Mire cómo se procesarán las diferentes referencias a una gama unidimensional.



Las gamas bidimensionales son como tablas comunes, mire:


Como se ve en la imagen, las gamas bidimensionales ya tienen dos índices como referencia al valor: el primer índice determina una fila; el segundo índice, una columna. Como las ganas unidimensionales, para la inicialización se utiliza una lista de valores. Así es como se mencionan los valores de las celdas de la tabla:




Como puede ver, está todo claro. Veamos cómo podemos pasar por todos los valores de una gama bidimensional. Se deben utilizar dos ciclos:

int array2D[3][3]={10,20,30,
                   40,50,60,
                   70,80,90};
 
for(int y=0;y<3;y++)
   for(int x=0;x<3;x++)
      MessageBox("array2D["+y+"]["+x+"]="+array2D[y][x]);

En este ejemplo a referencia va hacia abajo de derecha a izquierda. Sólo como entrenamiento, intente cambiar la dirección, por ejemplo, hacia arriba.

Las gamas tridimensionales sólo se diferencian en la presencia de un índice más como referencia de los valores de las celdas. Una gama tridimensional se puede presentar fácilmente como varias tablas (gamas bidimensionales). Así es cómo se puede pasar por todos los elementos de una gama tridimensional.

int array3D[3][3][3] = {11, 12, 13,
                        14, 15, 16,
                        17, 18, 19,
 
                        21, 22, 23,
                        24, 25, 26,
                        27, 28, 29,
 
                        31, 32, 33,
                        34, 35, 36,
                        37, 38, 39};
 
for(int z = 0; z < 3; z++)
    for(int y = 0; y < 3; y++)
        for(int x = 0; x < 3; x++)
            MessageBox("array3D["+z+"]["+y+"]["+x+"]=" + 
                       array3D[z][y][x]);

Estudiar a fondo las gamas bi y tridimensionales es muy importante. Una vez más, preste mucha atención a las imágenes explicativas. Hay muchas tareas diferentes que se solucionan utilizando gamas, así que invierta el tiempo suficiente en ellas y podrán serle muy útiles en un futuro. Si entiende lo básico del trabajo con gamas, no tendrá problemas trabajando con gamas de cualquier dimensión.


Algunas funciones para trabajar con gamas

Empecemos con funciones simples.

int ArraySize(object array[]);

Esta función devuelve la cantidad de elementos que tenga la gama. Funciona con todos los tipos. Por ejemplo:

// create two different arrays
int arrayInt[] = {1, 2, 3, 4};           
double arrayDouble[] = {5.9, 2.1, 4.7};
// here store the amount of elements 
int amount;                        
 
amount = ArraySize(arrayInt);      // note: 
                                   // to define a specific 
                                   // array, you need to indicate
                                   // only its name.
                                   // Now amount is equal to 4
 
 
amount = ArraySize(arrayDouble);   // amount is equal to 3

Siguiente función:

int ArrayInitialize(object array[],double value);
ArrayInitialize

le asigna un valor a todos los elementos de la gama, devuelve la cantidad de elementos a los que se les asignó un valor. Utilice esta función con gamas de tipo int y doble.


Siguiente:

int ArrayMaximum(double array[], int count = WHOLE_ARRAY, 
                 int start = 0);
int ArrayMinimum(double array[], int count = WHOLE_ARRAY, 
                 int start = 0);

Estas dos funciones devuelven el índice de un valor de celdda mínimo y máximo. Para usarlos, sólo tiene que indicar en qué gama deberían buscarse.

int array[] = {10, 100, 190, 3, 1};
// will be returned 1, because array[1] - maximal value
ArrayMaximum(array);
// will be returned 4, because array[4] - minimal value
ArrayMinimum(array);

Siguiente:

int ArrayDimension(object array[]);

Utilizando estas funciones, puede determinar la dimensionalidad de una gama, es decir, puede determinar si es unidimensional, bidimensional o de cualquier otra dimensión. Por ejemplo:

int array1D[15];
int array4D[3][3][3];
 
ArrayDimension(array1D); // get 1
ArrayDimension(array3D); // 3

Aquí hay funciones más complicadas y útiles:

int ArraySort(double&array[], int count = WHOLE_ARRAY, int start = 0,
              int sort_dir = MODE_ASCEND);

Esta función clasifica los elementos. Si no indica directamente los argumentos por defecto, por ejemplo así:

int array[5] = {1, 10, 5, 7, 8};
 
ArraySort(array);

los elementos deben clasificarse de manera ascendente. Puede utilizar parámetros adicionales para especificar el comportamiento de la función.

  • int count - el número de elementos que deben clasificarse
  • int start - el índice de un elemento desde el que debería empezar la clasificación
  • int sort_dir - la dirección de la clasificación (ascendente: MODE_ASCEND; o descendiente: MODE_DESCEND)

Aquí debería preguntarse: ¿qué es MODE_ASCEND y MODE_DESCEND? Según int, ¡debe ser un número entero! Tranquilo, todo se aclarará en la siguiente parte: "Preprocesador". Por ejemplo, si necesita clasificar 5 elementos empezando por el segundo, indique algo así:

ArraySort(array, 5, 1, MODE_DESCEND);

Y la última función de hoy:

int ArrayCopy(object&dest[], object source[], int start_dest = 0,
              int start_source=0, int count=WHOLE_ARRAY);

Se usa para copiar una gama a otra. Veamos los parámetros obligatorios:

  • dest[]: en qué gama copiar
  • source[]: desde qué gama copiar

Parámetros opcionaes:

  • start_dest: índice del elemento de una gama en el que se realiza la copia.
  • start_source: índice del elemento de una gama desde el que se realiza la copia.
  • int_count: la cantidad de elementos a copiar.

La función devuelve la cantidad de elementos copiados. Utilice ArrayCopy con mucho cuidado: asegúrese de que las gamas tiene la capacidad suficiente cuando copie algo en ellas.


Preprocesador

¿Qué es esto? El preprocesador es un mecanismo especial destinado al procesamiento del código fuente. Es decir, primero el preprocesador prepara un código y luego lo convierte para la recopilación. Hoy aprendemos una opción más útil: constantes.

¿Cuál es el objetivo principal? Para comprender esto, recordemos un ejemplo sobre switch:

switch(marketState)
  {
    case 1:
    // trading strategy for an uptrend
    break;
 
    case 2:
    // strategy for a downtrend
    break;
 
    case 3:
    // strategy for a flat
    break;
 
    default:
    // error: this state is not supported!
    break;
  }

En esta parte, activamos un mecanismo que actúa de diferentes maneras según el estado del mercado. ¿Recuerda? Así que sería más fácil y descriptivo escribir algo como TREN_UP, TREND_DOWN, FLAT, etc., en lugar de 1, 2 y 3.

switch(marketState)
  {
    case TREND_UP:
    // trading strategy for an uptrend
    break;
 
    case TREND_DOWN:
    // strategy for a downtrend
    break;
 
    case FLAT:
    // strategy for a flat
    break;
 
    default:
    // error: this state is not supported!
    break;
  }

En este caso, el código fuente parece más fácil de comprender y más vívido, ¿verdad? Entonces, las constantes permiten sustituir TREND_UP, TREND_DOWN y FLAT por los valores 1, 2 y 3 correspondientes antes de la recopilación. Todo lo que necesita es indicar qué debería cambiar el preprocesador. Se hace a través de las directivas del preprocesador, que se inician desde un símbolo especial, "#" Las directivas del preprocesador deberían colocarse en el principio de un archivo fuente junto a otras directivas. Miremos un ejemplo completo de uso de constantes:

//+------------------------------------------------------------------+
//|                                                 preprocessor.mq4 |
//|         Copyright © 2007, Antonio Banderass. All rights reserved |
//|                                               banderassa@ukr.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Antonio Banderass. All rights reserved"
#property link      "banderassa@ukr.net"
 
#define TREND_UP   1
#define TREND_DOWN 2
#define FLAT       3
 
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
   MessageBox("TREND_UP=" + TREND_UP + " TREND_DOWN=" + TREND_DOWN + 
              " FLAT=" + FLAT);
 
   return(0);
  }

Tenga en cuenta que se han colocado la declaración de constantes al principio del archivo, bajo otras directivas del preprocesador. Examinemos la declaración más de cerca:

#define TREND_UP 1

Primero se escribe la palabra clave #define. Le muestra al preprocesador que, tras eso, viene la declaración de constante. Luego se escribe el nombre de la constante, su identificador, es decir, una palabra con la que se referirá al valor de la constante. En este caso es TREND_UP. Después viene el valor - 1. Ahora, cuando el procesador vea TREND_UP en el código fuente, lo remplazará por 1, y es igual con las otras constantes. Aquí está el código fuente de nuestro ejemplo antes de ser procesado por un preprocesador:

int start()
  {
   MessageBox("TREND_UP=" + TREND_UP + " TREND_DOWN=" + 
              TREND_DOWN + " FLAT=" + FLAT);
   return(0);
  }

y después:

int start()
  {
   MessageBox("TREND_UP=" + 1 + " TREND_DOWN=" + 2 + 
              " FLAT=" + 3);
   return(0);
  }

Ahora debería entender lo que significan los MODE_ASCEND y MODE_DESCEND de la parte anterior del artículo. Son constantes con sus valores correspondientes.



Conclusión

Ha aprendido mucho material nuevo en este artículo: un nuevo tipo de ciclo: while; un nuevo tipo de condición: switch; los operadores break y continue. Ha aprendido a escribir funciones propias y a trabajar con gamas multidimensionales. Ha aprendido a utilizar constantes. Todo esto es su instrumento principal, una base para escribir elementos más avanzados, como los indicadores de usuario o los asesores expertos. Por eso tiene que asegurarse que ha estudiado a fondo el material de este artículo, porque es muy importante y lo usará constantemente en el futuro.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/1483

Archivos adjuntos |
preprocessor.mq4 (0.86 KB)
Trading automatizado atípico Trading automatizado atípico
Trading eficaz y cómodo con la plataforma MT4 sin análisis detallado del mercado: ¿es posible? ¿Se puede llevar a cabo un trading así? Supongo que sí. ¡Especialmente en términos de trading automatizado!
La contribución de Thomas DeMark al análisis técnico La contribución de Thomas DeMark al análisis técnico
En el artículo se describen los puntos TD y las líneas TD, inventados por Thomas DeMark. Se muestra su uso en la práctica. Asimismo, se demuestra el proceso de escritura de tres indicadores y dos expertos que usan las idea de Thomas DeMark.
Representación gráfica de las pruebas: Gráficos de estados de las cuentas Representación gráfica de las pruebas: Gráficos de estados de las cuentas
Disfrute del proceso de prueba con gráficos que muestran el balance: ¡ahora toda la información necesaria está siempre a la vista!
Se ha añadido a MetaTrader 5 el sistema de cobertura de registro de posiciones Se ha añadido a MetaTrader 5 el sistema de cobertura de registro de posiciones
Para ampliar las posibilidades de los tráders de divisas fórex, se ha añadido a la plataforma un segundo sistema de registro: la cobertura. Ahora puede haber multitud de posiciones de un instrumento, incluidas las posiciones opuestas. Esto hace que sea posible poner en práctica estrategias de negociación con el llamado bloqueo, si el precio va en contra del tráder, este tiene la posibilidad de abrir una posición en la dirección opuesta.