English Русский 中文 Deutsch 日本語 Português
Cómo funcionan las órdenes en los programas complejos

Cómo funcionan las órdenes en los programas complejos

MetaTrader 4Ejemplos | 28 enero 2016, 12:24
2 057 0
Сергей Ковалев
Сергей Ковалев


Si una estrategia de trading trabaja con una cantidad pequeña de órdenes, por ejemplo, una orden de compra y una orden de venta, el experto que implementa dicha estrategia no tiene por qué almacenar las ordenes. Tan solo toma decisiones de trading basándose en su propia lógica, por ejemplo, colocar una orden que siempre va en una dirección determinada.

Esta aproximación es aceptable pero solo sirve en programas pequeños, no se puede considerar universal. ¿Qué haría tal asesor experto si hubiera dos o más órdenes con el mismo símbolo? Es posible que dicha estrategia de trading no tenga en cuenta esa situación, y por tanto no ocurra. Lo anterior revela en cierto modo las debilidades y las limitaciones de esta concepción.

En cuanto el trader tiene experiencia suficiente para operar con varias órdenes, incluyendo las pendientes, tiene que tener en cuenta todas las órdenes, puesto que las órdenes pendientes se pueden convertir en órdenes abiertas. Por otra parte, los traders siempre pueden abrir una orden manual en el terminal. También es posible que varios traders operen con la misma cuenta. Y en un caso más general, hay estrategias de trading que implican el uso de una gran cantidad de órdenes.

Veamos ahora algunos detalles acerca de la gestión de las órdenes en los programas extensos.


1. Generalidades y características del entorno

Describamos brevemente las características del entorno donde trabaja nuestro programa.

1. En primer lugar, queremos saber qué órdenes tenemos, y cuántas; considerando que el programa recopila los datos. No basta con decir que tenemos, por ejemplo, tres órdenes de venta y cuatro órdenes de compra. El algoritmo de una estrategia de trading inteligente controla las características de la orden, esto es, los niveles de StopLoss y TakeProfit, y el OpenPrice de las órdenes pendientes. Además, necesitamos saber cuánto cuesta cada orden, cuál es su fecha de vencimiento, y qué programa la ha colocado.

2. Ticks. La información tiene sentido dentro del contexto del marco temporal correspondiente. Por otro lado, los asesores expertos trabajan con las cotizaciones que entran en el terminal cliente. Así pues, evidentemente, el estado de las órdenes puede cambiar cuando se produce un cambio en el precio, lo que significa que las órdenes se tienen que "reconsiderar" en cada tick.

3. El símbolo del experto asociado a una ventana se puede incluir en las "características generales".

Basándonos en todo esto podemos determinar los principios generales que rigen el desarrollo del programa.

Primero de todo, el sistema de trading debe solucionar varios problemas; por ejemplo, tiene que analizar la disponibilidad y la calidad de las órdenes y tomar decisiones con esos datos. Conociendo la situación actual se pueden hacer análisis. Esto significa que el código del programa que gestiona las órdenes se tiene que ejecutar antes que otros códigos. Lo mejor que podemos hacer es pues encapsular dicho código en una función separada. Llamémosla Terminal(), puesto que su tarea principal consiste en monitorizar las órdenes del terminal.

En segundo lugar, los datos recogidos por la función Terminal() tienen que estar disponibles en otras funciones. Por esta razón las variables que contienen información de las órdenes deben declararse a nivel global (no confundir con GlobalVariables).

En tercer lugar, puesto que trabajamos con conjuntos de información, es lógico organizar los datos en arrays de órdenes.


2. Estructura del programa

Con el razonamiento anterior ya podemos diseñar la estructura del programa que gestiona las órdenes:

// My_expert.mq4
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
#include ...
#include <Peremen.mq4>    // Descripción de las variables del experto.   
#include <Terminal.mq4>   // Adjuntamos la función del Terminal.
#include <Sobytiya.mq4>   // Adjuntamos la función Sobytiya.
#include ...
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//
// 
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int init()  
   {
   ...                    // Código de la función init()
   return;
   } 
//=================================================================
int start() 
   {
   Terminal();            // Esta función es la primera de 
                          // la secuencia de funciones
   ...                    // El código de la función start() posterior
   Sobytiya();            // Función de procesamiento de eventos
   ...                    // El código de la función start() posterior
   return;                                                                 
   }
//=================================================================
int deinit() 
   {   
   ...                    // Código de la función deinit()
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж


El archivo Peremen.mq4 describe las variables, y contiene la descripción de los arrays de las órdenes.
//  Peremen.mq4
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//==================================================================
int
...
//==================================================================
double
...
Mas_Ord_Tek[31][8], Mas_Ord_Old[31][8], 
// arrays de órdenes actual y antiguo
// el 1er índice = el número de orden en este array
// [][0] no definido
// [][1] precio de apertura de la orden (valor absoluto del precio)
// [][2] órdenes StopLoss (valor absoluto del precio)
// [][3] órdenes TakeProfit (valor absoluto del precio)
// [][4] número de orden        
// [][5] lotes de la orden (valor absoluto del precio)
// [][6] tipo de orden 1=B,2=S,3=BL,4=SL,5=BS,6=SS
// [][7] Número mágico de la orden
...
//=================================================================
string 
...
//=================================================================
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

Cuando se definen variables globales en programas pequeños, estas se escriben generalmente antes de la primera función. En los programas grandes y de tamaño medio las variables globales se agrupan en un archivo que luego se asocia al experto por medio de la instrucción #include. Las diferencias existentes entre estos métodos no importa en términos de eficiencia del código, pero en términos de usabilidad es preferible adjuntar el archivo. A continuación mostramos cómo adjuntar el archivo Peremen.mq4 al experto del ejemplo anterior.


3. Arrays

En el archivo Peremen.mq4 se definen dos arrays como variables globales:

Mas_Ord_Tek[31][8] - el array de órdenes actual;

Mas_Ord_Old[31][8] - el array de órdenes antiguo.

¿Por qué necesitamos dos arrays, y no solo uno? Esto es para poder monitorizar los eventos. Un poco más adelante describiremos los eventos, de momento, diremos que un evento queda definido por la comparación de su estado inicial con su estado actual. Si no hay datos sobre el estado, es imposible identificar un evento. En cuyo caso se utilizan los arrays de órdenes para informar sobre el estado del espacio de trading, antes y después del tick.

¿Por qué utilizamos un array 2D? Porque vamos a trabajar con varias órdenes simultáneamente, y guardaremos las características de cada una de ellas. El primer índice es el número de orden en el array; el segundo es la característica de la orden bajo un criterio determinado. En el ejemplo anterior, el primer índice no permite que haya más de 30 órdenes disponibles en el terminal. Pero usted puede cambiar esta cantidad como desee, permitiendo por ejemplo 50 o 100 órdenes simultáneas en el terminal. Por supuesto, esto tiene sentido solo si su sistema de trading está diseñado para trabajar con tal cantidad de órdenes. En condiciones normales suele haber una o dos posiciones, rara vez hay cuatro. En mi opinión, 30 son demasiadas.

¿Por qué los arrays tienen índices 31 y 8, en lugar de 30 y 7? Esto es porque los índices de los arrays MQL4 comienzan con el cero. No siempre se justifica el uso del cero en los elementos comunes. En mi opinión, lo más lógico es que el número de la orden se corresponda con el número del elemento en el array, por ejemplo, la tercera orden tendría que colocarse en la posición 3. De hecho, esta posición es la cuarta, pero el índice es 3 porque la primera posición es 0.

Echemos un vistazo a la siguiente tabla que muestra el interior de los arrays. Supongamos que solo hay tres órdenes: Buy, Sell y BuyStop:


La información de las órdenes se coloca en las posiciones de [1][1] a [7][30]. Por otro lado, pondremos la cantidad total de órdenes del array en la posición [0][0]. En este caso, 3. En los cálculos que se realizan más adelante, este número sirve para organizar los bucles, donde se analiza el estado actual.

Así almacenamos la información de 30 órdenes, cada una de las cuales tiene 7 características.

Si su estrategia de trading opera simultáneamente en varios símbolos, puede abrir varios arrays y ordenarlos de acuerdo a los pares de divisas. Este método es bastante aceptable, pero no muy recomendable. Si las órdenes consideradas se organizan así, hay que abrir otro array que almacene los nombres de los arrays que contienen la información de las órdenes.

Una solución más adecuada consiste en utilizar un array grande (único y nuevo) para todas las órdenes. Es mejor porque cuando el código procesa este array, entonces no hay que buscar los nombres de los arrays de órdenes de símbolos. Basta con organizar en el bucle la búsqueda de una variable numérica formal por uno de los índices del array.

El array que contiene la información de todas las órdenes se organiza de la siguiente manera:


La información de las órdenes de los símbolos se almacena en el mismo plano del índice, como en el ejemplo anterior. La diferencia es que en este caso hay varios planos; en la figura 3 hay tres: amarillo, rosa y verde. La cantidad total es igual a la cantidad de pares de divisas con los que vamos a trabajar, más uno: el cero. En este plano de índice (gris), el único valor, la cantidad total de órdenes se guarda en la celda [0][0][0].

La dimensión del array para, digamos 25 símbolos, será 26 para el primer índice. En este caso el archivo Peremen.mq4 que describe los arrays será como sigue:

//  Peremen.mq4
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//===========================================================================
int
...
//===========================================================================
double
...
Mas_Ord_Tek[26][31][8], Mas_Ord_Old[26][31][8], 
// Los arrays de órdenes actual y nuevo
// el 1er índice = número de símbolo
// el 2º índice = número de orden ...
// ... en el plano del símbolo
// [][][0] no definido
// [][][1] precio de apertura de la orden   (valor absoluto del precio)
// [][][2] órdenes StopLoss                 (valor absoluto del precio)
// [][][3] órdenes TakeProfit               (valor absoluto del precio)
// [][][4] número de orden        
// [][][5] lotes de la orden                (valor absoluto del precio)
// [][][6] tipo de orden 1=B,2=S,3=BL,4=SL,5=BS,6=SS
// [][][7] MagicNumber de la orden
//=================================================================
string 
      Instrument[26];                   // Array de los nombres de los símbolos
...
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//
//
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Predopred()
   {
//================================================= Predefiniciones =
   Instrument[1] = "EURUSD";
   Instrument[2] = "GBPUSD";
   ...
   Instrument[25]= "AUDCAD";
//==================================================================
   return();
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

El array Instrument[26] se abre al final del bloque de apertura de variables.

Los programas extensos suelen tener muchas variables cuyo valor no cambia durante la ejecución del programa. En nuestro caso estos son los elementos del array Instrument[]. Para que la programación sea más cómoda, es mejor agrupar dichas variables en una función. Esta función puede crearse en un archivo separado que luego se incluirá en el programa con la directiva #include.

En el siguiente ejemplo los elementos del array Instrument[] se predefinen en la función Predopred(), contenida en el mismo archivo Peremen.mq4. Solo hay que ejecutar esta función una vez, así que es lógico incluirla en el programa en la función especial init():

int init()  
   {
   Predopred();         // Predefinición de algunas variables
   return;
   }
Por consiguiente, el array Instrument[] hace corresponder los índices con los símbolos.


4. Funciones de gestión de órdenes

Analicemos la función Terminal() y echemos un vistazo a las órdenes de un símbolo. Esta función se implementa en un archivo separado llamado Terminal.mq4, y se asocia al Asesor Experto por medio de la instrucción #include.

// Terminal.mq4
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Terminal()
   {
//================================================ Predefinición ==
   ArrayCopy(Mas_Ord_Old, Mas_Ord_Tek);// Guardamos el historial precedente
   int Kol=0;                       // Establecemos a cero el contador de las órdenes
   ArrayInitialize(Mas_Ord_Tek,0);     // Establecemos a cero el array
//=============================================== Análisis de órdenes ==
   for (int i=0; i<OrdersTotal(); i++) 
// Para todas las órdenes del terminal
     {
      if((OrderSelect(i, SELECT_BY_POS)==true) && 
                      (OrderSymbol()==Symbol()))
                        // Si se trata de nuestro par de divisas
       {                                                                     
        Kol++;                   // Contamos el número total de órdenes
//---------------------------  Formación del nuevo array de órdenes --
        Mas_Ord_Tek[Kol][1] = NormalizeDouble(OrderOpenPrice(),
                                              Digits); 
// Precio de apertura de la orden
        Mas_Ord_Tek[Kol][2] = NormalizeDouble(OrderStopLoss(),
                                              Digits); 
// precio SL
        Mas_Ord_Tek[Kol][3] = NormalizeDouble(OrderTakeProfit(),
                                              Digits); 
// precio TP
        Mas_Ord_Tek[Kol][4] = OrderTicket();      // Número de la orden
        Mas_Ord_Tek[Kol][5] = OrderLots();        // Contamos los lotes
        Mas_Ord_Tek[Kol][6] = OrderType();        // Tipo de orden
        Mas_Ord_Tek[Kol][7] = OrderMagicNumber(); // Número mágico 
//-----------------------------------------------------------------
       }
     }
   Mas_Ord_Tek[0][0] = Kol;     // Guardamos la celda cero
//=================================================================
   return();
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

Lo primero que se tiene que hacer después de que el sistema pase el control a la función Terminal(), es guardar el estado anterior de las órdenes. Esto se hace en el array Mas_Ord_Tek[][], pero no es real en ese momento porque refleja el estado de las órdenes formadas en el tick anterior. El estado actual todavía no se conoce en el momento inicial.

En la línea

   ArrayCopy(Mas_Ord_Old, Mas_Ord_Tek); 
// Guardamos la historia precedente

el último estado de órdenes conocido se pasa al array Mas_Ord_Old[][].

La función utiliza la variable local Kol para reflejar la nueva cantidad de órdenes actual. La necesidad de utilizar esta variable surgió en MQL4, no se permite utilizar índices indexados. Como se observa en el código, se utiliza como valor del índice. Establecemos a cero el valor de esta variable, así como el array completo del estado actual, y nos centramos en el estado actual de las cosas.

Para ello implementamos un bucle que llama a todas las órdenes de manera consecutiva, descubriendo sus características.

   for (int i=0; i<OrdersTotal(); i++) 
// Para todas las órdenes del terminal

Nótese lo siguiente: OrdersTotal() determina la cantidad de órdenes. La cuenta del número de órdenes comienza con 0. Por esta razón, el signo " <" se utiliza en la línea del bucle, y el cambio de la variable interna del bucle comienza con cero: i=0.

El código siguiente pone énfasis en la orden del símbolo donde se adjunta el experto. Las funciones que determinan las características de la orden ponen la información obtenida en los elementos correspondientes del array Mas_Ord_Tek[][].

//--------------------------- Formación del nuevo array de órdenes --
       Mas_Ord_Tek[Kol][1] = NormalizeDouble(OrderOpenPrice(),
                                             Digits); 
// Precio de apertura de la orden
       Mas_Ord_Tek[Kol][2] = NormalizeDouble(OrderStopLoss() ,
                                             Digits); 
// precio SL
       Mas_Ord_Tek[Kol][3] = NormalizeDouble(OrderTakeProfit(),
                                             Digits); 
// precio TP
       Mas_Ord_Tek[Kol][4] = OrderTicket();      // Número de orden
       Mas_Ord_Tek[Kol][5] = OrderLots();        // Contamos 
                                                 // los lotes
       Mas_Ord_Tek[Kol][6] = OrderType();        // Tipo de orden
       Mas_Ord_Tek[Kol][7] = OrderMagicNumber(); // Número mágico 
//------------------------------------------------------------------

El contador que se rellena pasa su valor al elemento cero de array, al final del bucle.

   Mas_Ord_Tek[0][0] = Kol;        // Almacenar en la posición cero

Con el objetivo de operar simultáneamente en varios símbolos, la función Terminal() se construye de la siguiente manera:

// Terminal.mq4
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Terminal()
   {
//================================================== Predefiniciones =
   ArrayCopy(Mas_Ord_Old, Mas_Ord_Tek); 
// Guardamos la historia precedente
   ArrayInitialize(Mas_Ord_Tek,0);  
// Establecemos a cero el array de las órdenes actuales
//================================================== Análisis de órdenes =
   for (int i=0; i<OrdersTotal(); i++)  
// Para todas las órdenes del terminal
      {
      if(OrderSelect(i, SELECT_BY_POS)==true) 
// Si hay una orden "viva"
         {
//--------------------------------------- Definición del índice del símbolo -
         string Symb=OrderSymbol();
// Determinamos la divisa de la orden actual
         for (int ind=1; ind<=25; ind++)
// Buscamos en el array de símbolos
            {
            if (Symb==Instrument[ind])
// Índice encontrado, la búsqueda se ha completado
               break;            // Salimos del bucle por el valor ind
            }
//------------------------ Formación del nuevo array de órdenes ----
         Mas_Ord_Tek[0][0][0]++; 
// Contamos la cantidad total de órdenes
         Mas_Ord_Tek[ind][0][0]++; 
// Contamos la cantidad de órdenes de un símbolo
         int k=Mas_Ord_Tek[ind][0][0];   // Variable formal
         
         Mas_Ord_Tek[ind][k][1] = NormalizeDouble(OrderOpenPrice(),
                                                  Digits); 
// Precio de apertura de la orden
         Mas_Ord_Tek[ind][k][2] = NormalizeDouble(OrderStopLoss(),
                                                  Digits); 
// precio SL
         Mas_Ord_Tek[ind][k][3] = NormalizeDouble(OrderTakeProfit(),
                                                  Digits); 
// precio TP
         Mas_Ord_Tek[ind][k][4] = OrderTicket(); // Número de la orden
         Mas_Ord_Tek[ind][k][5] = OrderLots();   // Contamos los lotes
         Mas_Ord_Tek[ind][k][6] = OrderType();   // Tipo de orden
         Mas_Ord_Tek[ind][k][7] = OrderMagicNumber(); // Número
                                                      // mágico 
         
//-----------------------------------------------------------------
         }
      }
//=================================================================
   return();
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

El algoritmo que permite gestionar varios símbolos difiere del de un solo símbolo en un pequeño bloque que determina el índice del símbolo.

//----------------------------------- Definición del índice del símbolo ----
         string Symb=OrderSymbol(); 
// Determinamos la divisa de la orden actual
         for (int ind=1; ind<=25; ind++) 
// Buscamos en el array de símbolos
            {
            if (Symb==Instrument[ind]) 
// Índice encontrado, la búsqueda se ha completado
               break;              // Salimos del bucle por el valor ind
            }

En las líneas consecutivas de la función Terminal() encontramos el valor del índice del símbolo ind determina el índice del plano del array que contiene los datos de las órdenes del símbolo correspondiente.

En los ejemplos anteriores de implementación de función Terminal(), se normaliza el cálculo de algunas variables:

Mas_Ord_Tek[ind][k][1] = NormalizeDouble(OrderOpenPrice(),
                                         Digits); 
// Precio de apertura de la orden
Mas_Ord_Tek[ind][k][2] = NormalizeDouble(OrderStopLoss(),
                                         Digits); 
// precio SL
Mas_Ord_Tek[ind][k][3] = NormalizeDouble(OrderTakeProfit(),
                                         Digits); 
// precio TP

La necesidad de estos cálculos queda determinada por la intención de utilizar los valores normalizados de las variables en los operadores, en futuros cálculos. La cantidad de dígitos válidos se calcula en función de la variable predefinida Digits.

El sistema de trading también puede tener en cuenta otras características de las órdenes. Pero en los anteriores ejemplos, solo se aplican los principios generales de los programas extensos. Por ejemplo no hemos considerado las órdenes cerradas y las órdenes eliminadas, ni algunas características como la fecha de vencimiento de una orden pendiente. Si necesita procesar las características anteriores, reconfigure los arrays para almacenar los datos adicionales. Por ejemplo, puede incrementar la cantidad de los últimos elementos para guardar la hora de vencimiento de las órdenes pendientes.


5. Procesamiento de eventos

Llega un nuevo tick y la función Tеrminal() se dispara. El control se pasa a los operadores situados inmediatamente después de la función Terminal(). No se puede predecir en qué parte de la función especial start() hay que poner la función personalizada de procesamiento de eventos porque esto depende de la idea que hay detrás del sistema de trading en cuestión. En los casos más sencillos los eventos pueden procesarse inmediatamente.

Quisiera recordar que en algunos escenarios específicos el orden esperado de los eventos no se mantiene.

En primer lugar, algunos operadores como los bancos, por ejemplo, cierran de forma forzada todas las órdenes abiertas al final del día, y abren las mismas órdenes al comienzo de la siguiente sesión con precios que difieren del actual en varias decenas de punto. Estas decenas de puntos preparan el swap. El terminal muestra el swap como cero. En términos económicos los operadores no rompen ninguna regla. Pero para nosotros esta situación sí importa porque los números de las nuevas órdenes cambian, difieren por completo de los anteriores.

En segundo lugar, el cierre parcial de una orden separada se implementa en dos fases, en todos los operadores. Primero la orden se cierra completamente. En la segunda fase se abre una orden nueva con el nuevo precio disminuido. El número de la orden inicial está escrito en los comentarios de la nueva orden.

En tercer lugar, ocurre algo parecido cuando una orden se cierra utilizando otra, si estas órdenes tienen precios diferentes. En cuyo caso prácticamente se repite la situación de cierre parcial de una orden.

La única manera de identificar la orden consiste en inicializar esa característica que no cambia, ni se repite. De todas las herramientas que proporciona MQL4, a tal efecto puede se puede utilizar el MagicNumber. Pero incluso en ese caso, el programador no puede evaluar la creación de un control completo sobre la situación. La cuestión es que el MagicNumber no se puede cambiar programáticamente. Por un lado tiene una ventaja indiscutible: podemos afirmar que este parámetro no cambiará, incluso accidentalmente mientras la orden exista. Pero por otro lado, es deseable disponer de un parámetro ajustable al que se pueda acceder desde el programa. En la situación actual no existe tal parámetro. Por lo tanto, si hay una o más órdenes que no se han abierto con nuestro sistema de trading, sino con otro programa, o manualmente, dichas órdenes no se pueden distinguir.

Una alternativa un tanto insuficiente es un identificador único como la hora de apertura de la posición. Pero este criterio no es fiable ni universal, ya que es teóricamente posible que se abran varias órdenes al mismo tiempo (en el mismo segundo). Por ejemplo, si el precio se mueve rápidamente se pueden abrir simultáneamente dos órdenes pendientes en símbolos distintos.

Analicemos la implementación de la función de ejemplo Sobytiya() disponible en el archivo Sobytiya.mq4. Observaremos un evento sencillo, la eliminación o el cierre de una orden. Ya sabemos que el número de la orden no siempre encaja bien con esto, así que analizaremos el número mágico.
// Sobytiya.mq4   
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Sobytiya()
   {
//==================================== Búsqueda de órdenes perdidas ====
   for (int oo=1;oo<=Mas_Ord_Old[0][0];oo++)     
// Tomamos el número de la orden de un array antiguo
      {   
      int Sovpadenie=0; 
// Comenzamos estableciendo a cero los valores
      for (int i=1;i<=Mas_Ord_Tek[0][0];i++)     
// Intentamos encontrar esta orden en el array actual 
         {
         if (Mas_Ord_Tek[i][7]==Mas_Ord_Old[oo][7]) 
// Si el MagicNumber coincide, entonces recordamos que 
// todavía está ahí y salimos del bucle interno
            {
            Sovpadenie=1;
            break; 
            }
         }      
      if (Sovpadenie==1) continue;                  
// Vamos al siguiente array antiguo
      Alert("Orden cerrada ",Mas_Ord_Old[oo][4]);   
// Informamos de esto con una pantalla textual
      PlaySound( "Close_order.wav" );  // Y con sonido.
      }
//=================================================================
   return();
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

El evento se observa fácilmente si dispone de condiciones que lo describen. Solo hay que comparar secuencialmente las órdenes disponibles antes del tick con las disponibles después del tick. Ahí está la diferencia, así como la confirmación de que el evento ha ocurrido.

En el siguiente ejemplo buscamos otro evento, la modificación del tipo de orden. Se aplica el mismo principio pero con otro criterio. Es bastante aceptable para aplicar números de orden y análisis.

// Sobytiya_2.mq4   
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Sobytiya_2()
   {
//============ Búsqueda de órdenes que han cambiado sus tipos ====
   for(int oo=1;oo<=Mas_Ord_Old[0][0]; oo++)               
// Recorremos el array antiguo
      {
      for (int i=1;i<=Mas_Ord_Tek[0][0];i++)               
// Buscamos la orden en el array actual 
         {
         if (Mas_Ord_Tek[i][4] == Mas_Ord_Old[oo][4] &&    
// Si el array antiguo contenía la misma orden pero de otro tipo, 
// entonces: actualizamos la orden pendiente
             Mas_Ord_Tek[i][6] != Mas_Ord_Old[oo][6])      
            {   
            Alert("Orden cambiada",Mas_Ord_Tek[i][4]);
// Informamos de esto con una pantalla textual
            PlaySound("Transform.wav" );   // Y con sonido
            }
         }
      }
//=================================================================
   return();
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

Los eventos se observan en diferentes partes del programa, dependiendo de la idea de trading implementada en el asesor experto. El análisis de los eventos que nos interesan se puede encapsular en un solo archivo. El código tiene que modificarse varias veces para no ejecutar a menudo la búsqueda de arrays, por separado para cada criterio. Es sencillo componer un algoritmo que extraiga el número inicial de los comentarios de la orden cerrada parcialmente, para llevar a cabo un análisis posterior. Para ello, utilice la función OrderComment().

Además de las indicadas anteriormente, hay más características cuyo análisis exhaustivo nos puede ayudar a entender la realidad, y a ahorrarnos trabajo innecesario y errores fatales. Volvamos a los operadores que cierran las órdenes al final del día.

El valor del swap no suele ser divisible por decimales, lo que implica que el precio de apertura de la orden se incrementará en 1. Para tener en cuenta esta característica hay que normalizar este valor con precisión en una unidad más que Digits:
Mas_Ord_Tek[ind][k][1] = NormalizeDouble(OrderOpenPrice(),
                                         Digits+1); 
// Precio de apertura de la orden

Esta situación es notable porque puede cambiar el estado del precio de apertura de la orden. Si un trader opera con un sistema que toma decisiones relacionadas con el precio de apertura de la orden, dicho sistema se derrumbará al final del día. Tras un vistazo más exhaustivo, ¡llegaremos a la conclusión que el precio de apertura de la orden es irrelevante! El factor importante es la tendencia que señala el desarrollo de la situación; si va contra nosotros debemos cerrar la orden, esté donde esté.

El debate sobre los criterios que afectan a las decisiones de trading queda fuera del alcance de este artículo. Elegir adecuadamente los criterios que utiliza el programa es un factor clave en cualquier estrategia de trading.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1390

Eventos en MetaTrader 4 Eventos en MetaTrader 4
En este artículo vamos a tratar el seguimiento programado de eventos en el Terminal Cliente MetaTrader 4, tales como la apertura, el cierre y la modificación de órdenes. Se dirige a los usuarios que tienen unos conocimientos básicos en programación MQL 4 y ya saben manejar el terminal.
Trabajando con archivos. Un ejemplo de visualización de eventos importantes del mercado Trabajando con archivos. Un ejemplo de visualización de eventos importantes del mercado
Este artículo explica cómo se puede trabajar de forma más productiva con MQL4 en los mercados FOREX.
Cómo evaluar los resultados de los Asesores Expertos Cómo evaluar los resultados de los Asesores Expertos
El presente artículo explica el funcionamiento del Informe de pruebas de MetaTrader 4, mostrando los cálculos realizados.
AutoGraf, un Asesor Experto Gráfico AutoGraf, un Asesor Experto Gráfico
Este artículo explica cómo funcionan los gráficos en la creación de una interfaz para gestionar el trading de manera adecuada.